Just in:

Important Information for Thursday 5 January 2006

Microsoft announced that it would release a security update to help protect customers from exploitations of a vulnerability in the Windows Meta File (WMF) area of code in the Windows operating system on Tuesday, January 2, 2006, in response to malicious and criminal attacks on computer users that were discovered last week.

Microsoft will release the update today on Thursday, January 5, 2006, earlier than planned.

http://windowsupdate.microsoft.com


 
Categories:

Part 1, Part 2, Part 3, Part 4, Part 5, Part 6, Part 7

We’ve got all the moving pieces and what’s left is a way to configure the PoxEncoder into bindings and use those to hook a service up to the network and run it.

Bindings? Well, all Indigo (WCF) services need to know their ABC to function. ABC? I’ll quote from my WCF Introduction on MSDN:

“ABC” is the WCF mantra. “ABC” is the key to understanding how a WCF service endpoint is composed. Think Ernie, Bert, Cookie Monster or Big Bird. Remember "ABC".

·         "A" stands for Address: Where is the service?

·         "B" stands for Binding: How do I talk to the service?

·         "C" stands for Contract: What can the service do for me?

Web services zealots who read Web Service Description Language (WSDL) descriptions at the breakfast table will easily recognize these three concepts as the three levels of abstraction expressed in WSDL. So if you live in a world full of angle brackets, you can look at it this way:

·         "A" stands for Address—as expressed in the wsdl:service section and links wsdl:binding to a concrete service endpoint address.

·         "B" stands for Binding—as expressed in the wsdl:binding section and binds a wsdl:portType contract description to a concrete transport, an envelope format and associated policies.

·         "C" stands for Contract—as expressed in the wsdl:portType, wsdl:message and wsdl:type sections and describes types, messages, message exchange patterns and operations.

"ABC" means that writing (and configuring) a WCF service is always a three-step process:

·         You define a contract and implement it on a service

·         You choose or define a service binding that selects a transport along with quality of service, security and other options

·         You deploy an endpoint for the contract by binding it (using the binding definition, hence the name) to a network address.

A binding is a layered combination of a transport, an encoder and of any additional protocol channels (reliable session, transaction flow, etc.) that you’d like to assemble into a transport stack for exposing a service implementation on a specific endpoint address.

For exposing a HTTP-based RESTish service we need:

A.    The HTTP address to host the service at.

B.     Some binding configuration that tells Indigo’s HTTP transport to use our PoxEncoder.

C.     An implementation of a service-contract that’s configured (using the HttpMethodOperationSelectorSection config extension) or marked-up (with the HttpMethodOperationSelectorAttribute) to use our HttpMethodOperationSelectorBehavior for endpoint address filtering and selecting methods.

I’ve shown you quite a few contract variants in the first parts of this series and therefore I don’t really have to explain the C in too much detail anymore; except: While the A is just a plain HTTP address such as http://www.example.com/service, it’s interesting insofar as this address is, unlike as with SOAP services, really just the common address prefix for the dispatch URIs of the particular service and that there is a split between what is A and what is C.

As I’ve explained, the philosophy behind the contract design of my extensions is around the namespaces that are the basis for forming URIs. Because REST services aren’t simply using HTTP as a transport tunnel as SOAP services do, but rather leverage HTTP as the application protocol it is, the URI is a lot more than just a drop-off point for messages. With REST services, the URI is an expression that has both, addressing (transport) and contract (dispatch) aspects to it and we need to separate those out. A clear distinction between global and local namespaces allows us to do that (And I am going into a bit more detail than I usually would, to further address an objection of Mark Baker, 1st comment, on my choice of the programming model):

There is a global namespace that’s managed by the global DNS system of which anyone can reserve a chunk for themselves by registering a domain-name. The domain-name provides a self-manageable namespace root of which sub-namespaces (subdomains) can be derived and allocated to specific hosts/services or groups of hosts/services by the domain owners. On the particular host, you can put an application behind a specific port, which might either the default port of your particular application protocol or – diverging from the protocol standard – some other port of your choosing. Each Internet application deployment has therefore at least one unique mapping into this global namespace system.

Any further segmentation of the namespace except the host-name and the port-number are private matters of the application listing to that endpoint. With Indigo self-hosted HTTP services, the listening application is Windows (!) – more precisely it’s the HTTP.SYS kernel listener. For IIS/WAS hosted services, the listening application is IIS (for IIS 5.1 and below) or, again, Windows – through that very listener. At the HTTP.SYS listener, handler processes can register their interest in requests sent to certain sub-namespaces of the global namespace mapping (host/port), which are identified by relative URIs. To be clear: The HTTP.SYS API indeed requires the caller to provide an absolute URI like http://hostname:port/service, but the two main parts (scheme/host/port and path) of that URI are used for different purposes:

·         Global mapping: The hostname and port are used to establish a new listener on that particular port (if there is already a listener it is shared) and to populate the hostname-filter table that’s used to disambiguate requests by the Host header in case the IP address is mapped to multiple DNS host entries.

·         Local mapping: The path information of the URI (the remaining relative URI with scheme, hostname and port stripped) is used as a prefix-matching expression to figure out which handler process shall receive the request and, inside that handler process, to further identify and invoke the appropriate endpoint and handler that deals with the resource that the complete URI path represents.

As indicated, mapping URIs to an endpoint needs to distinguish between how we segment and map a local namespace and how we hook that into the global namespace. Hence, the root for any absolute URIs that’s establishing the mapping into the global namespace shall always be separate from the code and reside in configuration for reasons of flexibility as Mark was rightfully pointing out in his objection, while the shape and mapping of the local namespace is typically very application and use-case specific and might well be partially or entirely hardwired.

·         The Indigo A(ddress) of a REST service implemented with my particular programming model is used to hook a given service (or resource representation manager, if you like) into the global namespace: http://myservice.example.com/. Only to be pragmatic and to allow multiple such services to locally share a particular hostname and port and indeed only as an alternative and workaround to creating a separate DNS entry for each service, that mapping might include a path prefix allowing the local low-level infrastructure to demultiplex requests sent to the same global namespace mapping: http://myservices.example.com/serviceA and http://myservices.example.com/serviceB.

·         The Indigo C(ontract) of a REST service implemented with my particular programming model is used to define the shape of the local namespace that the service owns and which is used to provide access to the representations of the resource-types the service is responsible for.

The following configuration snippet for a simple web-server based on my extensions is illustrating that split:

<services>
   <
service type="LittleIndigoWebServer.MyWebServer">
      <
endpoint contract="LittleIndigoWebServer.IMyWebServer"
                address="http://localhost:8020/"
                
binding="customBinding"
                
bindingConfiguration="poxBinding"/>
   </
service>
</
services>

The address http://localhost:8020/ is how I map the service into the global addressing namespace. The local namespace shape for that particular service is a defined by the layout of the file-system directory from which the service grabs files and returns them. What? You can’t see the directory structure and the resulting URLs from the above mapping? Of course not. It’s a private matter of the service implementation what that the local namespace structure is and it’s up to me what parts I am exposing. If I am nice enough I will give you something on a GET/HEAD request on the root of my local namespace (= global address without any suffix), and if I am not nice you get a 404 and will just have to know what to ask for. The “will have to know” part is contract. It’s an assurance that if you come looking at a particular place in my namespace you will have access to a particular thing. My [HttpMethod] attributes manifest that assurance on Indigo contracts.

That leaves B. Before I got carried away by A and C, I wrote [now a bit annotated] “A binding is a layered combination of a transport, an encoder and of any additional protocol channels (reliable session, transaction flow, etc.) that you’d like to assemble into a transport stack for exposing a service implementation [C] on a specific endpoint address [A].”

Putting together such a binding is not much more work than putting a little text between angle brackets and quotation marks in config as shown in the following snippet:

<customBinding>
   <
binding name="poxBinding">
      <
poxEncoder/>
      <
httpTransport mapAddressingHeadersToHttpHeaders="true"
           
maxMessageSize="2048000" maxBufferSize="2048000" manualAddressing="true"
          
authenticationScheme="Anonymous" transferMode="StreamedResponse"  />
   </
binding>
</
customBinding>

I am building a custom binding that’s combining the HTTP transport with a custom binding element config extension I built for the PoxEncoder. It’s that simple. And adding the binding element extension does not require black magic, either. It’s just another XML snippet that maps the extension class to an element name (“poxEncoder”) as you can see in the extensions section of the complete config file:

 <?xml version=1.0 encoding=utf-8 ?>
<
configuration>
   <
system.serviceModel>
      <
extensions>
         <
bindingElementExtensions>
            <
add name="poxEncoder" type="newtelligence.ServiceModelExtensions.PoxEncoderBindingExtension, newtelligence.ServiceModelExtensions"/>
         </
bindingElementExtensions>
      </
extensions>
      <
bindings>
         <
customBinding>
        <
binding name="poxBinding">
               <
poxEncoder/>
               <
httpTransport mapAddressingHeadersToHttpHeaders="true"
                           
maxMessageSize="2048000" maxBufferSize="2048000" manualAddressing="true"
                           
authenticationScheme="Anonymous" transferMode="Streamed"  />
            </
binding>
         </
customBinding>
      </
bindings>
      <
services>
         <
service type="LittleIndigoWebServer.MyWebServer">
            <
endpoint contract="LittleIndigoWebServer.IMyWebServer"
                    address="http://localhost:8020/"
                    
binding="customBinding"
                    
bindingConfiguration="poxBinding"/>
         </
service>
      </
services>
  </
system.serviceModel>
</
configuration>

The PoxEncoderBindingExtension is a class that is based on System.ServiceModel.Configuration.BindingElementExtensionSection. Whenever the configuration is processed by Indigo, the presence of the “poxEncoder” element in a binding triggers the creation of an instance of the class and if we’d require any configuration attributes (which we don’t), those would be stuffed into the Properties collection.    

using System;
using System.ServiceModel.Configuration;
using System.ServiceModel;
using System.Configuration;

namespace newtelligence.ServiceModelExtensions
{
   public class PoxEncoderBindingExtension : BindingElementExtensionSection
   {
        /// <summary>
        /// Initializes a new instance of the <see cref="T:PoxEncoderBindingExtension"/> class.
        /// </summary>
      public PoxEncoderBindingExtension()
      {
      }

        /// <summary>
        /// Creates the binding element.
        /// </summary>
        /// <returns></returns>
      protected override BindingElement CreateBindingElement()
      {
         PoxEncoderBindingElement pcc = new PoxEncoderBindingElement();
         return pcc;
      }

        /// <summary>
        /// Gets the type of the binding element.
        /// </summary>
        /// <value>The type of the binding element.</value>
      public override Type BindingElementType
      {
         get
         {
            return typeof(PoxEncoderBindingElement);
         }
      }

        /// <summary>
        /// Gets the name of the configured section.
        /// </summary>
        /// <value>The name of the configured section.</value>
      public override string ConfiguredSectionName
      {
         get
         {
            return "poxEncoder";
         }
      }

      private ConfigurationPropertyCollection properties;
        /// <summary>
        /// Gets the collection of properties.
        /// </summary>
        /// <value></value>
        /// <returns>The <see cref="T:System.Configuration.ConfigurationPropertyCollection"></see> collection of properties for the element.</returns>
      protected override ConfigurationPropertyCollection Properties
      {
         get
         {
            if (this.properties == null)
            {
               ConfigurationPropertyCollection configProperties = new ConfigurationPropertyCollection();
               this.properties = configProperties;
            }
            return this.properties;
         }
      }
   }
}

Once the configuration information has been read, the extension is asked to create a BindingElement from the acquired information. So these extensions are really just factories for binding elements. The binding element, which can also be used to compose such a binding in code by explicitly adding it to a System.ServiceModel.CustomBinding is shown below:

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

namespace newtelligence.ServiceModelExtensions
{
    public class PoxEncoderBindingElement : BindingElement, IMessageEncodingBindingElement
   {
        /// <summary>
        /// Clones this instance.
        /// </summary>
        /// <returns></returns>
      public override BindingElement Clone()
      {
         return new PoxEncoderBindingElement();
      }

        /// <summary>
        /// Creates the message encoder factory.
        /// </summary>
        /// <returns></returns>
      public MessageEncoderFactory CreateMessageEncoderFactory()
      {
         return new PoxEncoderFactory();
      }

        /// <summary>
        /// Gets the addressing version.
        /// </summary>
        /// <value>The addressing version.</value>
      public AddressingVersion AddressingVersion
      {
         get
         {
            return AddressingVersion.Addressing1;
         }
      }

        /// <summary>
        /// Gets the protection requirements.
        /// </summary>
        /// <returns></returns>
      public override System.ServiceModel.Security.Protocols.ChannelProtectionRequirements GetProtectionRequirements()
      {
         return null;
      }

        /// <summary>
        /// Builds the channel factory.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <returns></returns>
      public override IChannelFactory BuildChannelFactory(ChannelBuildContext context)
      {
         if (context == null)
            throw new ArgumentNullException("context");

         context.UnhandledBindingElements.Add(this);
         return context.BuildInnerChannelFactory();
      }

        /// <summary>
        /// Builds the channel listener.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        public override IChannelListener<TChannel> BuildChannelListener<TChannel>(ChannelBuildContext context)
        {
            if (context == null)
            throw new ArgumentNullException("context");

         context.UnhandledBindingElements.Add(this);
         return context.BuildInnerChannelListener<TChannel>();
      }
   }
}

Binding elements are typically used to put together client-side (channel factory) or service-side (channel listener) transport stacks. At the bottom is the transport and layered on top of it are security, reliable sessions, transaction flow and all other protocol features you need. Each protocol or feature on the channel/listener level has its own binding element and using those you configure yourself a binding combining the features you need and in the order that they should be applied.

The binding elements for message encoders are a bit different, because they are not contributing their own channel factories or channel listeners into the stack, but rather “only” supply the message encoder for the configured transport.

Whenever a binding is instantiated, Indigo creates a ChannelBuildContext which contains the sequence of the binding elements that shall be stacked onto each other into a channel or listener stack and starts stacking them from top to bottom by invoking the topmost binding element’s BuildChannelListener or BuildChannelFactory method. Once the binding element is done creating its channel factory or channel listener, it invokes BuildInnerChannel[Listener/Factory] on the context to have the binding element underneath do its work. (The context is also used to validate whether combination of the elements yields a functional binding stack, but I won’t go into that here).

Our binding element, however, won’t create a channel factory or listener, but rather put itself into the UnhandledBindingElements collection on the build context and will then just have the context complete the construction work. With putting itself into that collection, the binding element makes itself and its most irresistible feature (you’d also think that if you were an Indigo transport) – the IMessageEncodingBindingElement implementation – visible to the transport and waves its hand that it wants to be used. The transport’s binding element, which is at the bottom of the stack and therefore asked to build its channel factory/listener after our binding element has been invoked, will go look in the UnhandledBindingElements  collection whether a message encoding binding element is advertising itself for use. And if that’s so it will forget all of its defaults and happily embrace and use an encoder created by the factory returned by IMessageEncodingBindingElement.CreateMessageEncoderFactory, which is, in our case, this rather simple class:

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

namespace newtelligence.ServiceModelExtensions
{
    /// <summary>
    ///
    /// </summary>
   public class PoxEncoderFactory : MessageEncoderFactory
   {
      MessageEncoder encoder;

        /// <summary>
        /// Initializes a new instance of the <see cref="T:PoxEncoderFactory"/> class.
        /// </summary>
      public PoxEncoderFactory()
      {
          encoder = new PoxEncoder();

      }

         /// <summary>
        /// Gets the encoder.
        /// </summary>
        /// <value>The encoder.</value>
        public override MessageEncoder Encoder
      {
         get
         {
            return encoder;
         }
      }

        /// <summary>
        /// Gets the message version.
        /// </summary>
        /// <value>The message version.</value>
      public override MessageVersion MessageVersion
      {
         get
         {
            return encoder.MessageVersion;
         }
      }
   }
}

Soooooooo….!

If you had actually copied all those classes from Parts 1-8 down into local files and compiled them into an assembly, you’d have all my REST/POX plumbing code by now (except, admittedly, an application-level utility class that helps putting messages together).

But wait … don’t do that. In the next part(s) I’ll give you the code all packed up and ready to compile along with the little web server that we’ve configured here and will also share some code snippets from my TV app … maybe the RSS and ASX pieces?


 
Categories: Indigo

January 4, 2006
@ 01:21 PM

In case you are not following my Indigo REST/POX series, I quote one paragraph from today's Part 7 that is well worth to be quoted out of context. It talks about (SOAP-) messages and the misconception that a message is a small thing:

There’s no specification that says that you cannot stick 500 Terabyte or 500 Exabyte worth of data (think 365x24 live 1080i video streams) into a single message. As long as you have some reason to believe that the sender will eventually, in 20 years from now, give you “</soap:Body></soap:Envelope>” to terminate the message, the message can be assumed to be well-formed and complete.

The WCF transports that support "streamed" transfer-mode (all except MSMQ) all consider messages to be monsters like that when streaming is enabled. I have a bit more on the streaming mode in today's part of the series.


 
Categories: Indigo

Part 1, Part 2, Part 3, Part 4, Part 5, Part 6, Part 7, Part 8, Part 9

Where are we?

·         In Parts 1 and 2, I explained contracts in the REST/POX context and the dispatch mechanisms that we need to enable Indigo to accept and handle REST/POX requests. With that I introduced a metadata extension, the [HttpMethod] attribute that can be used to mark up operations on an Indigo contract with HTTP methods and a URI suffixes that we can dispatch on. I also showed how we can employ a parameter inspector to extract URI-embedded arguments and flow them to the operation in a message property.

·         In Parts 3 and 4, I showed how we use the [HttpMethodOperationSelector] attribute to replace Indigo’s default address filtering and operation selection mechanisms, basically the entire message dispatch mechanism, with our own variants. The SuffixFilter is used to find the appropriate endpoint for an incoming request and the HttpMethodOperationSelectorBehavior  find the operation (method) on that endpoint which shall receive the incoming request message.

·         In Parts 5 and 6, you saw how the PoxEncoder puts outbound envelope-less POX documents onto the wire in its WriteMessage methods and accepts incoming non-SOAP XML requests through its ReadMessage methods and wraps them with an in-memory envelope (“message”) for further processing. I also showed the PoxBase64XmlStreamReader, which is an XML Infoset wrapper for arbitrary binary streams that interacts with the PoxEncoder to allow smuggling any sort of raw binary content through the Indigo infrastructure and onto the wire.

We’re pretty far along already. We’ve got the dispatch mechanisms, we know how to hook the dispatch metadata into the services, we’ve got the wire-encoding – we have most of the core pieces together. In fact, the last two key classes we’re missing (configuration hooks aside) are two specialized message classes that we need to handle incoming requests. In Part 6, you could see that the two ReadMessage overloads of the PoxEncoder delegate all work to the PoxBufferedMessage for the “buffered” transfer-mode overload and to PoxStreamedMessage for the “streamed” transfer mode overload.

ReadMessage is called on an encoder whenever a transport has received a complete message buffer (buffered mode) or has accepted and opened a network stream (streamed mode).

Using streamed mode means very concretely that Indigo will start handling the message even though the message might not have completely arrived. A transport in streaming mode will only do as much as it needs to do in order to deal with the transport-level framing protocol. I use “framing protocol” as a general term for what is done at the transport level to know what the nature of the payload is and where the payload starts and ends. For HTTP, the HTTP transport figures out whether an incoming request is indeed an HTTP request, will read/parse the HTTP headers, and will then layer a stream over the request’s content, irrespective of whether the transfer of that byte sequence has already been completed. This stream is immediately handed off to the rest of the Indigo infrastructure and the transport has done its work by doing so.

Pulling the remaining bytes from that stream is someone else’s responsibility in streamed mode. Whenever a piece of the infrastructure pulls data directly or indirectly from the stream and the data chunk requested is still in transfer, the stream will block and wait until the data is there. The transport’s handling of the framing protocol will typically also take care of chunking and thus make a chunked stream appear to be continuous. When I say “indirect pull” I mean that it may very well be an XmlDictionaryReader layered over an XmlReader layered over the incoming network stream.

The streaming mode is of particular interest for very large messages that may, in an extreme case, be virtually limitless in size. There’s no specification that says that you cannot stick 500 Terabyte or 500 Exabyte worth of data (think 365x24 live 1080i video streams) into a single message. As long as you have some reason to believe that the sender will eventually, in 20 years from now, give you “</soap:Body></soap:Envelope>” to terminate the message, the message can be assumed to be well-formed and complete.

No matter whether you use buffered or streamed mode, the configured encoder’s ReadMessage method is the first place where the read data chunk or the stream goes and that delegates, as shown to our two message classes. So let’s look at them.

We’ll primarily look at the PoxBufferedMessage, which is constructed over the read message buffer in the PoxEncoder like this:

public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager)
{
   return new PoxBufferedMessage(buffer, bufferManager);
}

The class PoxBufferedMessage is derived from the abstract System.ServiceModel.Message class and implements the base-class’s abstract properties Headers, Properties, and Version and overrides the OnClose(), OnGetReaderAtBodyContents(), and OnWriteBodyContents() virtual methods. Internally, Indigo has several such Message implementations that are each customized for certain scenarios. Implementing own variants of Message is simply another extensibility mechanism that Indigo gives us.

Using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using System.IO;
using System.Xml;
using System.Runtime.CompilerServices;
using System.ServiceModel.Channels;

namespace newtelligence.ServiceModelExtensions
{
    /// <summary>
    /// This class is one of the message classes used by the <see cref="T:PoxEncoder"/>
    /// It serves to wrap an unencapsulated data buffer with a message structure.
    /// The data buffer becomes the body content of the message.
    /// </summary>
   public class PoxBufferedMessage : Message, IPoxRawBodyMessage
   {
      MessageHeaders headers = new MessageHeaders(MessageVersion.Soap11Addressing1);
      MessageProperties properties = new MessageProperties();
      byte[] buffer;
      int bufferSize;
      BufferManager bufferManager;
      Stream body;
       
        /// <summary>
        /// Initializes a new instance of the <see cref="T:PoxBufferedMessage"/> class.
        /// </summary>
        /// <param name="buffer">The buffer.</param>
      public PoxBufferedMessage(byte[] buffer)
      {
            bufferManager = null;
            buffer = buffer;
            bufferSize = buffer.Length;
      }

        /// <summary>
        /// Initializes a new instance of the <see cref="T:PoxBufferedMessage"/> class.
        /// </summary>
        /// <param name="buffer">The buffer.</param>
        /// <param name="bufferManager">The buffer manager.</param>
        public PoxBufferedMessage(ArraySegment<byte> buffer, BufferManager bufferManager)
        {
            bufferManager = bufferManager;
            bufferSize = buffer.Count;
            buffer = bufferManager.TakeBuffer( bufferSize);
            Array.Copy(buffer.Array, buffer.Offset, buffer, 0, bufferSize);
        }     

We can construct instances of the class over a raw byte array or an “array segment” layered over such an array. Array segments are preferred over raw arrays, because their use eases memory management. You can keep a pool of buffers with a common size, even though the actual content is shorter than the buffer size and probably even offset from the lower buffer boundary. If we get a raw byte array we simply adopt it, but if we get an array segment alongside a reference to a buffer manager we take a new buffer from the buffer manager and copy the array segment to that acquired buffer.

        /// <summary>
        /// Called when the message is being closed.
        /// </summary>
        protected override void OnClose()
        {
            base.OnClose();
            if ( bufferManager != null)
            {
                bufferManager.ReturnBuffer( buffer);
            }           
        }

When we close the message and we have acquired it using the buffer manager (which is signaled by the presence of the reference) we duly return it once the message is being closed (or disposed or finalized).

The next two methods are an implementation of the IPoxRawBodyMessage interface that is, you guessed it, defined in my extensions. If the handler method wants to get straight at the raw body content knowing that it doesn’t expect XML, it can shortcut by the whole XmlReader and XML serialization story by asking for the BodyContentType and pull out the raw body data as a stream layered over the buffer:

        /// <summary>
        /// Gets the raw body stream.
        /// </summary>
        /// <returns></returns>
      [MethodImpl(MethodImplOptions.Synchronized)]
      public Stream GetRawBodyStream()
      {
         if ( body == null)
         {
             body = new MemoryStream( buffer,0, bufferSize,false,true);
         }
         return body;
      }

        /// <summary>
        /// Gets the content type of the raw message body based on the Content-Type HTTP header
        /// contained in the HttpRequestMessageProperty or HttpResponseMessageProperty of this
        /// message. The value is null if the type is unknown.
        /// </summary>
        public string BodyContentType
        {
            get
            {
                if (Properties.ContainsKey(HttpRequestMessageProperty.Name))
                {
                    return ((HttpRequestMessageProperty)Properties[HttpRequestMessageProperty.Name]).Headers["Content-Type"];
                }
                if (Properties.ContainsKey(HttpResponseMessageProperty.Name))
                {
                    return ((HttpResponseMessageProperty)Properties[HttpResponseMessageProperty.Name]).Headers["Content-Type"];
                }
                return null;
            }
        }

There is a bit of caution required using this mechanism, though. Because the message State (Created, Written, Read, Copied, Closed) is controlled by the base-class and cannot be set by derived classes, the message should be considered to be in the State==MessageState.Read after calling the GetRawBodyStream() method. That doesn’t seem to be necessary because we have a buffer here, but for the streamed variant that’s a must. And for the sake of consistency we introduce this constraint here.

The BodyContentType property implementation seems, admittedly, a bit strange at first sight. Even though you won’t see the message properties being populated anywhere inside this class, we’re asking for them and base the content-type detection on their values. That only makes sense when we consider the way messages are being populated by Indigo. As I explained, the first thing that gets called once the transport has a raw data chunk or stream in its hands that it believes to be a message, it invokes the encoder. For incoming requests/messages, the encoder is really serving as the message factory constructing Message-derived instances over raw data. Once the encoder has constructed the message in one of the ReadMessage overloads, the message is returned to the transport. If the transport wants, it can then (and the HTTP transport does) stick properties into that newly created message and then hand it off to the rest of the channel infrastructure for processing and dispatching. Because these extensions are built for REST/POX and therefore have HTTP affinity, that’s precisely what we assume to be happening for the BodyContentType property and the CreateBodyReader() method below. As I already explained in Part 1, the HTTP transport will always add a HttpRequestMessageProperty  to the message and that’s consequently from which we can grab the content-type of the incoming request data.

        private XmlDictionaryReader CreateBodyReader()
        {
            XmlDictionaryReader reader = null;

            /*
             * Check whether the message properties indicate that this is a raw binary message.
             * In that case, we'll wrap the body with a PoxBase64XmlStreamReader
             */
            bool hasPoxEncoderProperty = Properties.ContainsKey(PoxEncoderMessageProperty.Name);
            if (!(hasPoxEncoderProperty && ((PoxEncoderMessageProperty)Properties[PoxEncoderMessageProperty.Name]).RawBinary))
            {
                string contentType = null;

                /*
                 * Check for whether either the HttpRequestMessageProperty or the HttpResponseMessageProperty
                 * are present. If so, extract the HTTP Content-Type header. Otherwise the content-type is
                 * assumed to be text/xml ("POX")
                 */
                bool hasRequestProperty = Properties.ContainsKey(HttpRequestMessageProperty.Name);
                bool hasResponseProperty = Properties.ContainsKey(HttpResponseMessageProperty.Name);
                if (hasResponseProperty)
                {
                    HttpResponseMessageProperty responseProperty =
                      Properties[HttpResponseMessageProperty.Name] as HttpResponseMessageProperty;
                    contentType = responseProperty.Headers["Content-Type"];
                }
                else if (hasRequestProperty)
                {
                    HttpRequestMessageProperty requestProperty =
                       Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
                    contentType = requestProperty.Headers["Content-Type"];
                }

                if (contentType == null)
                {
                    contentType = "text/xml";
                }

                /*
                 * If the content type is text/xml (POX) we will create a plain XmlTextReader for the body.
                 */
                if (contentType.StartsWith("text/xml", StringComparison.OrdinalIgnoreCase))
                {
                   // do we only have a UTF byte-order mark?
                   if (_bufferSize <= 4)
                   {
                       // create a new reader over a fake infoset and place it on the EndElement
                      
reader = XmlDictionaryReader.CreateDictionaryReader(
                          new XmlTextReader(new StringReader("<no-data></no-data>")));
                       reader.Read(); reader.Read();
                   }
                   else
                  
{
                       reader = XmlDictionaryReader.CreateDictionaryReader(new XmlTextReader(GetRawBodyStream()));
                   }

                }
            }
            /*
             * If the content wasn't identified to be POX, we'll wrap it as binary. 
             */
            if (reader == null)
            {
                reader = XmlDictionaryReader.CreateDictionaryReader(new PoxBase64XmlStreamReader(GetRawBodyStream()));
            }
            return reader;
        }

The private CreateBodyReader() method that constructs XML readers for the both, the OnGetBodyReaderAtBodyContents() and the OnWriteBodyContents() overrides shown below, uses the same strategy to figure out the content-type of the message and therefore to guess what’s hidden inside the byte-array (or array segment) the message was constructed over. To make the message class useful for the request and response direction, we’ll distinguish there two separate cases here:

·         If the message is a response, the handling method in the user code might have indicated that it wants the encoder to serialize the message onto the wire in “raw binary” mode. The indicator for that is the presence of the PoxEncoderMessageProperty having the RawBinary property set to true. If that is the case, the reader we return is always our PoxBase64XmlStreamReader. The property cannot occur in request messages because the Indigo transports simply don’t know about it.

·         If the message is a request or a response with the mentioned property missing, we will try figuring out the message’s content-type using the described strategy of using the HTTP transport’s message properties. If we can’t figure out a content-type for a response (it’s optional for the responding handler code to supply it), we will assume that the content-type is “text/xml”. If the message is a request we can rely of getting a content-type as long as the underlying transport is Indigo’s HTTP transport implementation. If the content-type is indeed “text/xml” we construct an XmlTextReader over the raw data and return it. If the content-type is anything else, we use our PoxBase64XmlStreamReader wrapper, because we have to assume that the encapsulated data we’re dealing with is not XML.

The OnGetBodyReaderAtBodyContents() and the OnWriteBodyContents() overrides are consequently very simple:

        /// <summary>
        /// Called when the client requests a reader for the body contents.
        /// </summary>
        /// <returns></returns>
      protected override XmlDictionaryReader OnGetReaderAtBodyContents()
      {
         XmlDictionaryReader reader = CreateBodyReader();
         reader.MoveToContent();
         return reader;
      }

        /// <summary>
        /// Called when the client requests to write the body contents.
        /// </summary>
        /// <param name="writer">The writer.</param>
      protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
      {
         XmlDictionaryReader reader = CreateBodyReader();
         writer.WriteNode(reader, false);
      }

What’s left to complete the message implementation are the compulsory overrides of the abstract properties of Message, for which we have backing fields declared at the top of the class:

        /// <summary>
        /// Gets the message version.
        /// </summary>
        /// <value>The message version.</value>
      public override MessageVersion Version
      {
         get
         {
            return MessageVersion.Soap11Addressing1;
         }
      }

        /// <summary>
        /// Gets the SOAP headers.
        /// </summary>
        /// <value>The headers.</value>
      public override MessageHeaders Headers
      {
         get
         {
            return headers;
         }
      }

        /// <summary>
        /// Gets the message properties.
        /// </summary>
        /// <value>The properties.</value>
      public override MessageProperties Properties
      {
         get
         {
            return properties;
         }
      }
    }
}

The PoxStreamedMessage is only different from this class insofar as that it doesn’t have the buffer management. The GetRawBodyStream() method immediately returns the encapsulated stream and the remaining implementation is largely equivalent, if not identical (yes, I should consolidate that into a base class). Therefore I am not pasting that class here as code but rather just append as a downloadable file, alongside the declaration of IPoxRawBodyMessage and the twice mentioned and not yet shown PoxEncoderMessageProperty class.

With this, we’ve got all the moving pieces we need to build what’s essentially becoming an Indigo-based, message-oriented web-server infrastructure with a REST-oriented programming model. What’s missing is how we get our encoder configured into a binding so that we can put it all together and run it.

Configuration is next; wait for part 8.

Download: PoxEncoderMessageProperty.zip
Download: PoxStreamedMessage.zip
Download: IPoxRawBodyMessage.zip

[2006-01-13: Updated PoxBufferedMessage code to deal with entity bodies that only consist of a UTF BOM]


 
Categories: Indigo

January 2, 2006
@ 04:00 PM

Sabine and I were just browsing Channel 9 using TVTonic on our Media Center PC that's been recently connected to this christmas gift. We watched a few snippets of Microsoft PMs and other folks presenting their latest stuff and then that. Sabine (she's a nurse) said "...oh, that's like Hospital TV".

I can't help but admit that she does indeed have more than just one point in saying that.


 
Categories: Other Stuff

January 2, 2006
@ 03:08 AM

I recently needed a TCP port-forwarder that sits on a socket connection and monitors it. My concrete use-case is that I need to front the backend-server of my TV application with such a port forwarder in order to create live-TV streaming sessions as soon as a client requests them and also tears them down shortly after the client disconnects so that the session doesn’t need to time out and blocks the tuner until then. The backend also requires that I do a periodical “keep-alive” ping every 30-40 seconds, which isn’t a very practical requirement for some of my client scenarios. Therefore, I needed, generally speaking, something that would sit between the client and the backend server, monitors the data stream and would let me run some code (set up the live session and start the keep-alive timer) when I get a new client connection and just before I connect through to the target and which would let me run some code (shut down the session and stop the keep-alive) as soon as the connection is torn down.

Since, I didn’t find one (or was too blind or too lazy, you know how that goes), I wrote one. It’s a fully asynchronous TcpListener/TcpClient based implementation, it’s fast and stable enough for my purposes and it might or might not be for yours, it has a bit of tolerance for targets that don’t accept a connection on the first try, and you can hook up events to “before target connect” and “after target disconnect”. Since all the bytes fly by, you can instrument the thing further or monitor the stream as you like.  

The code is pretty straightforward, even though the asynchronous calls/callbacks admittedly make the execution paths in the implementation a bit challenging to follow, and should not require much further explanation. You construct an instance of TcpPortForwader passing the local port and the target port and host to forward to, call Start() and the listener starts listening. Stop() stops the listener. You can call Start() from any thread; the listener will implicitly use thread-pool threads to run on its own. Hook up the events and they are being raised. Simple enough. Download below.

Download: TcpPortForwarder.zip


 
Categories: CLR

Part 1, Part 2, Part 3, Part 4, Part 5

I threw a lot of unexplained code at you in Part 5 and that wasn’t really fair.

The PoxEncoder class is a replacement for Indigo’s default TextMessageEncoder class that’s used by the HTTP transport unless you explicitly configure something different. Indigo comes with three built-in encoders, namely:

·         The TextMessageEncoder serializes Indigo’s internal Message into SOAP 1.1 or SOAP 1.2 envelopes using (applies only to the latter) the desired character encodings (UTF-8, UTF-16, etc.) and of course it also deserializes incoming SOAP envelopes into the Indigo representation.

·         The MtomMessageEncoder serializes messages into SOAP 1.2 messages as specified by the MTOM specification, which allows for a much more compact transmission of binary-heavy SOAP envelopes than if you were simply using base64Binary encoded element data. MTOM is a good choice whenever the size of binary content in a SOAP envelope far exceeds the size of the rest of the data. Your mileage may vary, so that’s a thing to measure carefully unless it’s blatantly obvious such as in the case of writing a service for a digital imaging library.

·         The BinaryMessageEncoder serializes messages into SOAP 1.2 envelopes, but does so in a very compact binary format that preserves the XML information set, but is not at all like XML text. The gist of the binary encoding is the assumption that if both communicating parties are implemented with Indigo and share the same contract, the metadata existing at both ends reduces the hints that need to go on the wire. In other words: The binary encoding doesn’t need to throw all  these lengthy XML tag names and namespace names explicitly onto the wire, but can refer to them by pointing to a dictionary that’s identically constructed on both ends. The binary encoding in Indigo is a bit like the modern-day, loosely coupled grand-child of NDR and “midl.exe /Oicf” if you like. What’s important to note about this encoding is that its primary design goal is performance and interoperability is in fact a non-goal. The BinaryMessageEncoder assumes Indigo endpoints. If you don’t like that, you can always use the text encoding, which is designed for interoperability.

Our PoxEncoder here differs from all three Indigo encoders in that it does specifically not serialize SOAP messages, but rather just the body contents of a Message.

In order for you to understand what’s happening here, I’ll pick the most relevant methods and explain them in detail. We will start with the Initialize() method that is invoked by all three constructor overloads:

/// <summary>
///
Initializes common properties of the encoder.
/// </summary>
private void Initialize()
{
  if (this.MessageVersion.Envelope == EnvelopeVersion.Soap12)
  {
    // set the aprorpiate media type for SOAP 1.2
     this. mediaType = "application/soap+xml";
  }
  else if (this.MessageVersion.Envelope == EnvelopeVersion.Soap11)
  {
    // set the appropriate media type for SOAP 1.1
     this. mediaType = "text/xml";
  }
  // compose the content type from charset and media type
  this. contentType = string.Format(CultureInfo.InvariantCulture, "{0}; charset={1}", mediaType, textEncoding.WebName);
}

It is required for each MessageEncoder-derived class to implement the abstract properties MediaType, ContentType, and MessageVersion, and therefore we have to initialize the backing fields for these properties properly and return meaningful values even though the PoxEncoder is exactly the “anti-SOAP” encoder. The message version specified in the encoder is relevant for Indigo higher up on the stack, because it needs to know what rules and constraints apply to Message instances as they are constructed and processed. The content type and media types are required by the transports so that they know what content and/or media type to specify as metadata in their transport frame (eg. the Content-Type header in HTTP). If we initialize the encoder with the Soap12 message version, it will consequently report the application/soap+xml media type, even though the encoder doesn’t ever write such envelopes to the wire. You might consider that a bug in the PoxEncoder and you might be right, but it doesn’t really matter. Because any methods can return all sorts of payloads, we will override the content-type on the message-level so that this information has really no effect. I do need to clean this up a little. Later.

Now let’s look at the parts that actually do the work. I will start with the two WriteMessage overloads.

The first overload’s signature is
     public override ArraySegment<byte> WriteMessage(Message msg, int maxMessageSize, BufferManager bufferManager, int messageOffset)
and is invoked by the transport whenever a message must be wire-encoded and the output transfer mode is set to TransferMode.Buffered or TransferMode.StreamedRequest (which implies a buffered response). The second overload’s signature is
    public override void WriteMessage(Message msg, System.IO.Stream stream)
and is invoked by the transport whenever a message must be wire-encoded and the output transfer mode is set of TransferMode.Streamed or TransferMode.StreamedResponse (which implies a streamed response).

The transfer-mode property is configurable on all of the pre-built HTTP bindings and on the <httpTransport> binding element. “Buffered” encoding means that the entire message is encoded at once and written into a buffer, which is then given to the the transport for sending. “Streamed” encoding means that the message is pushed into to a stream, whereby the stream is typically immediately layered directly over the transport. That means that whenever our encoder writes data to that stream, it is immediately pushed to the remote communication partner. The “streamed” mode is the optimal choice for sending very large messages that are, for instance, too big to be reasonably handled as a single memory block. The buffered mode is better (and faster) for compact messages. I’ll dissect the buffered variant first:

public override ArraySegment<byte> WriteMessage(Message msg, int maxMessageSize, BufferManager bufferManager, int messageOffset)
{
   if (msg.IsEmpty)
   {
      // if the message is empty (no body defined) the result is an empty
      // byte array.
      byte[] buffer = bufferManager.TakeBuffer(maxMessageSize);
      return new ArraySegment<byte>(buffer, 0, 0);
   } 

If the message is empty (that means: the body is empty), we request a buffer from the buffer manager and return an empty slice of that buffer, because this encoder’s output is “nothing” if the body is empty.The BufferManager is an Indigo helper class that manages a pool of pre-allocated buffers and serves to optimize memory management by avoiding the allocation and the discarding of buffers for every message. And encoder should therefore use the buffer manager argument and use it to obtain the buffers backing the array segment that is to be returned. Once the message has been handled by the transport, the transport will return the buffer into the pool.

   else
   {
      // check RawBinary bit in the message property
          bool rawBinary = false;
          if (msg.Properties.ContainsKey(PoxEncoderMessageProperty.Name))
      {
         rawBinary = ((PoxEncoderMessageProperty)msg.Properties[PoxEncoderMessageProperty.Name]).RawBinary;
      }

If the message is not empty (we have a body), we check whether there is a PoxEncoderMessageProperty present in the message. This property is a plain CLR class that is part of my extensions and has two significant properties: Name is a static, constant string value used as the key for the message properties collection and RawBinary is a Boolean instance value that contains and indicator for whether the encoder shall encode the data as XML or as raw binary data. The Message property collection is a simple dictionary of objects keyed by strings. The properties allow application-level code to interact with infrastructure-level code in the way illustrated by this property. Whenever I want the encoder to use its “raw binary” mode, I add this property to the message and the encoder can pick up the information.

      ArraySegment<byte> retval = new ArraySegment<byte>();
      byte[] buffer = bufferManager.TakeBuffer(maxMessageSize);
      if (!rawBinary)
      {
         // If we're rendering XML data, we construct a memory stream
         // over the output buffer, layer an XMLDictionaryWriter on top of it
         // and have the message write the body content into the buffer as XML.
         // The buffer is then wrapped into an array segment and returned.
         MemoryStream stream = new MemoryStream(buffer);
         XmlWriterSettings settings = new XmlWriterSettings();
         settings.OmitXmlDeclaration = true;
         settings.Indent = true;
         settings.Encoding = this. textEncoding;
         XmlWriter innerWriter = XmlWriter.Create(stream, settings);
         XmlDictionaryWriter writer = XmlDictionaryWriter.CreateDictionaryWriter(innerWriter, false);
         msg.WriteBodyContents(writer);
         writer.Flush();
         retval = new ArraySegment<byte>(buffer, 0, (int)stream.Position);
      }

Next we take a buffer from the buffer manager and if we’re not in “raw binary” mode, we’ll construct a memory stream over the buffer, construct an XmlDictionaryWriter over that stream and ask the message to render its “body contents” into the writer and therefore into the memory stream and into the buffer. The “body contents” of a message is what would be the child nodes of the <soap:Body> element, if we were using that (but we don’t). Once the body contents have been written, we flush the writer to make sure that all buffered data is committed into the underlying stream and then construct the return value as an array segment over the buffer with the length of the bytes written to the stream.

      else
      {
         // If we're rendering raw binary data, we grab at most 'buffer.Length'
         // bytes from the binary content of the base64Binary element (if that
         // exists) and return the result wrapped into an array segment.
         XmlDictionaryReader dictReader = msg.GetReaderAtBodyContents();
         if (dictReader.NodeType == XmlNodeType.Element &&
            dictReader.LocalName == "base64Binary")
         {
            if (dictReader.Read() && dictReader.NodeType == XmlNodeType.Text)
            {
               int size = dictReader.ReadContentAsBase64(buffer, 0, buffer.Length);
               retval = new ArraySegment<byte>(buffer, 0, size);
            }
         }
      }
      return retval;
   }
}
 

If the “raw binary” mode is to be used, we are making a bit of an assumption inside the encoder. The assumption is that the body content consists of a single element named “base64Binary” and that its content is just that: base64 binary encoded content. That is of course the other side of the PoxBase64XmlStreamReader trick I explained in Part 5. For binary data we simply assume here that the body reader is our wrapper class and this is how arbitrary binary data is smuggled through the Indigo infrastructure. The array segment to be returned is constructed by reading the binary data into the buffer and setting the array segment length to the number of bytes we could get from the element content.

The streamed version of WriteMessage is quite different:

public override void WriteMessage(Message msg, System.IO.Stream stream)
{
    try
    {
        if (!msg.IsEmpty)
        {
            // check RawBinary bit in the message property
            bool rawBinary = false;
            if (msg.Properties.ContainsKey(PoxEncoderMessageProperty.Name))
            {
                rawBinary = ((PoxEncoderMessageProperty)msg.Properties[PoxEncoderMessageProperty.Name]).RawBinary;
            }
            if (!rawBinary)
            {
                // If we're rendering XML, we layer an XMLDictionaryWriter over the
                // output stream and have the message render its body content into
                // that writer and therefore onto the stream.
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.OmitXmlDeclaration = true;
                settings.Indent = true;
                settings.Encoding = this. textEncoding;
                XmlWriter innerWriter = XmlWriter.Create(stream, settings);
                XmlDictionaryWriter writer = XmlDictionaryWriter.CreateDictionaryWriter(innerWriter, false);
                msg.WriteBodyContents(writer);
                writer.Flush();
            }

The first significant difference is that if we’re using streams, we will simply ignore empty messages and do nothing with them. In streaming mode, the transport will do any setup work required for  sending a message before invoking the encoder and ready the output network stream so that the encoder can write to it. When the encoder returns, the transport considers the write action done. So if we don’t write to the output stream, there’s no payload data hitting the wire and that happens to be what we want.

If we have data and we’re not in “raw binary” mode, the encoder will construct an XmlDictionaryWriter over the supplied stream and have the message write its body contents to it. That’s all.

            Else
            {
                // If we're rendering raw binary data, we grab chunks of at most 1MByte
                // from the 'base64Binary' content element (if that exists) and write them
                // out as binary data to the output stream. Chunking is done, because we
                // have to assume that the body content is arbitrarily large. To optimize the
                // behavior for large streams, we read and write concurrently and swap buffers.
                XmlDictionaryReader dictReader = msg.GetReaderAtBodyContents();
                if (dictReader.NodeType == XmlNodeType.Element && dictReader.LocalName == "base64Binary")
                {
                    if (dictReader.Read() && dictReader.NodeType == XmlNodeType.Text)
                    {
                        byte[] buffer1 = new byte[1024*1024], buffer2 = new byte[1024*1024];
                        byte[] readBuffer = buffer1, writeBuffer = buffer2;
                       
                        int bytesRead = 0;
                        // read the first chunk into the read buffer
                        bytesRead = dictReader.ReadContentAsBase64(readBuffer, 0, readBuffer.Length);
                        do
                        {
                            // the abort condition for the loop is that we can't read
                            // any more bytes from the input because the base64Binary element is
                            // exhausted.
                            if (bytesRead > 0 )
                            {
                                // make the last read buffer the write buffer
                                writeBuffer = readBuffer;
                                // write the write buffer to the output stream asynchronously
                                IAsyncResult result = stream.BeginWrite(writeBuffer, 0, bytesRead,null,null);
                                // swap the read buffer
                                readBuffer = (readBuffer == buffer1) ? buffer2 : buffer1;
                                // read a new chunk into the 'other' buffer synchronously
                                bytesRead = dictReader.ReadContentAsBase64(readBuffer, 0, readBuffer.Length);
                                // wait for the write operation to complete
                                result.AsyncWaitHandle.WaitOne();
                                stream.EndWrite(result);
                            }
                        }
                        while (bytesRead > 0);
                    }
                }
            }
        }
    }
    catch
    {
        // the client may disconnect at any time, so that's an expected exception and absorbed.
    }
}

In streamed “raw binary” mode things get a bit more complicated. Under these circumstances we assume that the output we are sending is HUGE. The use-case I had in mind when I wrote this is the download of multi-GByte video recordings. Therefore I construct two 1MByte buffers that are used in turns to read a chunk of data from the source body reader (for which we make the same content assumption as for the buffered case: This is believed to be a PoxBase64XmlStreamReader compatible infoset) and asynchronously push the read data into the output stream.

Because it may take a while to get a huge data stream to the other side, a lot of things can happen to the network connection during that time. Therefore the encoder fully expects that the network connection terminates unexpectedly. If that happens, we’ll catch and absorb the network exception and happily return to the caller as if we’re done.

Compared to all the complexity of the WriteMessage  overloads, the respective ReadMessage methods look fairly innocent, simple, and similar:

/// <summary>
///
Reads an incoming array segment containing a message and
/// wraps it with a buffered message. The assumption is that the incoming
/// data stream is <i>not</i> a SOAP envelope, but rather an unencapsulated
/// data item, may it be some raw binary, an XML document or HTML form
/// postback data. This method is called if the inbound transfer mode of the
/// transport is "buffered".
/// </summary>
///
<param name="buffer">Buffer to wrap</param>
///
<param name="bufferManager">Buffer manager to help with allocating a copy</param>
///
<returns>Buffered message</returns>
public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager)
{
   return new PoxBufferedMessage(buffer, bufferManager);
}

/// <summary>
///
Reads an incoming stream containing a message and
/// wraps it with a streamed message. The assumption is that the incoming
/// data stream is <i>not</i> a SOAP envelope, but rather an unencapsulated
/// data item, may it be some raw binary, an XML document or HTML form
/// postback data. This method is called if the inbound transfer mode of the
/// transport is "streamed".
/// </summary>
///
<param name="stream">Input stream</param>
///
<param name="maxSizeOfHeaders">Maximum size of headers in bytes</param>
///
<returns>Stream message</returns>
public override Message ReadMessage(System.IO.Stream stream, int maxSizeOfHeaders)
{
   return new PoxStreamedMessage(stream, maxSizeOfHeaders);
}

Both variants take the raw incoming data (whatever it is) and hand it to the PoxStreamMessage class or PoxBufferedMessage class that adopt the buffer or stream as their body content, respectively. I’ll explain those in Part 7.

Happy New Year!


 
Categories: Indigo

December 30, 2005
@ 03:08 PM

My little “TV anywhere“ project makes a bit more sense now, does it? Because Sabine and I will more than likely find ourselves somewhere in the Seattle area by mid-2006 (I’ll be telecommuting and “long-haul shuttling” for a while) and we are both big time German football (as in “soccer”) fans, we just need to fix a problem.

And I am doing it just because I can, of course. The whole Indigo REST/POX series here on the blog does nothing more than describe all the WCF extensions I wrote to build my personal TV server. The first screenshot here on the right shows the current state of things as it shows up in Media Player. The UI is a Windows Media Player hosted AJAX app with EPG data in tooltips as I hover over the channel icons, I can schedule recordings with a single mouse click and I have access to all my recordings on a separate channel or just on the channel that’s currently being watched. But that’s just the “Clemens on the road” version of this.

The other front-end is the “far away at home” version of it and that looks like the screen shots on the left. Meanwhile I have an AJAX front-end that’s built for Windows XP Media Center Edition (MCE) and snaps right into the MCE experience. My dad will get the PC that sits here in my living room and host it at his house behind an upgraded DSL line and my (to be bought) MCE machine over in Seattle will connect to it and give me remote (control) access to the 35 cable channels over here. That’s the plan.

The backend is and remains Beyond TV, because it’s a very flexible, programmable and – most importantly – streaming enabled TV engine. It’s an unlikely couple, but I decided that Beyond TV and MCE should have a wedding on my boxes. Works well.

The immediate question is of course still “Looks cool, when can I have it?” The issue is that this is a lot more of a tricky story than DasBlog, because I am depending on an existing backend software with its own, a bit limiting EULA, I am relying on a foundation that isn’t even released (WCF) and I am a lot more worried about the support situation, because setting this up correctly with Beyond TV alongside MCE and my service is … ummm… only something for folks who have no fear of the gates of Mordor and beyond. We’ll see what I can do…


 
Categories:

Part 1, Part 2, Part 3, Part 4

POX means “plain old XML” and I’ve also heard a definition saying that “POX is REST without the dogma”, but that’s not really correct. POX is not really well defined, but it’s clear that the “plain” is the focus and that means typically that folks who talk about “POX web services” explicitly mean that those services don’t use SOAP. You could see POX as an antonym for SOAP.

The design of Indigo (WCF) assumes that all messages that go onto the wire and come from the wire have a shape that is aligned with SOAP. That means that they have a “body” containing the user-defined message payload and a “header” section that contains the out-of-band metadata that helps getting the message from one place to the next, possibly through a chain of intermediaries. Most of the Indigo binding elements and their implementations also assume that those metadata elements (headers) conform to their respective WS-* standard that they are dealing with.

However, Indigo isn’t hard-wired to a specific envelope format. The default “encoders” that are responsible for turning a message into data stream (or a data package) that a transport can throw down a TCP socket or into a message queue (or whatever else) and which are likewise responsible for picking up the data from the wire to turn them into Message objects have two envelope formats baked in: SOAP 1.1 and SOAP 1.2. But that doesn’t mean that you have to use those. If your envelope format were different (there seem to be thousands, I’ll name AdsML [spec] as an example) and that’s what you want to use on the wire, you can assemble a binding that will compose an Indigo transport with your encoder. Moving away from SOAP means, though, that you can’t use the standard implementations of capabilities such as message-level security, reliable delivery, and transaction flow, because all of these are built on the assumption that you are exchanging WS-* headers with the other party and all of these specs depend on the SOAP information model. But if there are comparable specifications that come with your envelope format you can of course write Indigo extensions that you can configure into a binding just like you can compose the default binding elements. It’d be a lot of work to do that, but you’d still benefit greatly from the Indigo architecture per-se.

When we want to use a REST/POX model, our envelope format is quite simple: We don’t really have an envelope.

The idea of POX is that there’s only payload and that out-of-band metadata is unnecessary fluff. The idea of REST is that there is already and appropriate place for out-of-band metadata and that’s the HTTP headers.

In order to make REST/POX work, we therefore need to replace the Indigo default encoder with an encoder that fulfills these requirements:

1.      Extract the message body XML content of any outbound message and format it for the wire as-is and without a SOAP envelope around it and

2.      Accept an arbitrary inbound XML data and wrap it into a Message-derived class so that Indigo can handle it.

Since the use-case in whose context I’ve developed these extensions is a bit more far reaching than POX, but I indeed want to support RESTful access to any data including multi-GByte unencapsulated MPEG recordings I make on my Media PC, I’ve broadened these two requirements a bit and left out the “XML” constraint:

1.      Extract the message body XML content of any outbound message and format it for the wire as-is and without a SOAP envelope around it and

2.      Accept an arbitrary inbound XML data and wrap it into a Message-derived class so that Indigo can handle it.

XML aka POX is an interesting content-type to throw around, but it’s by no means the only one and therefore let’s not restrict ourselves too much here. Any content is good.

But then again, Indigo is assuming that all messages flowing through its channels contain XML payloads and therefore we’ve got a bit of a nut to crack when we want to use Indigo for arbitrary, non-XML payloads of arbitrary size. Luckily, XML is just an illusion.

The Indigo Message holds the message body content inside an XmlDictionaryReader (which is an optimized derivation of the well-known XmlReader). To construct a message, you can walk up to the static Message.CreateMessage(string action, XmlDictionaryReader reader) factory method and pass the readily formatted body content as a reader object and the message will happily adopt it. But can we use the XmlReader to smuggle arbitrary binary content into the message so that our own encoder can later unwrap it and put it onto the wire in whatever raw binary format we like? Sure we can! The class below may look a bit like an evil hack, but it’s a perfectly legal construct:

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.Xml.Schema;

namespace newtelligence.ServiceModelExtensions
{
   public class PoxBase64XmlStreamReader :
XmlTextReader
   {
      private const string xmlEnvelopeString =
           "<base64Binary xmlns:xsi=\"" + XmlSchema.InstanceNamespace + "\" " +
           "xmlns:xsd=\"" + XmlSchema.Namespace + "\" " +
           "xsi:type=\"xsd:base64Binary\">placeholder</base64Binary>";
      Stream innerStream;

      ///
<summary>
      /// Initializes a new instance of the <see cref="T:PoxBase64XmlStreamReader"/>
class.
      ///
</summary>
      /// <param name="stream">The stream.
</param>
      public PoxBase64XmlStreamReader(Stream stream)
         : base(new StringReader(xmlEnvelopeString))
      {
         innerStream = stream;
      }

      ///
<summary>
      ///
Gets The Common Language Runtime (CLR) type for the current node.
      ///
</summary>
      ///
<value></value>
      /// <returns>The CLR type that corresponds to the typed value of the node. The default is System.String.
</returns>
      public override Type ValueType
      {
         
get
         {
            if (NodeType == XmlNodeType.Text && base.Value == "placeholder")
            {
               return typeof(Byte[]);
            }
            
else
            {
               return base.ValueType;
            }
         }
      }
   
      ///
<summary>
      ///
Gets the text value of the current node.
      ///
</summary>
      public override string Value
      {
         
get
         {
            if (NodeType == XmlNodeType.Text && base.Value == "placeholder")
            {
               BinaryReader reader = new BinaryReader(innerStream);
               return Convert.ToBase64String(reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position)));
            }
            return base.Value;
         }
      }

      ///
<summary>
      ///
Reads the content and returns the Base64 decoded binary bytes.
      ///
</summary>
      /// <param name="buffer">The buffer into which to copy the resulting text. This value cannot be null.
</param>
      /// <param name="index">The offset into the buffer where to start copying the result.
</param>
      /// <param name="count">The maximum number of bytes to copy into the buffer. The actual number of bytes copied is returned from this method.
</param>
      ///
<returns>
      ///
The number of bytes written to the buffer.
      ///
</returns>
      public override int ReadContentAsBase64(byte[] buffer, int index, int count)
      {
         if (NodeType == XmlNodeType.Text && base.Value == "placeholder")
         {
            return innerStream.Read(buffer, index, count);
         }
         
else
         {
            return base.ReadContentAsBase64(buffer, index, count);
         }
      }
   }
}

The PoxBase64XmlStreamReader is a specialized XML reader reading a fixed info-set constructed from a string that has a “placeholder” in whose place the content of a wrapped data stream is returned “as base64 encoded content”. Of course that latter statement is hogwash. The data is never encoded in base64 anywhere. But the consumer of the reader thinks that it is and that’s really good enough for us here. The XmlReader creates the illusion that the wrapped data stream were the “text” node of a base64Binary typed element and if that’s what the client wants to believe, we’re happy.  The implementation trick here is of course very simple. As long as the reader isn’t hitting the text node with the “placeholder” all work is being delegated to the base class. Once we arrive at that particular node, we change tactics and return the data type (byte[]) and the content of the wrapped stream instead of the “placeholder” string. After that we continue delegating to the base class. If the client asks for the Value of the text node, we are returning a base64 encoded string representation of the wrapped stream which might end up being pretty big. However, if the client is a bit less naïve about the content, it will figure that the data type is byte[] and therefore retrieve the data in binary chunks through the ReadContentAsBase64() method. Let’s assume that the client will be that clever.

It doesn’t take too much imagination talent to do so, because I’ve got the client right here. I used Doug Purdy’s PoxEncoder that he showed at PDC05 as a basis for this and extended it (quite) a bit:

using System;
using System.IO;
using System.Xml;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Design;
using System.Runtime.CompilerServices;
using System.ServiceModel.Configuration;
using System.Configuration;
using System.Globalization;
using System.Xml.Schema;
using System.Diagnostics;

namespace newtelligence.ServiceModelExtensions
{
    /// <summary>
    /// This class is a wire-format encoder for System.ServiceModel that renders
    /// only the content (body) of a <see cref="T:Message"/> onto the wire, but not
    /// the surrounding SOAP message elements such as the enevlope, the headers or
    /// the body element. Likewise, the encoder expects input to be in 'raw', unwrapped
    /// form and will wrap it into a message for processing by the System.ServiceModel
    /// infrastructure.
    /// </summary>
    public class PoxEncoder : MessageEncoder
   {
      string contentType;
      string mediaType;
      Encoding textEncoding;
      MessageVersion messageVersion;

      /// <summary>
      /// Creates a new instance of PoxEncoder
      /// </summary>
      public PoxEncoder()
      {
          messageVersion = MessageVersion.Soap11Addressing1;
          textEncoding = Encoding.UTF8;
         Initialize();
      }

      /// <summary>
      /// Creates a new instance of PoxEncoder
      /// </summary>
      /// <param name="messageVersion"></param>
      public PoxEncoder(MessageVersion messageVersion)
      {
         this. messageVersion = messageVersion;
          textEncoding = Encoding.UTF8;
         Initialize();
      }


      /// <summary>
      /// Creates a new instance of PoxEncoder
      /// </summary>
      /// <param name="textEncoding"></param>
      /// <param name="messageVersion"></param>
      public PoxEncoder(Encoding textEncoding, MessageVersion messageVersion)
      {
         this. textEncoding = textEncoding;
         this. messageVersion = messageVersion;
         Initialize();
      }

        /// <summary>
        /// Initializes common properties of the encoder.
        /// </summary>
      private void Initialize()
      {
         if (this.MessageVersion.Envelope == EnvelopeVersion.Soap12)
         {
                // set the aprorpiate media type for SOAP 1.2
            this. mediaType = "application/soap+xml";
         }
         else if (this.MessageVersion.Envelope == EnvelopeVersion.Soap11)
         {
                // set the appropriate media type for SOAP 1.1
            this. mediaType = "text/xml";
         }
            // compose the content type from charset and media type
         this. contentType = string.Format(CultureInfo.InvariantCulture, "{0}; charset={1}", mediaType, textEncoding.WebName);
      }

        /// <summary>
        /// Gets the content type for the encoder instance
        /// </summary>
      public override string ContentType
      {
         get
         {
            return contentType;
         }
      }

        /// <summary>
        /// Gets the media type for the encoder instance
        /// </summary>
      public override string MediaType
      {
         get
         {
            return mediaType;
         }
      }

        /// <summary>
        /// Gets an indicator for whether a given input content type is
        /// supported.
        /// </summary>
        /// <param name="contentType">ContentType</param>
        /// <returns>Indicates whether the content type is supported</returns>
        /// <remarks>
        /// TODO: This currently returns 'true' for all content types because the
        /// encoder isn't locked down in features yet and this easier to debug.
        /// The plan is to support at least: application/x-www-form-urlencoded,
        /// text/xml, application/soap+xml
        /// </remarks>
      public override bool IsContentTypeSupported(string contentType)
      {
         return true;
      }

        /// <summary>
        /// Gets the supported message version of this instance
        /// </summary>
      public override MessageVersion MessageVersion
      {
         get
         {
            return messageVersion;
         }
      }

        /// <summary>
        /// Reads an incoming array segment containing a message and
        /// wraps it with a buffered message. The assumption is that the incoming
        /// data stream is <i>not</i> a SOAP envelope, but rather an unencapsulated
        /// data item, may it be some raw binary, an XML document or HTML form
        /// postback data. This method is called if the inbound transfer mode of the
        /// transport is "buffered".
        /// </summary>
        /// <param name="buffer">Buffer to wrap</param>
        /// <param name="bufferManager">Buffer manager to help with allocating a copy</param>
        /// <returns>Buffered message</returns>
        public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager)
      {
         return new PoxBufferedMessage(buffer, bufferManager);
      }

        /// <summary>
        /// Transforms an incoming message into a raw byte array that a transport can
        /// literally put on the wire as it is returned. This method is called if the outbound
        /// transfer mode of the transport is "buffered".
        /// </summary>
        /// <param name="msg">Input message</param>
        /// <param name="maxMessageSize">Maximum message size to be rendered</param>
        /// <param name="bufferManager">Buffer manager to optimize buffer allocation</param>
        /// <param name="messageOffset">Offset into the message to render.</param>
        /// <returns>Array segment containing the binary data to be put onto the wire by the transport.</returns>
        /// <remarks>
        /// <para>This method is the "secret sauce" of the the PoxEncoder. Instead of encoding the
        /// message in its entirety, this encoder will unwrap the message body and toss out
        /// the envelope and all headers. The resulting "raw" message body (everything inside
        /// and not including soap:Body) will be written out to the transport.</para>
        /// <para>The encoder has an optional, "out of band" argument that is flowing into it
        /// as part of the message's Properties. By adding a <see cref="T:PoxEncoderMessageProperty"/>
        /// to the <see cref="Message.Properties"/> and setting its <see cref="PoxEncoderMessageProperty.RawBinary"/>
        /// property to 'true', you can switch the encoder into its 'raw binary' mode.</para>
        /// <para> In 'raw binary' mode, the encoder expects that the only child of the message
        /// body element is an element with a local name of "base64Binary" containing base64 encoded
        /// binary data. If that is the case, the encoder will read the content of that element
        /// and return it (not the XML wrapper) to the transport in binary form. If the content does
        /// not comply with this requirement, an empty array is returned.
        /// </para>
        /// </remarks>
      public override ArraySegment<byte> WriteMessage(Message msg, int maxMessageSize, BufferManager bufferManager, int messageOffset)
      {
         if (msg.IsEmpty)
         {
            // if the message is empty (no body defined) the result is an empty
            // byte array.
            byte[] buffer = bufferManager.TakeBuffer(maxMessageSize);
            return new ArraySegment<byte>(buffer, 0, 0);
         }
         else
         {
            // check RawBinary bit in the message property
                bool rawBinary = false;
                if (msg.Properties.ContainsKey(PoxEncoderMessageProperty.Name))
            {
               rawBinary = ((PoxEncoderMessageProperty)msg.Properties[PoxEncoderMessageProperty.Name]).RawBinary;
            }

            ArraySegment<byte> retval = new ArraySegment<byte>();
            byte[] buffer = bufferManager.TakeBuffer(maxMessageSize);
            if (!rawBinary)
            {
               // If we're rendering XML data, we construct a memory stream
               // over the output buffer, layer an XMLDictionaryWriter on top of it
               // and have the message write the body content into the buffer as XML.
               // The buffer is then wrapped into an array segment and returned.
               MemoryStream stream = new MemoryStream(buffer);
               XmlWriterSettings settings = new XmlWriterSettings();
               settings.OmitXmlDeclaration = true;
               settings.Indent = true;
               settings.Encoding = this. textEncoding;
               XmlWriter innerWriter = XmlWriter.Create(stream, settings);
               XmlDictionaryWriter writer = XmlDictionaryWriter.CreateDictionaryWriter(innerWriter, false);
               msg.WriteBodyContents(writer);
               writer.Flush();
               retval = new ArraySegment<byte>(buffer, 0, (int)stream.Position);
            }
            else
            {
               // If we're rendering raw binary data, we grab at most 'buffer.Length'
               // bytes from the binary content of the base64Binary element (if that
               // exists) and return the result wrapped into an array segment.
               XmlDictionaryReader dictReader = msg.GetReaderAtBodyContents();
               if (dictReader.NodeType == XmlNodeType.Element &&
                  dictReader.LocalName == "base64Binary")
               {
                  if (dictReader.Read() && dictReader.NodeType == XmlNodeType.Text)
                  {
                     int size = dictReader.ReadContentAsBase64(buffer, 0, buffer.Length);
                     retval = new ArraySegment<byte>(buffer, 0, size);
                  }
               }
            }
            return retval;
         }
      }

        /// <summary>
        /// Reads an incoming stream containing a message and
        /// wraps it with a streamed message. The assumption is that the incoming
        /// data stream is <i>not</i> a SOAP envelope, but rather an unencapsulated
        /// data item, may it be some raw binary, an XML document or HTML form
        /// postback data. This method is called if the inbound transfer mode of the
        /// transport is "streamed".
        /// </summary>
        /// <param name="stream">Input stream</param>
        /// <param name="maxSizeOfHeaders">Maximum size of headers in bytes</param>
        /// <returns>Stream message</returns>
      public override Message ReadMessage(System.IO.Stream stream, int maxSizeOfHeaders)
      {
         return new PoxStreamedMessage(stream, maxSizeOfHeaders);
      }

        /// <summary>
        /// Transforms an incoming message into a stream that a transport can
        /// literally put on the wire as it is filled. This method is called if the outbound
        /// transfer mode of the transport is "streamed".
        /// </summary>
        /// <param name="msg">Input message</param>
        /// <param name="stream">Stream to write to</param>
        /// /// <remarks>
        /// <para>This method is the "secret sauce" of the the PoxEncoder. Instead of encoding the
        /// message in its entirety, this encoder will unwrap the message body and toss out
        /// the envelope and all headers. The resulting "raw" message body (everything inside
        /// and not including soap:Body) will be written out to the transport.</para>
        /// <para>The encoder has an optional, "out of band" argument that is flowing into it
        /// as part of the message's Properties. By adding a <see cref="PoxEncoderMessageProperty"/>
        /// to the <see cref="Message.Properties"/> and setting its <see cref="PoxEncoderMessageProperty.RawBinary"/>
        /// property to 'true', you can switch the encoder into its 'raw binary' mode.</para>
        /// <para> In 'raw binary' mode, the encoder expects that the only child of the message
        /// body element is an element with a local name of "base64Binary" containing base64 encoded
        /// binary data. If that is the case, the encoder will read the content of that element
        /// and write it (not the XML wrapper) onto the stream in binary form and in at most
        /// 1MByte large chunks. If the content does not comply with this requirement, nothing is written.
        /// </para>
        /// </remarks>
        public override void WriteMessage(Message msg, System.IO.Stream stream)
        {
            try
            {
                if (!msg.IsEmpty)
                {
                    // check RawBinary bit in the message property
                    bool rawBinary = false;
                    if (msg.Properties.ContainsKey(PoxEncoderMessageProperty.Name))
                    {
                        rawBinary = ((PoxEncoderMessageProperty)msg.Properties[PoxEncoderMessageProperty.Name]).RawBinary;
                    }

                    if (!rawBinary)
                    {
                        // If we're rendering XML, we layer an XMLDictionaryWriter over the
                        // output stream and have the message render its body content into
                        // that writer and therefore onto the stream.
                        XmlWriterSettings settings = new XmlWriterSettings();
                        settings.OmitXmlDeclaration = true;
                        settings.Indent = true;
                        settings.Encoding = this. textEncoding;
                        XmlWriter innerWriter = XmlWriter.Create(stream, settings);
                        XmlDictionaryWriter writer = XmlDictionaryWriter.CreateDictionaryWriter(innerWriter, false);
                        msg.WriteBodyContents(writer);
                        writer.Flush();
                    }
                    else
                    {
                        // If we're rendering raw binary data, we grab chunks of at most 1MByte
                        // from the 'base64Binary' content element (if that exists) and write them
                        // out as binary data to the output stream. Chunking is done, because we
                        // have to assume that the body content is arbitrarily large. To optimize the
                        // behavior for large streams, we read and write concurrently and swap buffers.
                        XmlDictionaryReader dictReader = msg.GetReaderAtBodyContents();
                        if (dictReader.NodeType == XmlNodeType.Element && dictReader.LocalName == "base64Binary")
                        {
                            if (dictReader.Read() && dictReader.NodeType == XmlNodeType.Text)
                            {
                                byte[] buffer1 = new byte[1024*1024], buffer2 = new byte[1024*1024];
                                byte[] readBuffer = buffer1, writeBuffer = buffer2;
                               
                                int bytesRead = 0;
                                // read the first chunk into the read buffer
                                bytesRead = dictReader.ReadContentAsBase64(readBuffer, 0, readBuffer.Length);
                                do
                                {
                                    // the abort condition for the loop is that we can't read
                                    // any more bytes from the input because the base64Binary element is
                                    // exhausted.
                                    if (bytesRead > 0 )
                                    {
                                        // make the last read buffer the write buffer
                                        writeBuffer = readBuffer;
                                        // write the write buffer to the output stream asynchronously
                                        IAsyncResult result = stream.BeginWrite(writeBuffer, 0, bytesRead,null,null);
                                        // swap the read buffer
                                        readBuffer = (readBuffer == buffer1) ? buffer2 : buffer1;
                                        // read a new chunk into the 'other' buffer synchronously
                                        bytesRead = dictReader.ReadContentAsBase64(readBuffer, 0, readBuffer.Length);
                                        // wait for the write operation to complete
                                        result.AsyncWaitHandle.WaitOne();
                                        stream.EndWrite(result);
                                    }
                                }
                                while (bytesRead > 0);
                            }
                        }
                    }
                }
            }
            catch
            {
                // the client may disconnect at any time, so that's an expected exception and absorbed.
            }
        }
   }
}


The encoder shown above fulfills my two requirements and it is aware of the PoxBase64XmlReader trickery. It renders unencapsulated data onto the wire and accepts and wraps unencapsulated data from the wire. Furthernore, it supports buffered messages and it supports Indigo’s streaming mode, which allows sending messages of arbitrary size. What’s still missing in the picture is how we hook the encoder into the binding and how we can control whether the encoder works in “POX mode” rending XML or in “Raw Binary” mode rendering arbitrary data content. I might also have to explain what a PoxStreamedMessage is. I might also have to explain a bit better what the encoder does to begin with ;-)

Well, at least you have the code already, Part 6 comes with the prose. 


 
Categories: Indigo

Part 1, Part 2, Part 3

The SuffixFilter that I have shown in Part 3 of this little series interacts with the Indigo dispatch internals to figure out which endpoint shall receive an incoming request. If the filter reports true from it’s Match() method, the service endpoint that owns the particular filter is being picked and its channel gets the message. But at that point we still don’t know which of the operations on the endpoint’s contract shall be selected to handle the request.

We’ll take a step back and recap what we have by citing one of the contract declarations from Part 1:

[ServiceContract, HttpMethodOperationSelector]
interface IMyApp
{
    [OperationContract, HttpMethod("GET",UriSuffix="/customers/*")]
    CustomerInfo GetCustomerInfo();
    [OperationContract, HttpMethod("PUT", UriSuffix = "/customers/*")]
    void UpdateCustomerInfo(CustomerInfo info);
    [OperationContract, HttpMethod("DELETE", UriSuffix = "/customers/*")]
    void DeleteCustomerInfo();
}

If we implement this contract on a class and host the service endpoint for it at, say, http://www.example.com/myapp this particular endpoint will only accept requests on http://www.example.com/myapp/customers/* (whereby ‘*’ can really be any string) because our suffix filter that’s being hooked in my the HttpMethodOperationSelectorAttribute and populated with “/customers/*” suffix won’t let any other request pass. Only those requests for which a pattern match can be found when combining an operation’s suffix pattern with the endpoint URI are positively matched by the suffix filter. For a more complex example I’ll let you peek at a (shortened) snippet of one the contracts of the TV server I am working on:

/// <summary>
///
Contract for the channel service
/// </summary>
[ServiceContract(Namespace = Runtime.ChannelServiceNamespaceURI), HttpMethodOperationSelector]
public interface IChannelService
{
    /// <summary>
    /// Gets the default RSS for this channel.
    /// </summary>
    /// <param name="message">Input message.</param>
    /// <returns>Reply message with 'text/xml' RSS content</returns>
    [OperationContract, HttpMethod("GET")]
    Message GetRss(Message message);
    /// <summary>
    /// Gets the channel logo as a raw binary image with appropriate
    /// media type, typically image/gif, image/jpeg or image/png
    /// </summary>
    /// <param name="message">Input message.</param>
    /// <returns>Reply message with 'image/*' binary content</returns>
    [OperationContract, HttpMethod("GET", UriSuffix = "/logo")]
    Message GetLogo(Message message);
    /// <summary>
    /// Gets the RSS for "now", which is typically including
    /// the next 12 hours of guide data from the current time
    /// onward and including currently running shows.
    /// </summary>
    /// <param name="message">Input message.</param>
    /// <returns>Reply message with 'text/xml' <a href="http://blogs.law.harvard.edu/tech/rss">
    /// RSS 2.0</a> content</returns>
    [OperationContract, HttpMethod("GET", UriSuffix = "/now")]
    Message GetRssForNow(Message message);
   
    ...

    /// <summary>
    /// Gets an ASX media metadata document containing a reference to
    /// the live TV stream for this channel and a reference to the
    /// HTMLView that provides the UI inside Windows Media Player.
    /// </summary>
    /// <param name="message">Input message.</param>
    /// <returns>Reply message with 'video/x-ms-asf' <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmplay10/mmp_sdk/asxelement.asp">
    /// ASX 3.0</a> content.</returns>
    [OperationContract, HttpMethod("GET", UriSuffix = "/media")]
    Message GetMedia(Message message);
    /// <summary>
    /// Gets information about the current media session hosted by the provider.
    /// </summary>
    /// <param name="message">Input message.</param>
    /// <returns>Reply message with 'text/xml' content</returns>
    [OperationContract, HttpMethod("GET", UriSuffix = "/media/session")]
    Message GetMediaSession(Message message);
    /// <summary>
    /// Gets the "media display envelope". This is an HTML stream that is loaded
    /// by Windows Media Player to render an AJAX UI for accessing this service.
    /// </summary>
    /// <param name="message">Input message.</param>
    /// <returns>Reply message with 'text/html' content</returns>
    [OperationContract, HttpMethod("GET", UriSuffix = "/media/envelope")]
    Message GetMediaDisplayEnvelope(Message message);
    /// <summary>
    /// Gets a media display envelope collateral data element. This method
    /// acts as a web-server and serves up binary files or text files referenced
    /// by the media display envelope. Requests to this endpoint are HTTP GET
    /// requests to the service base URL with the suffix '/media/envelope' with an
    /// appended '/' and the file name of the file that is being requested from the
    /// service runtime's 'envelope' directory.
    /// </summary>
    /// <param name="message">Input message.</param>
    /// <returns>Reply message containing a raw binary file with appropriate media type</returns>
    [OperationContract, HttpMethod("GET", UriSuffix = "/media/envelope/*")]
    Message GetMediaDisplayEnvelopeCollateral(Message message);
    /// <summary>
    /// Gets the detail information for a particular episode
    /// in the EPG guide data (linked from RSS) or for a given
    /// recording.
    /// </summary>
    /// <param name="message">Input message.</param>
    /// <returns>Reply message containing 'text/xml' with detail information.</returns>
    [OperationContract, HttpMethod("GET", UriSuffix = "/item/?")]
    Message GetItemDetail(Message message);
    /// <summary>
    /// Adds detail information for a particular episode. Concretely this
    /// allows adding a recoding job to the episode data that will cause this
    /// show to be recorded.
    /// </summary>
    /// <param name="message">Input message.</param>
    /// <returns>Reply message with HTTP 200 OK status code</returns>
    [OperationContract, HttpMethod("POST", UriSuffix = "/item/?")]
    Message PostItemDetail(Message message);
    /// <summary>
    /// Deletes some of the item detail information for a particular episode.
    /// This is used to cacnel a recording for the episode.
    /// </summary>
    /// <param name="message">Input message.</param>
    /// <returns>Reply message with HTTP 200 OK status code.</returns>
    [OperationContract, HttpMethod("DELETE", UriSuffix = "/item/?")]
    Message DeleteItemDetail(Message message);
    /// <summary>
    /// Method receiving all unknown messages sent to this endpoint
    /// </summary>
    /// <param name="message">The message</param>
    /// <returns></returns>
    [OperationContract(Action = "*")]
    Message HandleUnknownMessage(Message message);
}

If you look at the individual operations in the above contract, you’ll see that the suffix filter would – given a base address of http://www.example.com/TV – match requests made on the URIs  http://www.example.com/TV/logo,  http://www.example.com/TV/now, and http://www.example.com/TV/media to name just a few. A special case is the GetRss() operation, which does not have an explicit suffix defined and therefore causes the suffix filter to match on the base address. An important aspect of the suffix filter is that it does not consider the HTTP method (GET, POST). Matching the HTTP method to an operation is the job of the HttpMethodOperationSelectorBehavior, which acts higher up on the endpoint level and picks out the exact method that the call is being dispatched to. The filter is only deciding whether the message is “ours” with respect to the namespace it is targeting.

The HttpMethodOperationSelectorBehavior is hooked into the service endpoint by the HttpMethodOperationSelectorAttribute’s implementation of IContractBehavior that you can look up in Part 3. In BindDispatch(), the dispatcher’s OperationSelector property is set to a new instance of our specialized operation selector. An “operation selector” is a class that takes an incoing request on an endpoint and figures out the proper operation to dispatch to. The default operation selector in Indigo acts according to the SOAP dispatch rules that I explained in Part 1 (see “Figuring out a programming model”).

However, in our REST/POX world that we’re building here we do not have a concept of “SOAP action”, but rather URIs and HTTP methods and therefore the default dispatch mechanism doesn’t take us very far. Hence, we need to replace the operation selection algorithm with our own and we do that by implementing IDispatchOperationSelector:

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>
    ///
    /// </summary>
   public class HttpMethodOperationSelectorBehavior : IDispatchOperationSelector
   {
      ContractDescription description;
      IDispatchOperationSelector defaultSelector;

        /// <summary>
        /// Initializes a new instance of the <see cref="T:HttpMethodOperationSelectorBehavior"/> class.
        /// </summary>
        /// <param name="description">The description.</param>
        /// <param name="defaultSelector">The default selector.</param>
      public HttpMethodOperationSelectorBehavior(ContractDescription description, IDispatchOperationSelector defaultSelector)
      {
         this.description = description;
         this.defaultSelector = defaultSelector;
      }

        /// <summary>
        /// Selects the operation.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <returns></returns>
      public string SelectOperation(ref Message message)
      {
         if (message.Properties.ContainsKey(HttpRequestMessageProperty.Name))
         {
             HttpRequestMessageProperty msgProp =
                 message.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
             string baseUriPath = message.Headers.To.AbsolutePath;
             List<OperationDescription> operationsWithSuffix = new List<OperationDescription>();

             /* Check methods with UriSuffix first. For that we first add
              * operation descriptions that have the correct http method into
              * a list and then sort that list by the processing order */
             foreach (OperationDescription opDesc in description.Operations)
             {
                 HttpMethodAttribute methodAttribute = opDesc.Behaviors.Find<HttpMethodAttribute>();
                 if (methodAttribute != null &&
                      String.Compare(methodAttribute.Method, msgProp.Method, true) == 0 &&
                      methodAttribute.UriSuffix != null)
                 {
                     operationsWithSuffix.Add(opDesc);
                 }
             }

             /*
              * We are sorting the list based on two criteria:
              * a) ProcessingPriority value, and if that's equal:
              * b) Length of the UriSuffix expression
              */
             operationsWithSuffix.Sort(
                 delegate(OperationDescription descA, OperationDescription descB)
                 {
                     HttpMethodAttribute descAAttr = descA.Behaviors.Find<HttpMethodAttribute>();
                     HttpMethodAttribute descBAttr = descB.Behaviors.Find<HttpMethodAttribute>();
                     int result = descAAttr.Priority.CompareTo(descBAttr.Priority);
                     if (result == 0)
                     {
                         result = Math.Sign(descAAttr.UriSuffix.Length - descBAttr.UriSuffix.Length);
                     }
                     return result;
                 }
             );

             for (int i = operationsWithSuffix.Count-1; i >= 0; i--)
             {
                 OperationDescription opDesc = operationsWithSuffix[i];
                 HttpMethodAttribute methodAttribute = opDesc.Behaviors.Find<HttpMethodAttribute>();
                 // we have a method attribute, the attribute's method value matches
                 // the incoming http request and we do have a regex.
                 Match match = methodAttribute.UriSuffixRegex.Match(baseUriPath);
                 if (match != null && match.Success)
                 {
                     return opDesc.Name;
                 }
             }
            

             /* now check the rest */
             foreach (OperationDescription opDesc in description.Operations)
             {
                 HttpMethodAttribute methodAttribute = opDesc.Behaviors.Find<HttpMethodAttribute>();
                 if (methodAttribute != null && methodAttribute.UriSuffixRegex == null)
                 {
                     // we have a http method attribute and the method macthes the request
                     // method: match
                     if (String.Compare(methodAttribute.Method, msgProp.Method, true) == 0)
                     {
                         return opDesc.Name;
                     }
                 }
                 else if (String.Compare(opDesc.Name, msgProp.Method, true) == 0)
                 {
                     // we do not have a http method attribute, but the method name
                     // equals the http method.
                     return opDesc.Name;
                 }
             }

             // No match so far. Now lets find a wildcard method.
             foreach (OperationDescription opDesc in description.Operations)
             {
                 if (opDesc.Messages.Count > 0 &&
                     opDesc.Messages[0].Action == "*" &&
                     opDesc.Messages[0].Direction == TransferDirection.Incoming)
                 {
                     return opDesc.Name;
                 }
             }
         }

            // No match so far, delegate to the default selector if one is present
         if (defaultSelector != null)
         {
            return defaultSelector.SelectOperation(ref message);
         }
         return "";
      }
   }
}

As you can see, there is only one method: SelectOperation. The method will only do work on its own if the incoming request is an HTTP request received by Indigo’s HTTP transport. We can figure this out by looking into the message properties and looking for the presence of a property with the name HttpRequestMessageProperty.Name. The presence of this property is required, because that’s the vehicle through which Indigo gives us access to the HTTP method that was used for the request. What we’re looking for sits as an instance string property on HttpRequestMessageProperty.Method.

The algorithm itself is fairly straightforward:

1.      We grab all operations whose HttpMethodAttribute.Method property matches (case-insensitively) the incoming HTTP method string and which have a suffix expression and throw them into a list.

2.      We sort the list by the priority of the attributes amongst each other. I introduced the priorities, because I am allowing wildcards here and I want to allow the suffixes /item/detail and /item/* (read: “anything except detail”) to coexist on the same endpoint, but I need a something other than method order to specify that the match on the concrete expression should be done before the wildcard expression. In absence of priorities and/or in the case of collisions, longer suffixes always trump shorter expressions for matching priority.

3.      We match the sorted list in reverse order (higher priority is better) and return the first operation in the list whose suffix expression matches the incoming messages “To” header (which is the same as the HTTP request URI).

4.      If we don’t have a match, we proceed to iterate over all operations that do not have a suffix and see whether we can find a match solely based on the  HttpMethodAttribute.Method value or, if the HttpMethodAttribute is absent, on the plain method name. (So if the method just named “Get” and there is no attribute, an HTTP GET request will still match).

5.      If we still don’t have a match, we look for the common “all messages without a proper home” method with an OperationContract.Action value of “*”.

6.      And as the very last resort we fall back to the default selector if we have been given one and else we fail out by returning an empty string, which means that there is no match at at all.

If we find a match, we return a string that’s the same as the name of the method we want to dispatch to and Indigo will them promptly do the right thing and call the respective method, either by passing the raw message outright (as in my TV app) or by breaking up the message body using the XmlFormatter or the XmlSerializer and passing a typed message or a set of parameters.

Step 4 is noteworthy insofar as that the [HttpMethod] attributes aren’t strictly necessary. If you name your methods exactly like the HTTP methods they should handle, the operation selector will figure this out. If that’s what you want, you don’t even need the [HttpMethodOperationSelector] attribute, if you choose to add that information in the configuration file instead. To enable that. I’ve built the required configuration class that you can register in the <behaviorExtensions> and map to the <behaviors> section of an endpoint’s configuration. The class is very, very simple:

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

namespace newtelligence.ServiceModelExtensions
{
   public class HttpMethodOperationSelectorSection : BehaviorExtensionSection
   {
      public HttpMethodOperationSelectorSection()
      {
      }

      protected override object CreateBehavior()
      {
         return new HttpMethodOperationSelectorAttribute();
      }

      public override string ConfiguredSectionName
      {
         get
         {
            return "httpMethodOperationSelector";
         }
      }
   }
}

Alright, so where are we? We’ve got dispatch metadata, we’ve got an endpoint dispatch mechanism and we’ve got an operation dispatch mechanism. Furthermore we have a tool that conveniently grabs “parameter segments” from the URI and maps them to an out-of-band collection on the UriArgumentsMessageProperty from where we can conveniently fetch them inside the service implementation.

What we don’t have is POX. We’re still dealing with SOAP messages here. So the next step is to modify the wire encoding in a way that we unwrap the content and throw away the envelope on the way out and that we wrap incoming “raw” data into an envelope to make Indigo happy with incoming requests.

That’s plenty of material for Part 5 and beyond. Stay tuned.

Go to Part 5


 
Categories: Indigo

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


 
Categories: Indigo

December 27, 2005
@ 05:25 AM

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)
 
Categories: