Dan Rigsby – Coding Up Style

Developer.Speaker.Blogger

Archive for the 'Wcf' Category

REST Services and Metadata Endpoints in WCF

Posted by Dan Rigsby on 29th May 2008

As mentioned in a previous article, there is no defined a way to get metadata about REST based services using webHttpBinding.  Since REST doesn’t use SOAP, there is no WSDL that defines the service and no built in way to generate metadata about it.  REST operations return back POX or JSON or something else. 

You can still create a mexHttpBinding endpoint which can be used to represent the structure of the data that the REST service understands.  You just cant really use this metadata to build a proxy client based on the REST interface. You don’t need any addition endpoints to expose the WSDL, having just a webHttpBinding endpoint is enough.  You just need to enable httpGet on the serviceMetadata (see here for more detailed information on this):

<serviceBehaviors>
    <behavior name="contactServiceBehavior">
        <serviceMetadata httpGetEnabled="true"/>
    </behavior>
</serviceBehaviors>

One common tactic to give the REST service some kind of documentation, is to have a "Documentation" or "Help" method on your service that returns a an HTML page as a Stream which describes how to work with the REST service (as seen in pictureservices).  This isn’t really metadata that can be consumed to generate a proxy class, but it is informative to other developers and consumers of your REST service.

Example

Lets look at an example of the "Documentation" method on a REST service.  This example is based on a simple contact service that holds a collection of contacts.  Some of the methods are AddContact, GetContact, UpdateContact, etc. The complete interface for the service is:

using System.Collections.Generic;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Syndication;
using System.ServiceModel.Web;

namespace Rigsby.RestDocumentation
{
    [ServiceContract]
    public interface IContactService
    {
        [OperationContract]
        [WebGet(UriTemplate = "help")]
        Stream GetDocumentation();

        [OperationContract]
        [WebGet(UriTemplate = "contacts")]
        List<Contact> GetAllContacts();

        [OperationContract]
        [WebGet(UriTemplate = "contacts/feed?format={format}",
            BodyStyle = WebMessageBodyStyle.Bare)]
        [ServiceKnownType(typeof(Atom10FeedFormatter))]
        [ServiceKnownType(typeof(Rss20FeedFormatter))]
        SyndicationFeedFormatter GetContactsFeed(string format);

        [OperationContract]
        [WebGet(UriTemplate = "contact/{contactId}")]
        Contact GetContact(string contactId);

        [OperationContract]
        [WebGet(UriTemplate = "contact/name/{name}")]
        List<Contact> GetContactByName(string name);

        [OperationContract]
        [WebGet(UriTemplate="contact/name/startswith/{startsWith}")]
        List<Contact> GetContactsWhereNameStartsWith(string startsWith);

        [OperationContract]
        [WebGet(UriTemplate = "contact/name/endsWith/{endsWith}")]
        List<Contact> GetContactsWhereNameEndsWith(string endsWith);

        [OperationContract]
        [WebGet(UriTemplate = "contact/name/contains/{contains}")]
        List<Contact> GetContactsWhereNameContains(string contains);

        [OperationContract]
        [WebInvoke(Method = "POST", UriTemplate = "contact/{name}")]
        void AddContact(string name);

        [OperationContract(Name = "AddFullContact")]
        [WebInvoke(Method = "POST", UriTemplate = "contact")]
        void AddContact(Contact contact);

        [OperationContract]
        [WebInvoke(Method="DELETE", UriTemplate = "contact/{contactId}")]
        int DeleteContact(string contactId);

        [OperationContract]
        [WebInvoke(Method = "PUT", UriTemplate = "contact/{contactId}")]
        void UpdateContact(string contactId, Contact contact);
    }
}

The operation to look at is "GetDocumentation".  This method returns a stream which will be the HTML of the documentation for the service.  The UriTemplate we are using is just "help", so the full path would just be something like "http://localhost:8080/ContactService/help".

[OperationContract]
[WebGet(UriTemplate = "help")]
Stream GetDocumentation();
 
The implementation of this is pretty straight forward.  We basically just create a new StreamWriter, write the contents of our HTML to it, set content type of the outgoing response to "text/html", and return the stream:
 
public Stream GetDocumentation()
{
    MemoryStream stream = new MemoryStream();

    StreamWriter writer = new StreamWriter(stream, Encoding.UTF8);
    writer.Write(Properties.Resources.Documentation);
    writer.Flush();
    stream.Position = 0;

    WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";

    return stream;
}
 
When a user navigates to "http://localhost:8080/ContactService/help", the following HTML page is displayed which documents how to use the REST interface:

restdoc

The HTML for this was manually hacked together, but you could write some process that looks at some custom attributes on the service to build this help file:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
<head>
    <title>Contact Service - Documentation</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <style type="text/css">
        body {margin: 0px;padding: 0px;font-family: Calibri, Tahoma, Arial;}
        .banner {padding: 5px 5px 5px 15px;background-color: Gray;color: White;}
        .content {margin: 15px;}
    </style>
</head>
<body>
    <div class="banner">
        <h1>Contact Service</h1>
    </div>
    <div class="content">
        <h2>Available Feeds</h2>
        <ul>
            <li><b>GET /contacts/feed?format={format}</b> &mdash; Returns a feed of all contacts as "rss" or "atom"</li>
        </ul>
        <h2>Available Endpoints</h2>
        <ul>
            <li><b>GET /help</b> &mdash; Displays the service documentation</li>
            <li><b>GET /contacts</b> &mdash; Returns all contacts</li>
            <li><b>GET /contact/{contactId}</b> &mdash; Returns a contact by contactId</li>
            <li><b>GET /contact/name/{name}</b> &mdash; Returns all contacts with the specified name</li>
            <li><b>GET /contact/name/startswith/{startswith}</b> &mdash; Returns all contacts whose name starts with the specified string</li>
            <li><b>GET /contact/name/endsWith/{endsWith}</b> &mdash; Returns all contacts whose name ends with the specified string</li>
            <li><b>GET /contact/name/contains/{contains}</b> &mdash; Returns all contacts whose name contains the specified string</li>

            <li><b>POST /contact/{name}</b> &mdash; Adds a new contact with the specified name (ignores POST data)</li>
            <li><b>POST /contact</b> &mdash; Adds a new contact with the POST data</li>
            <li><b>DELETE /contact/{contactId}</b> &mdash; Deletes a contact by contactId</li>
            <li><b>PUT /contact/{contactId}</b> &mdash; Updates a contact by contactId</li>
        </ul>
    </div>
</body>
</html>

You can download a complete sample of the code discussed in this article here: http://www.danrigsby.com/Files/Rigsby.RestDocumentation.zip

kick it on DotNetKicks.com

Posted in REST, Wcf | 14 Comments »

WCF Metadata

Posted by Dan Rigsby on 27th May 2008

The WCF team has gone to great lengths to ensure that it doesn’t tie itself down to a single service architecture or naming. This can be best demonstrated by how WCF refers to its metadata. Most users will think of this metadata as WSDL. And in WCF today, it is WSDL. However, what will WSDL be in 5 years? What happens when something better comes along? Or what if we want some metadata for REST which doesn’t use SOAP? Instead, it is just called Metadata.

So what is the this metadata?  Metadata is basically to describe how to interact with the service’s endpoints.  This includes metadata about:

  1. The operations a service can perform
  2. The structure of the data types that the operations work with or return
  3. Definitions of all the endpoints implemented by the service and the various options needed for each such as security

By default service metadata is turned off.  This has been a problem for some people because you have to manually configure the service to publish the metadata.  This is by design because metadata can expose parts of your service you don’t want to expose.  Many services out in the wild do not want to publish metadata at all.  Personally, I am a bit torn about this.  Part of me understands why they implemented it this way, but the more common use is to expose metadata always.  It seems that the default should be metadata on, with the option to turn metadata off for the more rare occasions.  However, the WCF team really wanted it to be "secure by default", which means it needed to be turned off.  This can throw off classic WebService developers because in ASMX you needed to opt-out of exposing metadata, while WCF requires opt-in of exposing metadata.

The metadata can be used to generate proxy classes with svcutil.exe, "Add Service Reference" in Visual Studio, wcftestclient.exe, or any other program that can interpret the metadata and build proxies.  This data can also by used to pull out specific information about a service such as its’ endpoints, or simply just for reference information about the service.

Exposing Metadata

To expose metadata you need to turn on the serviceMetaData property in the service behavior that the service is implementing.  This can be done declaratively through the xml config files, or programmatically directly in your code:

Declaratively

The minimum you need is to add the serviceMetaData node to the serviceBehavior being used by the service:

<serviceBehaviors>
  <behavior name = "MetadataBehavior">
    <serviceMetadata />
  </behavior>
</serviceBehaviors>
 
In a full configuration file this may look like something like this:
 
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name = "MetadataBehavior">
         <serviceMetadata httpGetEnabled = "true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service name = "MyService"
               behaviorConfiguration = "MetadataBehavior">
        <host>
          <baseAddresses>
            <add baseAddress =
                 "http://localhost:8080/MyService"
                 "net.tcp://localhost:9000/MyService"/>
          </baseAddresses>
        </host>
        <endpoint address = ""
                  binding = "wsHttpBinding"
                  contract = "IMyService"/>
        <endpoint address = ""
                  binding = "netTcpBinding"
                  contract = "IMyService"/>
        <endpoint address = "net.tcp://localhost:9000/MyService/mex"
                  binding = "mexTcpBinding"
                  contract = "IMetadataExchange"/>
      </service>
    </services>
  </system.serviceModel>
</configuration>

Programmatically

Adding this in code is similar.  You need to add a ServiceMetadataBehavior object to the behaviors of the serviceHost:

ServiceHost host = new ServiceHost(
    typeof(MyService),
    new Uri("http://localhost:8080/MyService"),
    new Uri("net.tcp://localhost:9000/MyService"));

host.AddServiceEndpoint(
    typeof(IMyService),
    new WSHttpBinding(),
    "");
host.AddServiceEndpoint(
    typeof(IMyService),
    new NetTcpBinding(),
    "");
Binding mexBinding = MetadataExchangeBindings.CreateMexTcpBinding();
host.AddServiceEndpoint(
    typeof(IMetadataExchange),
    mexBinding,
    "net.tcp://localhost:9000/MyService/mex");

ServiceMetadataBehavior metadataBehavior =
    new ServiceMetadataBehavior();
metadataBehavior.HttpGetEnabled = true;
host.Description.Behaviors.Add(metadataBehavior);

 

Enabling the serviceMetaData property is enough to expose metadata through all binding types except http and https.  For these you have to specify "HttpGetEnabled=true" or "HttpsGetEnabled=true" depending on if you are using http or https.  You must expose at least one endpoint for http or https and declare a base address or you will get a runtime exception with HttpGetEnabled or HttpsGetEnabled enabled.

Http and Https can expose metadata simply by appending "?wsdl" to the end of the base address.  For any binding type, you need to specify a metadata binding endpoint to retrieve the metadata from.  This is done by creating an endpoint that uses the IMetadataExchange interface, a corresponding "mex" binding for the transport (more on this later), and the address where the metadata published.  You can also use an IMetadataExchange address for http and https as well, but normally the "?wsdl" site is enough.

There are a few properties of ServiceMetadata:

  • ExternalMetadataLocation: A Uri that contains the location of a WSDL file, which is returned to the user in response to WSDL and MEX requests instead of the auto-generated WSDL. When this attribute is not set, the default WSDL is returned. The default is an empty string.
  • HttpGetEnabled: A Boolean value that specifies whether to publish service metadata for retrieval using an HTTP/Get request. The default is false. If the httpGetUrl attribute is not specified, the address at which the metadata is published is the service address plus a "?wsdl". For example, if the service address is "http://localhost:8080/MyService", the HTTP/Get metadata address is "http://localhost:8080/MyService?wsdl". If this property is false, or the address of the service is not based on HTTP or HTTPS, “?wsdl” is ignored.
  • HttpGetUrl: A Uri that specifies the address at which the metadata is published for retrieval using an HTTP/Get request.
  • HttpsGetEnabled: A Boolean value that specifies whether to publish service metadata for retrieval using an HTTPS/Get request. The default is false. If the httpsGetUrl attribute is not specified, the address at which the metadata is published is the service address plus a "?wsdl". For example, if the service address is https://localhost:8080/MyService, the HTTP/Get metadata address is "https://localhost:8080/MyService?wsdl". If this property is false, or the address of the service is not based on HTTP or HTTPS, “?wsdl” is ignored.
  • HttpsGetUrl: A Uri that specifies the address at which the metadata is published for retrieval using an HTTPS/Get request.

Metadata Exchange Endpoint

A metadata exchange endpoint is an endpoint that returns back the metadata about the service. You can have as many metadata exchange endpoints as you want. You could have one for each service endpoint, one that all endpoints share, or 100s that just return the same data.  Usually one metadata endpoint is sufficient, but it is common to see one for each service endpoint as well.

Like all endpoints it is comprised of the ABCs: Address, Binding, and Contract:

Address

The address is just the Uri that the endpoint can be can found.  In a metdata exchange endpoint this is commonly done by appending "mex" to the base address such as "net.tcp://localhost/MyService/mex", but you can use whatever address you choose.

Binding

There are only 4 bindings that are defined to be used as a metadata endpoint:

  1. mexHttpBinding: Specifies the settings for a binding used for the WS-MetadataExchange (WS-MEX) message exchange over HTTP.
  2. mexHttpsBinding: Specifies the settings for a binding used for the WS-MetadataExchange (WS-MEX) message exchange over HTTPS.
  3. mexNamedPipesBinding: Specifies the settings for a binding used for the WS-MetadataExchange (WS-MEX) message exchange over named pipe.
  4. mexTcpBinding: Specifies the settings for a binding used for the WS-MetadataExchange (WS-MEX) message exchange over TCP

You can use any of these in the configuration file to define metadata endpoints, such as:

<endpoint address = "net.tcp://localhost:9000/MyService/mex"
    binding = "mexTcpBinding"
    contract = "IMetadataExchange"/>

In code however, these bindings must be created through the static MetadataExchangeBindings class.  It has the following 4 methods:

You can use any of these methods in your code go generate the bindings for the corresponding transport, such as:

Binding mexBinding = MetadataExchangeBindings.CreateMexTcpBinding();
host.AddServiceEndpoint(
    typeof(IMetadataExchange),
    mexBinding,
    "net.tcp://localhost:9000/MyService/mex");

Contract

A contract is just an interface that the endpoint must follow. So, what is this IMetadataExchange interface?  It only has 3 methods:

  • BeginGet: Starts an asynchronous retrieval of metadata.
  • EndGet: Concludes the retrieval of metadata.
  • Get: Returns the service metadata

Since BeginGet and EndGet are just an asynchronous version of Get, what does Get do?  Well, as you may have guessed, it just returns the metadata for the service.

REST and webHttpBinding

So what about REST based services using webHttpBinding?  No where is there defined a way to get metadata about it.  Well, since it is REST, there is no WSDL that defines the service and no built in way to generate metadata about it.  One common tactic is to have a "Documentation" method on your service that returns a stream of data that is an HTML page which describes how to work with the REST service.  This isn’t really metadata that can be consumed to generate a proxy class, but it is informative to other developers and consumers of your REST services.

kick it on DotNetKicks.com

Posted in Wcf | 7 Comments »

Get the Service Endpoint address a Client is accessing in WCF

Posted by Dan Rigsby on 25th May 2008

In a previous post I talked about how to get the address of a client accessing a WCF service.  I got a few questions after this asking how you would get the endpoint address of the service that the client is accessing?  A single service could have multiple endpoints, and when a client comes into the service you may branch the logic slightly depending on how they are accessing the data.  For instance, you might have a separate endpoint that is exposed outside of your network for external customers, and may want to restrict the amount of data they can access through a method. Or maybe if the client is using “Http” you might want to return back less data than if the client is using “Tcp”.

Getting the service endpoint address is actually much easier then getting the address of the client.  You just need to look at the LocalAddress on the Channel of the current Operation Context in the method:

OperationContext.Current.Channel.LocalAddress

Here is an example of a method that branches its results based on the schema (http, tcp, etc) of the endpoint that a client is accessing:

public List<Customer> GetCustomers()
{
    var customers = new List<Customer>();

    if (OperationContext.Current.Channel.LocalAddress.Uri.Scheme == "http")
    {
        // TODO: Get partial customer objects
    }
    else
    {
        // TODO: Get full customer objects
    }

    return customers;
}

Posted in Wcf | 5 Comments »

Extending WCF InstanceContext to store custom state

Posted by Dan Rigsby on 24th May 2008

InstanceContext in Wcf Series:
Part 1: Understanding InstanceContext
Part 2: Extending InstanceContext to store custom state

This is Part 2 in a series on InstanceContexts.  You might want to read Part 1: Understanding InstanceContext in WCF before continuing on with this post.

Like most things in WCF, there are a few ways to extend an InstanceContext:

  1. IExtension<InstanceContext>: This interface is used to create objects that can be attached to the InstanceContext through the Extensions property.  These objects can store additional state information or behaviors.  This works off the standard extensible object pattern is used in WCF to either extend existing run-time classes with new functionality or to add new state features to an object.
  2. IInstanceContextProvider: Implement to participate in the creation or choosing of a InstanceContext, especially to enable shared sessions.
  3. IInstanceContextInitializer: Defines the methods necessary to inspect or modify the creation of InstanceContext objects when required. This is typically added to attach an IExtension<InstanceContext> to the InstanceContext object as a mechanism for passing data throughout an application.

Lets look at an example that implements some of these extension mechanisms to store additional state information with the InstanceContext.  For this sample, I want some extension that allows me to store the DateTime that an instance of the service was created and what is the creation index count of this instance.  The goal is to just be able to add an Attribute to the service and have it automatically store these values in the InstanceContext. To do this I need an IExtension that defines the values I want to store, an IInstanceContextProvider that adds the IExtension to the service instance when it is created, and an Attribute that implements IContractBehavior that we can use on the service.

1. IExtension<InstanceContext>

The IExtension interface is part of the extensible object pattern is used in WCF to either extend existing run-time classes with new functionality or to add new state features to an object. Since InstanceContext derives from IExtensibleObject, we can add these extension controls to it in order to provide more state information with the InstanceContext.  This interface defines 2 methods:

  1. void Attach(T owner): Enables an extension object to find out when it has been aggregated. Called when the extension is added to the IExtensibleObject<T>Extensions property.
  2. void Detach(T owner): Enables an object to find out when it is no longer aggregated. Called when an extension is removed from the IExtensibleObject<T>Extensions property.

In this example we are only using the extension to hold data and do not care what happens when it is attached or detached from the owner.  So we only need to define the two properties we want to track:

[DataContract]
public class InstanceCreationExtension :
    IExtension<InstanceContext>
{
    private int m_InstanceCreationIndex;
    private DateTime m_InstanceCreated;

    [DataMember]
    public int InstanceCreationIndex
    {
        get { return m_InstanceCreationIndex; }
    }

    [DataMember]
    public DateTime InstanceCreated
    {
        get { return m_InstanceCreated; }
    }

    public InstanceCreationExtension(
        int instanceCreationIndex,
        DateTime instanceCreated)
    {
        m_InstanceCreationIndex = instanceCreationIndex;
        m_InstanceCreated = instanceCreated;
    }

    public override string ToString()
    {
        return String.Format("Creation Index {0}, Created: '{1}'",
            m_InstanceCreationIndex,
            m_InstanceCreated);
    }

    public void Attach(
        InstanceContext owner)
    {
    }

    public void Detach(
        InstanceContext owner)
    {
    }
}

2. IInstanceContextInitializer

The IInstanceContextInitializer interfacedDefines the methods necessary to inspect or modify the creation of InstanceContext objects.  When an InstanceContext is created, this interface can be used to perform additional operations on it through the Initialize method.  In our example, we want to add a our custom IExtension object to the Extensions collection when the InstanceContext is created:

public class InstanceCreationInitializer :
    IInstanceContextInitializer
{
    private static int m_InstanceCreationIndex = 0;

    public void Initialize(
        InstanceContext instanceContext,
        Message message)
    {
        // Increment instance creation index (thread safe)
        System.Threading.Interlocked.Increment(
            ref m_InstanceCreationIndex);

        // Add extension which contains the new instance creation index
        instanceContext.Extensions.Add(
            new InstanceCreationExtension(
                m_InstanceCreationIndex,
                DateTime.Now));
    }
}

3. IContractBehavior Attribute

Now that we have defined an object to store our data and a way to populate it, we have to wire up our custom IInstanceContextInitializer so that it can do its job.  There are a few ways to do this, but perhaps the easiest way is to create a custom attribute that can be added to the service which wires it up.  To do this, we just need to extend the IContractBehavior interface. This interface defines the methods that can be used to extend run-time behavior for a contract in either a service or client application.  For this example, we only need to modify the dispatch behavior that is used or the service.  In this method we are going to added our custom IInstanceContextInilializer to the InstanceContextInitializers collection on the DispatchRuntime.  This basically means that when this attribute is applied to a service, then every time an instance is created, it will call the custom IInstanceContextInilializer that we have defined.

public class InstanceCreationAttribute :
    Attribute, IContractBehavior
{
    public void AddBindingParameters(
        ContractDescription contractDescription,
        ServiceEndpoint endpoint,
        BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(
        ContractDescription contractDescription,
        ServiceEndpoint endpoint,
        ClientRuntime clientRuntime)
    {
    }

    public void ApplyDispatchBehavior(
        ContractDescription contractDescription,
        ServiceEndpoint endpoint,
        DispatchRuntime dispatchRuntime)
    {
        dispatchRuntime.InstanceContextInitializers.Add(
            new InstanceCreationInitializer());
    }

    public void Validate(
        ContractDescription contractDescription,
        ServiceEndpoint endpoint)
    {
    }
}

Contract

We now have all of the customizations we need defined.  Now we can see how it is applied to a service.  For this example, we can define a contract with a single method that returns a string which will show us the service instance creation count and the DateTime in which the service was created:

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    string GetInstanceDescription();
}

Service

The service is pretty straight forward.  The implementation of the GetInstanceDescription method just pulls our custom IExtension from the Extensions collection of the current InstanceContext that the operation is running on.  Notice that we have set the InstanceContextMode to PerCall.  This means that every time we call a method a new instance of a service will be created.  So this method should return a unique string every time.  (You can change this to PerSession and Single to see different results.)

The real magic that gets our example working is the [InstanceCreation] attribute we defined on the service.  This is the custom IContractBehavior attribute that will inject our custom IInstanceContextInitializer and add our custom IExtension object to the InstanceContext.

[ServiceBehavior(
    InstanceContextMode=InstanceContextMode.PerCall)]
[InstanceCreation]
public class MyService : IMyService
{
    public string GetInstanceDescription()
    {
        InstanceContext ic = OperationContext.Current.InstanceContext;

        InstanceCreationExtension extension =
            ic.Extensions.Find<InstanceCreationExtension>();

        return extension.ToString();
    }
}

Example Client

In this sample client we are going to just call the method on the service and display a MessageBox with data from the InstanceContext on the service.  Since we have the service InstanceContextMode set as PerCall, this message will be different each time you click the button on the form.

public partial class ClientForm : Form
{
    IMyService m_Client;

    public ClientForm()
    {
        InitializeComponent();

        ChannelFactory<IMyService> channeFactory =
            new ChannelFactory<IMyService>("NetTcpBinding_IMyService");
        m_Client = channeFactory.CreateChannel();
    }

    private void m_AddNameButton_Click(object sender, EventArgs e)
    {
        MessageBox.Show(m_Client.GetInstanceDescription());
    }
}

 

You can use this sample to add any type of information you want to each instance of a service.  This is most useful if you are using PerCall or PerSession InstanceContextMode.  You could have done some of these operations in the service constructor, but this type of extension allows you to bury this logic into a reusable component and access data that may not normally have access to.

You can download a complete sample of the code discussed in this article here: http://www.danrigsby.com/Files/Rigsby.WcfServiceContexts.zip

 

kick it on DotNetKicks.com

Posted in Wcf | 6 Comments »

Understanding InstanceContext in WCF

Posted by Dan Rigsby on 23rd May 2008

InstanceContext in Wcf Series:
Part 1: Understanding InstanceContext
Part 2: Extending InstanceContext to store custom state

InstanceContext in WCF seems to be somewhat misunderstood.  I have seen a number of questions on MSDN Forums asking what this is or how it is used.  Conceptually it just represents the running instance of the service. Often times it is helpful to think of InstanceContext along with OperationContext. This is the transverse of OperationContext which is the instance of the client accessing the service.  From the service you can access the OperationContext of the client by simply looking at System.ServiceModel.OperationContext.Current.  This object has reference to the InstanceContext of the service it is accessing.  The InstanceContext derives from CommunicationObject

Methods to Note

  1. IncrementManualFlowControlLimit: Increases the number of messages that can be processed by the service instance by a specified about.  This method returns the new limit on the number of messages, after the number to increase by has been added.
  2. GetServiceInstance: Returns the instance of the service, or creates a new instance of the service if the service doesn’t exits or has been released.
  3. ReleaseServiceInstance:  Releases the service instance.

When ReleaseServiceInstance is called the runtime will disassociate the instance from the InstanceContext and call dispose (is IDisposable is implemented) on the instance. A new instance of the service will be created when a new message arrives of if GetServiceInstance is called. (see here Mahjayar’s Weblog for more details)

Properties to note

  1. State: (Derived from CommunicationObject.) Gets a value that indicates the current state of the communication object.
    1. Created: Indicates that the communication object has been instantiated and is configurable, but not yet open or ready for use
    2. Opening: Indicates that the communication object is being transitioned from the Created state to the Opened state.
    3. Opened: Indicates that the communication object is now open and ready to be used.
    4. Closing: Indicates that the communication object is transitioning to the Closed state.
    5. Closed: Indicates that the communication object has been closed and is no longer usable.
    6. Faulted: Indicates that the communication object has encountered an error or fault from which it cannot recover and from which it is no longer usable.
  2. Extensions: Gets the collection of extensions associated with the service instance.  These extensions would be classes derived from IExtension<InstanceContext>
  3. ManualFlowControlLimit: Gets or sets a limit on the number of messages that can be processed by the instance context.
  4. SynchronizationContext: Gets or sets the context used for thread synchronization with the current instance context.
  5. IncomingChannels: Gets the sessionful channels that are incoming to the service instance.
  6. OutgoingChannels: Gets the sessionful channels that are outgoing from the service instance.

InstanceContextMode

In the ServiceBehaviorAttribute you can set the InstanceContextMode of the service.  This property defines how new service objects are created.  There are three options here:

  1. PerSession: A new InstanceContext object is created for each session.  This means a new instance of the service itself is created for every unique client connection. If the channel does not create a session this value behaves as if it were PerCall.
  2. PerCall: A new InstanceContext object is created prior to and recycled subsequent to each call.   So a new instance of the service is created for every call even if the calls are coming from the same client.
  3. Single: Only one InstanceContext object is used for all incoming calls and is not recycled subsequent to the calls. If a service object does not exist, one is created.

The default option is PerSession, but if you aren’t using a binding that allows sessions, then the behavior will be like that of PerCall. (See here for a list of bindings that support or don’t support sessions).

Here is an example of setting context mode on a server:

[ServiceBehavior(
    InstanceContextMode = InstanceContextMode.Single)]
public class MyService : IMyService
{
    ...
}

Technically whenever the user calls InstanceContext.ReleaseServiceInstance() the runtime will disassociate the instance from the InstanceContext and call dispose (If the instance inherits from IDisposable) on the instance. A new instance will be created when a new message arrives for that endpoint or the user explicitly calls InstanceContext.GetServiceInstance().

Accessing the Instance of a service a client is running on

You might want to access the InstanceContext that a client is running against.  These instances can be different since a new instance could be created PerSession or PerCall.  To access this InstanceContext, you can look at it directly in the current OperationContext:

InstanceContext ic = OperationContext.Current.InstanceContext;

Obtain a unique Id for an InstanceContext

Since each InstanceContext is unique, you can call GetHashCode() on the InstanceContext to get a unique identifier for the InstanceContext.  If you are using PerSession this may be important to ensure that the session is the same:

int serviceInstanceId =
    OperationContext.Current.InstanceContext.GetHashCode();

When might you create your own instance of InstanceContext?

The most common use for this is when using Duplexing.  In a Duplex system, the service can callback to the client via a CallbackContract.  This CallbackContract is much like a service on the client side that is listening for calls from the service on the channel that the client has opened.  This “client callback service” can only be accessed via the same channel it used on the service and therefore only that service has access to it.  In order to create the connection to the duplexed service you must specify an InstanceContext like so:

// "this" represents an object that implements the callback contract IMyDuplexServiceCallback
InstanceContext ic = new InstanceContext(this);
var m_ChannelFactory = new DuplexChannelFactory<IMyDuplexService>(ic);

Basically what we have done here is created a standard connection to the server, and gave it an object (InstanceContext) that represents the “client callback service”.

On the service you can access the “client callback service” via the GetCallbackChannel method like so:

IMyServiceCallback callback =
    OperationContext.Current.GetCallbackChannel<IMyServiceCallback>()

Extending InstanceContext

Like most things in WCF, there are a few ways to extend an InstanceContext:

  1. IExtension<InstanceContext>: This interface is used to create objects that can be attached to the InstanceContext through the Extensions property.  These objects can store additional state information or behaviors.  This works off the standard extensible object pattern is used in WCF to either extend existing run-time classes with new functionality or to add new state features to an object.
  2. IInstanceContextProvider: Implement to participate in the creation or choosing of a InstanceContext, especially to enable shared sessions.
  3. IInstanceContextInitializer: Defines the methods necessary to inspect or modify the creation of InstanceContext objects when required. This is typically added to attach an IExtension<InstanceContext> to the InstanceContext object as a mechanism for passing data throughout an application.

Look for a second part of this post that will explain extending the InstanceContext in more detail.

kick it on DotNetKicks.com

Posted in Wcf | 5 Comments »

Get the Client’s Address in WCF

Posted by Dan Rigsby on 21st May 2008

In .Net 3.0 there was not a reliable way to obtain the address of the client connecting to a WCF service.  In .Net 3.5 a new property was introduced called RemoteEndpointMessageProperty.  This property gives you the IP address and port that the client connection came into the service on. Obtaining the this information is pretty straight forward.  Just pull it from the IncomingMessageProperties of the current OperationContext by the RemoteEndpointMessageProperty.Name and access the Address and Port properties.

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    string GetAddressAsString();
}

public class MyService : IMyService
{
    public string GetAddressAsString()
    {
        RemoteEndpointMessageProperty clientEndpoint =
            OperationContext.Current.IncomingMessageProperties[
            RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;

        return String.Format(
            "{0}:{1}",
            clientEndpoint.Address, clientEndpoint.Port);
    }
}

Things to note:

  1. This property only works on http and tcp transports.  On all other transports such as MSMQ and NamedPipes, this property will not be available.
  2. The address and port are reported by the socket or http.sys of the service’s machine.  So if the client came in over a VPN or some other proxy that modified the address, that new address will be represented instead of the client’s local address.  This is desirable and important because this is the address and port that the service sees the client as, not as the client sees itself as.  This also means that there could be some spoofing going on.  A client or something in between the client and server could spoof an address. So, do not use the address or port for any security decisions unless you add in some other custom checking mechanisms.
  3. If you are using duplexing on your service, then not only will the service have this property populated for the client, but the client will also have this property populated for the service for each call from that service.

You can download a sample service using this code here: http://www.danrigsby.com/Files/Rigsby.WcfClientAddress.zip

Posted in Wcf | 4 Comments »

Impersonate a Client’s Identity in Wcf

Posted by Dan Rigsby on 17th April 2008

Impersonation is the process of impersonating a user in an application that isn’t necessarily running as that user.  In Wcf, a service may need to impersonate the user of the client in order to access a resource such as a file share, another machine, etc.  The service may even need to call a different Wcf service on the client’s behalf.

First off, you need to be using a binding that supports impersonation. They are:

To setup impersonation you can follow one of two models: Declarative and Imperative.

Declarative Model

The easiest way to setup impersonation is declaratively through a System.ServiceModel.ImpersonationOption.  This is a property of the OperationBehaviorAttribute that indicates the level of impersonation that the operation supports.  There are three options here:
  1. NotAllowed: Impersonation is not performed. If ImpersonateCallerForAllOperations is equal to true, a validation exception occurs at service startup time.
  2. Allowed: Impersonation is performed if credentials are available and ImpersonateCallerForAllOperations is equal to true.
  3. Required: Impersonation is required. This method can’t run unless the user can be impersonated.  The value of ImpersonateCallerForAllOperations doesn’t matter here.  Impersonation always takes place.

The default value is NotAllowed.  So if you are going to use ImpersonateCallerForAllOperations, you will need to make sure to set all of your methods to ImpersonationOption.Allowed.  If you are not using ImpersonateCallerForAllOperations and just want to use a impersonation for a single method, the set ImpersonationOption.Required.

[OperationBehavior(Impersonation=ImpersonationOption.Required)]
public bool MyMethod(string input)
{
    return true;
}

Imperative model

If you chose to setup the impersonation in code, System.ServiceModel.ServiceSerurityContext has everything you need.  But, if the declarative model is so easy to use, why would you want to set this up through code? Well, this model is best used if only a part of your method needs to use impersonation.  The declarative model uses client impersonation for everything in the method.  Depending on what your system is doing, one model may be better than another.

public bool MyMethod(string myParameter)
{
    // Set security context for the current user
    System.ServiceModel.ServiceSecurityContext securityContext =
        System.ServiceModel.ServiceSecurityContext.Current;

    // Make sure there is a windows identity present and impersonate it
    if (securityContext != null
        && securityContext.WindowsIdentity != null)
    {
        // Can check the securityContext.WindowsIdentity.ImpersonationLevel
        // here to make sure we are allowed to impersonate before
        // actually creating the impersonation context

        using (securityContext.WindowsIdentity.Impersonate())
        {
            // TODO: Perform operations here as the impersonated user
        }
    }

    return false;
}
 
Seems easy enough right?  You just grab the current windows identity and create a WindowsImpersonationContext
 

Impersonation for all Methods

If you need to use impersonation for all methods on a service. You can use the ServiceAuthorizationBehavior and set the ImpersonateCallerForAllOperations property to true.  This can be done programmatically on the servicehost like so:

ServiceAuthorizationBehavior serviceAuthoriationBehavior =
    serviceHost.Description.Behaviors.Find<ServiceAuthorizationBehavior>();
serviceAuthoriationBehavior.ImpersonateCallerForAllOperations = true;

Or through the application configuration as such:

<behaviors>
    <serviceBehaviors>
        <behavior name="myBehavior">
            <serviceAuthorization impersonateCallerForAllOperations="true" />
        </behavior>
    </serviceBehaviors>
</behaviors>

Client Configuration

There is a bit more to this story.  The default ImpersonationLevel of the client is set to Identification which doesn’t allow impersonation.  You must setup the client connection to allow impersonation.  Here is a list of the impersonation levels you can use:
  1. None: An impersonation level is not assigned.
  2. Anonymous: The server process cannot obtain identification information about the client, and it cannot impersonate the client.
  3. Identification: The server process can obtain information about the client, such as security identifiers and privileges, but it cannot impersonate the client. This is useful for servers that export their own objects, for example, database products that export tables and views. Using the retrieved client-security information, the server can make access-validation decisions without being able to use other services that are using the client’s security context.
  4. Impersonation: The server process can impersonate the client’s security context on its local system. The server cannot impersonate the client on remote systems.
  5. Delegation: The server process can impersonate the client’s security context on remote systems.

If you need impersonation, you will have to choose between Impersonation or Delegation depending on your needs. 

If you are using a proxy client to connect to the service, you could setup the impersonation level like so:

// Create a new client and set the impersonation level
MyServiceClient client = new MyServiceClient();
client.ClientCredentials.Windows.AllowedImpersonationLevel =
     System.Security.Principal.TokenImpersonationLevel.Impersonation;
 
Using a ChannelFactory is very similar:
 
// Create a new channel factory and set the impersonation level
ChannelFactory<IMyService> channelFactory =
    new ChannelFactory<IMyService>();
channelFactory.Credentials.Windows.AllowedImpersonationLevel =
     System.Security.Principal.TokenImpersonationLevel.Impersonation;
 

Impersonate a totally different Windows User in a client

There may also be times when on the client you want to impersonate a different user than what is currently being used. To do this, you must know the domain, username, and password for that user. You then just use these values to set the client credential for the client:

MyServiceClient client = new MyServiceClient();
client.ClientCredentials.Windows.ClientCredential.Domain = domain;
client.ClientCredentials.Windows.ClientCredential.UserName = username;
client.ClientCredentials.Windows.ClientCredential.Password = password;
client.ClientCredentials.Windows.AllowedImpersonationLevel =
     System.Security.Principal.TokenImpersonationLevel.Impersonation;
 

Or through a ChannelFactory as such:

ChannelFactory<IMyService> channelFactory =
    new ChannelFactory<IMyService>();
channelFactory.Credentials.Windows.ClientCredential.Domain = domain;
channelFactory.Credentials.Windows.ClientCredential.UserName = username;
channelFactory.Credentials.Windows.ClientCredential.Password = password;
channelFactory.Credentials.Windows.AllowedImpersonationLevel =
     System.Security.Principal.TokenImpersonationLevel.Impersonation;
 
You can read more about impersonation here: http://msdn2.microsoft.com/en-us/library/ms730088.aspx

kick it on DotNetKicks.com

 

Posted in Wcf | 6 Comments »

Specifying a different serializer per endpoint in Wcf

Posted by Dan Rigsby on 10th April 2008

I got a question recently on the MSDN forums about being able to specify a different serializer per endpoint in Wcf.  For instance, you might have a single service, but some clients want to access it with either XmlSerializer serialized or DataContractSerializer serialized data.  If want to know about more about these different serializers, I recommend you read "XmlSerializer vs. DataContractSerializer: Serialization in Wcf".

The problem is that to specify a service is to use the XmlSerializer you need to declare the [XmlSerializerFormat] attribute on the service or the contract.  Well since we want to use the same for both endpoints we can’t place it there, so we are left with placing it on the contract.  However, when it boils down to it, both endpoints are using the same service and vicariously the same contract right?

Well, it doesn’t have to be so.  You could have a contract A derive from contract B, then have the service implement contract A such that everything in both contracts is part of the service. For this example though, contract B will be our standard contract, and contract A will be an interface that just defines the [XmlSerializerFormat] attribute.

Here is a sample service and contract implementation which illustrates this:

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    MyDataType GetData(int id);
}

[ServiceContract]
[XmlSerializerFormat]
public interface IMyServiceXmlSerializer : IMyService
{
}

public class MyService : IMyServiceXmlSerializer
{
    public MyDataType GetData(int id)
    {
        MyDataType myData = null;

        // Do logic to get data by id

        return myData;
    }
}

[DataContract]
[Serializable]
public class MyDataType
{
}

 

Here is the app.config for the service.  Note the 2 different endpoints are each specifying a different contract and therefore will use different serializers.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="MyNamespace.MyService" behaviorConfiguration="serviceBehavior">
        <host>
          <baseAddresses>
            <add baseAddress = "http://localhost:8080/MyService" />
          </baseAddresses>
        </host>
        <endpoint
            name="dataContractSerializer"
            address =""
            binding="wsHttpBinding"
            contract="MyNamespace.IMyService"/>
        <endpoint
            name="xmlSerializer"
            address ="xmlSerializer"
            binding="wsHttpBinding"
            contract="MyNamespace.IMyServiceXmlSerializer"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="serviceBehavior">
          <serviceMetadata httpGetEnabled="True"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

 

kick it on DotNetKicks.com

Posted in Wcf | 2 Comments »

Async Operations in Wcf: Canceling Operations

Posted by Dan Rigsby on 30th March 2008

Async Operations in Wcf Series:
Part 1: Event Based Model
Part 2: IAsyncResult Model (Client-Side)
Part 3: IAsyncResult Model (Server-Side)
Part 4: Canceling Operations
Part 5: Handling Exceptions

This is the fourth in a four part series on asynchronous operations in Wcf.  If you are new to this series, you might want to read the first section of part one to get an introduction to this post: http://www.danrigsby.com/blog/index.php/2008/03/18/async-operations-in-wcf-event-based-model/

What is Canceling Wcf Operations

In some situations, when you submit an asynchronous call to the server, you might want to be able to cancel the operation.  Let’s say you have a query running that will may last over 30 seconds and the user navigates away.  Or suppose you are running an expensive database update and realize that you need to cancel the operation before it completes.

Windows Communication Foundation has no support for canceling operations and some pitfalls in trying to implement it are addressed here: http://blogs.msdn.com/drnick/archive/2007/12/27/cleaning-up-async.aspx.  This article will explain an approach to implement canceling support.  The process explained here uses a custom library called “Rigsby.AsyncOperation” and a class called “PendingOperationController”. This approach has one major pitfall: if an operation has completed, the best chance a cancel operation has may be to cancel the return to the client.  While this can save network bandwidth, the operation is still completed.  This can be undesirable in situations like a database update, but you there is little that can be done once everything in complete.  What this approach does offer is a way to cancel an operation that will try to cancel at multiple stages:

  1. If the operation is just sitting in the thread pool and hasn’t yet been processed, then it will be removed.
  2. If the operation is already running, then it will try to cancel the operation after it is complete.  It does this via a TransactionScope to attempt to rollback the operation.
  3. The operation itself can check the status of the request to check if it has been canceled at any time.  So if you have an operation which does 3 updates to the database, you can double check between each update if the request has been canceled, and if so bail out and let the TransactionScope roll back the pervious updates.

The PendingOperationController can also be used for other server-side asynchronous operations as well.  The controller could just be used to handle queuing of requests and signaling their completion.  This can make server-side code much cleaner while giving you the ability to add canceling support in the future.

What is AsyncOperation library

The AsyncOperation library is a custom library that can be used to assist with asynchronous operations in Wcf and provide support for cancellations.  (You can download the library here, but the code for each file is included inline as well.) The goal of this library and the PendingOperationController is all about extensibility and flexibility to work with many different systems and scenarios. The library contains 5 items:

1. AsyncStatus Enum

To convey the status of a pending operation, this enumeration contains all of the states that a pending operation can be in:

namespace Rigsby.AsyncOperation
{
    /// <summary>
    /// The status for an asynchronous operation.
    /// </summary>
    public enum AsyncStatus
    {
        /// <summary>
        /// The status is unknown.
        /// </summary>
        Unknown = 0,

        /// <summary>
        /// The asynchronous operation has not yet been started, but is queued up.
        /// </summary>
        Queued,

        /// <summary>
        /// The asynchronous operation has been started.
        /// </summary>
        Started,

        /// <summary>
        /// The asynchronous operation has completed.
        /// </summary>
        Completed,

        /// <summary>
        /// The asynchronous operation has been canceled.
        /// </summary>
        Canceled
    }
}

2. AsyncResult Class

This class was introduced in the IAsyncResult Model (Server-Side) article.  You could use the System.Runtime.Remoting.Messaging.AsyncResult, but many times you will want your own implementation of IAsyncResult.  I use a custom AsyncResult base class and inherit from it to add in properties and methods needed by the operations. Here is a base AsyncResult class that you can use:

using System;
using System.Threading;

namespace Rigsby.AsyncOperation
{
    /// <summary>
    /// The result of an asynchronous operation.
    /// </summary>
    public class AsyncResult : IAsyncResult, IDisposable
    {
        private AsyncCallback m_AsyncCallback;
        private object m_State;
        private ManualResetEvent m_ManualResentEvent;

        /// <summary>
        /// Initializes a new instance of the <see cref="AsyncResult"/> class.
        /// </summary>
        /// <param name="callback">The callback.</param>
        /// <param name="state">The state.</param>
        public AsyncResult(
            AsyncCallback callback,
            object state)
        {
            this.m_AsyncCallback = callback;
            this.m_State = state;
            this.m_ManualResentEvent = new ManualResetEvent(false);
        }

        /// <summary>
        /// Completes this instance.
        /// </summary>
        public virtual void OnCompleted()
        {
            m_ManualResentEvent.Set();
            if (m_AsyncCallback != null)
            {
                m_AsyncCallback(this);
            }
        }

        #region IAsyncResult Members
        /// <summary>
        /// Gets a user-defined object that qualifies or contains information about an asynchronous operation.
        /// </summary>
        /// <value></value>
        /// <returns>A user-defined object that qualifies or contains information about an asynchronous operation.</returns>
        public object AsyncState
        {
            get
            {
                return m_State;
            }
        }

        /// <summary>
        /// Gets a <see cref="T:System.Threading.WaitHandle"/> that is used to wait for an asynchronous operation to complete.
        /// </summary>
        /// <value></value>
        /// <returns>A <see cref="T:System.Threading.WaitHandle"/> that is used to wait for an asynchronous operation to complete.</returns>
        public System.Threading.WaitHandle AsyncWaitHandle
        {
            get
            {
                return m_ManualResentEvent;
            }
        }

        /// <summary>
        /// Gets an indication of whether the asynchronous operation completed synchronously.
        /// </summary>
        /// <value></value>
        /// <returns>true if the asynchronous operation completed synchronously; otherwise, false.</returns>
        public bool CompletedSynchronously
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// Gets an indication whether the asynchronous operation has completed.
        /// </summary>
        /// <value></value>
        /// <returns>true if the operation is complete; otherwise, false.</returns>
        public bool IsCompleted
        {
            get
            {
                return m_ManualResentEvent.WaitOne(0, false);
            }
        }
        #endregion IAsyncResult Members

        #region IDisposable Members
        private bool m_IsDisposed = false;
        private event System.EventHandler m_Disposed;

        /// <summary>
        /// Gets a value indicating whether this instance is disposed.
        /// </summary>
        /// <value>
        ///     <c>true</c> if this instance is disposed; otherwise, <c>false</c>.
        /// </value>
        [System.ComponentModel.Browsable(false)]
        public bool IsDisposed
        {
            get
            {
                return m_IsDisposed;
            }
        }

        /// <summary>
        /// Occurs when this instance is disposed.
        /// </summary>
        public event System.EventHandler Disposed
        {
            add
            {
                m_Disposed += value;
            }
            remove
            {
                m_Disposed -= value;
            }
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        public void Dispose()
        {
            if (!m_IsDisposed)
            {
                this.Dispose(true);
                System.GC.SuppressFinalize(this);
            }
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            try
            {
                if (disposing)
                {
                    m_ManualResentEvent.Close();
                    m_ManualResentEvent = null;
                    m_State = null;
                    m_AsyncCallback = null;

                    System.EventHandler handler = m_Disposed;
                    if (handler != null)
                    {
                        handler(this, System.EventArgs.Empty);
                        handler = null;
                    }
                }
            }
            finally
            {
                m_IsDisposed = true;
            }
        }

        /// <summary>
        ///    <para>
        ///        Checks if the instance has been disposed of, and if it has, throws an <see cref="ObjectDisposedException"/>; otherwise, does nothing.
        ///    </para>
        /// </summary>
        /// <exception cref="System.ObjectDisposedException">
        ///    The instance has been disposed of.
        ///    </exception>
        ///    <remarks>
        ///    <para>
        ///        Derived classes should call this method at the start of all methods and properties that should not be accessed after a call to <see cref="Dispose()"/>.
        ///    </para>
        /// </remarks>
        protected void CheckDisposed()
        {
            if (m_IsDisposed)
            {
                string typeName = GetType().FullName;

                // TODO: You might want to move the message string into a resource file
                throw new System.ObjectDisposedException(
                    typeName,
                    String.Format(System.Globalization.CultureInfo.InvariantCulture,
                        "Cannot access a disposed {0}.",
                        typeName));
            }
        }
        #endregion IDisposable Members
    }
}

3. PendingAsyncResult Class

This class is an extension of the AsyncResult class.  It is designed to contain all of the information needed as a operation moves through its stages.  Included in this are its status, the input values, and the output values:

  1. String Id property:  This is a simple identifier to distinguish the operation.  This should be a System.Guid value exposed as a string.  We can’t just use the IAsyncResult to identify the operation because it the SendAsyncResult class (discussed in the IAsyncResult Model (Server-Side) article) is not serializable.  Since we need to be able to identify the operation in order to cancel it or get it’s status, this is pretty important.
  2. Generic Input property: This property represents the input values.  It is quite possible and likely to have multiple input values for the operation you want this class to represent.  However to make this class be as flexible as possible, there is only a single generic input class.  If you have more than one input value, you should create an intermediate class that contains the different input values and use that class as the TInput template.  For example, if you have an “Addition” operation that takes in two numbers to add, you might have an Input class that contains two integers.
  3. Generic Output property: This property represents the out value of the operation.  This will always be a single value since that is all a method returns.  The type of the output value should be represented with the TOutput template.
  4. Events for status changes: For each of the major statuses there is an event that is fired for each.  You could feasibly change this to be a single event for all status changes, if you so choose.
  5. Methods for moving through statuses: To change statuses there is a method to move between the major statuses.  To move to the Canceled status, you would call the OnCanceled method, etc.
using System;

namespace Rigsby.AsyncOperation
{
    /// <summary>
    /// A pending asynchronous operation.
    /// </summary>
    public class PendingAsyncResult<TInput, TOutput> : AsyncResult
    {
        private string m_Id = String.Empty;
        private TInput m_Input;
        private TOutput m_Output;

        private EventHandler m_Canceled;
        private EventHandler m_Queued;
        private EventHandler m_Started;

        /// <summary>
        /// A generic object to perform a 'lock' on.
        /// </summary>
        protected object m_SyncRoot = new object();

        /// <summary>
        /// Protected implmenetation of <see cref="AsyncStatus"/>.
        /// </summary>
        protected AsyncStatus m_AsyncStatus;

        /// <summary>
        /// Gets or sets the async status.
        /// </summary>
        /// <value>The async status.</value>
        public AsyncStatus AsyncStatus
        {
            get
            {
                return m_AsyncStatus;
            }
        }

        /// <summary>
        /// Gets or sets the id.
        /// </summary>
        /// <value>The id.</value>
        public string Id
        {
            get
            {
                return m_Id;
            }
            set
            {
                m_Id = value;
            }
        }

        /// <summary>
        /// Gets or sets the input for the operation.
        /// </summary>
        /// <value>The input.</value>
        public TInput Input
        {
            get
            {
                return m_Input;
            }
            set
            {
                m_Input = value;
            }
        }

        /// <summary>
        /// Gets or sets the output of the operation.
        /// </summary>
        /// <value>The output.</value>
        public TOutput Output
        {
            get
            {
                return m_Output;
            }
            set
            {
                m_Output = value;
            }
        }

        #region Public Events
        /// <summary>
        /// Occurs when the operation has been canceled.
        /// </summary>
        public event EventHandler Canceled
        {
            add
            {
                m_Canceled += value;
            }
            remove
            {
                m_Canceled -= value;
            }
        }

        /// <summary>
        /// Occurs when the operation has been started.
        /// </summary>
        public event EventHandler Started
        {
            add
            {
                m_Started += value;
            }
            remove
            {
                m_Started -= value;
            }
        }

        /// <summary>
        /// Occurs when the operation has been eueued.
        /// </summary>
        public event EventHandler Queued
        {
            add
            {
                m_Queued += value;
            }
            remove
            {
                m_Queued -= value;
            }
        }
        #endregion Public Events

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="CancellableAsyncResult"/> class.
        /// </summary>
        /// <param name="callback">The callback.</param>
        /// <param name="state">The state.</param>
        public PendingAsyncResult(
            AsyncCallback callback,
            object state) : this(default(TInput), String.Empty, callback, state)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CancellableAsyncResult"/> class.
        /// </summary>
        /// <param name="callback">The callback.</param>
        /// <param name="state">The state.</param>
        public PendingAsyncResult(
            string id,
            AsyncCallback callback,
            object state) : this(default(TInput), id, callback, state)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CancellableAsyncResult"/> class.
        /// </summary>
        /// <param name="input">The input.</param>
        public PendingAsyncResult(
            TInput input,
            string id,
            AsyncCallback callback,
            object state) : base(callback, state)
        {
            m_Input = input;

            if (String.IsNullOrEmpty(id))
            {
                Id = Guid.NewGuid().ToString();
            }
            else
            {
                Id = id;
            }
        }
        #endregion Constructors

        /// <summary>
        /// Called when [queued].
        /// </summary>
        public virtual void OnQueued()
        {
            lock (m_SyncRoot)
            {
                if (m_AsyncStatus != AsyncStatus.Completed
                    && m_AsyncStatus != AsyncStatus.Canceled)
                {
                    m_AsyncStatus = AsyncStatus.Queued;
                }
            }

            EventHandler eventHandler = m_Queued;
            if (eventHandler != null)
            {
                eventHandler(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// Called when [started].
        /// </summary>
        public virtual void OnStarted()
        {
            lock (m_SyncRoot)
            {
                if (m_AsyncStatus != AsyncStatus.Completed
                    && m_AsyncStatus != AsyncStatus.Canceled)
                {
                    m_AsyncStatus = AsyncStatus.Started;
                }
            }

            EventHandler eventHandler = m_Started;
            if (eventHandler != null)
            {
                eventHandler(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// Cancels this instance.
        /// </summary>
        public virtual void OnCanceled()
        {
            lock (m_SyncRoot)
            {
                if (m_AsyncStatus != AsyncStatus.Completed)
                {
                    m_AsyncStatus = AsyncStatus.Canceled;
                }
            }

            EventHandler eventHandler = m_Canceled;
            if (eventHandler != null)
            {
                eventHandler(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// Completes this instance.
        /// </summary>
        public override void OnCompleted()
        {
            lock (m_SyncRoot)
            {
                m_AsyncStatus = AsyncStatus.Completed;
            }

            base.OnCompleted();
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                // Null out event to remove subscribers
                m_Started = null;
                m_Queued = null;
                m_Canceled = null;
            }

            base.Dispose(disposing);
        }
    }
}

One possible addition to this class could be to extend the concept of “status” to include more such as a “percent complete”.  It would be up to you how you would calculate the completion percent.

4. PendingOperationEventHandler Delegate

This delegate represents the method that the PendingOperationController will call when it is actually ready to do its work.  This method uses the same TInput and TOutput templates discussed in the PendingAsyncResult class.  For instance if this operation is a database insert, the method represented in this delegate would be the method that actually performs the database insert.

namespace Rigsby.AsyncOperation
{
    /// <summary>
    /// Represents a method that is called from a <see cref="PendingOperationController"/>.
    /// </summary>
    public delegate TOutput PendingOperationEventHandler<TInput, TOutput>(TInput data);
}

5. PendingOperationController Class

This is the heart of the AyncOperation library.  This class controls and monitors pending operations.  You could use this class if you implement canceling abilities or not.  This class is designed such that there is one PendingOperationController for each type of operation.  To instantiate the class you must specify the types for TInput and TOuput as well as the PendingOperationEventHandler delegate that represents the method that this class should call when executing the operation.  Once the class has been instantiated there three methods that can be called:

  1. AddPendingOperation: This method queues up an operation to be processed.  Each pending operation is added to the thread pool and the method is returned.  When a thread is available in the thread pool, the Callback method is called which checks to see if the operation has yet been canceled, then calls the method represented in the PendingOperationEventHandler delegate with the TInput and TOuput values from the PendingAsyncResult object.  The Callback method implements a TransactionScope.  At the end of the method, it checks one last time to see if the operation has been canceled.  If it has, then the the transaction is rolled back, otherwise the transaction completes and the client is signaled that the operation is complete.
  2. GetPendingOperationStatus:  This method returns the status of a pending operation in the queue.  If the operation is not found the “Unknown” result is returned.  This method may be called by the method represented in the PendingOperationEventHandler delegate to see if the operation has been canceled before proceeding on through the lines in the method.
  3. CancelPendingOperation: This method canceling pending operation.  It returns true if the operation has been canceled, and false if the operation cannot be canceled.  If this returns false, then the operation has probably already completed.
using System;
using System.Collections.Generic;
using System.Threading;

namespace Rigsby.AsyncOperation
{
    /// <summary>
    /// Controls pending asynchronous operations.
    /// </summary>
    /// <typeparam name="TInput">The type of the input.</typeparam>
    /// <typeparam name="TOutput">The type of the output.</typeparam>
    public class PendingOperationController<TInput, TOutput>
    {
        public ReaderWriterLockSlim m_PendingOperationsLock =
            new ReaderWriterLockSlim();
        private static Dictionary<string, PendingAsyncResult<TInput, TOutput>> m_PendingOperations =
            new Dictionary<string, PendingAsyncResult<TInput, TOutput>>();

        private PendingOperationEventHandler<TInput, TOutput> m_Operation;

        /// <summary>
        /// Initializes a new instance of the <see cref="PendingOperationController&lt;TInput, TOutput&gt;"/> class.
        /// </summary>
        /// <param name="operation">The operation that is called when a pending operation is running.</param>
        public PendingOperationController(
            PendingOperationEventHandler<TInput, TOutput> operation)
        {
            m_Operation = operation;
        }

        /// <summary>
        /// Adds the pending operation.
        /// </summary>
        /// <param name="asyncResult">The async result.</param>
        public void AddPendingOperation(
            PendingAsyncResult<TInput, TOutput> asyncResult)
        {
            m_PendingOperationsLock.EnterWriteLock();
            try
            {
                if (!m_PendingOperations.ContainsKey(asyncResult.Id))
                {
                    m_PendingOperations.Add(asyncResult.Id, asyncResult);
                }
                else
                {
                    m_PendingOperations[asyncResult.Id] = asyncResult;
                }
                asyncResult.OnQueued();
            }
            finally
            {
                m_PendingOperationsLock.ExitWriteLock();
            }

            ThreadPool.QueueUserWorkItem(
                new WaitCallback(
                    Callback), asyncResult);
        }

        /// <summary>
        /// Gets the pending operation status.
        /// </summary>
        /// <param name="operationId">The operation id.</param>
        /// <returns></returns>
        public AsyncStatus GetPendingOperationStatus(
            string operationId)
        {
            AsyncStatus status = AsyncStatus.Unknown;

            m_PendingOperationsLock.EnterReadLock();
            try
            {
                if (m_PendingOperations.ContainsKey(operationId))
                {
                    status = m_PendingOperations[operationId].AsyncStatus;
                }
            }
            catch (KeyNotFoundException)
            {
                // ignore
            }
            finally
            {
                m_PendingOperationsLock.ExitReadLock();
            }

            return status;
        }

        /// <summary>
        /// Cancels the pending operation.
        /// </summary>
        /// <param name="operationId">The operation id.</param>
        /// <returns>Whether or not the operation was canceled.  
        /// If false, then the operation has probably already completed or the operationId was not valid.</returns>
        public bool CancelPendingOperation(
            string operationId)
        {
            bool result = false;

            PendingAsyncResult<TInput, TOutput> asyncResult = null;
            m_PendingOperationsLock.EnterReadLock();
            try
            {
                if (m_PendingOperations.ContainsKey(operationId))
                {
                    asyncResult = m_PendingOperations[operationId];
                }
            }
            catch (KeyNotFoundException)
            {
                // ignore
            }
            finally
            {
                m_PendingOperationsLock.ExitReadLock();
            }

            if (asyncResult != null)
            {
                asyncResult.OnCanceled();
                result = true;
                RemovePendingOperation(operationId);
                asyncResult.Dispose();
            }

            return result;
        }

        /// <summary>
        /// Gets the pending operation result.
        /// </summary>
        /// <param name="asyncResult">The async result.</param>
        /// <returns></returns>
        public TOutput GetOperationResult(
            IAsyncResult asyncResult)
        {
            TOutput result;

            PendingAsyncResult<TInput, TOutput> myAsyncResult =
                (PendingAsyncResult<TInput, TOutput>)asyncResult;
            result = myAsyncResult.Output;
            myAsyncResult.AsyncWaitHandle.WaitOne();
            myAsyncResult.Dispose();

            return result;
        }

        private void Callback(
            object state)
        {
            PendingAsyncResult<TInput, TOutput> asyncResult =
                state as PendingAsyncResult<TInput, TOutput>;

            // Make sure the operation isn't canceled yet.
            if (asyncResult.AsyncStatus != AsyncStatus.Canceled
                && m_PendingOperations.ContainsKey(asyncResult.Id))
            {
                using (System.Transactions.TransactionScope transactionScope =
                    new System.Transactions.TransactionScope())
                {
                    try
                    {
                        asyncResult.OnStarted();
                        asyncResult.Output = m_Operation.Invoke(asyncResult.Input);
                    }
                    finally
                    {
                        if (asyncResult.AsyncStatus != AsyncStatus.Canceled)
                        {
                            // Mark transaction completed
                            transactionScope.Complete();

                            asyncResult.OnCompleted();
                        }

                        RemovePendingOperation(asyncResult.Id);
                    }
                }
            }
        }

        private void RemovePendingOperation(
            string operationId)
        {
            m_PendingOperationsLock.EnterWriteLock();
            try
            {
                if (m_PendingOperations.ContainsKey(operationId))
                {
                    PendingAsyncResult<TInput, TOutput> asyncResult = m_PendingOperations[operationId];
                    m_PendingOperations.Remove(operationId);
                }
            }
            catch (KeyNotFoundException)
            {
                // ignore
            }
            finally
            {
                m_PendingOperationsLock.ExitWriteLock();
            }
        }
    }
}

How to implement it

Continuing with the previous articles in this series, the example implementation in this article be a service that calculates a square root.  Normally this operation is very fast, so the service implements a 4 second thread sleep, so that we can show the asynchronous operations and allow time to cancel a pending operation.  To better understand these example you might want to look over the previous articles especially: IAsyncResult Model (Server-Side).

Contract

The contract is much like that in previous articles with the following changes:

  1. The BeginGetSquareRoot now takes in the operationId.  The client determines the operation id so that it can use that identifier to reference the pending operation in the future.  This parameter can be anywhere in the parameter list, but I recommend that it be the last parameter for the AysncCallback and object parameters which must always be the last two parameters in an asynchronous operation.  If your method takes in more or one parameters, they should be displayed first.
  2. The synchronous and asynchronous versions of the operation must have different names (not including the “Begin” prefix on the asynchronous method).  We couldn’t have a method called GetSquareRoot and BeginGetSquareRoot.  This would cause a runtime exception because both the synchronous and asynchronous versions of a method must have the same parameters.  Since we have added the operationId, the method names must be different.  If you need to keep the same names, you could pass in the operationId to the synchronous method as well, but this doesn’t make sense.  One option I recommend is to just append “Async” to the asynchronous versions of the methods.  So you could have GetSquareRoot and BeginGetSquareRootAsync.
  3. We have added a CancelGetSquareRoot method that can be used to cancel an asychronous operation.  This method returns a boolean value that represents if the cancellation succeeded or not.
[ServiceContract]
public interface IMyService
{
    [OperationContract]
    double FindSquareRoot(double value);

    [OperationContract(AsyncPattern=true)]
    IAsyncResult BeginGetSquareRoot(double value, string operationId, AsyncCallback callback, object state);

    double EndGetSquareRoot(IAsyncResult asyncResult);

    [OperationContract]
    bool CancelGetSquareRoot(
        string asyncResultID);
}

Service

Our service is actually much simpler in this version than in previous articles since much of the work has been pushed to the PendingOperationController.  In the constructor of the service we build the PendingOperationController for our GetSquareRoot operations.  The FindSquareRoot method is the method that actually does our calculations.  This is the method that the PendingOperationEventHandler delegate represents, and this is the method passed into the constructor of the PendingOperationController.  The Begin, End, and Cancel operations all just call into the corresponding methods in the PendingOperationController.  The Begin method does have to create the intial PendingAsyncResult object, but otherwise the code in this methods should be very short.

[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple)]
public class MyService : IMyService
{
    private PendingOperationController<double, double> m_GetSquareRootOperationController;

    public MyService()
    {
        // Create the pending operation controller
        m_GetSquareRootOperationController =
            new PendingOperationController<double, double>(
                new PendingOperationEventHandler<double, double>(FindSquareRoot));
    }

    #region IMyService Members
    public double FindSquareRoot(double value)
    {
        Thread.Sleep(4000); // Wait 4 seconds
        return Math.Sqrt(value);
    }

    public IAsyncResult BeginGetSquareRoot(double value, string operationId, AsyncCallback callback, object state)
    {
        // Create pending result
        PendingAsyncResult<double, double> asyncResult =
            new PendingAsyncResult<double, double>(value, operationId, callback, state);

        // Queue pending result
        m_GetSquareRootOperationController.AddPendingOperation(asyncResult);

        return asyncResult;
    }

    public double EndGetSquareRoot(IAsyncResult asyncResult)
    {
        // Get pending result
        return m_GetSquareRootOperationController.GetOperationResult(asyncResult);
    }

    public bool CancelGetSquareRoot(string operationId)
    {
        // Cancel pending result
        return m_GetSquareRootOperationController.CancelPendingOperation(operationId);
    }
    #endregion IMyService Members
}

Example Client

For our example client, we have a basic windows forms application where the user can enter a value, send it to the server, and the result will be displayed.  We have added a cancel button as well that can be used while the operation is being processed:

client

Here is the code behind this page.  The only tricky things here are the callback method that is passed to the BeginGetSquareRoot method and the call to the EndGetSquareRoot method from that callback method.  I explained these two methods in more depth in the IAsyncResult Model (Server-Side) article.  We have extended this by adding in a cancel method.  The form now needs to store the Id for the operation being run, so that this Id can be used to cancel the operation.

public partial class Form1 : Form
{
    IMyService m_Client;
    string m_MyOperationId;

    public Form1()
    {
        InitializeComponent();

        ChannelFactory<IMyService> factory = new ChannelFactory<IMyService>("netTcp");
        factory.Open();
        m_Client = factory.CreateChannel();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        double value = 0;
        Double.TryParse(m_ValueTextBox.Text, out value);

        m_MyOperationId = Guid.NewGuid().ToString();

        m_Client.BeginGetSquareRoot(value, m_MyOperationId, new AsyncCallback(OnEndGetSquareRoot), null);

        m_StartButton.Enabled = false;
        m_CancelButton.Enabled = true;
        m_ResultTextBox.Text = "Loading...";
    }

    private void m_CancelButton_Click(object sender, EventArgs e)
    {
        bool canceled = m_Client.CancelGetSquareRoot(m_MyOperationId);

        m_StartButton.Enabled = canceled;
        m_CancelButton.Enabled = false;

        if (canceled)
        {
            m_ResultTextBox.Text = "Canceled";
        }
    }

    public void OnEndGetSquareRoot(IAsyncResult asyncResult)
    {
        if (this.IsHandleCreated && !this.IsDisposed)
        {
            this.Invoke(
                new MethodInvoker(delegate()
                {
                    m_ResultTextBox.Text = m_Client.EndGetSquareRoot(asyncResult).ToString();

                    m_StartButton.Enabled = true;
                    m_CancelButton.Enabled = false;
                }));
        }
    }
}

Notice that in the OnEndGetSquareRoot method, we can invoking the operation using “this.Invoke”.  This ensures that the operation is called on the UI thread since we are updating a UI element.  We know that OnEndGetSquareRoot is called by the signal on the server, so the method is always called by a thread from the server.

You can download a complete sample of the code discussed in this article here: http://www.danrigsby.com/Files/Rigsby.WcfAsyncOperation.zip

Posted in Wcf | 9 Comments »

Async Operations in Wcf: IAsyncResult Model (Server-Side)

Posted by Dan Rigsby on 26th March 2008

Async Operations in Wcf Series:
Part 1: Event Based Model
Part 2: IAsyncResult Model (Client-Side)
Part 3: IAsyncResult Model (Server-Side)
Part 4: Canceling Operations
Part 5: Handling Exceptions

This is the third in a four part series on asynchronous operations in Wcf.  If you are new to this series, you might want to read the first section of part one to get an introduction to this post: http://www.danrigsby.com/blog/index.php/2008/03/18/async-operations-in-wcf-event-based-model/

What is the IAsyncResult Model (Server-Side)

The IAsyncResult Model (Server-Side) basically allows you to send a request to the server and the server will callback when the result is ready.  Inside the “callback” method you can send another request to get the actual result.   It is important to note though that this callback method will be invoked on a thread from the server.  So, if you are working with UI code you will need to check if InvokeRequired and Invoke the operation on the UI thread (there is an example of this below).

The IAsyncResult Model (Server-Side) in Wcf is what I call “server-side asynchronous”.  This means that the operations to the server are done completely asynchronously.  The IAsyncResult Model can work as “client-side asynchronous” which was discussed in the previous article: IAsyncResult Model (Client-Side).

There are a few benefits for using “server-side asynchronous” model over a “client-side asynchronous”:

  1. The client doesn’t have to create extra threads.  The can limit programming confusion and help conserve resources on the client.
  2. Opens the door for operations such as canceling an operation or getting the status of a pending operation.  If a “client-side asynchronous” model is used, the operation to the server is done synchronously so there is no way to perform these operation.
  3. Allows the use of both ChannelFactory<> and ClientBase<>  to connect to the server.  In the “client-side asynchronous” model only a ClientBase<> can be used.

How to implement it

AsyncResult Class

The patterns works off of the standard IAsyncResult interface.  You could use the System.Runtime.Remoting.Messaging.AsyncResult, but many times you will want your own implementation of IAsyncResult.  I use a custom AsyncResult base class and inherit from it to add in properties and methods needed by the operations. Here is a base AsyncResult class that you can use:

using System;
using System.Threading;

namespace Rigsby.AsyncOperation
{
    /// <summary>
    /// The result of an asynchronous operation.
    /// </summary>
    public class AsyncResult : IAsyncResult, IDisposable
    {
        private AsyncCallback m_AsyncCallback;
        private object m_State;
        private ManualResetEvent m_ManualResetEvent;

        /// <summary>
        /// Initializes a new instance of the <see cref="AsyncResult"/> class.
        /// </summary>
        /// <param name="callback">The callback.</param>
        /// <param name="state">The state.</param>
        public AsyncResult(
            AsyncCallback callback,
            object state)
        {
            this.m_AsyncCallback = callback;
            this.m_State = state;
            this.m_ManualResetEvent = new ManualResetEvent(false);
        }

        /// <summary>
        /// Completes this instance.
        /// </summary>
        public virtual void OnCompleted()
        {
            m_ManualResetEvent.Set();
            if (m_AsyncCallback != null)
            {
                m_AsyncCallback(this);
            }
        }

        #region IAsyncResult Members
        /// <summary>
        /// Gets a user-defined object that qualifies or contains information about an asynchronous operation.
        /// </summary>
        /// <value></value>
        /// <returns>A user-defined object that qualifies or contains information about an asynchronous operation.</returns>
        public object AsyncState
        {
            get
            {
                return m_State;
            }
        }

        /// <summary>
        /// Gets a <see cref="T:System.Threading.WaitHandle"/> that is used to wait for an asynchronous operation to complete.
        /// </summary>
        /// <value></value>
        /// <returns>A <see cref="T:System.Threading.WaitHandle"/> that is used to wait for an asynchronous operation to complete.</returns>
        public System.Threading.WaitHandle AsyncWaitHandle
        {
            get
            {
                return m_ManualResetEvent;
            }
        }

        /// <summary>
        /// Gets an indication of whether the asynchronous operation completed synchronously.
        /// </summary>
        /// <value></value>
        /// <returns>true if the asynchronous operation completed synchronously; otherwise, false.</returns>
        public bool CompletedSynchronously
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// Gets an indication whether the asynchronous operation has completed.
        /// </summary>
        /// <value></value>
        /// <returns>true if the operation is complete; otherwise, false.</returns>
        public bool IsCompleted
        {
            get
            {
                return m_ManualResetEvent.WaitOne(0, false);
            }
        }
        #endregion IAsyncResult Members

        #region IDisposable Members
        private bool m_IsDisposed = false;
        private event System.EventHandler m_Disposed;

        /// <summary>
        /// Gets a value indicating whether this instance is disposed.
        /// </summary>
        /// <value>
        ///     <c>true</c> if this instance is disposed; otherwise, <c>false</c>.
        /// </value>
        [System.ComponentModel.Browsable(false)]
        public bool IsDisposed
        {
            get
            {
                return m_IsDisposed;
            }
        }

        /// <summary>
        /// Occurs when this instance is disposed.
        /// </summary>
        public event System.EventHandler Disposed
        {
            add
            {
                m_Disposed += value;
            }
            remove
            {
                m_Disposed -= value;
            }
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        public void Dispose()
        {
            if (!m_IsDisposed)
            {
                this.Dispose(true);
                System.GC.SuppressFinalize(this);
            }
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            try
            {
                if (disposing)
                {
                    m_ManualResentEvent.Close();
                    m_ManualResentEvent = null;
                    m_State = null;
                    m_AsyncCallback = null;

                    System.EventHandler handler = m_Disposed;
                    if (handler != null)
                    {
                        handler(this, System.EventArgs.Empty);
                        handler = null;
                    }
                }
            }
            finally
            {
                m_IsDisposed = true;
            }
        }

        /// <summary>
        ///    <para>
        ///        Checks if the instance has been disposed of, and if it has, throws an <see cref="ObjectDisposedException"/>; otherwise, does nothing.
        ///    </para>
        /// </summary>
        /// <exception cref="System.ObjectDisposedException">
        ///    The instance has been disposed of.
        ///    </exception>
        ///    <remarks>
        ///    <para>
        ///        Derived classes should call this method at the start of all methods and properties that should not be accessed after a call to <see cref="Dispose()"/>.
        ///    </para>
        /// </remarks>
        protected void CheckDisposed()
        {
            if (m_IsDisposed)
            {
                string typeName = GetType().FullName;

                // TODO: You might want to move the message string into a resource file
                throw new System.ObjectDisposedException(
                    typeName,
                    String.Format(System.Globalization.CultureInfo.InvariantCulture,
                        "Cannot access a disposed {0}.",
                        typeName));
            }
        }
        #endregion IDisposable Members
    }
}
Continuing with our square root service from the previous articles, we will want to extend this base AyncResult class to hold both the input and output values for our operation.  You could have multiple input values such as two numbers you want to add.  In which case you could either have two input values stored in this class or create a “container” class that stores both of the numbers you wish to add.  Since our example has only one input value, our AsyncResult object for determining a square root could look like this:
 
public class GetSquareRootAsyncResult : AsyncResult
{
    private double m_Value;
    private double m_Result;

    public double Value
    {
        get { return m_Value; }
        set { m_Value = value; }
    }

    public double Result
    {
        get { return m_Result; }
        set { m_Result = value; }
    }

    public GetSquareRootAsyncResult(
        AsyncCallback callback,
        object state) : base (callback, state)
    {
    }
}

Contract

For our service contract, we have the GetSquareRoot method which will act as our synchronous version of the operation.  There are 2 new methods here called BeginGetSquareRoot and EndGetSquareRoot.  You must prefix these methods with “Begin” and “End”.  The “Begin” method must return IAsyncResult and the last two parameters must be an AsyncCallback and an object that represents the state.  The “End” method must have a single parameter for the IAsyncResult.  The return value of the “End” method represents the actual result of the operation.  Notice that only the “Begin” version of the the method is decorated with the OperationContract attribute and not the “End” method.  This is important for how these operations are wired up.  As long as you have “AsyncPattern=true” on the “Begin” method’s OperationContract attribute, the service and client will know to look for a corresponding “End” method.

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    double GetSquareRoot(double value);

    [OperationContract(AsyncPattern=true)]
    IAsyncResult BeginGetSquareRoot(double value, AsyncCallback callback, object state);

    double EndGetSquareRoot(IAsyncResult asyncResult);
}

Service

Our service is basically a bare bones implementation of the contract.  The GetSquareRoot method is our synchronous operation and implements a 4 second thread sleep command to simulate the operation taking longer than what it really does.  This will be important when testing the asynchronous vs. the synchronous versions of the method.  Otherwise both methods would return in less than a second.

The BeingGetSquareRoot method creates a new instance of our GetSquareRootAsyncResult class and populates it with the value that we want to get the square root of.  The operation is then pushed into the threadpool and the IAsyncResult is returned from the method.  Once in the threadpool, the operation will be processed when the next thread is available by the Callback method.  The Callback method, executes the operation and calls the OnCompleted method on the GetSquareRootAsyncResult object which in turn signals the callback method on the client.

The EndGetSquareRoot method is will be called by callback method on the client to retrieve the value stored on the server after the client has been signaled.  This method basically just casts the IAsyncResult object passed to it as the GetSquareRootAsyncResult type and returns the value.  You might be asking yourself why the client can’t just do that itself.  The reason is that the IAsyncResult object passed to the client isn’t the actual object on the server, but basically a reference pointer that is passed to the client that the client can send back to the server to identity the object in the server’s memory. (The IAsyncResult returned to the client is of type System.ServiceModel.Channels.ServiceChannel.SendAsyncResult, but you wont find much about this class on msdn or anywhere else on the web.)

Here is an example of a service written against our contract for the GetSquareRoot service:

[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple)]
public class MyService : IMyService
{
    #region IMyService Members
    public double GetSquareRoot(double value)
    {
        Thread.Sleep(4000); // Wait 4 seconds
        return Math.Sqrt(value);
    }

    public IAsyncResult BeginGetSquareRoot(double value, AsyncCallback callback, object state)
    {
        GetSquareRootAsyncResult asyncResult =
            new GetSquareRootAsyncResult(callback, state);
        asyncResult.Value = value;

        ThreadPool.QueueUserWorkItem(
            new WaitCallback((Callback)),
            asyncResult);

        return asyncResult;
    }

    public double EndGetSquareRoot(IAsyncResult asyncResult)
    {
        double result = 0;

        using (GetSquareRootAsyncResult getSquareRootAsyncResult =
            asyncResult as GetSquareRootAsyncResult)
        {
            getSquareRootAsyncResult.AsyncWaitHandle.WaitOne();
            result = getSquareRootAsyncResult.Result;
        }

        return result;
    }
    #endregion IMyService Members

    private void Callback(object asyncResult)
    {
        GetSquareRootAsyncResult getSquareRootAsyncResult
            = (GetSquareRootAsyncResult)asyncResult;
        try
        {
            getSquareRootAsyncResult.Result =
                GetSquareRoot(getSquareRootAsyncResult.Value);
        }
        finally
        {
            getSquareRootAsyncResult.OnCompleted();
        }
    }
}

Example Client

For our example client, we have a basic windows forms application where the user can enter a value, send it to the server, and the result will be displayed:

SquareRoot

Here is the code behind this page.  The only tricky things here are the callback method that is passed to the BeginGetSquareRoot method and the call to the EndGetSquareRoot method from that callback method.

public partial class Form1 : Form
{
    IMyService m_Client;

    public Form1()
    {
        InitializeComponent();

        ChannelFactory<IMyService> factory =
            new ChannelFactory<IMyService>("netTcp");
        factory.Open();
        m_Client = factory.CreateChannel();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        double value = 0;
        Double.TryParse(m_ValueTextBox.Text, out value);

        m_Client.BeginGetSquareRoot(
            value,
            new AsyncCallback(OnEndGetSquareRoot),
            null);

        m_StartButton.Enabled = false;
        m_ResultTextBox.Text = "Loading...";
    }

    public void OnEndGetSquareRoot(IAsyncResult asyncResult)
    {
        this.Invoke(
            new MethodInvoker(delegate()
            {
                m_ResultTextBox.Text =
                    m_Client.EndGetSquareRoot(asyncResult).ToString();

                m_StartButton.Enabled = true;
            }));
    }
}
 

Notice that in the OnEndGetSquareRoot method, we can invoking the operation using “this.Invoke”.  This ensures that the operation is called on the UI thread since we are updating a UI element.  We know that OnEndGetSquareRoot is called by the signal on the server, so the method is always called by a thread from the server.

You can download a complete sample of the code discussed in this article here: http://www.danrigsby.com/Files/Rigsby.ServerSideIAsyncResultOperation.zip

Posted in Wcf | 8 Comments »