My durable WCF RESTful calculator

A durable service in WCF is by a definition a service that can persist all its internal state across calls in some durable storage. For every operation, the service state is retrieved from the storage, the operation is executed and finally the state is persisted again in the storage. Therefore, there is not need to keep the service instance idle in memory while waiting for client calls. It is equivalent to a long run session, which make this feature something ideal for long-running processes like workflows (In fact, workflow services are mount on top of this feature),

In order to create a durable service, WCF provides a "DurableService" attribute (It's a service behavior) that can be applied to a regular service definition. The service itself has to be either serializable or have members decorated with DataContract or DataMember attributes to be serialized and stored in the persistent storage.

The service activation, as in workflow services, is managed by the WCF context correlation mechanism. Once a service instance has been created, the client application has to propagate some context information(which includes the service instance id) in order to route all the new messages to the right service instance. Jesus has already discussed how this mechanism works more in detail in this post (Although the post is bit old and some names have changed since then, it is worth reading).

For purposes of this post, I decided to create a simple calculator example that exposes different operations through the classic http verbs,

[ServiceContract(Namespace = "http://Microsoft.WorkflowServices.Samples")]

public interface ICalculator

{

    [OperationContract()]

    [WebInvoke(Method = "POST")]

    int PowerOn();

 

    [OperationContract()]

    [WebInvoke(Method = "PUT", UriTemplate = "add")]

    int Add(int value);

 

    [OperationContract()]

    [WebInvoke(Method = "PUT", UriTemplate = "subtract")]

    int Subtract(int value);

 

    [OperationContract()]

    [WebInvoke(Method = "PUT", UriTemplate = "multiply")]

    int Multiply(int value);

 

    [OperationContract()]

    [WebInvoke(Method = "PUT", UriTemplate = "divide")]

    int Divide(int value);

 

    [OperationContract()]

    [WebInvoke(Method = "DELETE")]

    void PowerOff();

The implementation of this service is also quite straightforward.

[Serializable]

[DurableService]

public class DurableCalculator : ICalculator

{

    int _currentValue = 0;

 

    [DurableOperation(CanCreateInstance=true)]

    public int PowerOn()

    {

        return _currentValue;

    }

 

    [DurableOperation]

    public int Add(int value)

    {

        return (_currentValue += value);

    }

 

    [DurableOperation]

    public int Subtract(int value)

    {

        return (_currentValue -= value);

    }

 

    [DurableOperation]

    public int Multiply(int value)

    {

        return (_currentValue *= value);

    }

 

    [DurableOperation]

    public int Divide(int value)

    {

        return (_currentValue /= value);

    }

 

    [DurableOperation(CompletesInstance=true)]

    public void PowerOff()

    {

    }

}

As you can see, I decorated the service implementation with the "DurableService" and "DurableOperation" attributes to make this simple service a durable one.

WCF only comes with built-in support for transferring the context information between the client and service with Http Cookies or Soap Headers. While cookies would be the right mechanism for http REST services, unfortunately they do not work as expected. The path that WCF uses for creating the cookies is relative, so the context manager throws the following exception on the client side,

Unhandled Exception: System.Net.CookieException: An error occurred when parsing the Cookie header for Uri 'http://localhost:8080/DurableCalculator'. ---> System.Net.CookieException: The 'Path'='/DurableCalculator/PowerOn' part of the cookie  is invalid.

As workaround, we can use for this scenario the custom context binding I created some weeks ago to exchange the context information as regular http headers.

<connectionStrings>

  <add name="DurableService" connectionString="Initial Catalog=SQLWorkflows;Data Source=.\SQLEXPRESS;Integrated Security=SSPI;"/>

</connectionStrings>

<system.serviceModel>

  <services>

    <service name="ServiceConsole.DurableCalculator" behaviorConfiguration="MyServiceBehavior">

      <endpoint address="" behaviorConfiguration="MyServiceBehavior" binding="webHttpContext" contract="ServiceConsole.ICalculator" />

    </service>

</services>

<behaviors>

  <endpointBehaviors>

    <behavior name="MyServiceBehavior">

      <webHttp />

    </behavior>

  </endpointBehaviors>

  <serviceBehaviors>

    <behavior name="MyServiceBehavior">

      <persistenceProvider type="System.ServiceModel.Persistence.SqlPersistenceProviderFactory, System.WorkflowServices, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DurableService"/>

    </behavior>

  </serviceBehaviors>

</behaviors>

<extensions>

  <bindingExtensions>

    <add name="webHttpContext" type="Microsoft.ServiceModel.Samples.WebHttpContextBindingCollectionElement, WebHttpContext, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />

  </bindingExtensions>

</extensions>

</system.serviceModel>

If you pay special attention to the configuration settings above, in addition to the binding configuration, I also included the "persitenceProvider" behavior for configuring the persistence provider that will serialize and store the service instance (In this case, the SQL server provider).

Now, thanks to this support, my calculator service will survive to application and server restarts :). Download the complete code from this location.

3 Comments

  • It's similar, but not the same thing. What I am showing here is how to use Durable services with REST interfaces.

  • This may be using http verbs and XML, but it's certainly not restful. It violates one of the constraints, the one where state is self-contained within representations.

    Maybe when you say rest you mean POX?

  • I am not completely agree with you, the state is actually self-contained within representations in this example. The operations are modifying the resource representation, a result of some calculations in this example, and stored in a database. If forgot to provide a GET method in this example to get the current resource representation, but that method would be idempotent by sure. Yes, it is also POX, a REST/POX example. The only thing I am doing here is to automatically load/save the current resource state so it can be modified by the operations, otherwise the developer would have to perform these load/save the resource state manually from somewhere. Do you get my point ?.

Comments have been disabled for this content.