It's 2008. Where's my flying car? RSS 2.0
 Tuesday, December 27, 2005

Part 1, Part 2

If you’ve read the first two parts of this series, you should know by now (if I’ve done a reasonable job explaining) about the fundamental concepts of how incoming web service messages (requests) are typically dispatched to their handler code and also understand how my Indigo REST/POX extensions are helping to associate the metadata required for dispatching plain, envelope-less HTTP requests with Indigo service operations using the HttpMethod attribute and how the HttpMethodParameterInspector breaks up the URI components into easily consumable, out-of-band parameters that flow into the service code the UriArgumentsMessageProperty.

What I have not explained is how the dispatching is actually done. There are two parts to that story: Dispatching to services on the listener level (which I will cover here) and dispatching to operations at the endpoint level (which I’ll cover in part 4).

When an HTTP request is received on a namespace that Indigo has registered with HTTP.SYS, the request is matched against a collection of “address filters”. “Registering a namespace” means that if you configure a service-endpoint to listen at the endpoint http://www.example.com/foo, the service-endpoint “owns” that URI.

What’s noteworthy is that if you have an Indigo/WCF application listening to endpoints at http://www.example.com/baz, http://www.example.com/foo and http://www.example.com/foo/bar, the demultiplexing (“demuxing” in short) of the requests is done by Indigo and not by the network stack. HTTP.SYS will push requests from any registered URI namespace of the particular application into the “shared” Indigo HTTP transport and leave it up to Indigo to figure out the right endpoint to dispatch to. And that turns out to be perfect for our purposes.

Whenever an incoming message needs to be dispatched to an endpoint, the message is matched against an address filter table. [For the very nosy: The place where it all happens is in the internal EndpointListenerTable class’s Lookup method, which you could probably look at if you had the right tools, but I didn’t say that.]

By default, the address filter that is used for any “regular” service is the EndpointAddressFilter, which reports a match if the incoming message’s “To” addressing header (which is constructed from the HTTP header information if it’s not immediately contained in the incoming message) is a match for the registered URI. Whether a match is found is dependent on the URI’s port and host-name (controllable by the HostNameComparisonMode in the HTTP binding configuration) and the URIs remaining path, which must be an exact match for the registered service endpoint URI. Since we want to introduce a slightly different dispatch scheme that is based on matching not only on the exact endpoint URI’s path but also on suffixes appended to that URI, we must put a hook into the dispatch mechanism and extend the default behavior. If a method marked up with [HttpMethod(“GET”,UriSuffix=”/bar”)] and the endpoint is hosted at http://www.example.com/foo, we want any HTTP GET request to http://www.example.com/foo/bar to be dispatched to that endpoint and, subsequently, to that exact method.

To infuse that behavior into Indigo, we need to tell it so. If you take a look at Part 2 and at the service contract declarations that I posted there, you will notice the HttpMethodOperationSelector attribute alongside the ServiceContract attribute. That attribute class does the trick:

using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;

namespace newtelligence.ServiceModelExtensions
{
   public class HttpMethodOperationSelectorAttribute :
                  Attribute, IContractBehavior, IEndpointBehavior
   {
      public void BindDispatch(
                ContractDescription description,
                IEnumerable<ServiceEndpoint> endpoints,
                DispatchBehavior dispatch,
                BindingParameterCollection parameters)
      {
         dispatch.OperationSelector =
              new HttpMethodOperationSelectorBehavior(description, dispatch.OperationSelector);
         foreach (ServiceEndpoint se in endpoints)
         {
            if (se.Behaviors.Find<HttpMethodOperationSelectorAttribute>() == null)
            {
               se.Behaviors.Add(this);
            }
         }
           
      }

      public void BindProxy(
                     ContractDescription description,
                     ServiceEndpoint endpoint,
                     ProxyBehavior proxy,
                     BindingParameterCollection parameters)
      {

      }

      public bool IsApplicableToContract(Type contractType)
      {
         return true;
      }

      public void BindServiceEndpoint(
                     ServiceEndpoint serviceEndpoint,
                     EndpointListener endpointListener,
                     BindingParameterCollection parameters)
      {
            SuffixFilter suffixFilter = null;

            if (endpointListener.AddressFilter == null ||
                !(endpointListener.AddressFilter is SuffixFilter))
            {
                suffixFilter = new SuffixFilter(endpointListener, endpointListener.AddressFilter);
                endpointListener.AddressFilter = suffixFilter;
                ((Dispatcher)endpointListener.Dispatcher).Filter = suffixFilter;
            }
            else
            {
                suffixFilter = endpointListener.AddressFilter as SuffixFilter;
            }

         foreach (OperationDescription opDesc in serviceEndpoint.Contract.Operations)
         {
            HttpMethodAttribute methodAttribute = opDesc.Behaviors.Find<HttpMethodAttribute>();
            if (methodAttribute != null)
            {
               if (methodAttribute.UriSuffixRegex != null)
               {
                  suffixFilter.AddSuffix(methodAttribute.UriSuffixRegex);
               }
            }
         }
      }
   }
}


In the attribute’s implementation of IEndpointBehavior.BindServiceEndpoint, which is invoked by Indigo as the endpoint is initialized (in response to ServiceHost.Open() ), we replace the service’s default endpoint filter with our own SuffixFilter class. Once we’ve done that, we iterate over the HttpMethodAttribute metadata elements that sit on the individual operations/methods in the contract description (this is the actual reason we put them there, see Part 2) and add any suffix we find to the filter’s suffix table. We’ll get back to this class in the next part while to investigate how the “operation selector” is hooked in; let’s investigate the suffix filter first.

using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.ServiceModel;
using System.ServiceModel.Configuration;
using System.ServiceModel.Channels;

namespace newtelligence.ServiceModelExtensions
{
    /// <summary>
    /// This class implements a specialized ServiceModel address filter
    /// that allows matching URL suffixes.
    /// </summary>
    /// <remarks>
    /// The class aggregates an EndpointAddressFilter to helpi with the matching logic.
    /// </remarks>
    public class SuffixFilter : Filter
    {
        /// <summary>
        /// List for the suffixes.
        /// </summary>
        List<Regex> suffixes;
        /// <summary>
        /// Original filter that we delegate to if we can't match with this
        /// one.
        /// </summary>
        Filter originalFilter;
        /// <summary>
        /// The endpoint listener that this filter is applied to
        /// </summary>
        EndpointListener endpointListener;
        /// <summary>
        /// The aggregated endpoint address filter
        /// </summary>
        EndpointAddressFilter addressFilter;

        /// <summary>
        /// Creates a new instance of SuffixFilter
        /// </summary>
        /// <param name="endpointListener">EndpointListener this filter is attached to</param>
        /// <param name="originalFilter">Original AddressFilter of the EndpointListener</param>
        public SuffixFilter(EndpointListener endpointListener, Filter originalFilter)
        {
            this. suffixes = new List<Regex>();
            this. originalFilter = originalFilter;
            this. endpointListener = endpointListener;
        }

        /// <summary>
        /// Implements the matching logic
        /// </summary>
        /// <param name="message">Message that shall be matched</param>
        /// <returns>Returns an indicator for whether the message is considered a match</returns>
        public override bool Match(Message message)
        {
            // Workaround for Nov2006 CTP bug. GetEndpointAddress() cannot be
            // called on an EndpointListener before the listener is running.
            if ( addressFilter == null)
            {
                addressFilter = new EndpointAddressFilter( endpointListener.GetEndpointAddress(), false);
            }

            // check whether we have an immediate match, which means that the message's
            // To Header is an excat match for the EndpointListener's address
            if ( addressFilter.Match(message))
            {
                return true;
            }
            else
            {
                // no direct match. Save the original header value and chop off the
                // query portion of the URI.
                Uri originalTo = message.Headers.To;
                string baseUriPath = originalTo.AbsolutePath;
                string baseUriRoot = originalTo.GetLeftPart(UriPartial.Authority);

                // match against the suffix list
                foreach (Regex suffixExpression in suffixes)
                {
                    Match match = suffixExpression.Match(baseUriPath);
                    if (match != null && match.Success)
                    {
                        string filterUri = baseUriRoot+baseUriPath.Remove(baseUriPath.LastIndexOf(match.Value));
                        message.Headers.To = new Uri(filterUri);
                        if ( addressFilter.Match(message))
                        {
                            message.Headers.To = originalTo;
                            return true;
                        }
                        message.Headers.To = originalTo;
                    }                       
                }
            }
            if ( originalFilter != null)
            {
                // of no match has been found up to here, we match against the
                // original filter if that was provided.
                return originalFilter.Match(message);
            }
            return false;
        }

        /// <summary>
        /// Implements the matching logic by constructing a Message over
        /// a MessageBuffer and delegating to the Match(Message) overload
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        public override bool Match(MessageBuffer buffer)
        {
            Message msg = buffer.CreateMessage();
            bool result = Match(msg);
            msg.Close();
            return result;
        }

        /// <summary>
        /// Adds a new suffix to the suffix table
        /// </summary>
        /// <param name="suffix">Suffix value</param>
        public void AddSuffix(Regex suffix)
        {
            suffixes.Add(suffix);
        }

        /// <summary>
        /// Removes a suffix from the suffix table
        /// </summary>
        /// <param name="suffix"></param>
        public void RemoveSuffix(Regex suffix)
        {
            suffixes.Remove(suffix);
        }
    }
}


The filter’s filet piece is in the Match method. To finally figure out whether a message is a match, we employ the matching logic of the default EndpointAddressFilter, which deals with matching the host names and the “base URI” at which the service was registered. What the suffix filter does in addition is to match the suffix regex pattern against the incoming message’s “To” header and if that is a match, the suffix is stripped and the remaining URI is matched against the aggregated EndpointAddressFilter. Only if we get a match for the suffix and for the remainder URI, we’ll report a positive match back to the infrastructure by returning true. And in that case and only in that case the service endpoint for which “this” suffix filter was installed and populated gets the request.

For each incoming request, Indigo goes through all registered endpoint address filters and asks them whether they want to service it. And that really means “all”. Indigo will refuse to service the request if two or more filters report ownership of the respective request and will throw a traceable (using Indigo tracing) internal exception that will cause none of the services to be picked due to this ambiguity. In the case of overlapping dispatch namespaces, none is indeed better than “any random”.

Next part: HttpMethodOperationSelectorBehavior

Go to Part 4

Tuesday, December 27, 2005 10:20:50 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0] - Trackback
Indigo

Before I get back to the POX/REST story, I promised a few folks to re-publish an updated version of my „JITA pool“ that I published over three years ago. Many people have used the technique that this utility class enables and have seen dramatic performance improvements with their Enterprise Services applications. And until Indigo ships, Enterprise Services (a.k.a. “COM+” or, shorter, “ES”) is still the most powerful application server technology on the Windows platform, so I think it deserves continued attention.

One of the common misconceptions around ES is that keep hearing is that it comes with such a significant overhead for each call that turns your server application into a fat, slow moving thing. And as things are, there are always two sides to every story and it turns out that if you use ES correctly, it is probably faster than most other cross-process technologies you can easily use from managed code. I write “probably”, because as with every distributed systems technology, “your mileage may vary” based on what your scenario is.

Before I show you the code, let’s take a quick dive into the ES/COM+ internals so that you understand what I mean with “use ES correctly”. To use technology in an optimal way you either need to understand how things work and how all technology pieces fit together or you need absolutely precise documentation that gives you the guidance you’d otherwise have to work out yourself. The Microsoft of the “COM+ era” (2000 and earlier) didn’t do so well on giving us either. And unfortunately it’s still very often the case that Microsoft’s technical marketing teams drop a technology like a hot potato once it has shipped and the launch events are over. And so ES still suffers from former negligence and in managed code land it’s clearly overshadowed by ASP.NET, Windows Forms and everything else that has design-time support and demos easily. Anyways, let’s dig in:   

Assume you had a ServicedComponent and you’d call it from a client application in the following way:

MyComponent myComp = new MyComponent();
myComp.MyMethod()

Surprising to many is that it turns out that the innocent looking “new” is sometimes the more costly of these two code lines. Invoking and executing the functionality you’ve been implementing might in some cases indeed be significantly quicker than constructing the component instance. Why is that so? Because constructing ES/COM+ component instances is a lot of work. The picture above is a simplified illustration of the moving parts involved in the process. (Mind that I am simplifying the explanation a bit. I’ve already written about the internals in 2003, but in a bit different context.)

The COM+ infrastructure is essentially an aspect engine that allows plugging interception sinks into the call chain that leads from the client proxy to the server component instance. Whenever a (any) COM object is constructed on Windows 2000 (or later), the CoCreateInstance(Ex) API function will route the request through a chain of “activators” that are registered in the COM+ catalog, which is a simple ISAM database with very fast read-capabilities that has been custom-built for COM+. If an component isn’t “configured” (registered in a proper COM+ application), the activation process shortcuts out of the activator chain and creates a “normal” COM object, otherwise the activator chain is fully processed. “Activators” are nothing but proper COM components implementing a special interface ISystemActivator whose CLSID is registered in the COM+ catalog. In the illustration about the activators are depicted as yellow circles. Whenever a new instance must be created, each activator is polled for whether it has interest in contributing a “policy” (blue rectangles) into the interceptor chain. It does so by checking the COM+ catalog for whether the component or the application has been configured to use the feature the activator is responsible for. Conceptually, each COM+ feature (Transactions, Security, JITA, Object Pooling) therefore has an activator even though one activator may (and in fact does) do the work for multiple features and install multiple policies.

A policy is also a COM component (or two) implementing the IPolicy and IPolicyMaker interfaces. The former interface has the interceptor methods that are being invoked before and after the method call and before and after leaving the context, the latter has methods for actually installing that interceptor into the call chain. The interceptor methods in IPolicy are the ones where the COM+ functionality actually sits. The transaction policy will open/close new transaction scopes here, the object pooling will pool/depool components, the JITA policy connects/disconnects instances, and the tracker starts and stops its stopwatch to measure the call times. The resulting policies form a sink-chain, which means that any policy can absorb a call or change the environment before it lets the call proceed. The policy objects have context-affinity, which means that they are created anew for each context.

What that all means is that whenever you create a new instance of your serviced component, you don’t create just one object, you create a whole lot and I haven’t really gone into the additional managed code object instances that are created for the proxy/dispatcher trickery of hooking it all up to the Remoting infrastructure. In addition to all that context setup work, a cross-process connection (on-machine and off-machine) does, of course, require a DCOM/MS-RPC connection to be established, which comes with additional cost.

Mind that while this mechanism is theoretically extensible using arbitrary plug-ins, it’s not practically possible to do so. Contrary to the open extensibility model of Indigo that was specifically designed for 3rd party extensibility, the COM+ model is so tightly coupled and there are so many interdependencies between the respective behaviors that you would practically need to sit on the same floor with the development team to do anything meaningful with the extensibility features even if you had the header and IDL files for it.

And looking at all that internal effort that’s hidden in the guts of COM+/ES, it is now not very surprising that that creating a component is pretty costly, is it?

The goal for optimizing a COM+/ES application must therefore be to eliminate as much of that cost as possible. And it turns out that two of the policies sitting in the server context stage are incredibly helpful in getting this done. The “Just In Time Activation” feature of COM+/ES is in fact a policy that will drop the reference to the object instance on its right (in the illustration above) once the completion-bit in the context properties is set. Before it does so, it calls the Deactivate() method if the component supports IObjectControl. The object-pooling policy will grab such a deactivated object and move it into a server-side object pool is the object agrees to that by returning true from CanBePooled(). Even though the policy chain (“context”) has no active instance sitting at its far end, it is alive and doing quite well. Whenever the next call is made on the proxy, the call comes through the chain, the “Just in Time Activation” policy will create a new instance and, if present, the object pooling policy will supply one from the pool. Otherwise a new instance is created. The key aspect here is that the entire context and all that context setup work is reused, even though there’s an entirely new or a recycled component acting on the server side.

This is quite similar to databases where you have connections (context) and statements (instance/call). A serviced component proxy is not just a proxy. It’s got the whole policy chain and the server connection behind it. And as we know, database connections are pretty expensive to establish as well and therefore the infrastructure you use to connect to them (ADO, System.Data, OLE DB) commonly gives you “connection pools” from which pre-established connections are recycled even though the API creates the illusion that you are creating new connections every time you call Connect() or Open().  

Consequently and learning from the database folks, what we’ll do for optimizing ES is to steal that idea and build a connection pool. The downloadable file below contains an implementation of such a pool. The JustInTimeActivationProxyPool<T> class implements a simple, lockless, SMP safe pool of static size that keeps references to existing proxies. To create a pool on the client side, you will typically add a static field like  JustInTimeActivationProxyPool<MyComponent> myComponentPool to your client implementation and initialize it appropriately. Once you’ve done that, you can obtain a proxy with Pop() and return the proxy after use with Push(). Because all serviced components you write in managed code are implicitly multi-threading aware (MTA), this works perfectly well in multi-threaded environments.

However, due to the connection-oriented nature of COM, there’s a bit of a complication in case the server application recycles (stops and restarts). In that case, all the proxies you have cached are stale and will throw an exception with the HRESULT 0x800706bf (E RPC CALL FAILED DNE), which means that the call couldn’t be made. In that case you need to create a new proxy and simply reissue the call. The two other special cases for COM+/ES (security errors and general network failures aside) are those where the target application has been paused or disabled, in which case the proxies are also invalid. The older versions of my pool class did not address these issues, but this new one does.

The example below shows the proper usage of the pool with the pool’s Using() method and an anonymous inline method. This technique allows me to call the user code in three different contexts that I can establish inside the implementation of Using(). The first is when the call were to be executed within a preexisting transaction context, which disallows the use of pooled proxies, the second is the normal Pop()/Push() bracket around the call and the third is the new/Push() exception case for when the proxy is detected to be stale.

 

[WebService(Name="CatalogQueriesWebService",Namespace=Namespaces.CatalogQueriesNamespaceUri)]
public class CatalogQueriesWebService : ICatalogQueries
{
    static JustInTimeActivationProxyPool<ES.CatalogQueries> jitaPool = new JustInTimeActivationProxyPool<ES.CatalogQueries>();
   
    public  GetAllCategoriesReplyMessage GetAllCategories()
    {
        GetAllCategoriesReplyMessage result = null;
       
        jitaPool.Using(
            delegate(ES.CatalogQueries service)
            {
                result = service.GetAllCategories();
            }
        );
        return result;
    }
   
    …
}


The “requirement” for the server component is that Just-In-Time Activation is enabled (the [JustInTimeActivation] attribute on the serviced-component class will do that and the [Transaction] attribute with the TransactionOption.Supported/Required/RequiresNew optional will implicitly do that, too) , even though stateful components could be pooled as well with this technique.

Download the code for the class below and try it out.

JustInTimeActivationProxyPool.cs.txt (10.03 KB)
Tuesday, December 27, 2005 5:25:34 AM (Pacific Standard Time, UTC-08:00)  #    Comments [1] - Trackback

 Wednesday, December 21, 2005

Yes, all the rumors are true. I am moving from the consumer side of things to the builder side of things. From February 1st, 2006 I will be a “blue badge” and work for Microsoft as a Program Manager on the Windows Communication Foundation. The guys convinced me that it would be a good idea to make the move.

I’ve been spending so much time talking about and writing extensions for the shipping and not-yet shipping Microsoft distributed systems technologies stuff that it became the logical next step for me to become part of the team that creates all of these things. I hope that I can make some contribution to the cause.

As for why I am leaving my baby newtelligence? It’s the urge to build stuff that matters in a big way. Bart and Achim (my partners) have given me all the support they could since January in pursuing this goal. We’ve worked hard to put the company into a position that allows me to make this move and we are all delighted with the way things are. newtelligence is expanding its consulting business, continues to deliver world-class developer education and will continue to be a strong partner for our customers, which makes it easier for me to let go.

I’ll tell you more about it in the upcoming weeks…

Wednesday, December 21, 2005 9:35:10 PM (Pacific Standard Time, UTC-08:00)  #    Comments [14] - Trackback

 Monday, December 12, 2005

In the first part of this series, I gave you a little introduction to REST/POX in contrast to SOAP and also explained some of the differences in how incoming requests are dispatched. Now I’ll start digging into how we can teach Indigo a RESTish dispatch mechanism that dispatches based on the HTTP method and by matching on the URI against a suffix pattern.

The idea here is that we have a service implementation that takes care of a certain resource namespace. To stick with the example from Part 1, we assume that the resources managed within this (URI) namespace are customers and data related to customers. Mind that this might not be all data of a respective customer, but that some data may very well be residing in completely different namespaces (and on different servers).

As a reminder: When I write “namespaces” I specifically mean that we’re creating hierarchical scopes for data. All customer representations managed by our imaginary service are subordinates of the namespace http://www.example.com/customers, the representation of the customer identified by customer-id 00212332 occupies the namespace http://www.example.com/customers/00212332, all communication (phone) numbers of that customer are subordinates of http://www.example.com/customers/00212332/comm and the home phone number might be identified by http://www.example.com/customers/00212332/comm/home-phone. However, all orders made by that respective customer might be found somewhere completely different; maybe here:  http://www.tempuri.org/ordersystem/customer-orders/00212332. The data representation of the customer would contain that link, but the customer service would not manage those resources (the orders), at all.

Purists might (and do) argue that plain HTTP handlers (or “servlets”, in Java terms) representing exactly one resource type are the best way to implement the processing logic for this URI/HTTP centric model, but since I am much more a pragmatist than a purist, I prefer using a infrastructure that maps incoming requests to a programming model that’s easy enough for most programmers to deal with. It turns out that a class with methods that deal with related stuff (a customer and his addresses and phone numbers) is something that most programmers can handle pretty well by now and there’s nothing wrong with co-locating related handlers for data from a given data source on one flat interface, even if the outside representation of that data suggests that the data and its “endpoints” are ordered hierarchically. In the end, the namespace organization is just a smokescreen that we put in front of our implementation. Just to make Mark happy, I’ll show a very HTTP and service-per-object aligned contract model and, later in the next part, also a more readable model for the rest of us to explain how the dispatch works. I’ll start with the model for idealists:

[ServiceContract, HttpMethodOperationSelector]
interface
ICustomerResource
{
    [OperationContract,
     HttpMethod("GET", UriSuffix = "/customers/?")]
    Message Get(Message msg);
    [OperationContract,
     HttpMethod("PUT", UriSuffix = "/customers/?")]
    Message Put(Message msg);
    [OperationContract,
     HttpMethod("POST", UriSuffix = "/customers/?")]
    Message Post(Message msg);
    [OperationContract,
     HttpMethod("DELETE", UriSuffix = "/customers/?")]
    Message Delete(Message msg);
}

[ServiceContract, HttpMethodOperationSelector]
interface
ICommunicationResource
{
    [OperationContract,
     HttpMethod("GET", UriSuffix = "/customers/?/comm/?")]
    Message Get(Message msg);
    [OperationContract,
     HttpMethod("PUT", UriSuffix = "/customers/?/comm/?")]
    Message Put(Message msg);
    [OperationContract,
     HttpMethod("POST", UriSuffix = "/customers/?/comm/?")]
    Message Post(Message msg);
    [OperationContract,
      HttpMethod("DELETE", UriSuffix = "/customers/?/comm/?")]
    Message Delete(Message msg);
 }

We have two different contracts here, one for the “customers” namespace and one for the “comm” sub-namespace, and the implementation of these two contracts could be sitting on the same implementation class or on two different classes whereby they could be co-located at the exact same root address or sitting on different machines. All of that doesn’t really matter, since the filtering/dispatch logic we’ll use here will figure out the right thing to do, meaning the right handler method to dispatch to. Also mind that there’s a difference to the examples I show in Part 1 in that I am now using messages.

The UriSuffix of the HttpMethodAttribute serves three purposes. First, it is used to construct a regular expression that is used to match incoming messages to the right endpoint using a custom endpoint Filter. Second, the same regular expression is used to figure out which method the message shall be dispatched on at that endpoint using a custom implementation of IDispatchOperation. Third, the regular expression is also used to isolate the URI-embedded parameters and make them easily accessible on a message property. So for the ICommunicationResource.Get() operation above, the handler implementation would start out as follows and would make the values occurring at the two “?” of the suffix available in the UriArgumentsMessageProperty.InUrlArgs collection that is shown further below:

Message ICommunicationResource.Get(Message msg)
{
   UriArgumentsMessageProperty uriArgs = UriArgumentsMessageProperty.FromOperationContext();
   string customerid = uriArgs.InUrlArgs[0];
   string commid = uriArgs.InUrlArgs[1];
   ...

The expressions for UriSuffix support two different wildcards. The “*”wildcard will match any character and the “?” wildcard will match any character except the forward slash. If you would, for instance, want to build an operation that behaves like a web server and might serve up data from a directory and its subdirectories, you’d use something as global as “/*” and any URI would match the respective endpoint/method. If you want to match/extract segments of a namespace path as we do here, you use the “?”.

And so here is the complete and rather straightforward implementation of the HttpMethodAttribute:

using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using System.Text.RegularExpressions;

namespace newtelligence.ServiceModelExtensions
{
    ///
<summary>
    ///
The HttpMethodAttribute is used to declare the HTTP method and
    ///
an optional suffix for the REST/POX extensions to dispatch on. In absence of
    ///
this attribute, the dispatch mechanism will attempt to dispatch on the
    ///
name of the operation and try matching by name it to the HTTP method used.
    ///
</summary>
   [AttributeUsage(AttributeTargets.Method)]
   public class HttpMethodAttribute : Attribute,
IOperationBehavior
   {
      ///
<summary>
      /// Initializes a new instance of the <see cref="T:HttpMethodAttribute"/>
class.
      ///
</summary>
      /// <param name="method">The method.
</param>
      public HttpMethodAttribute(string method)
      {
         _Method = method;
      }

      private string _Method;
      ///
<summary>
      ///
Gets the HTTP method. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
      ///
</summary>
      /// <value>The method.
</value>
      public string Method
      {
         
get
         {
            return _Method;
         }
      }

      private string _UriSuffix;
      ///
<summary>
      ///
Sets or gets the Uri suffix. The Uri suffix is an expression used
      ///
to match an incoming request against the endpoint and this method.
      ///
The UriSuffix may contain two different wildcards: '*' matches the
      ///
shortest sequence of arbitrary character up to the next concrete character
      ///
in the suffix string. The '?' behaves similarly, but excludes the '/'
      ///
character from matching.
      ///
</summary>
      /// <value>The URI suffix.
</value>
      public string UriSuffix
      {
         
set
         {
             _UriSuffix = value;
             _UriSuffixRegex = new Regex(
                    Regex.Escape(_uriSuffix).Replace("\\*", "(.*?)")
                                            .Replace("\\?", "([^/]*?)") + "$",
                    RegexOptions.CultureInvariant |
                    RegexOptions.IgnoreCase |
                    RegexOptions.Singleline |
                    RegexOptions.Compiled);
         }
           
get
            {
                return _UriSuffix;
            }
      }

        private Regex _UriSuffixRegex;
        ///
<summary>
        ///
Gets the regular match expression constructed from
        ///
the UriSuffix.
        ///
</summary>
        /// <value>The URI suffix regex.
</value>
        public Regex UriSuffixRegex
        {
           
get
            {
                return _UriSuffixRegex;
            }
        }

        private int _Priority;
        ///
<summary>
        ///
Gets or sets the priority. The priority is used to control the
        ///
order in which the suffix expressions are processed when matching.
        ///
A higher priority causes the expression to be matched earlier.
        ///
</summary>
        /// <value>The priority.
</value>
        public int Priority
        {
           
get
            {
                return _Priority;
            }
           
set
            {
                _Priority = value;
            }
        }

        ///
<summary>
        ///
Applies the behavior.
        ///
</summary>
        /// <param name="description">Description.
</param>
        /// <param name="proxy">Proxy.
</param>
        /// <param name="parameters">Parameters.
</param>
      public void ApplyBehavior(OperationDescription description,
                ProxyOperation proxy, BindingParameterCollection parameters)
      {
           
// do nothing proxy-side
      }

        ///
<summary>
        ///
Applies the behavior.
        ///
</summary>
        /// <param name="description">Description.
</param>
        /// <param name="dispatch">Dispatch.
</param>
        /// <param name="parameters">Parameters.
</param>
      public void ApplyBehavior(OperationDescription description,
                    DispatchOperation dispatch, BindingParameterCollection parameters)
      {
           
// We're adding a parameter inspector that parses the Uri parameters into
           
// an UriArgumentsMessageProperty
            dispatch.ParameterInspectors.Add( new HttpMethodParameterInspector(this));
      }
   }
}


Of course this attribute is a bit special. You might have noticed that it implements the IOperationBehavior interface with its two method overloads of ApplyBehavior whereby one is for the proxy side of a channel (which we don’t care about in this case) and the other for the dispatcher (service-) side of an implementation. The presence of this interface causes the Indigo runtime to instantiate the attribute and add it to the contract metadata whenever the contract is built using reflection. You could also instantiate the attribute yourself and add it to any existing in-memory Indigo contract’s operation description if you liked. This is a convenient way to get the additional metadata into the contract description because we need it at several places later.

At the dispatch-side we’re also adding an implementation of IParameterInspector, whose job it is to extract the URI-embedded arguments and also parse “key=value” pairs of an optional query string, if one is present.

Parameter inspectors are called immediately before and after a method has been invoked and, as their name implies, are meant to be used to inspect a method’s parameters and/or output. However, their use is not restricted to that. Because the operation context is also available when the inspectors are called, you can also inspect headers, properties or any other context information at this point.

Even though this is largely a convenience feature not central to the dispatcher, I’ll show the class here, because I mentioned the UriArgumentsMessageProperty above. This is where it gets populated and set:

using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Text.RegularExpressions;
using System.Collections.Specialized;

namespace newtelligence.ServiceModelExtensions
{
    class HttpMethodParameterInspector :
IParameterInspector
    {
        HttpMethodAttribute _metadata;
        ///
<summary>
        ///
Creates a new instance of HttpMethodParameterInspector
        ///
</summary>
        public HttpMethodParameterInspector(HttpMethodAttribute metadata)
        {
            _metadata = metadata;
        }
       
        #region IParameterInspector Members

        public object BeforeCall(string operationName, object[] inputs)
        {
            OperationContext opCtx = OperationContext.Current;
            NameValueCollection queryArguments;
            StringCollection inUrlArgs = new StringCollection();
            Uri toHeader = opCtx.IncomingMessageHeaders.To;

           
// Parse query strings
            if (opCtx.IncomingMessageProperties.ContainsKey(HttpRequestMessageProperty.Name))
            {
                HttpRequestMessageProperty rqMsgProp =
                   opCtx.IncomingMessageProperties[HttpRequestMessageProperty.Name]
                      as HttpRequestMessageProperty;
                queryArguments = UriHelper.ParseQueryString(rqMsgProp.QueryString);
            }
           
else
            {
                queryArguments = UriHelper.ParseQueryString(toHeader.Query);
            }

           
// Get the in URL arguments from the regex captures
            Match match = _metadata.UriSuffixRegex.Match(toHeader.AbsolutePath);
            if (match.Success && match.Groups.Count > 0)
            {
               
// if we have more than 1 capture group (the first is always the
                
// full match expression), we store the next groups in the
               
// irUrlArgument collection in order of occurrence.
                for (int i = 1; i < match.Groups.Count; i++)
                {
                    inUrlArgs.Add(match.Groups[i].Value);
                }
            }

            opCtx.IncomingMessageProperties.Add(
                UriArgumentsMessageProperty.Name,
                new UriArgumentsMessageProperty(queryArguments,inUrlArgs)
            );

            return null;
        }

        public void AfterCall(string operationName, object[] outputs,
                      object returnValue, object correlationState)
        {
           
// do nothing
        }      

        #endregion
    }
}

The query string is parsed using a helper class which splits the query string at each ‘&’ first and then splits the segments at ‘=’ and throws the resulting pairs into a NameValueCollection. That is no big deal and I'll omit the helper here. The UriArgumentsMessageProperty that gets put into the mesage properties is just a class that holds the query arguments and the string collection with the regex matches. It is quite trivial:

using System;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;

namespace newtelligence.ServiceModelExtensions
{

    ///
<summary>
    ///
Message property class holding arguments fro the request URI.
    ///
</summary>
    public class
UriArgumentsMessageProperty
    {
        NameValueCollection _queryArguments;
        StringCollection _inUrlArgs;

        ///
<summary>
        ///
Creates a new instance of UrlArgumentsMessageProperty
        ///
</summary>
        internal UriArgumentsMessageProperty(NameValueCollection queryArguments,
                                             StringCollection inUrlArgs)
        {
            _queryArguments = queryArguments;
            _inUrlArgs = inUrlArgs;
        }

        ///
<summary>
        ///
Gets the query arguments.
        ///
</summary>
        /// <value>The query arguments.
</value>
        public NameValueCollection QueryArguments
        {
           
get
            {
                return _queryArguments;
            }
        }

        ///
<summary>
        ///
Gets the arguments in the URL.
        ///
</summary>
        /// <value>The in URL args.
</value>
        public StringCollection InUrlArgs
        {
           
get
            {
                return _inUrlArgs;
            }
        }

        ///
<summary>
        ///
Gets the name of the property.
        ///
</summary>
        /// <value>The name.
</value>
        public static string Name
        {
           
get
            {
                return "urlArguments";
            }
        }

        ///
<summary>
        ///