Browse Category: WCF

WCF custom authentication using ServiceCredentials

The generally accepted way of authenticating a user with WCF is with a User Name and Password with the UserNamePasswordValidator class.  So common that even MSDN has a tutorial, and the MSDN documentation for WCF is seriously lacking at best.  The username/password approach does what it says on the tin, you pass along a username and password credential from the client to the server, do your authentication, and only if there is a problem then you throw an exception.  It’s a primitive approach, but it works.  But what about when you want to do something a little bit less trivial than that? ServiceCredentials is probably what you need.

Source code for this post is available on GitHub.

Scenario

I should prefix this tutorial with a disclaimer, and this disclaimer is just my opinion.  WCF is incredibly poorly documented and at times counter intuitive.  In fact, I generally avoid WCF development like the black plague, preferring technologies such as Web API.  The saving grace of WCF is that you have full control over a much more substantial set of functionality, and you’re not limited by REST but empowered by SOAP.  WCF plays particularly nicely with WPF, my favourite desktop software technology.  I’ve never used WCF as part of a web service before, and I doubt I ever will.

Tangent aside, sometimes its not appropriate to authenticate a user with simply a username or password.  You might want to pass along a User Name and a License Key, along with some kind of unique identification code based on the hardware configuration of the users computer.  Passing along this kind of information in a clean way can’t be done with the simple UserNamePasswordValidator, without using some hacky kind of delimited string approach (“UserName~LicenseKey~UniqueCode”).

So this is what we will do for this tutorial; pass a User Name, License Key and “Unique Key” from the client to the server for authentication and authorization.  And for security, we will avoid using WsHttpBinding and instead create a CustomBinding and use an SSL certificate (PFX on the server, CER on the client).  The reasons for this are discussed throughout this tutorial, but primarily because I’ve encountered so many problems with WsHttpBinding when used in a load balanced environment that its just not worth the hassle.

As a final note, we will also go “configuration free”.   All of this is hard coded because I can’t make the assumption that if you use this code in a production environment that you will have access to the machine certificate store, which a lot of web hosting providers restrict access to. As far as I know, the SSL certificate cannot be loaded from a file or a resource using the Web.config.

Server Side Implementation

Basic Structure

All preamble aside, lets dive straight in.  This tutorial isn’t about creating a full featured WCF service (a quick Google of the term “WCF Tutorial” presents about 878,000 results for that) so the specific implementation details aren’t important.  What is important is that you have a Service Contract with at least one Operation Contract, for testing purposes.  Create a new WCF Service Application in Visual Studio, and refactor the boiler plate code as follows;

[ServiceContract]
public interface IEchoService
{
    [OperationContract]
    string Echo(int value);
}

public class EchoService : IEchoService
{
    public string Echo(int value)
    {
        return string.Format("You entered: {0}", value);
    }
}

And rename the SVC file to EchoService.svc.

Open up the Web.config file and delete everything inside the <system.serviceModel> element.  You don’t need any of that.

NuGet Package

It is not exactly clear to me why, but you’ll also need to install the NuGet package Microsoft ASP.NET Web Pages (Install-Package Microsoft.AspNet.WebPages).  I suppose this might be used for the WSDL definition page or the help page.  I didn’t really look into it.

 

Hosting In Local IIS (Internet Information Services)

I’m hosting this in IIS on my local machine (using a self-signed certificate) but I’ve thoroughly tested on a real server using a “real” SSL certificate, so I’ll give you some helpful hints of that as we go along.

First things first;

  1. Open IIS Manager (inetmgr)
  2. Add a new website called “echo”
  3. Add a HTTP binding with the host name “echo.local”
  4. Open up the hosts file (C:\Windows\System32\drivers\etc) and add an entry for “echo.local” and IP address 127.0.0.1
  5. Use your favourite SSL self signed certificate creation tool to generate a certificate for cn=echo.local  (See another tutorial I wrote that explains how to do this).  Be sure to save the SSL certificate in PFX format, this is important for later.
  6. The quickest way I’ve found to generate the CER file (which is the certificate excluding the private key, for security) is to import the PFX into the Personal certificate store for your local machine.  Then right click > All Tasks > Export (excluding private key) and select DER encoded binary X.509 (.CER).  Save to some useful location for use later.  Naturally when doing this “for real”, your SSL certificate provider will provide the PFX and CER (and tonnes of other formats) so you can skip this step.  This tutorial assumes you don’t have access to the certificate store (either physically or programmatically) on the production machine.
  7. DO NOT add a binding for HTTPS unless you are confident that your web host fully supports HTTPS connections.  More on this later.
  8. Flip back to Visual Studio and publish your site to IIS.  I like to publish in “Debug” mode initially, just to make debugging slightly less impossible.

ImportCertificate

Open your favourite web browser and navigate to http://echo.local/EchoService.svc?wsdl.  You won’t get much of anything at this time, just a message to say that service metadata is unavailable and instructions on how to turn it on.  Forget it, its not important.

Beyond UserNamePasswordValidator

Normally at this stage you would create a UserNamePasswordValidator, add your database/authentication/authorization logic and be done after about 10 minutes of effort.  Well forget that, you should expect to spend at least the next hour creating a myriad of classes and helpers, authenticators, policies, tokens, factories and credentials.  Hey, I never said this was easy, just that it can be done.

Factory Pattern

The default WCF Service Application template you used to create the project generates a ServiceHost object with a Service property that points to the actual implementation of our service, the guts.  We need to change this to use a ServiceHostFactory, which will spawn new service hosts for us.  Right click on the EchoService.svc file and change the Service property to Factory, and EchoService to EchoServiceFactory;

//Change 
Service="WCFCustomClientCredentials.EchoService"

//To
Factory="WCFCustomClientCredentials.EchoServiceFactory"

Just before we continue, add a new class to your project called EchoServiceHost and derive from ServiceHost.  This is the actual ServiceHost that was previously created automatically under the hood for us.  We will flesh this out over the course of the tutorial.  For now, just add a constructor that takes an array of base addresses for our service, and which passes the type of the service to the base.

public class EchoServiceHost : ServiceHost
{
    public EchoServiceHost(params Uri[] addresses)
        : base(typeof(EchoService), addresses)
    {

    }
}

Now add another new class to your project, named EchoServiceFactory, and derived from ServiceHostFactoryBase.  Override CreateServiceHost and return a new instance of EchoServiceHost with the appropriate base address.

public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
{
    return new EchoServiceHost(new[]
    {
        new Uri("http://echo.local/")
    });
}

We won’t initialize the ServiceHost just let, we’ll come back to that later.

Custom ServiceCredentials

ServiceCredentials has many responsibilities, including; serialization/deserialization and authentication/authorization.  Not to be confused with ClientCredentials, which has the additional responsibility of generating a token which contains all the fields to pass to the service (User Name, License Key and Unique Code).  There is a pretty decent tutorial on MSDN which explains some concepts in a little bit more detail that I will attempt.  The ServiceCredentials will (as well as all the aforementioned things) load in our SSL certificate and use that to verify (using the private key) that the certificate passed from the client is valid before attempting authentication/authorization. Before creating the ServiceCredentials class, add each of the following;

  1. EchoServiceCredentialsSecurityTokenManager which derives from ServiceCredentialsSecurityTokenManager.
  2. EchoSecurityTokenAuthenticator which derives from SecurityTokenAuthenticator.

Use ReSharper or Visual Studio IntelliSense to stub out any abstract methods for the time being.  We will flesh these out as we go along.

You will need to add a reference to System.IdentityModel, which we will need when creating our authorization policies next.

You can now flesh out the EchoServiceCredentials class as follows;

public class EchoServiceCredentials : ServiceCredentials
{
    public override SecurityTokenManager CreateSecurityTokenManager()
    {
        return new EchoServiceCredentialsSecurityTokenManager(this);
    }

    protected override ServiceCredentials CloneCore()
    {
        return new EchoServiceCredentials();
    }
}

If things are not clear at this stage, stick with me… your understanding will improve as we go along.

Namespaces and constant values

Several namespaces are required to identify our custom token and its properties.  It makes sense to stick these properties all in one place as constants, which we will also make available to the client later.  The token is ultimately encrypted using a Symmetric encryption algorithm (as shown later), so we can’t see the namespaces in the resulting SOAP message, but I’m sure they’re there.

Create a new class called EchoConstants, and add the following;

public class EchoConstants
{
    public const string EchoNamespace = "https://echo/";

    public const string EchoLicenseKeyClaim = EchoNamespace + "Claims/LicenseKey";
    public const string EchoUniqueCodeClaim = EchoNamespace + "Claims/UniqueCode";
    public const string EchoUserNameClaim = EchoNamespace + "Claims/UserName";
    public const string EchoTokenType = EchoNamespace + "Tokens/EchoToken";

    public const string EchoTokenPrefix = "ct";
    public const string EchoUrlPrefix = "url";
    public const string EchoTokenName = "EchoToken";
    public const string Id = "Id";
    public const string WsUtilityPrefix = "wsu";
    public const string WsUtilityNamespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";

    public const string EchoLicenseKeyElementName = "LicenseKey";
    public const string EchoUniqueCodeElementName = "UniqueCodeKey";
    public const string EchoUserNameElementName = "UserNameKey";
}

All these string values (except for the WsUtilityNamespace) are arbitrary values.  They give the message structure and conformity with open standards.

We will use these constant values throughout the remainder of the tutorial.

Security Token

Lets work through this starting with the most interesting classes first, and work backwards in descending order.  The SecurityToken contains all our custom credentials that we will ultimately use to determine if the user is allowed to use the service.  A security token can contain pretty much anything you want, as long as the token itself has a unique ID, and a valid from/to date and time.

Add the following class to your project;

public class EchoToken : SecurityToken
{
    private readonly DateTime _effectiveTime = DateTime.UtcNow;
    private readonly string _id;
    private readonly ReadOnlyCollection<SecurityKey> _securityKeys;

    public string LicenseKey { get; set; }
    public string UniqueCode { get; set; }
    public string UserName { get; set; }

    public EchoToken(string licenseKey, string uniqueCode, string userName, string id = null)
    {
        LicenseKey = licenseKey;
        UniqueCode = uniqueCode;
        UserName = userName;

        _id = id ?? Guid.NewGuid().ToString();
        _securityKeys = new ReadOnlyCollection<SecurityKey>(new List<SecurityKey>());
    }

    public override string Id
    {
        get { return _id; }
    }

    public override ReadOnlyCollection<SecurityKey> SecurityKeys
    {
        get { return _securityKeys; }
    }

    public override DateTime ValidFrom
    {
        get { return _effectiveTime; }
    }

    public override DateTime ValidTo
    {
        get { return DateTime.MaxValue; }
    }
}

There are a few things to note here;

  1. The token has a unique identifier, in this case a random Guid.  You can use whatever mechanism you like here, as long as it results in a unique identifier for the token.
  2. The token is valid from now until forever.  You might want to put a realistic timeframe in place here.
  3. I don’t know what SecurityKeys is for, and it doesn’t seem to matter.

Before you rush off to MSDN, here is what it says;

Base class for security keys.

Helpful.

We’re not quite ready to use this token yet, so we’ll revisit later.  All the pieces come together at once, like a really dull jigsaw.

Authorization Policy

We only care at this point about authorizing the request based on the User Name, License Key and Unique Code provided in the token.  We could however use an Authorization Policy to limit access to certain service methods based on any one of these factors.  If you want to restrict access to your API in this way, see the MSDN documentation for more information.  If, however, the basic authorization is good enough for you, add the following code;

public class EchoTokenAuthorizationPolicy : IAuthorizationPolicy
{
    private readonly string _id;
    private readonly IEnumerable<ClaimSet> _issuedClaimSets;
    private readonly ClaimSet _issuer;

    public EchoTokenAuthorizationPolicy(ClaimSet issuedClaims)
    {
        if (issuedClaims == null)
        {
            throw new ArgumentNullException("issuedClaims");
        }

        _issuer = issuedClaims.Issuer;
        _issuedClaimSets = new[] { issuedClaims };
        _id = Guid.NewGuid().ToString();
    }

    public ClaimSet Issuer
    {
        get { return _issuer; }
    }

    public string Id
    {
        get { return _id; }
    }

    public bool Evaluate(EvaluationContext context, ref object state)
    {
        foreach (ClaimSet issuance in _issuedClaimSets)
        {
            context.AddClaimSet(this, issuance);
        }

        return true;
    }
}

The key to this working is the Evaluate method.  We are just adding each claim to the EvaluationContext claim set, without doing any sort of checks.  This is fine because we will do our own authorization as part of the SecurityTokenAuthenticator, shown next.

Security Token Authentication and Authorization

Now that we have our Authorization Policies in place, we can get down to business and tell WCF to allow or deny the request.  We must create a class that derives from SecurityTokenAuthenticator, and override the ValidateTokenCore method.  If an exception is thrown in this method, the request will be rejected.  You’re also required to return the authorization policies, which will be evaluated accordingly and the request rejected if the token does not have the claims required to access the desired operation.  How you authorize/authenticate the request is down to you, but will inevitably involve some database call or similar tasks to check for the existence and legitimacy of the given token parameters.

Here is a sample implementation;

public class EchoSecurityTokenAuthenticator : SecurityTokenAuthenticator
{
    protected override bool CanValidateTokenCore(SecurityToken token)
    {
        return (token is EchoToken);
    }

    protected override ReadOnlyCollection<IAuthorizationPolicy> ValidateTokenCore(SecurityToken token)
    {
        var echoToken = token as EchoToken;

        if (echoToken == null)
        {
            throw new ArgumentNullException("token");
        }

        var authorizationException = IsAuthorized(echoToken.LicenseKey, echoToken.UniqueCode, echoToken.UserName);
        if (authorizationException != null)
        {
            throw authorizationException;
        }

        var policies = new List<IAuthorizationPolicy>(3)
        {
            CreateAuthorizationPolicy(EchoConstants.EchoLicenseKeyClaim, echoToken.LicenseKey, Rights.PossessProperty),
            CreateAuthorizationPolicy(EchoConstants.EchoUniqueCodeClaim, echoToken.UniqueCode, Rights.PossessProperty),
            CreateAuthorizationPolicy(EchoConstants.EchoUserNameClaim, echoToken.UserName, Rights.PossessProperty),
        };

        return policies.AsReadOnly();
    }

    private static Exception IsAuthorized(string licenseKey, string uniqueCode, string userName)
    {
        Exception result = null;

        //Check if user is authorized.  If not you must return a FaultException

        return result;
    }

    private static EchoTokenAuthorizationPolicy CreateAuthorizationPolicy<T>(string claimType, T resource, string rights)
    {
        return new EchoTokenAuthorizationPolicy(new DefaultClaimSet(new Claim(claimType, resource, rights)));
    }
}

Token Serialization

Before we can continue, we have neglected to discuss one very important detail.  WCF generates messages in XML SOAP format for standardised communication between the client and the server applications.  This is achieved by serializing the token using a token serializer.  Surprisingly, however, this doesn’t happen automatically.  You have to give WCF a hand and tell it exactly how to both read and write the messages.  It gives you the tools (an XmlReader and XmlWriter) but you have to do the hammering yourself.

The code for this isn’t short, so I apologise for that.  Here is an explanation of what happens;

  1. CanReadTokenCore is called when deserializing a token.  The responsibility of this method is to tell the underlying framework if this class is capable of reading the token contents.
  2. ReadTokenCore is called with an XmlReader, which provides access to the raw token itself.  You use the XmlReader to retrieve the parts of the token of interest (the User Name, Unique Code and License Key) and ultimately return a new SecurityToken (EchoSecurityToken).
  3. CanWriteTokenCore is called when serializing a token.  Return true if the serializer is capable of serializing then given token.
  4. WriteTokenCore is called with an XmlWriter and the actual SecurityToken.  Use both objects to do the serialization manually.

And the code itself;

public class EchoSecurityTokenSerializer : WSSecurityTokenSerializer
{
    private readonly SecurityTokenVersion _version;

    public EchoSecurityTokenSerializer(SecurityTokenVersion version)
    {
        _version = version;
    }

    protected override bool CanReadTokenCore(XmlReader reader)
    {
        if (reader == null)
        {
            throw new ArgumentNullException("reader");
        }
        if (reader.IsStartElement(EchoConstants.EchoTokenName, EchoConstants.EchoNamespace))
        {
            return true;
        }
        return base.CanReadTokenCore(reader);
    }

    protected override SecurityToken ReadTokenCore(XmlReader reader, SecurityTokenResolver tokenResolver)
    {
        if (reader == null)
        {
            throw new ArgumentNullException("reader");
        }
        if (reader.IsStartElement(EchoConstants.EchoTokenName, EchoConstants.EchoNamespace))
        {
            string id = reader.GetAttribute(EchoConstants.Id, EchoConstants.WsUtilityNamespace);

            reader.ReadStartElement();

            string licenseKey = reader.ReadElementString(EchoConstants.EchoLicenseKeyElementName, EchoConstants.EchoNamespace);
            string companyKey = reader.ReadElementString(EchoConstants.EchoUniqueCodeElementName, EchoConstants.EchoNamespace);
            string machineKey = reader.ReadElementString(EchoConstants.EchoUniqueCodeElementName, EchoConstants.EchoNamespace);

            reader.ReadEndElement();

            return new EchoToken(licenseKey, companyKey, machineKey, id);
        }
        return DefaultInstance.ReadToken(reader, tokenResolver);
    }

    protected override bool CanWriteTokenCore(SecurityToken token)
    {
        if (token is EchoToken)
        {
            return true;
        }
        return base.CanWriteTokenCore(token);
    }

    protected override void WriteTokenCore(XmlWriter writer, SecurityToken token)
    {
        if (writer == null)
        {
            throw new ArgumentNullException("writer");
        }
        if (token == null)
        {
            throw new ArgumentNullException("token");
        }

        var EchoToken = token as EchoToken;
        if (EchoToken != null)
        {
            writer.WriteStartElement(EchoConstants.EchoTokenPrefix, EchoConstants.EchoTokenName, EchoConstants.EchoNamespace);
            writer.WriteAttributeString(EchoConstants.WsUtilityPrefix, EchoConstants.Id, EchoConstants.WsUtilityNamespace, token.Id);
            writer.WriteElementString(EchoConstants.EchoLicenseKeyElementName, EchoConstants.EchoNamespace, EchoToken.LicenseKey);
            writer.WriteElementString(EchoConstants.EchoUniqueCodeElementName, EchoConstants.EchoNamespace, EchoToken.UniqueCode);
            writer.WriteElementString(EchoConstants.EchoUserNameElementName, EchoConstants.EchoNamespace, EchoToken.UserName);
            writer.WriteEndElement();
            writer.Flush();
        }
        else
        {
            base.WriteTokenCore(writer, token);
        }
    }
}

Service Credentials Security Token Manager

A long time ago… in a blog post right here, you created a class called EchoServiceCredentialsSecurityTokenManager.  The purpose of this class is to tell WCF that we want to use our custom token authenticator (EchoSecurityTokenAuthenticator) when it encounters our custom token.

Update the EchoServiceCredentialsSecurityTokenManager as follows;

public class EchoServiceCredentialsSecurityTokenManager : ServiceCredentialsSecurityTokenManager
{
    public EchoServiceCredentialsSecurityTokenManager(ServiceCredentials parent)
        : base(parent)
    {
    }

    public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
    {
        if (tokenRequirement.TokenType == EchoConstants.EchoTokenType)
        {
            outOfBandTokenResolver = null;
            return new EchoSecurityTokenAuthenticator();
        }
        return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
    }

    public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)
    {
        return new EchoSecurityTokenSerializer(version);
    }
}

The code is pretty self explanatory.  When an EchoToken is encountered, use the EchoSecurityTokenAuthenticator to confirm that the token is valid, authentic and authorized.  Also, the token can be serialized/deserialized using the EchoSecurityTokenSerializer.

Service Host Endpoints

The last remaining consideration is exposing endpoints so that the client has “something to connect to”.  This is done in EchoServiceHost by overriding the InitializeRuntime method, as shown;

protected override void InitializeRuntime()
{
    var baseUri = new Uri("http://echo.local");
    var serviceUri = new Uri(baseUri, "EchoService.svc");

    Description.Behaviors.Remove((typeof(ServiceCredentials)));

    var serviceCredential = new EchoServiceCredentials();
    serviceCredential.ServiceCertificate.Certificate = new X509Certificate2(Resources.echo, string.Empty, X509KeyStorageFlags.MachineKeySet);
    Description.Behaviors.Add(serviceCredential);

    var behaviour = new ServiceMetadataBehavior { HttpGetEnabled = true, HttpsGetEnabled = false };
    Description.Behaviors.Add(behaviour);

    Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;
    Description.Behaviors.Find<ServiceDebugBehavior>().HttpHelpPageUrl = serviceUri;

    AddServiceEndpoint(typeof(IEchoService), new BindingHelper().CreateHttpBinding(), string.Empty);

    base.InitializeRuntime();
}

The code does the following;

  1. Define the base URL of the and the service URL
  2. Remove the default implementation of ServiceCredentials, and replace with our custom implementation.  Ensure that the custom implementation uses our SSL certificate (in this case, the SSL certificate is added to the project as a resource).  If the PFX (and it must be a PFX) requires a password, be sure to specify it.
  3. Define and add a metadata endpoint (not strictly required)
  4. Turn on detailed exceptions for debugging purposes, and expose a help page (again not strictly required)
  5. Add an endpoint for our service, use a custom binding.  (DO NOT attempt to use WsHttpBinding or BasicHttpsBinding, you will lose 4 days of your life trying to figure out why it doesn’t work in a load balanced environment!)

Custom Http Binding

In the interest of simplicity, I want the server and the client to use the exact same binding.  To make this easier, I’ve extracted the code out into a separate helper class which will be referenced by both once we’ve refactored (discussed next).  We’re using HTTP  right now but we will discuss security and production environments towards the end of the post.  The custom binding will provide some level of security via a Symmetric encryption algorithm that will be applied to aspects of the message.

public Binding CreateHttpBinding()
{
    var httpTransport = new HttpTransportBindingElement
    {
        MaxReceivedMessageSize = 10000000
    };

    var messageSecurity = new SymmetricSecurityBindingElement();

    var x509ProtectionParameters = new X509SecurityTokenParameters
    {
        InclusionMode = SecurityTokenInclusionMode.Never
    };

    messageSecurity.ProtectionTokenParameters = x509ProtectionParameters;
    return new CustomBinding(messageSecurity, httpTransport);
}

Note, I’ve increased the max message size to 10,000,000 bytes (10MB ish) because this is appropriate for my scenario.  You might want to think long and hard about doing this.  The default message size limit is relatively small to help ward off DDoS attacks, so think carefully before changing the default.  10MB is a lot of data to receive in a single request, even though it might not sound like much.

With the endpoint now exposed, a client (if we had one) would be able to connect.  Lets do some refactoring first to make our life a bit easier.

Refactoring

In the interest of simplicity, I haven’t worried too much about the client so far.  We need to make some changes to the project structure so that some of the lovely code we have written so far can be shared and kept DRY.  Add a class library to your project, called Shared and move the following classes into it (be sure to update the namespaces and add the appropriate reference).

  1. BindingHelper.cs
  2. IEchoService.cs
  3. EchoSecurityTokenSerializer.cs
  4. EchoConstants.cs
  5. EchoToken.cs

Client Side Implementation

We’re about 2/3 of the way through now.  Most of the leg work has been done and we just have to configure the client correctly so it can make first contact with the server.

Create a new console application (or whatever you fancy) and start by adding a reference to the Shared library you just created for the server.  Add the SSL certificate (CER format, doesn’t contain the private key) to your project as a resource.  Also add a reference to System.ServiceModel.

Custom ClientCredentials

The ClientCredentials works in a similar way to ServiceCredentials, but a couple of subtle differences.  When you instantiate the ClientCredentials, you want to pass it all the arbitrary claims you want to pass to the WCF service (License Key, Unique Code, User Name).  This object will be passed to the serializer that you created as part of the server side code (EchoSecurityTokenSerializer) later on.

First things first, create the EchoClientCredentials class as follows;

public class EchoClientCredentials : ClientCredentials
{
    public string LicenseKey { get; private set; }
    public string UniqueCode { get; private set; }
    public string ClientUserName { get; private set; }

    public EchoClientCredentials(string licenseKey, string uniqueCode, string userName)
    {
        LicenseKey = licenseKey;
        UniqueCode = uniqueCode;
        ClientUserName = userName;
    }

    protected override ClientCredentials CloneCore()
    {
        return new EchoClientCredentials(LicenseKey, UniqueCode, ClientUserName);
    }

    public override SecurityTokenManager CreateSecurityTokenManager()
    {
        return new EchoClientCredentialsSecurityTokenManager(this);
    }
}

The ClientCredentials has an abstract method CreateSecurityTokenManager, where we will use to tell WCF how to ultimately generate our token.

Client side Security Token Manager

As discussed, the ClientCredentialsSecurityTokenManager is responsible for “figuring out” what to do with a token that it has encountered.  Before it uses its own underlying token providers, it gives us the chance to specify our own, by calling CreateSecurityTokenProvider.  We can check the token type to see if we can handle that token ourselves.

Create a new class, called EchoClientCredentialsSecurityTokenManager, that derives from ClientCredentialsSecurityTokenManager, and add the following code;

public class EchoClientCredentialsSecurityTokenManager : ClientCredentialsSecurityTokenManager
{
    private readonly EchoClientCredentials _credentials;

    public EchoClientCredentialsSecurityTokenManager(EchoClientCredentials connectClientCredentials)
        : base(connectClientCredentials)
    {
        _credentials = connectClientCredentials;
    }

    public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
    {
        if (tokenRequirement.TokenType == EchoConstants.EchoTokenType)
        {
            // Handle this token for Custom.
            return new EchoTokenProvider(_credentials);
        }
        if (tokenRequirement is InitiatorServiceModelSecurityTokenRequirement)
        {
            // Return server certificate.
            if (tokenRequirement.TokenType == SecurityTokenTypes.X509Certificate)
            {
                return new X509SecurityTokenProvider(_credentials.ServiceCertificate.DefaultCertificate);
            }
        }
        return base.CreateSecurityTokenProvider(tokenRequirement);
    }

    public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)
    {
        return new EchoSecurityTokenSerializer(version);
    }
}

The code is pretty verbose, and we can see clearly what is happening here.  We can inspect the token type and see if it makes that of our Echo token.  If we find a match, return an EchoTokenProvider (coming next) which is just simply a wrapper containing our claims.  Note that we also are able to reuse the token serializer that we created as part of the server side work, a nice (not so little) time saver!

Security Token Provider

In this case, the security token provider is nothing more than a vessel that contains our client credentials.  The token provider instantiates the token, passes the client credentials, and passes the token off for serialization.

public class EchoTokenProvider : SecurityTokenProvider
{
    private readonly EchoClientCredentials _credentials;

    public EchoTokenProvider(EchoClientCredentials credentials)
    {
        if (credentials == null) throw new ArgumentNullException("credentials");

        _credentials = credentials;
    }

    protected override SecurityToken GetTokenCore(TimeSpan timeout)
    {
        return new EchoToken(_credentials.LicenseKey, _credentials.UniqueCode, _credentials.ClientUserName);
    }
}

Test Client

The client side code for establishing a connection with our service is relatively simple. We need each of the following:

  1. Define the endpoint (the address) of our service
  2. Create an instance of EchoClientCredentials
  3. Load the SSL certificate (the public key aspect at least) and pass to the credentials object we just instantiated
  4. Remove the default implementation of ClientCredentials and pass in our own
  5. Create a channel factory, and call our service method

Here is an example of what your client code would look like;

var serviceAddress = new EndpointAddress("http://echo.local/EchoService.svc");

var channelFactory = new ChannelFactory<IEchoService>(new BindingHelper().CreateHttpBinding(), serviceAddress);

var credentials = new EchoClientCredentials("license key", "unique code", "user name");
var certificate = new X509Certificate2(Resources.echo);
credentials.ServiceCertificate.DefaultCertificate = certificate;

channelFactory.Endpoint.Behaviors.Remove(typeof(ClientCredentials));
channelFactory.Endpoint.Behaviors.Add(credentials);

var service = channelFactory.CreateChannel();
Console.WriteLine(service.Echo(10));

Security and Production Environment Considerations

Throughout this tutorial I have used HTTP bindings and told you explicitly not to use HTTPS, and there is a very good reason for that.  If you have a simple hosting environment, i.e. an environment that is NOT load balanced, then you can go ahead and make the following changes;

  • Change your service URL to HTTPS
  • Change HttpTransportBindingElement (on the server, inside the BindingHelper) to HttpsTransportBindingElement.
  • Add a HTTPS binding in IIS

Re-launch the client and all should be good.  If you get the following error message, you’re in big trouble.

The protocol ‘https’ is not supported.

After 4 days of battling with this error, I found what the problem is.  Basically WCF requires end to end HTTPS for HTTPS to be “supported”.  Take the following set up;

load-balancing-1

Some hosting companies will load balance the traffic.  That makes absolutely perfect sense and is completely reasonable.  The communications will be made from the client (laptop, desktop or whatever) via HTTPS, that bit is fine.  If you go to the service via HTTPS you will get a response.  However, and here’s the key, the communication between the load balancer and the physical web server probably isn’t secured.  I.e. doesn’t use HTTPS.  So the end-to-end communication isn’t HTTPS and therefore you get the error message described.

To work around this, use a HTTPS binding on the client, and a HTTP binding on the server.  This will guarantee that the traffic between the client and the server will be secure (thus preventing MIM attacks) but the traffic between the load balancer and the physical web server will not be secure (you’ll have to decide for yourself if you can live with that).

Quirks

I’ve encountered a few quirks whilst developing this service over the last few weeks.  Quirks are things I can’t explain or don’t care to understand.  You must make the following changes to the server side code, or else it might not work.  If you find any other quirks, feel free to let me know and I’ll credit your discovery;

 

You must add the AddressFilterMode ‘Any’ to the service implementation, or it won’t work.

[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]

Summary

A lot of work is required to be able to do custom authentication using ServiceCredentials with WCF, no fewer than 18 classes in total. For cases when a trivial User Name and password simply won’t suffice, you can use this approach. WCF works really well when developing non-web based applications, but the lack of documentation can make development and maintenance harder than it should be. Be careful when using in a load balanced environment, you may need to make some changes to your bindings as already discussed.

Easy WCF Security and authorization of users

There are several steps involved in making your WCF service secure, and ensure that clients consuming your service are properly authenticated.  WCF uses BasicHttpBinding out-of-the-box, which generates SOAP envelopes (messages) for each request.  BasicHttpBinding works over standard HTTP, which is great for completely open general purpose services, but not good if you are sending sensitive data over the internet (as HTTP traffic can easily be intercepted).

This post discusses how to take a basic WCF service, which uses BasicHttpBinding, and upgrade it to use WsHttpBinding over SSL (with username/password validation). If you want to become a better WCF developer, you may want to check out Learning WCF: A Hands-on Guide by Michele Lerouz Bustamante. This is a very thorough and insightful WCF book with detailed and practical samples and tips.

Here is the basic sequence of steps needed;

  • Generate a self-signed SSL certificate (you would use a real SSL certificate for live) and add this to the TrustedPeople certificate store.
  • Add a UserNamePasswordValidator.
  • Switch our BasicHttpBinding to WsHttpBinding.
  • Change our MEX (Metadata Exchange) endpoint to support SSL.
  • Specify how the client will authenticate, using the ServiceCredentials class.

You may notice that most of the changes are configuration changes.  You can make the same changes in code if you so desire, but I find the process easier and cleaner when done in XML.

 

BasicHttpBinding vs. WsHttpBinding

Before we kick things off, i found myself asking this question (like so many others before me).  What is the difference between BasicHttpBinding and WsHttpBinding?

If you want a very thorough explanation, there is a very detailed explanation written by Shivprasad Koirala on CodeProject.com.  I highly recommend that you check this out.

The TL:DR version is simply this;

  • BasicHttpBinding supports SOAP v1.1 (WsHttpBinding supports SOAP v1.2)
  • BasicHttpBinding does not support Reliable messaging
  • BasicHttpBinding is insecure, WsHttpBinding supports WS-* specifications.
  • WsHttpBinding supports transporting messages with credentials, BasicHttpBinding supports only Windows/Basic/Certificate authentication.

The project structure

You can view and download the full source code for this project via GitHub, see the end of the post for more details.

We have a WCF Service application with a Service Contract as follows;

[ServiceContract]
public interface IPeopleService
{
    [OperationContract]
    Person[] GetPeople();
}

And the implementation of the Service Contract;

public class PeopleService : IPeopleService
{
    public Person[] GetPeople()
    {
        return new[]
                    {
                        new Person { Age = 45, FirstName = "John", LastName = "Smith" }, 
                        new Person { Age = 42, FirstName = "Jane", LastName = "Smith" }
                    };
    }
}

The model class (composite type, if you will) is as follows;

[DataContract]
public class Person
{
    [DataMember]
    public int Age { get; set; }

    [DataMember]
    public string FirstName { get; set; }

    [DataMember]
    public string LastName { get; set; }
}

The initial configuration is as follows;

<system.serviceModel>
  <behaviors>
    <serviceBehaviors>
      <behavior>
        <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
        <serviceDebug includeExceptionDetailInFaults="false"/>
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <protocolMapping>
    <add binding="basicHttpsBinding" scheme="https"/>
  </protocolMapping>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>

The WCF service can easily be hosted in IIS, simply add a service reference to the WSDL definition file and you’re away. In the interest of completeness, here is the entire client code;

static void Main(string[] args)
{
    PeopleServiceClient client = new PeopleServiceClient();

    foreach (var person in client.GetPeople())
    {
        Console.WriteLine(person.FirstName);
    }

    Console.ReadLine();
}

Hosting in IIS

As briefly mentioned, you can (and probably always will) host your WCF service using Internet Information Services (IIS).

Generating an SSL certificate

Before doing anything, you need an SSL certificate.  Transport based authentication simply does not work if A) You are not on a secure channel and B) Your SSL certificate is not trusted.  You don’t have to purchase an SSL certificate at this stage as a self-signed certificate will suffice (with 1 or 2 extra steps).  You will want to purchase a real SSL certificate when you move your service to the production environment.

You can generate a self-signed SSL certificate either 1 of 2 ways.  You can either do it the hard way, using Microsoft’s rather painful MakeCert.exe Certificate Creation Tool or you can download a free tool from PluralSight (of all places), which provides a super simple user interface and can even add the certificate to the certificate store for you.

Once you have downloaded the tool, run it as an Administrator;

SelfCert

For the purposes of this tutorial, we will be creating a fake website called peoplesite.local.  We will add an entry into the hosts file for this and set it up in IIS.  Its very important that the X.500 distinguished name matches your domain name (or it will not work!).  You will also want to save the certificate as a PFX file so that it can be imported into IIS and used for the HTTPS binding.

Once done open up IIS, click on the root level node, and double click on Server Certificates.  Click Import (on the right hand side) and point to the PFX file you saved on the desktop.  Click OK to import the certificate.

Import

Next, create a new site in IIS called PeopleService.  Point it to an appropriate folder on your computer and edit the site bindings.  Add a new HTTPS binding and select the SSL certificate you just imported.

EditBinding

Be sure to remove the standard HTTP binding after adding the HTTPS binding as you wont be needing it.

Update the hosts file (C:\Windows\System32\Drivers\etc\hosts) with an entry for peoplesite.local as follows;

127.0.0.1            peoplesite.local

Finally, flip back to Visual Studio and create a publish profile (which we will use later once we have finished the configuration).  The publish method screen should look something like this;

Publish

Configuration

Ok we have set up our environment, now its time to get down to the fun stuff…configuration.  Its easier if you delete everything you have between the <system.serviceModel> elements and follow along with me.

Add the following skeleton code between the <system.serviceModel> opening and closing tags, we will fill in each element separately;  (update the Service Name to match that in your project)

<services>
  <service name="PeopleService.Service.PeopleService" behaviorConfiguration="ServiceBehaviour">
    <host>
    </host>
  </service>
</services>
<bindings>
</bindings>
<behaviors>
  <serviceBehaviors>
  </serviceBehaviors>
</behaviors>

Base Address

Start by adding a base address (directly inside the host element) so that we can use relative addresses’;

<baseAddresses>
  <add baseAddress="https://peoplesite.local/" />
</baseAddresses>

Endpoints

Next, add two endpoints (one for the WsHttpBinding and one for MEX);

<endpoint address="" binding="wsHttpBinding" bindingConfiguration="BasicBinding" contract="PeopleService.Service.IPeopleService" name="BasicEndpoint" />
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" name="mex" />

Note that we are using mexHttpsBinding because our site does not support standard HTTP binding.  We don’t need to explicitly add a binding for the MEX endpoint as WCF will deal with this automatically for us.  Add a wsHttpBinding as follows;

<wsHttpBinding>
  <binding name="BasicBinding">
    <security mode="TransportWithMessageCredential">
      <message clientCredentialType="UserName" />
    </security>
  </binding>
</wsHttpBinding>

Bindings

This is where we specify what type of security we want to use.  In our case, we want to validate that the user is whom they say they are in the form of a username/password combination.  The TransportWithMessageCredential basic http security mode requires the username/password combination be passed in the message header.  A snoop using a HTTP proxy tool (such as Fiddler) reveals this;

fiddler

Service Behaviours

Finally we need to update our existing service behaviour with a serviceCredentials element as follows;

<behavior name="ServiceBehaviour">
  <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
  <serviceDebug includeExceptionDetailInFaults="true" />
  <serviceCredentials>
    <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="PeopleService.Service.Authenticator, PeopleService.Service" />
    <serviceCertificate findValue="peoplesite.local" storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName" />
  </serviceCredentials>
</behavior>

The two elements of interest are userNameAuthentication and serviceCertificate.

User Name Authentication

This is where we tell WCF about our custom authentication class.  Lets go ahead and create this.  Add a new class to your project called Authenticator.cs and add the following code;

using System.IdentityModel.Selectors;
using System.ServiceModel;

public class Authenticator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        if (userName != "peoplesite" && password != "password")
        {
            throw new FaultException("Invalid user and/or password");
        }
    }
}

Basically, you can add whatever code you want here to do your authentication/authorisation.  Notice that the Validate method returns void.  If you determine that the credentials supplied are invalid, you should throw a FaultException, which will be automatically handled for you by WCF.

You should ensure that the customUserNamePasswordValidatorType attribute in your App.config file is the fully qualified type of your authenticator type.

Service Certificate

This is key, if this is not quite right nothing will work.  Basically you are telling WCF where to find your SSL certificate.  Its very important that the findValue is the same as your SSL certificate name, and that you point to the correct certificate store.  Typically you will install the certificate on the LocalMachine in the TrustedPeople certificate store.  I would certainly recommend sticking with the FindBySubjectName search mode, as this avoid issues when you have multiple SSL certificates with similar details.  You may need a little trial and error when starting out to get this right.  If you have been following this tutorial throughout, you should be OK with the default.

Supplying user credentials

We just need one final tweak to our test client to make all this work.  Update the test client code as follows;

PeopleServiceClient client = new PeopleServiceClient();
client.ClientCredentials.UserName.UserName = "peoplesite";
client.ClientCredentials.UserName.Password = "password";

We pass in the client credentials via the, you guessed it, ClientCredentials object on the service client.

If you run the client now, you should get some test data back from the service written out to the console window.  Notice that you will get an exception if the username/password is incorrect, or if the connection is not over SSL.

Troubleshooting

SecurityNegotiationException

As an aside, if you receive a SecurityNegotiationException please ensure that your self-signed certificate is correctly named to match your domain, and that you have imported it into the TrustedPeople certificate store.

SecurityNegotiationException

A handy trick for diagnosing the problem is by updating the service reference, Visual Studio will advise you as to what is wrong with the certificate;

SecurityAlert

Summary

With a few small configuration changes you can easily utilise WS-Security specifications/standards to ensure  that your WCF service is secure.  You can generate a self-signed SSL certificate using a free tool from Pluralsight, and install it to your local certificate store and IIS.  Then you add a UserNamePasswordValidator to take care of your authentication.  Finally, you can troubleshoot and debug your service using Fiddler and Visual Studio.

github4848_thumb.pngThe source code is available on GitHub

How to create a RESTful web service using WCF (Part 3 of 3)

RESTful (Representational State Transfer) web services use HTTP verbs to map CRUD operations to HTTP methods.  RESTful web services expose either a collection resource (representational of a list) or an element resource (representational of a single item in the list).

Other parts in this series:
How to create a RESTful web service using WCF (Part 1 of 3)
How to create a RESTful web service using WCF (Part 2 of 3)

Testing the WCF service using Fiddler

If you haven’t come across Fiddler before, its a very helpful tool for capturing HTTP traffic.  Fiddler lets us create HTTP messages and send them to our WCF service, it also shows us the response to our message.

HTTP GET

We will start by testing the HTTP GET method that we wrote a little earlier (we know for sure that already works).

execute_thumb2

getresponse_thumb2

Open Fiddler, click the Composer tab and enter the Url to the web service (the same Url you entered into your web browser earlier).  Once done, ensure that GET is selected, and click the Execute button (above).

The web service should respond after a couple of seconds, and you can see that response by clicking the Inspectors tab and clicking JSON (shown on the left)

HTTP POST/PUT

Testing the other HTTP verbs takes a little bit more effort, but not much.  Flip back to the Composer tab and take the following steps;

  1. Change the HTTP verb from GET to POST.
  2. Add a Content-Type: application/json header
  3. Change the service Url to /BlogService/Post
  4. Add the following response body;
{
    "id": "0",
    "title": "This is a test",
    "url": "http://www.developerhandbook.com"
}

The web service should respond with HTTP status code 200 (OK).  Also the web service will return the new blog post, with its Id property set to a proper value (6 in this case).

To update the entity, switch the HTTP verb from POST to PUT (which is Update in RESTful speak)Change the title property, and the Id property to 6 and click Execute again.  Again the web service should return a 200 status code and the entity in JSON format (and again, with the Id of 6).

The difference between a POST and a PUT is simple.  POST should always return a different object than the object you sent it.  PUT should always return the same object that you send to it.  These are the characteristics of a properly implemented RESTful web service.

HTTP DELETE

Change Fiddler to use the DELETE verb.  When you do this, the Request Body field in Fiddler will turn red.  That’s because, usually, no request body is sent along with DELETE requests.

Delete the request body and change the Url to; http://localhost:8085/BlogService/Post/6

Note that we are indicating which resource we want to delete via the Url, rather than having to pass an object to the server.

Consume the web service using jQuery

We won’t get too much into the nitty-gritty about how to consume the web service using jQuery, after all the entire source code is available on GitHub.  I personally used jQuery’s ajax method and simply varied the type depending on the verb I wanted to use.

For example;

$.ajax({
        type: "POST",
        url: baseServiceUrl + "/Post",
        contentType: "application/json",
        data: JSON.stringify(blogPost),
        dataType: "json",
        success: function (data) {
        blogPost.id = data.id;
        self.reset();
    }
});

And the DELETE request is even simpler (shown below).

$.ajax({
    url: baseServiceUrl + "/Post/" + blogPost.id,
    type: "DELETE",
    contentType: "application/json;charset=UTF-8"
});

We’re really just copying what we’ve already achieved using Fiddler.

For the demo I’ve used jQuery, Bootstrap, and KnockoutJS…so please be sure to download it and check it out for yourself!

Summary

WCF provides out of the box support for writing RESTful web services.  Using service contracts, operation contracts, and data contracts, we can make available all the basic information about our web service for consumption from any external clients, including non- .NET clients.  We can easily test that our service is working using Fiddler, a free debugging proxy tool that allows us to intercept and “fiddle” with traffic.

…and after all that, if your thinking “why not just use Web API?”, my response would be “its hard to disagree with you!”.

github4848_thumb.pngDownload the full source code including the full demo project from GitHub today!

How to create a RESTful web service using WCF (Part 2 of 3)

RESTful (Representational State Transfer) web services use HTTP verbs to map CRUD operations to HTTP methods.  RESTful web services expose either a collection resource (representational of a list) or an element resource (representational of a single item in the list).

Create the WCF service contract

Every WCF service begins with a service contract.  A service contract defines what operations are supported/provided by the service.  An operation contract is the definition of a method that can be invoked by a client application.

A WCF service can exist without any operations, but it wouldn’t be of much use.  Usually, all the WCF related definitions are placed on an interface, which is implemented on a normal class (this helps keep everything nice and tidy).  Although this is not strictly required.

Data Contract

Before we can get onto the goodness of implementing our WCF service, we need to make a small alteration to our BlogPost.cs model class.

A data contract is basically a promise (contract!) that describes the data that can be transferred between the client and the server.  A data contract is denoted by the DataContract attribute, which is added to each class you want to be serializable.  Each property that you want to be serialized is decorated with the DataMember attribute.  The DataMember attribute can be given additional metadata such as a name, which overrides the name of the property. 

Being able to define a name for each property when the serialization takes place is particularly important.  We will be writing a JavaScript front end for this application, which prefers field names to be in camel case… and we want to be consistent with that.

Update your model class (BlogPost.cs) as follows;

[DataContract]
public class BlogPost
{
    [DataMember(Name = "id")]
    public int Id { get; set; }

    [DataMember(Name = "title")]
    public string Title { get; set; }

    [Column("Url")]
    [DataMember(Name = "url")]
    public string UriString
    {
        get
        {
            return Url == null ? null : Url.ToString();
        }
        set
        {
            Url = value == null ? null : new Uri(value);
        }
    }

    [NotMapped]
    public Uri Url { get; set; }
}

Note that we haven’t decorated the Url property with the DataMember attribute because we don’t want it to be transferred to/from the client.

HTTP GET

In the Service project, add a new interface named IBlogService.cs and add the ServiceContract attribute.  Then add a new method definition, GetBlogPosts which returns an array of BlogPost (you will need to add a reference to the Data project here).

[ServiceContract]
public interface IBlogService
{
    [OperationContract]
    [WebGet]
    BlogPost[] GetBlogPosts();
}

The WebGet attribute is a REST specific attribute indicating that the operation is accessible via the HTTP GET verb.  The WebInvoke attribute can be used for POST, PUT and DELETE verbs.

Next, create a class named BlogService which implements IBlogService.  Add a static constructor to initialise the database and update the GetBlogPosts method to return all the blog posts in your database;

public class BlogService : IBlogService
{
    static BlogService()
    {
        Database.SetInitializer(new BlogInitializer());
    }

    public BlogPost[] GetBlogPosts()
    {
        using (BlogContext context = new BlogContext())
        {
            return context.BlogPosts.ToArray();
        }
    }
}

Before we can test our WCF service, we need to make a few edits to the configuration file, which was added for us when we created the project.  Open app.config and make the following alterations;

1. Make sure that the service name matches the full namespace for your service interface;

<system.serviceModel>
    <services>
      <service name="RESTfulTutorial.Service.BlogService">

2. Update the base address to tell WCF to use the port number 8085, and simplify the address a little to tidy it up;

<baseAddresses>
    <add baseAddress="http://localhost:8085/BlogService/" />
</baseAddresses>

3. Update the endpoint to use webHttpBinding rather than basicHttpBinding  Also check that the contract namespace is correct, and add a behaviourConfiguration named Web (we will define this shortly).

<endpoint address=""
    binding="webHttpBinding"
    contract="RESTfulTutorial.Service.IBlogService"
    behaviorConfiguration="Web"/>

4. Add an endpoint behaviour (just after the service behaviours section), which will tell WCF to respond in JSON by default, but permit responses in both JSON and XML;

<endpointBehaviors>
    <behavior name="Web">
        <webHttp automaticFormatSelectionEnabled="True" defaultOutgoingResponseFormat="Json" />
    </behavior>
</endpointBehaviors>

If you query http://localhost:8085/BlogService/GetBlogPosts using your web browser, you should see all the blog posts returned as an array (and in XML).  This works because by default, of course, your web browser issues a HTTP GET request, which we permitted using the WebGet attribute.

Whilst this works, its not very RESTful.  What I mean by this is that simply the URL describes the operation, rather than being representational of the data (see what I did there.).  To make the operation RESTful, update the WebGet attribute as follows;

[OperationContract]
[WebGet(UriTemplate = "/Posts")]
BlogPost[] GetBlogPosts();

If you query http://localhost:8085/BlogService/Posts this time, you should get the same data back as before, but in the proper RESTful way.

Parameters

It is possible, and useful, to pass parameters into a URL in order to return a specific resource rather than a collection of resources.

Take the following method;

[OperationContract]
[WebGet(UriTemplate = "/Post/{id}")]
BlogPost GetBlogPost(string id);

A place-marker ({id}) is used to indicate that a parameter will be provided, and that marker matches the name of the parameter accepted by the operation.  Unfortunately, when using custom Uri templates like this, WCF can’t identify the type of the parameter, only strings… so you have to manually cast the string to, in this case, an integer before using it (sigh).

Note that I have also changed the Uri template to Post rather than Posts, simply because I only want to return a single blog post in this case (again this is consistent with the REST specification).

HTTP POST/PUT/DELETE

Other HTTP verbs are just as easy to implement.  Add the following operations to your service contract;

[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "/Post")]
BlogPost CreateBlogPost(BlogPost post);

[OperationContract]
[WebInvoke(Method = "PUT", UriTemplate = "/Post")]
BlogPost UpdateBlogPost(BlogPost post);

[OperationContract]
[WebInvoke(Method = "DELETE", UriTemplate = "/Post/{id}")]
void DeleteBlogPost(string id);

Instead of using the WebGet attribute, we use the WebInvoke attribute, which basically means most other verbs other than GET.  As we’re not using Uri templates with place-markers, we can pass in a complex object from the client and WCF will just figure out what to do with it.

For completeness, here is the implementation for each operation that we added to the service contract;

public BlogPost GetBlogPost(string id)
{
    int identifier;
    if (int.TryParse(id, out identifier))
    {
        using (BlogContext context = new BlogContext())
        {
            return context.BlogPosts.FirstOrDefault(post => post.Id == identifier);
        }
    }

    return null;
}

public BlogPost CreateBlogPost(BlogPost post)
{
    using (BlogContext context = new BlogContext())
    {
        context.BlogPosts.Add(post);
        context.SaveChanges();
    }

    return post;
}

public BlogPost UpdateBlogPost(BlogPost post)
{
    using (BlogContext context = new BlogContext())
    {
        context.Entry(post).State = EntityState.Modified;
        context.SaveChanges();
    }

    return post;
}

public void DeleteBlogPost(string id)
{
    int identifier;
    if (int.TryParse(id, out identifier))
    {
        using (BlogContext context = new BlogContext())
        {
            var entity = context.BlogPosts.FirstOrDefault(blogPost => blogPost.Id == identifier);
            if (entity != null)
            {
                context.BlogPosts.Remove(entity);
                context.SaveChanges();
            }
        }
    }
}

Summary

We’ve looked at how to define a WCF service contract, how to define so operations, and how to make our model classes serializable.  We’ve also looked at how to use various attributes to change how methods are accessed, to bring them into line with the REST specification.  In the final part of this series, we will look at how to test the web service using Fiddler, and a high level look at how we might implement a client application using jQuery.

How to create a RESTful web service using WCF (Part 1 of 3)

RESTful (Representational State Transfer) web services use HTTP verbs to map CRUD operations to HTTP methods.  RESTful web services expose either a collection resource (representational of a list) or an element resource (representational of a single item in the list).

HTTP verbs are used as follows;

  • Create (POST) > create a new resource.
  • Read (GET) > retrieve one or many resources.
  • Update (PUT) > update an existing resource.
  • Delete (DELETE) > delete an existing resource.

This tutorial demonstrates to how implement a simple RESTful web service using WCF, and how to query it using various jQuery methods (at a high level).  Entity Framework code first will be used for data persistence.  The program we will create will be for reading, editing and updating a list of blog posts… what else?! Smile

By the way, throughout this tutorial I will use the terms RESTful service, web service, and WCF service interchangeably…which is fine for this tutorial (but not in the wild).

Project Structure

I think its very important to establish the correct project structure before developing a solution, as it can often be hard to change later.

SolutionAdd three new projects; Data, Service and Web (as shown to the left).  We want to define clear boundaries in our solution, which would (if this were a real project) make future maintenance easier.

The data project will contain our entities, and all (surprisingly little) logic required to persist and retrieve data from an external data store. In this case, for simplicity, I have used Entity Framework code first approach.

The service layer will contain our WCF RESTful service definition, all associated configuration, and each of our CRUD methods.

Finally, the Web project will be the client.  Again for simplicity, I simply added a HTML file (index.html) and jQuery to pass requests to the service.  We will not dive too much into how this works, because its relatively straightforward.  All associated source code for this solution is available on GitHub.

Add each project using the following templates;

  • Data > standard C# class library
  • Service > WCF Service library
  • Web  > Empty ASP .NET Web application (completely empty).

Cross Origin Request Service (CORS)

I found that CORS requires quite a bit of additional code to work correctly.  In case you don’t know, CORS enables us to make requests to the web service across domains.  By default, Visual Studio will spin up the WCF service and the IIS Express instance on different ports, so basically nothing will work out of the box (CORS is strictly disabled by default).

To make your client and WCF service run on the same ports, follow these steps;

  • When we define an endpoint for our service (a little later on) set the port number to 8085.  This is an arbitrary number.
  • Right click on your Web project, and click properties.
  • Click the Web tab.
  • Set the project Url to; http://localhost:8085 (or whatever port number you have decided to go with).  What matters is that they are the same.

Web

So now your WCF service and client run on the same port number, all the extra agony that comes with CORS is avoided.

Data persistence using Entity Framework Code First

I find Entity Framework code first to be one of the best and fastest ways to rapidly prototype a SQL server database, fill it with data, and query that data.  Perhaps not an approach you would want to use in a production environment, I find the whole concept of migrations to be a little clunky, but great for getting up and running quickly. 

I’m assuming that you have a good working knowledge of Entity Framework code first.  If not, then have a look at my tutorial on Entity Framework code first in 15 minutes. And by the way, if you also need to scrub up on code first migrations, have a look at Entity Framework code first migrations tutorial.

A blog post, for this tutorial at least, consists simply of an Id, Title and Url property. Add BlogPost.cs to your Data project as follows;

public class BlogPost
{
    public int Id { get; set; }
    public string Title { get; set; }

    [Column("Url")]
    public string UriString
    {
        get { return Url == null ? null : Url.ToString(); }
        set { Url = value == null ? null : new Uri(value); }
    }

    [NotMapped]
    public Uri Url { get; set; }
}

As you may know, Entity Framework can only deal with simple types so we need a wrapper property to retrieve and set the value of the actual property for us.  We have used the ColumnAttribute to indicate the name of the column that the property is to be mapped to, and used the NotMappedAttribute to explicitly tell Entity Framework not to use said Url property.  (By default Entity Framework tries to map all public properties).

We will revisit this class later and tidy it up for WCF and so that it can be consumed properly by the client.

Next, add a BlogContext.cs as follows;

public class BlogContext : DbContext
{
    public BlogContext()
        : base("BlogContext")
    {
    }

    public DbSet<BlogPost> BlogPosts { get; set; }
}

And finally, add a database initializer and define some seed data;

public class BlogInitializer : DropCreateDatabaseAlways
{
    protected override void Seed(BlogContext context)
    {
        context.BlogPosts.AddRange(
            new[]
        {
            new BlogPost { Id = 0, Title = "Resilient Connection for Entity Framework 6", Url = new Uri("http://developerhandbook.com/2014/02/05/resilient-connection-for-entity-framework-6/") },
            new BlogPost { Id = 1, Title = "How to pass Microsoft Exam 70-486 (Developing ASP.NET MVC 4 Web Applications) in 30 days", Url = new Uri("http://developerhandbook.com/2014/02/01/how-to-pass-microsoft-exam-70-486-developing-asp-net-mvc-4-web-applications-in-30-days/") },
            new BlogPost { Id = 2, Title = "5 easy security enhancements for your ASP .NET application", Url = new Uri("http://developerhandbook.com/2014/01/26/5-easy-security-enhancements-for-your-asp-net-application/") },
            new BlogPost { Id = 3, Title = "10 things every software developer should do in 2014", Url = new Uri("http://developerhandbook.com/2014/01/18/10-things-every-software-developer-should-do-in-2014/") },
            new BlogPost { Id = 4, Title = "15 reasons why I can’t work without JetBrains ReSharper", Url = new Uri("http://developerhandbook.com/2013/12/28/15-reasons-why-i-cant-work-without-jetbrains-resharper/") }
        });
    }
}

I went with the DropCreateDatabaseAlways initializer so that I can add whatever dummy data I like and just reset everything by simply restarting the application.

Summary

We’ve set the important groundwork for developing our RESTful WCF service.  In the subsequent parts of this tutorial we will look at creating a WCF service contract, and how to invoke it using various HTTP verbs.  Stay tuned!

Consuming a WCF service without adding a Service Reference

A problem I have had with WCF since I first discovered it a few years ago is related to Service References.  The fact that I have to rely on the ServiceModel Metadata Utility Tool (Svcutil.exe) to generate a proxy class on my behalf left a sour taste in my mouth.  A good solution would be for me to be able to write code myself to take this pain away.

A Simple Approach

One approach to do this is to take over the responsibility of creating bindings and endpoints yourself in your consuming application to take over this job, and its really a lot simpler than it seems.

To make this work, we are going to need to place all of our Service Contracts and Data Contracts into a shared library, which can be consumed by our client application.  I suggest creating a new project using the ‘WCF Service Library’ project template;

WCF Service Library Template

Move your Service Contracts and Data Contracts into the shared library and update your main WCF service application project to reflect the changes (add a reference to the shared library).

Consuming the WCF Service

Consumption of the service is now reasonably trivial.  You need to create a Binding, an Endpoint and a Channel;

BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpoint = new EndpointAddress("http://localhost:51011/PracticeService.svc");

IPracticeService service = ChannelFactory<IPracticeService>.CreateChannel(binding, endpoint);

I like to neaten this up a little and create a helper class which hides away some of this logic;

public class ServiceFactory<T> where T : class
{
    private T _service;

    public T GetService(string address)
    {
        return _service ?? (_service = GetServiceInstance(address));
    }

    private static T GetServiceInstance(string address)
    {
        BasicHttpBinding binding = new BasicHttpBinding();
        EndpointAddress endpoint = new EndpointAddress(address);

        return ChannelFactory<T>.CreateChannel(binding, endpoint);
    }
}

Making my initialisation code now a little simpler;

//Get an instance of the service
ServiceFactory<IPracticeService> serviceFactory = new ServiceFactory<IPracticeService>();
IPracticeService service = serviceFactory.GetService("http://localhost:51011/PracticeService.svc");

To call the GetData method on my service, I simply treat the service object like it were any other;

//Call the GetData method
Console.WriteLine(service.GetData(10));

Limitations

For me, this solution is only suitable for smaller, simpler applications as a lot of the configuration that makes WCF so powerful is taken away by this approach. Our binding is hard coded, meaning that if we change it in our WCF service, we would need to also change it in our consuming application.

Summary

We can remove the service reference (proxy class) from our projects very simply by creating our own Binding, Endpoint and ChannelFactory objects. This approach may not scale well as our bindings are hard coded and our Service Contracts/Data Contracts have to live in a seperate WCF Service Application Library project.