File Persistence Provider Sample

Download sample

This sample demonstrates how to create a persistence provider that works with durable services. The state of the service instance is stored in files on your computer.

The sample also contains a calculator service implementation, which is the same as the Durable Services. The difference is that this service uses the file persistence provider created in the sample rather than using the standard Locking SQL persistence provider.

Note

This sample requires that .NET Framework version 3.5 is installed to build and run. Visual Studio 2008 is required to open the project and solution files.

The Calculator Client Sample must be run with this service (For more information, see , the set up procedures at the end of this topic).

File Persistence Provider

The file persistence provider in this sample is defined in the file FilePersistenceProviderFactory.cs. Note that the actual FilePersistenceProvider class is located in an embedded class. To create the file persistence provider, a factory pattern is used in which the factory passes the actual persistence provider class to the service runtime when required. This is the standard way to create providers in WCF.

The file persistence provider factory class inherits from the PersistenceProviderFactory abstract class. The PersistenceProviderFactory abstract class is defined in the following code.

namespace System.ServiceModel.Persistence
{
    public abstract class PersistenceProviderFactory : CommunicationObject
    {
        protected PersistenceProviderFactory();

        public abstract PersistenceProvider CreateProvider(Guid id);
    }
}

Note that PersistenceProviderFactory inherits from the CommunicationObject abstract class. CommunicationObject provides the methods required to manage the lifetime of the object throughout its use in the service runtime.

The factory pattern for the provider helps ensure that the factory manages any resources that are common across all instances of the provider. For example, in the case of the file persistence provider, the factory can determine the location in which the persistence files are stored and then shared across all instances of the actual file persistence provider.

As a result there is one instance of the provider for every instance of the service. There is also one instance of the factory for each host.

The file persistence provider itself inherits from the PersistenceProvider abstract class. This class is defined in the following code.

namespace System.ServiceModel.Persistence
{
    public abstract class PersistenceProvider : CommunicationObject
    {
        protected PersistenceProvider(Guid id);

        public Guid Id { get; }

        public abstract IAsyncResult BeginCreate(object instance, TimeSpan timeout, AsyncCallback callback, object state);
        public abstract IAsyncResult BeginDelete(object instance, TimeSpan timeout, AsyncCallback callback, object state);
        public abstract IAsyncResult BeginLoad(TimeSpan timeout, AsyncCallback callback, object state);
        public virtual IAsyncResult BeginLoadIfChanged(TimeSpan timeout, object instanceToken, AsyncCallback callback, object state);
        public abstract IAsyncResult BeginUpdate(object instance, TimeSpan timeout, AsyncCallback callback, object state);
        public abstract object Create(object instance, TimeSpan timeout);
        public abstract void Delete(object instance, TimeSpan timeout);
        public abstract object EndCreate(IAsyncResult result);
        public abstract void EndDelete(IAsyncResult result);
        public abstract object EndLoad(IAsyncResult result);
        public virtual bool EndLoadIfChanged(IAsyncResult result, out object instance);
        public abstract object EndUpdate(IAsyncResult result);
        public abstract object Load(TimeSpan timeout);
        public virtual bool LoadIfChanged(TimeSpan timeout, object instanceToken, out object instance);
        public abstract object Update(object instance, TimeSpan timeout);    
    }
}

The persistence provider class is also a communication object. There are 4 methods in the persistence provider: Create(), Update(), Load(), and Delete(). Asynchronous variants of these methods are defined as well as overloads of the asynchronous variants. The following rules apply to storing the state of the instance in the files:

  • The actual files are stored in a directory named FilePersistenceProvider in the Temp directory on the computer on which the service is hosted.

  • The state of an instance is stored in a file, the name of which is the unique identifier of the instance. This file is stored with a .bin extension.

  • When a file must be deleted, it is not actually deleted, but is instead renamed as "deleted".

Configuration of the Persistence Provider

Before using it, the file persistence provider must be specified in the configuration file for the service. The configuration of the persistence provider is specified in the servicebBehaviors section of the configuration file. This example shows the entry in the Web.config file.

<behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehavior"  >
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
          <serviceCredentials>
            <windowsAuthentication allowAnonymousLogons="false" includeWindowsGroups="true" />
          </serviceCredentials>
          <persistenceProvider type="Microsoft.WorkflowServices.Samples.FilePersistenceProviderFactory, DurableServiceFactory, Version=1.0.0.0"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>  

Durable Service Code - Service Contract

The following code shows the service contract for the calculator service.

[ServiceContract(Namespace = "http://Microsoft.WorkflowServices.Samples")]
    public interface ICalculator
    {
        [OperationContract()]
        int PowerOn();
        [OperationContract()]
        int Add(int value);
        [OperationContract()]
        int Subtract(int value);
        [OperationContract()]
        int Multiply(int value);
        [OperationContract()]
        int Divide(int value);
        [OperationContract()]
        void PowerOff();
    }  

Service Implementation

In the following code, the DurableServiceAttribute attribute is used in the service implementation to specify that it is a durable service.

[Serializable]
[DurableService]
public class DurableCalculator : ICalculator
{
    int currentValue = default(int);

    [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()
    {
    }

}

The DurableOperationAttribute attribute specifies that the instance state is saved after the operation is complete.

There are 2 parameters that can be used in the DurableOperationAttribute attribute. The CanCreateInstance property specifies that the instance is created when that operation is invoked. The CompletesInstance property specifies that the service instance is completed once the operation on which this attribute is specified has finished running. The state is also deleted from the database after the operation is complete.

The following code shows the .svc file for hosting this sample in Internet Information Services (IIS).

<%@ServiceHost language=c# Debug="true" Service="Microsoft.WorkflowServices.Samples.DurableCalculator" Factory="System.ServiceModel.Activation.ServiceHostFactory" %>

The binding for the service is configured in the Web.config file. The WSHttpContextBinding binding helps to maintain the context that is used to route requests to a particular instance of the application. The persistence provider entry that specifies the persistence provider is located in the ServiceBehaviors section.

To set up, build and run the sample

  1. Ensure that you perform the set up instructions in One-Time Set Up Procedure for the Windows Communication Foundation Samples.

  2. In IIS, enable Windows Authentication on the ServiceModelSamples virtual directory.

    To enable Windows Authentication in IIS 5.1 or 6.0:

    1. Open a command prompt window and type start inetmgr to open the Internet Information Services (IIS) MMC snap-in.

    2. Right-click the virtual root ServiceModelSamples inside Default Web Site, click Properties, and then click the Directory Security tab.

    3. Under Authentication and Access Control, click Edit.

    4. In the Authentication Methods dialog box, select Integrated Windows Authentication.

    To enable Windows Authentication in IIS 7.0:

    1. Open a command prompt window and type start inetmgr to open the Internet Information Services (IIS) MMC snap-in.

    2. Select the ServiceModelSamples virtual root inside Default Web Site.

    3. Inside the ServiceModelSamples home pane, double-click Authentication inside the IIS group.

    4. Select Windows Authentication and select the Enable action.

  3. Build the project. The project builds and updates ServiceModelSamples.

  4. To ensure that the service is property installed, point to the address https://localhost/servicemodelsamples/service.svc. You should see the help page for the service. To look at the Web Services Descriptor Language (WSDL), type https://localhost/servicemodelsamples/service.svc?wsdl.

  5. To run this sample, you must use the Calculator Client Sample. It is a calculator user interface created using Windows Presentation Foundation (WPF) that acts as a client for the service. To test the durable nature of the service, close the client and reopen it while the calculator service is running. The calculator client communicates back to the same service instance and displays the instance ID at the bottom. The calculator client uses a text file called Client.ctx to store the context in a durable place the first time a call is made (in this case, in the \bin directory of your sample). When you reopen the client, it checks whether the file is present. If it is, it applies the stored context to the channel that is being created. If the service has finished and you open the client with the Client.ctx file still in your \bin directory, it attempts to apply the context to the channel. You receive an error because the service with which you want to communicate is not there. Delete the file and try again.

  6. You can also recycle the service by restarting IIS. Because you are using a persistence store after every operation, the state of the service is stored. Therefore, when you try to communicate with the service from the client after IIS has restarted, the service infrastructure receives the instance from the persistence store, and you can communicate with the same instance.

    Note

    When you invoke an operation for the first time after restarting IIS, you receive a MessageSecurityException exception, which is caused by an expired security token on the channel. Invoke another operation and it will succeed.

© 2007 Microsoft Corporation. All rights reserved.