Posts tagged WCF

Presenting on OData and WCF 4 at St Louis Day of .NET

If you haven’t registered, you should join the 600+ people who have registered for the 2010 St Louis Day of .NET, making this our biggest year yet!

I will have two presentations that are scheduled for both days of the conference.  Kicking off the morning with the JumpStart series, I will be delivering the WCF 4 JumpStart.  In this session we’ll cover the basics of WCF 4: What’s new/changed from 3.5, REST Support, the Routing Service and Deployment to IIS on multiple bindings (BasicHttp, Rest, and Net.Tcp).

The OData talk will be the same one I have delivered at Iowa Code Camp and the St Louis .NET Users Group.  If you haven’t seen the session covers the basics of OData, how to query OData sources, and finally we’ll build an OData service following the Hanselman Stackoverflow Challenge.

Beyond my small contributions there are over a 100 great sessions to look for.  Check out the agenda, our speakers, and try out the schedule builder to build a personalized schedule!

The Protocol ‘Net.Pipe’ is not supported–WCF/IIS7/WAS

Want to host a WCF service using the NetNamedPipeBinding?  I did too.  Except IIS told me I couldn’t.  After some frustrated Bing’ing and Googl’ing I found my answer.

This article on MSDN outlines how to enable Net.Pipe in IIS7.  First you must enable the binding for the IIS site you are hosting the service in using this command (each command goes on a single line):

%windir%\system32\inetsrv\appcmd.exe set site "{YOUR_SITE_NAME}" -+bindings.protocol=’net.pipe’,bindingInformation=’*']

You can also accomplish this in the IIS Manager.  Click on the site you want to enable Net.Pipe on, then click “Bindings”:

image

Select net.pipe from the list and in the Binding Information put an asterisk “*” (no quotes)
image

Click OK and you’re done.  Using the IIS manager or the appcmd.exe will have the same effect.

Next we need to allow Net.Pipe for the virtual directory your service will be hosted in.

c:\windows\system32\inetsrv\appcmd.exe set app "{YOUR_SITE_NAME}/{Virtual_Directory"}" /enabledProtocols:http,net.pipe

This can be accomplished in the IIS Manager as well.  Click on the virtual directory you want to add net.pipe to and then click “Advanced Settings…”

image

Next, in the enabled protocols box add the protocols you want, separating them with a comma.
image

Click OK and you’re done.  Using the IIS manager or the appcmd.exe will have the same effect.

Once you have completed both these steps you should now be able to access your service over Net.Pipe after configuring the binding in your WCF service config.

Pretty URIs in WCF Data Services – Lose the .svc File

I’m still testing this, but, it looks like in .NET 4 you will be able to use the new URL Routing to lose the .svc file in your WCF Data Services.

Step-by-step

Follow the standard steps for creating a WCF Data Service.

  • Create a new, “Empty ASP.NET Web Application”
  • Add an Entity Data Model

Once you have your entity data model, add a new class, derive it from DataService<T> where T is the entity set you created in the previous steps:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Services;
using System.Data.Services.Common;

namespace ODataSample
{
    public class ProductService : DataService<AdventureWorksLT2008Entities>
    {
        public static void InitializeService(DataServiceConfiguration                                                  config)
        {
            config.DataServiceBehavior.MaxProtocolVersion =                  DataServiceProtocolVersion.V2;
            config.SetEntitySetAccessRule("Products",                 EntitySetRights.AllRead);
            config.SetEntitySetPageSize("Products", 20);
        }
    }
}

Add a Global Application Class (global.asax).  In the Application_Start method add the following snippet:

RouteTable.Routes.Add(new ServiceRoute("ProductCatalog", new WebServiceHostFactory(), typeof(ProductService)));

If all is well you should be able to hit F5 to debug.  Since there is not a default page you’ll have to add the route name you specified onto the end of the URI.  If all goes well you should see:

image

In my testing thus far it appears everything works as you’d expect in terms of appending on query parameters, etc. 

image

image

Redirecting From a WCF REST Service

REST is based on HTTP and revolves around using the standard HTTP verbs GET, POST, PUT as well as standard HTTP error codes.  The error codes that have to do with redirection are in the 300 block.  Today we’ll focus on 302 which is the status code for a redirection (other 300 codes, such as 301 indicate that the URI moved permanently).

The following code will redirect the client with a 302 status code:

WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.Redirect;
WebOperationContext.Current.OutgoingResponse.Location = "/someOtherPage.aspx";
return null; 

For an additional measure we’ll return null as well so that there is no output emitted to the client.  The end result will be that the headers include the 302 status code, the location to redirect to and the body of the response will be empty.

Drop the Soap: WCF, REST, and Pretty URIs in .NET 4

Years ago I was working in libraries when the Web 2.0 revolution began.  One of the things that caught my attention about early start-ups using the AJAX/REST/Web 2.0 model was how nice the URIs were for their applications.  Those were my first impressions of REST; pretty URIs.  Turns out there is a little more to it than that.

REST is an architectural style that focuses on resources and structured ways to access those resources via the web.  REST evolved as an “anti-SOAP” movement, driven by developers who did not want to deal with all the complexity SOAP introduces (which is al lot when you don’t have frameworks hiding it all).  One of the biggest benefits to REST is that browsers can talk to rest services directly because REST works using URIs, QueryStrings, Cookies, SSL, and all those HTTP verbs that we don’t have to think about anymore.

If you are familiar with ASP.NET MVC then you have been exposed to rest at some level.  MVC is relies heavily on routing to generate consistent and clean URIs.  REST for WCF gives you the same type of feel for your services.  Let’s dive in.

WCF REST in .NET 3.5 SP1 and .NET 4

This post will cover WCF REST in .NET 4 which drew heavily from the REST Starter Kit and community feedback.  There is basic REST support in .NET 3.5 SP1 and you can also grab the REST Starter Kit to enable some of the features you’ll find in .NET 4.

This post will cover REST in .NET 4 and Visual Studio 2010.

Getting Started

To get started we’ll create a basic WCF Rest Service Application using the new on-line templates option in VS 2010:

image

When you first install a template you are prompted with this dialog:

image

Dude Where’s my .Svc File?

The WCF REST template shows us the new way we can simply build services.  Before we talk about what’s there, let’s look at what is not there:

  • The .Svc File
  • An Interface Contract
  • Dozens of lines of configuration that you have to change to make your service work

REST in .NET 4 is greatly simplified and leverages the Web Routing capabilities used in ASP.NET MVC and other parts of the web frameworks.  With REST in .NET 4 you use a global.asax to set the route to your service using the new ServiceRoute class.  From there, the WCF runtime handles dispatching service calls to the methods based on the Uri Templates.

global.asax

using System;
using System.ServiceModel.Activation;
using System.Web;
using System.Web.Routing;

namespace Blog.WcfRest.TimeService
{
    public class Global : HttpApplication
    {
        void Application_Start(object sender, EventArgs e)
        {
            RegisterRoutes();
        }

        private static void RegisterRoutes()
        {
            RouteTable.Routes.Add(new ServiceRoute("TimeService",
                new WebServiceHostFactory(), typeof(TimeService)));
        }
    }
}

The web.config contains some new structures to support a configuration free deployment.  Note that this is the default config generated with the template.  I did not make any changes to web.config.

web.config

<?xml version="1.0"?>
<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>

  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule,
           System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    </modules>
  </system.webServer>

  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
    <standardEndpoints>
      <webHttpEndpoint>
        <!--
            Configure the WCF REST service base address via the global.asax.cs file and the default endpoint
            via the attributes on the <standardEndpoint> element below
        -->
        <standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true"/>
      </webHttpEndpoint>
    </standardEndpoints>
  </system.serviceModel>

</configuration>

Building the Time Service

We’ll create a simple “TimeService” that will return the current time.  Let’s start with the following code:

using System;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;

namespace Blog.WcfRest.TimeService
{
    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class TimeService
    {
        [WebGet(UriTemplate = "CurrentTime")]
        public string CurrentTime()
        {
            return DateTime.Now.ToString();
        }
    }
}

The endpoint for this service will be http://[machinename]:[port]/TimeService.  To get the current time http://[machinename]:[port]/TimeService/CurrentTime will do the trick.

The Results Are In

image

Remember That Route In global.asax?

Turns out it is pretty important.  When you set the route name, that defines the resource name starting after the host portion of the Uri. 

image

Help Pages in WCF 4

Another feature that came from the starter kit are the help pages.  To access the help pages simply append Help to the end of the service’s base Uri.

image

image

Dropping the Soap

Having dabbled with REST in the past and after using Soap for the last few years, the WCF 4 REST support is certainly refreshing.  I’m currently working on some REST implementations in .NET 3.5 and VS 2008 and am looking forward to working on REST in .NET 4 and VS 2010.

WCF 4 – Loosening the Chains of Configuration

If you have spent anytime in WCF land the first thing you learn about is the joys of configuration.  For the coming release of .NET 4 and WCF 4 the team heard that feedback and has made configuration much easier for the development experience.

Let’s take a look at what’s changed:

Sample 1 – WCF Configuration on .NET 3.5 SP1

  <system.serviceModel>
    <services>
      <service name="WcfServiceConfig35.Service1" behaviorConfiguration="WcfServiceConfig35.Service1Behavior">
        <!-- Service Endpoints -->
        <endpoint address="" binding="wsHttpBinding" contract="WcfServiceConfig35.IService1">
          <!--
              Upon deployment, the following identity element should be removed or replaced to reflect the
              identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity
              automatically.
          -->
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="WcfServiceConfig35.Service1Behavior">
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

By the way, I left out about 100 lines of other configuration “stuff” that had to do with System.Web, etc.

Sample 2 – WCF Configuration for the same service as Sample 1, in .NET 4

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
</configuration>

Notice there is no (none, nada, zero) system.serviceModel element.  That said, if you start your service this way you have one teeny issue:

image

By default WCF disables metadata publishing (security through obscurity) so no one could query your service WSDL to build a client.  In order to do that, you simply need the default code that WCF 4 puts in your config.

Sample 3 – WCF Configuration to enable metadata publishing, in .NET 4

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
</configuration>

I will certainly be looking forward to the easing of the configuration pains in WCF 4!

Reclaiming Your Identity with Windows Identity Foundation

Windows Identity Foundation is a new framework from Microsoft that helps to solve the identity crisis so many users face with multiple accounts for on-line services, applications, etc.  WIF (dub-eye-eff, not “wiff”), supports the notion of claims-based authentication where a user will authenticate with an external provider and return to your application with a set of claims (in the form of an encrypted token such as SAML) which you then verify and accept.  Delegating authentication is meant to remove the responsibility of authenticating from your application so that it can focus on doing what the app needs to do and not become full of logic to authenticate users.

What’s in a Claim Anyway?

Claims based security isn’t something new.  The idea behind claims is simple.  Users go to a centralized provider where they authenticate and are given a token which contains information about that user; their name, roles, and any other data the authentication store provides.  The user then takes those claims and presents them to the application.  The application verifies the authenticity of the claims and allows the user to access the resources which they are authorized to use.

Real World Claims

The identity problem hasn’t been eliminated in the real-world.  Think about how many cards you carry in your wallet that identify you to some other external party.  You have a drivers license, credit cards, video club cards, etc.  These cards are generally only trusted by the person issuing them.

Since I’ve been doing a lot of flying lately, let’s consider this example.  When you go through the airport now you are required to have a “government issued ID” in addition to your boarding pass.  In the United States alone there are 50 governments responsible for issuing IDs.  You can also print your own boarding pass and each of the airlines format is slightly different.  When you hand your ID and boarding pass to the TSA agent they are not going to verify who actually printed your ID or the legitimacy of your boarding pass.  They are looking for signs of fraud and that the person in the picture resembles the person standing in front of them.

You present the TSA agent your claims (valid boarding pass and government issued ID) and they verify your claims by checking against known signs of fraudulent IDs.

WIF Terms

Claim – Comes from the attribute store for a user.  Typically a key value pair.

Identity Provider – The service responsible for provisioning users & their attributes.

Relying party – The application which will rely on an STS to provide authentication and a token containing claims.

Security Token Service (STS) – The interface of the Identity Provider which allows you to interact with the Identity Provider as a web service.

Token – The “thing” that contains claims to be used by an application. Typically it is an encrypted cookie or xml file.

Getting Started with WIF

To build your first claims aware application you’ll need to grab the SDK here.  To use WIF you need to have IIS installed.  For instructions on installing IIS on Windows 7, check this post.  Included in the samples are several ways you can use WIF.  For this post we’ll look at the PassiveRedirectBasedClaimsAwareWebApp found in {Program Files}\Windows Identity Foundation SDK\v3.5\Samples\Quick Start\Web Application.

To get started with the samples after you installed IIS, be sure to run the SamplesPreReqSetup.bat in {Program Files}\Windows Identity Foundation SDK\v3.5\Samples\Utilities (You must run this “as administrator”)
image 

After running the pre-requisite setup, you need to run the Setup.bat in {Program Files}\Windows Identity Foundation SDK\v3.5\Samples\Quick Start\Web Application and once again be sure to run as administrator.

To test your app just point your browser to https://localhost/WebControlBasedClaimsAwareWebApp/default.aspx.  Log in with your windows account and you should see a page listing the claims in the token.  Note the https; during the pre-requisite setup the scripts will create an SSL cert and enable SSL on your machine. 

Let’s Add a Claim

The STS is located in the PassiveSTS project.  Open App_Code and then the MySecurityTokenService.cs file.  This is the STS implementation.  You can look through the code to get a feel for how the STS works.  To add claims, jump down to the GetOutputClaimsIdentityMethod.  To add a claim use the following snippet:

outputIdentity.Claims.Add(new Claim("http://christopherDeweese.com/Claims/Twitter", "@cdeweese"));

We’ll also need to alter the web applications to support the claim.  The code in the apps will ignore claims it is not expecting.  Open the default.aspx.cs in WebControlBasedClaimsAwareWebApp.  Add the following code near the top where the ExpectedClaims field is defined:

 string[] ExpectedClaims = new string[]  {   Microsoft.IdentityModel.Claims.ClaimTypes.Name,
"http://WindowsIdentityFoundationSamples/myID",
"http://WindowsIdentityFoundationSamples/2008/05/AgeClaim",
"http://christopherDeweese.com/Claims/Twitter"
                                            };

When you browse to the page your output should look something like:

image 

What Just Happened?

Nothing like learning about it by diving in head-first.  When we made our first request to the web app it could not locate our token with the claims and we were immediately redirected to the STS where we were prompted for our logon credentials.  After we were authenticated the STS built an identity which was returned in an encrypted token and we were redirected back to the web app.  This time the web app found our token and allowed us in, displaying the page we see above.

Conclusion

Windows Identity Foundation is a different way to solve your identity problems.  WIF focuses on a model that focuses on how the problem is dealt with in the “real-world”; though we haven’t solved it there yet either.  This will hopefully be part one of many posts that will cover WIF and the good, bad, and ugly of using it to tackle identity problems head-first.

Calling SharePoint Services with WCF and Impersonation

After battling with error 0×80004004 the WCF client I was testing started received a new error.

Could not load file or assembly ‘System.Web.Services, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’ or one of its dependencies. Either a required impersonation level was not provided, or the provided impersonation level is invalid. (Exception from HRESULT: 0×80070542)

A search yielded this post, which contained some key information.  Interestingly enough, we were seeing the “White Screen” issue on our local instance under similar circumstances: a WCF client calling the list service.

Since the behaviors section is not specifying the clientCredentials, the allowedImpersonationLevel is set to Identification.  This means that the server can get the Identity of the user, but it is unable to impersonate the user.

This was almost identical circumstances to our problem except that we were not running in the context of Biztalk.  The solution was to allow Impersonation by adding an endpoint behavior.

<endpointBehaviors>
  <behavior name="ImpersonationBehavior">
    <clientCredentials>
      <windows allowedImpersonationLevel="Impersonation" />
    </clientCredentials>
  </behavior>
</endpointBehaviors>

Once this was set the service client began working and it was back to the SharePoint dev races.  For more on calling SharePoint Services with WCF check out this post.

Calling SharePoint Services Over SSL with WCF (WSS 3.0)

While troubleshooting another SharePoint WSS issue (related to DCOM permissions) I had to test calling the List Service against an Instance of SharePoint that was running over SSL.  I was using WCF as the client and the biggest pain was the configuration (which is usually the case with WCF).  Based on several other posts, here is what I tried.

1. Added Service Reference which generated configuration info for the service

2. Changed the config and set the security model to “Transport” and clientCredentialType to “Ntlm”.  “Transport” is required when calling over SSL.

    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="ListsSoap" closeTimeout="00:01:00" openTimeout="00:01:00"
                    receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
                    bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
                    useDefaultWebProxy="true">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <security mode="Transport">
                      <transport clientCredentialType="Ntlm"/>
                    </security>
                </binding>

            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="https://someserver/somesite/_vti_bin/lists.asmx"
                binding="basicHttpBinding" bindingConfiguration="ListsSoap"
                contract="SharePointServices.ListsSoap" name="ListsSoap" />
        </client>
    </system.serviceModel>

3. In code, the only trick I had to use was to AllowNtlm by setting the property on the ClientCredential object.


            using (var client = new SharePointServices.ListsSoapClient())
            {
                try
                {
                    client.ClientCredentials.Windows.ClientCredential 

                 = new NetworkCredential("username", "password", "domain");
                    client.ClientCredentials.Windows.AllowNtlm = true;
                    var lists = client.GetListCollection();
                    var listsXElement = XElement.Parse(lists.OuterXml);
                    Console.WriteLine(listsXElement);
                }
                catch (Exception ex)
                {
                    client.Abort();
                    Console.WriteLine(ex.ToString());
                }
            }

Troubleshooting 0×80004004 in WSS 3.0 (SharePoint)

Today I spent some time working through a few issues with SharePoint and DCOM permissions.  Hopefully this helps another developer on a quest to solve this issue.

If you’ve found 0×80004004 then you are already pretty far along to the solution.  While testing calls to the List service in SharePoint using WCF for the client I received the following error from the List service which I captured by enabling tracing on my WCF client.

<soap:Fault>
    <faultCode xmlns="">soap:Server</faultCode>
    <faultString xmlns="">Exception of type 'Microsoft.SharePoint.SoapServer.SoapServerException' was thrown.</faultString>
    <detail xmlns="">
      <errorstring xmlns="http://schemas.microsoft.com/sharepoint/soap">Operation aborted (Exception from HRESULT: 0x80004004 (E_ABORT))</errorstring>
      <errorcode xmlns="http://schemas.microsoft.com/sharepoint/soap">0x80004004</errorcode>
    </detail>
  </soap:Fault>

Repeated searches on Bing and Google yielded nothing with a direct solution.  But I did find a few pointers that helped my quest.

Digging through program files\common files\Microsoft Shared\Web Server Extensions\12\LOGS I found log files with rows looking similar to this:

w3wp.exe (0×1718) 0×1418 Windows SharePoint Services General 8e2s Medium Unknown SPRequest error occurred.  More Information: 0×80004004

This confirmed the error, but wasn’t helpful.  However, the line just above that was slightly more revealing:

w3wp (0×1718) 0×1418 Windows SharePoint Services Database 6f8g Unexpected Unexpected query execution failure, error code 11.  Additional error information from SQL Server is included below. “[DBNETLIB][ConnectionWrite (WrapperWrite()).]General network error.  Check your network documentation.” Query text (if available): “{?=call proc_GetTpWebMetaDataAndListMetaData( [some values here] ) }

My immediate thought was, “ok, database permissions”.  I was able to locate the stored procedure in question as belonging to the Administration database (SharePoint_AdminContent).  I tweaked a few permissions to no avail.

The project architect suggested I try the same code against a different SharePoint instance.  Sadly, when I tried that the only problem I had to fight was getting the NTLM credentials to work using WCF and SSL.  Things worked flawlessly after that.

With the assistance of our IT pro, he found this article which discusses DCOM permission issues with SP.  Unfortunately we found ourselves unable to change the IIS WAMREG permissions until we found this article which helped us slay that problem.  After taking ownership of the appropriate registry key, we were able to change permissions on the IIS WAMREG DCOM component to allow the SharePoint WPG groups to have Local Launch and Local Activate.

Apparently this issue stems from how the local SharePoint install was configured.  Seems that many people run into this issue when trying to consume SharePoint services on a local machine.

After a reboot and an IIS reset the problem went away.  Sadly, my WCF client received a new error which I will cover in a future post.