WCF HTTP Native types support

02.02.2011 20:33Comments
If you are using the new WCF HTTP stack, you might have noticed that there is no support for native types (current version 01.15.2011) in the variables defined in the UriTemplate of WebGet and WebInvoke. For example this will not work because of the int type of the id parameter (only string is supported):
[WebGet(UriTemplate = "{id}")]
public Contact Get(int id, HttpResponseMessage response)
{
  //logic here.
}
This shouldn't be a problem since the WCF HTTP team has commited to providing support for native types in the future, but if you are eager you can use this as a workaround. Thanks to the new Pipeline provided in WCF HTTP we can build ourselves a Processor that will take the parameters returned by the UriTemplate and apply the conversion from string to the right native type (such as int, bool, etc).  Here is the code for the processor:
        public class NativeTypesSupportProcessor : Processor
        {
            private HttpOperationDescription operation;
            private ProcessorArgument[] inArguments;
            private ProcessorArgument[] outArguments;

            public NativeTypesSupportProcessor(HttpOperationDescription operation)
            {
                this.operation = operation;

                outArguments = operation.GetUriTemplate().PathSegmentVariableNames
                    .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 };
            }
        }
And here is how to plug it into the pipeline:
    public class RestHostConfiguration : HttpHostConfiguration, IProcessorProvider
    {
        private RestHostConfiguration()
        {
        }

        public void RegisterRequestProcessorsForOperation(System.ServiceModel.Description.HttpOperationDescription operation, IList<System.ServiceModel.Dispatcher.Processor> processors, MediaTypeProcessorMode mode)
        {
            processors.Add(new NativeTypesSupportProcessor(operation));
        }

        public void RegisterResponseProcessorsForOperation(System.ServiceModel.Description.HttpOperationDescription operation, IList<System.ServiceModel.Dispatcher.Processor> processors, MediaTypeProcessorMode mode)
        {
        }
    }
So now you can enjoy your int parameters ;)

comments powered by Disqus