19

In an ASP.NET 4.5 MVC 4 Web API project, I want to add a custom HttpMessageHandler. I've changed WebApiConfig class (in \App_Satrt\WebApiConfig.cs), as follows:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional },
            constraints: null,
            handler: new MyCustomizedHttpMessageHandler()
        );
    }
}

Then I developed MyCustomizedHttpMessageHandler:

public class MyCustomizedHttpMessageHandler : HttpMessageHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        IPrincipal principal = new GenericPrincipal(
            new GenericIdentity("myuser"), new string[] { "myrole" });
        Thread.CurrentPrincipal = principal;
        HttpContext.Current.User = principal;

        return Task<HttpResponseMessage>.Factory.StartNew(() => request.CreateResponse());
    }
}

However, the request to the API (let's say http://mylocalhost.com/api/values), always returns status code 200, without any data. I mean it never gets to ValuesController.cs's 'GET()' method.

What have I missed? How can I implement HttpMessageHandler properly?

PS: Have already read this one: https://stackoverflow.com/a/12030785/538387 , doesn't help me.

3 Answers 3

24

Here you are creating a HttpMessageHandler which short circuits the request and doesn't let the request pass through the rest of the pipeline. Instead, you should create a DelegatingHandler.

Also there are 2 kinds of message handler pipelines in Web API. One is a regular pipeline in which all requests for all routes pass through and other where one could have message handlers specific to certain routes only.

  1. Try to create a DelegatingHandler and add it to your HttpConfiguration's list of message handlers:

    config.MessageHandlers.Add(new HandlerA())
    
  2. If you want to add a route specific message handler, then you could do the following:

    config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional },
                constraints: null,
                handler: 
                       HttpClientFactory.CreatePipeline(
                              new HttpControllerDispatcher(config), 
                              new DelegatingHandler[]{new HandlerA()})
                );
    

This Web Api Poster shows the pipeline flow.

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you. Solution (1) works well. But number 2, new HttpControllerDispatcher() says: System.Web.Http.Dispatcher.HttpControllerDispatcher does not contain a constructor that takes 0 arguments - Update: I fixed your code. Thank you.
Please also add this part of Cuong Le's answer to your answere: To write a custom message handler, you should derive from System.Net.Http.DelegatingHandler.
The link for the poster is broken.
in which file do we need to add the code: config.MessageHandlers.Add(new HandlerA())
17

To write a custom message handler, you should derive from System.Net.Http.DelegatingHandler

class CustomMessageHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> 
      SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        IPrincipal principal = new GenericPrincipal(
            new GenericIdentity("myuser"), new string[] { "myrole" });
        Thread.CurrentPrincipal = principal;
        HttpContext.Current.User = principal;

        return base.SendAsync(request, cancellationToken);
    }
}

And call base.SendAsync to send the request to the inner handler.

3 Comments

@Cuonge Le - Thank you for the answer. After I replaced CustomMessageHandler with your code, it raises error on return base.SendAsync(request, cancellationToken); saying: The inner handler has not been assigned. . What I missed again?
@Counge Le - The combination of your answer and Kirran Chall's, has fixed the issue. Thank you again.
@Cuong Le what is the equivalent for .NET 4.0? I could not find DelegatingHandler for .NET .4... how can do messagehandling in 4.0. Thanks for your help.
1

I used @cuongle answer to solve my problem. Just with one addition. So I did not get "The inner handler has not been assigned.". Thank you @coungle.

public class CustomMessageHandler : DelegatingHandler
{
        public CustomMessageHandler ()
        {
              //add this to solve "The inner handler has not been assigned"
               InnerHandler = new HttpClientHandler();
        }
    
        protected override async Task<HttpResponseMessage> 
          SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            // Before request 
            IPrincipal principal = new GenericPrincipal(
                new GenericIdentity("myuser"), new string[] { "myrole" });
            Thread.CurrentPrincipal = principal;
            HttpContext.Current.User = principal;
    
            var result = await base.SendAsync(request, cancellationToken);
    
            // After request when response arrives
            
            return result;
        }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.