Configuring a DelegateHandler

Topics: Web Api
Jan 17, 2012 at 6:05 PM
Edited Jan 17, 2012 at 6:06 PM

I would like to intercept all messages in my service and manage the setting of their Accept header.  Implementing DelegatingHandler and overriding SendAsync like this post is what I want to do: http://codepaste.net/wehh49

The end of the post says "To plug in use the MessageHandlerFactory property / MessageHandlerTypes property on config."  Can anyone point to an example of this or provide a simple snippet?

Also, as a possibly related question, I was trying to get to the configuration with HttpHostConfiguration.  I may be missing something, but I can't find that class in any of the assemblies that I got from the WebApi.All.0.6.0.

Thanks

Jan 17, 2012 at 6:10 PM

Here is an example of a JSON message handler that sets the accept values.

 

    public class ForceJsonMessageHandler : DelegatingHandler
    { 
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
        protected void Application_Start()
        {
            RouteTable.Routes.SetDefaultHttpConfiguration(new AuthenticationHttpConfiguration());
}
if (ShouldForceJson(request)) { request.Headers.Accept.Clear(); //clear the accept and replace it to use JSON. request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); } return base.SendAsync(request, cancellationToken); } public static bool ShouldForceJson(HttpRequestMessage request) { if (request.Headers.Accept.Contains(new MediaTypeWithQualityHeaderValue("application/xml"))) return false; return true; } }

 


This is how I configure it in the global.asax:

 

        protected void Application_Start()
        {
            RouteTable.Routes.SetDefaultHttpConfiguration(new AuthenticationHttpConfiguration());
}

 

 

My configuration class just does stuff in its constructor:

    public class AuthenticationHttpConfiguration : WebApiConfiguration
    {
        public AuthenticationHttpConfiguration()
        {
            var existingFactory = RequestHandlers;
            RequestHandlers = (handlers, endpoint, operation) =>
            {
                if (existingFactory != null)
                {
                    existingFactory(handlers, endpoint, operation);
                }

            MessageHandlerFactory = () =>
            {
                return new List<DelegatingHandler>()
                {
                    new ForceJsonMessageHandler()
};
};
}
}

Jan 17, 2012 at 6:11 PM

Sorry for the formatting but this WYSIWYG is horrible, at best.

Jan 17, 2012 at 9:03 PM

Thanks - I am having a problem finding classes like WebApiConfiguration, RequestHandlers and MessageHandlerFactory.  What assemblies are these in?

Jan 17, 2012 at 9:05 PM

You need to include the binaries for WebApi in your project. This code is not distributed with .NET.

If you know how to use NuGet:

Open NuGet package manager, go to online, search for "webapi.all" and add that to your project.

Then right click all the missing types and say resolve, and choose the first option for them.

Jan 17, 2012 at 9:08 PM
Edited Jan 17, 2012 at 9:09 PM

Here is what I have as my usings for the AuthenticationHttpConfiguration class

 

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.ApplicationServer.Http;
using WebApi.Http.MessageHandlers;
using System.Net.Http;
using WebApi.Http.RequestHandlers;
using WebApi.Http.ResponseHandlers;
using WebApi.Http.ErrorHandlers;
using System.ServiceModel;
using StructureMap;
using WebApi.Configuration;

 

Delete what you dont need, like structuremap. And WebApi.Configuration, etc. (WebApi is my proj name)

Jan 18, 2012 at 8:42 PM

Thanks again - I am using webapi.all but there was something else dumb that I was doing - my bad.

Final question: I am self-hosting so I don't have the global.asax.  Do you know how to register the configuration otherwise?

Currently, I am doing this in a console:

var instance = new FailureModeResource();

using (var host = new HttpServiceHost(instance, "http://localhost/todo"))
{
     host.Open();
     Console.ReadLine();
}
The HttpServiceHost constructor has an overload that takes an HttpConfiguration, but if I do this:

var instance = new FailureModeResource();
var config = new FailureModeHttpConfiguration();
            
using (var host = new HttpServiceHost(instance, config, "http://localhost/todo"))
{
     host.Open();
     Console.ReadLine();
}

I get an InvalidOperationException when the MessageHandlerFactory is set in the config class:
The 'HttpConfiguration' instance has already been applied to one or more 
'HttpServiceHost'. 'HttpConfiguration' can only be modified before passing 
it to the first 'HttpServiceHost'.
Jan 18, 2012 at 8:44 PM

Btw, my FailureModeHttpConfiguration is the same code as your AuthenticationHttpConfiguration.

Jan 18, 2012 at 10:02 PM

This is an example of how to apply it when you startup your service host.
                var config = new HttpConfiguration
                {
                    // Adding an API key message handler
                    MessageHandlerFactory = () => 
                        new List<DelegatingHandler> { new ApiKeyHandler() { Key = apiKey } }
                };
                host = new HttpServiceHost(typeof(SampleService), config, baseAddress);
                host.Open();

Try passing the type instead.

 

Is your FailureModeHttpConfiguration inheriting from WebApiConfiguration or HttpConfiguration ?

Jan 19, 2012 at 1:29 PM

Perfect - that works! Thanks man.