WCF HTTP – Processors under the hood

17.02.2011 21:52Comments
One of the coolest features of WCF HTTP is this new Processors pipeline that’s been introduced. With processors, you can shape pretty much everything in the request and response pipeline. The request pipeline is in charge of deserializing the request, and the response pipeline is responsible for serializing the response. These pipelines are used from the HttpPipelineFormatter which implements the IDispatchMessageFormatter interface. So here’s a diagram of what the pipelines look like inside the HttpPipelineFormatter: image Each processor takes a list of ProcessorArguments, and returns a list of ProcessorArguments. There are some very common arguments which are provided by the HttpPipeline formatter, so that we can use them out of the box. Here’s a list:
  • HttpRequestMessage
  • HttpResponseMessage
  • Uri
  • RequestHeaders
  • ResponseHeaders
One thing to keep in mind, is that processors are added in a per-operation basis. So you are going to have a different request/response pipeline for each operation. You can choose which operations you add your processors to. The pipeline also takes care of arranging the order in which the processors run, so that the output from one processor is the input of the next processor. In order to establish the order, it checks for the arguments’ name and type.

Our first processor

So as we can see from our diagram, processors are usually about serializing/deserializing stuff before and after an operation has been executed. There’s a type of processor that’s particularly useful in REST applications, and those are MediaTypeProcessors. MediaTypeProcessor is a base class that inherits from Processor and handles some of the basic plumbing for evaluating the content-type on request and responses, and serialize/deserialize when appropiate. These processors are very easy to implement, since all you have to do is declare the content-type you can handle in your processor and then provide the serialization logic. MediaTypeProcessors sit at the beginning of the request pipeline, and at the end of the response pipeline: image WCF HTTP ships with some pre-built media type processors, you can find them in them in here: image One of the problems we might find when using the XmlProcessor that ships with WCF HTTP is that it’s using the XmlSerializer underneath, and the client side API for QueryComposition is using DataContractSerializer. So let’s say that we wanted to make our own processor for serializing XML and use the DataContractSerializer instead (just for fun). Here’s how it may look like:
public class DataContractProcessor : MediaTypeProcessor
        {
            public DataContractProcessor(HttpOperationDescription operation, MediaTypeProcessorMode mode)
                : base(operation, mode)
            {
            }

            public override IEnumerable<string> SupportedMediaTypes
            {
                get
                {
                    return new List<string> { "text/xml", "application/xml" };
                }
            }

            public override void WriteToStream(object instance, System.IO.Stream stream, HttpRequestMessage request)
            {
                var serializer = new DataContractSerializer(Parameter.ParameterType);
                serializer.WriteObject(stream, instance);
            }

            public override object ReadFromStream(System.IO.Stream stream, HttpRequestMessage request)
            {
                var serializer = new DataContractSerializer(Parameter.ParameterType);
                return serializer.ReadObject(stream);
            }
        }
And you would plug that in the processors list through the HttpHostConfiguration as usual (you might want to remove the default XmlProcessor from the processors list too).

A more advanced processor…

Ok, so far so good, the DataContractProcessor was really easy to implement because it is a somewhat known type of processor, and WCF HTTP already ships a base class for that. But let’s build our first processor from scratch. In the current WCF HTTP version (01.15.2011) there’s no support for native types in the WebGet/WebInvoke UriTemplates. All the parameters coming from the Url have to be of type “string”, so you can’t do this (because of the “int” parameter):
[WebGet(UriTemplate = "{id}")]
        public Contact Get(int id)
        {
            //code here...
            throw new NotImplementedException();
        }
So it would actually be cool to have this kind of support, so here’s what we need. We need to create a processor, that will take an argument of type string, with name “id”, and it wil return an argument of type “int” and name “id”. The processors pipeline, tries to match by both argument name, and argument type. So when we return the argument with name “id” and type “int”, it will be processed by the dispatcher of the operation (since that’s what it’s waiting). So this processor is going to sit near the dispatching of the operation: image So what we’ll do is “inner join” the parameters coming in the UriTemplate with the parameters on the operation, and take the type from the operation description, finally with the name and the type we are ready to return our out arguments:
var uriTemplateVariables = operation.GetUriTemplate().PathSegmentVariableNames
                    .Concat(operation.GetUriTemplate().QueryValueVariableNames);
                
                outArguments = uriTemplateVariables
                    .Join(operation.InputParameters,
                        o => o.ToUpper(),
                        i => i.Name.ToUpper(),
                        (i, o) => new ProcessorArgument(i, o.ParameterType)).ToArray();
And now we can calculate the in arguments by changing the type of the out argumetns to “string”:
inArguments = outArguments
                    .Select(x => new ProcessorArgument(x.Name, typeof(string)))
                    .ToArray();
And the final part of the puzzle is to apply the convertion using the Convert class. Here’s the whole thing:
public class NativeTypesSupportProcessor : Processor
        {
            private HttpOperationDescription operation;
            private ProcessorArgument[] inArguments;
            private ProcessorArgument[] outArguments;

            public NativeTypesSupportProcessor(HttpOperationDescription operation)
            {
                this.operation = operation;
                var uriTemplateVariables = operation.GetUriTemplate().PathSegmentVariableNames
                    .Concat(operation.GetUriTemplate().QueryValueVariableNames);
                
                outArguments = uriTemplateVariables
                    .Join(operation.InputParameters,
                        o => o.ToUpper(),
                        i => i.Name.ToUpper(),
                        (i, o) => new ProcessorArgument(i, o.ParameterType)).ToArray();

                inArguments = outArguments
                    .Select(x => new ProcessorArgument(x.Name, typeof(string)))
                    .ToArray();
            }

            protected override IEnumerable<ProcessorArgument> OnGetInArguments()
            {
                return inArguments;
            }

            protected override IEnumerable<ProcessorArgument> OnGetOutArguments()
            {
                return outArguments;
            }

            protected override ProcessorResult OnExecute(object[] input)
            {
                if (inArguments.Count() != input.Length)
                    throw new ArgumentException("Input does not contain the right amount of items.");

                var output = new object[input.Length];
                for (int i = 0; i < input.Length; i++)
                {
                    output[i] = Convert.ChangeType(input[i], outArguments[i].ArgumentType);
                }

                return new ProcessorResult() { Output = output };
            }
        }
In this post we have seen the new pipelines shipped in the new WCF HTTP and we have seen how we can modify and extend the behavior of our services by building our custom processors.

comments powered by Disqus