Howiecamp
Howiecamp

Reputation: 3111

Route-specific ASP.NET MVC Web API message handler not invoking controller action

I've got an ASP.NET MVC Web API controller:

[HttpPost]
public async Task<HttpResponseMessage> Post(HttpRequestMessage req, CancellationToken cancellationToken) {...}

And a custom message handler I created:

public class MyMessageHandler : DelegatingHandler
{
     protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
     {
         // ...

         var response = await base.SendAsync(request, cancellationToken);

         // ...

        return response;
      }
  }

And in WebConfigApi.cs I wire up the message handler route-specific to the controller action method:

configuration.Routes.MapHttpRoute(
   name: "UpdateStuffAPI",
   routeTemplate: "api/updatestuff/post/{stuffid}",
   defaults: new { feedid = RouteParameter.Optional },
   constraints: null,
   handler: new MyMessageHandler()
);

When I POST to the controller action method, e.g.:

http://hostname/api/updatestuff/post?stuffid=12345

The message handler intercepts the request as expected. But in stepping through the line:

var response = await base.SendAsync(request, cancellationToken);

the controller action method is never hit.

As a test I removed the route-specific wiring and made the message handler global:

configuration.MessageHandlers.Add(new MyMessageHandler());

and SendAsync properly invokes my controller's action method.

So my thought was that something is wrong with the route definition. However, the message handler is invoked with the route-specific wiring, and, Route Debugger shows that when I POST to my controller (http://hostname/api/updatestuff/post?stuffid=12345), that that route is being used.

Why isn't my action method being invoked when I wire up the message handler in a route-specific way?

Upvotes: 1

Views: 1013

Answers (2)

Howiecamp
Howiecamp

Reputation: 3111

I was missing the code that ties the message handler back to the route/controller it should invoke next.

Route-specific message handlers must be specifically told about the Web Api application's HttpConfiguration. What I had in WebConfigApi.cs was:

configuration.Routes.MapHttpRoute(
   name: "UpdateStuffAPI",
   routeTemplate: "api/updatestuff/post/{stuffid}",
   defaults: new { feedid = RouteParameter.Optional },
   constraints: null,
   handler: new MyMessageHandler()
);

What I needed to was:

configuration.Routes.MapHttpRoute(
   name: "UpdateStuffAPI",
   routeTemplate: "api/updatestuff/post/{stuffid}",
   defaults: new { feedid = RouteParameter.Optional },
   constraints: null,
   handler: new MyMessageHandler(configuration)
);

In other words, the configuration object needed to be passed to the message handler upon construction. So the message handler needs a constructor:

public MyMessageHandler(HttpConfiguration httpConfiguration)
{
   InnerHandler = new HttpControllerDispatcher(httpConfiguration);
}

I naively assumed that setting handler: new MyMessageHandler() in the route map was enough to tie the message handler back to the controller(s) that the route maps to.

While this is resolved, I admittedly don't yet understand why this is required (why my assumption was incorrect) so I'm going to read up on that.

Upvotes: 1

Rohit Garg
Rohit Garg

Reputation: 493

Have you tried enabling attribute routing using:

configuration.Routes.MapMvcAttributeRoutes();

Routing is also dependent on order in which you map attribute route and normal http route.

Upvotes: 0

Related Questions