Dan Rigsby - Coding Up Style

.Net, C#, & Wcf Development

Archive for the 'Wcf' Category


REST and Max URL Size

Posted by Dan Rigsby on 17th June 2008

I have heard many people say that the definition of REST is to just put everything in the URL.  This isn’t true.  One of the tenants of REST is to “embrace” the URL and use it as much as possible, but moving information to POST data is just as important and often necessary.  I can understand how this can be misunderstood.  Most REST interfaces do take in all values in into the URL to make it easier to navigate the data.  Having to build a POST package can be tedious at times.  So, what if you do want to send larger data to the service?  When should you decide to move away from a pure URL approach and start using POST data in the header?

Browser and WebServer Limits: http://www.boutell.com/newfaq/misc/urllength.html

  • Internet Explorer: 2,083 characters, with no more than 2,048 characters in the path portion of the URL
  • Firefox: 65,536 characters show up, but longer URLs do still work even up past 100,000
  • Safari: > 80,000 characters
  • Opera: > 190,000 characters
  • IIS: 16,384 characters, but is configurable
  • Apache: 4,000 characters

Different things can happen when you go beyond these URL limits depending on the browser and web servers. It could be a “413 (Entity Too Large)” error, “414 (Request-URI Too Long)” error, the URL could be truncated, or it may just work.  However since different things can happen and your service could be consumed by any source, you have to assume the worst could happen.

By looking at just these numbers, it seems you would be pretty safe with a URL that gets up to 2,000 characters.  However, lets look at the W3C standards on this.  The HTTP specification doesn’t really set a size for the length of a URL, but it does recommend being cautious when going above 255. According to Hypertext Transfer Protocol - HTTP/1.1 section 3.2:

Servers ought to be cautious about depending on URI lengths above 255 bytes, because some older client or proxy implementations might not properly support these lengths.

So for the sake of a REST interface you should avoid setting up an interface where there is any possibility of a URL getting beyond 255.  If you are using a GET verb to request a resource via the URL you should be pretty safe.  However POSTing or PUTing an insert or update via a URL may not be the way to go unless the data size is very small.

The most important thing is to keep your interfaces consistent.  You don’t want one operation that allows an insert via the URL and another through POST data.  This just makes things confusing and less discoverable.  Especially since REST has no way to publish metadata about the operations.   You could follow standards such as these:

CRUD Operation HTTP Verb Data Location
Create POST or PUT POST Data
Read GET URL
Update POST or PUT POST Data
Delete DELETE URL

In general this follows “High REST” which is the more pure REST.  This dictates that the HTTP Verbs define the methods to act on the resource.

Ultimately it’s up to you how you implement the REST interface, but stay consistent, be careful about URL limits, and try to follow industry standards.

Posted in REST, Wcf | 1 Comment »

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 | 9 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 | 4 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 | 2 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.Rigsby.WcfServiceContexts.zip

 

kick it on DotNetKicks.com

Posted in Wcf | 5 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 | 2 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 | 2 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: