Http Message Channels in WCF Web Apis Preview 4

The new WCF Web Apis Preview 4 released yesterday in the wcf.codeplex.com introduced a new extensibility point for intercepting messages at channel level. The name for this new feature is “Http Message Channels” and the good thing is that you don’t need to rely anymore on the REST Starter Kit request interceptors for doing the same thing. Actually, a Http Message Channel is more useful as you can intercept either request or response messages, and also you get an Http message with all the context information you might need and not a WCF generic message, which usually requires some additional processing.

A Http Message Channel uses the new Task-Based Asynchronous pattern for implementing asynchronous work, which simplifies the implementation a lot. This is how a generic Http Message Channel looks like,

public class MyHttpChannel : DelegatingChannel
{
    public MyHttpChannel(HttpMessageChannel innerChannel)
        : base(innerChannel)
    {
    }
 
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // DO YOUR WORK Here
    }
}

You need to derive the base class “DelegatingChannel” and override the method “SendAsync” to provide your implementation. You only receive the request message as input argument, but you can call the inner channel in the stack for processing the request and getting an instance of the response message if you want to do some processing on the response as well.

The following example shows a typical channel for validating a API key. The API key is passed in a custom header “X-AuthKey” as part of the request message-

public class ApiKeyVerificationChannel : DelegatingChannel
{
    public const string KeyHeaderName = "X-AuthKey";
 
    IKeyVerifier keyVerifier;
 
    public ApiKeyVerificationChannel(HttpMessageChannel innerChannel)
        : this(innerChannel, new KeyVerifier())
    {
    }
 
    public ApiKeyVerificationChannel(HttpMessageChannel innerChannel, IKeyVerifier keyVerifier)
        : base(innerChannel)
    {
        this.keyVerifier = keyVerifier;
    }
 
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        IEnumerable<string> values = null;
        if (request.Headers.TryGetValues(KeyHeaderName, out values))
        {
            var key = values.First();
 
            if (this.keyVerifier.Verify(key))
            {
                return base.SendAsync(request, cancellationToken);
            }
        }
 
        return Task.Factory.StartNew(() =>
            {
                var response = new HttpResponseMessage(HttpStatusCode.Unauthorized, "You need to provide a valid key for consume these Apis");
                return response;
            });
    }
}

This implementation basically validates the received key in the http header and calls the inner channel for further processing of the request (base.SendAsync). However, if the key is not provided or it is invalid, a new response is returned and the execution is interrupted.

As you can see, this interception mechanism is also great for implementing common concerns like security that needs to run much before the service is invoked.

Finally, a custom Http Message Channel can be injected in the WCF pipeline with the new fluent configuration interface as it is showed bellow,

public class Global : System.Web.HttpApplication
{
    private void Application_Start(object sender, EventArgs e)
    {
        var config = HttpHostConfiguration.Create().
            SetMessageHandlerFactory(typeof(ApiKeyVerificationChannel));
 
        // setting up contacts services
        RouteTable.Routes.MapServiceRoute<ContactsResource>("contacts", config);
    }
}
The SetMessageHandlerFactory receives either an array of “Type”s representing the channels or an instance of a HttpMessageHandlerFactory that knows how to instantiate new channels. You might want to extend the default HttpMessageHandlerFactory to use your favorite DI framework to resolve the channels.

Comments

No Comments