shane87
shane87

Reputation: 3120

ASP.NET Web Api configuring a specific route not executing message handler

I am trying to configure a specific route to execute a message handler before it hits the controller, however the message handler is never executed.

I have the following controller:

public class TestController : ApiController
{
    [Route("private/users")]
    public IHttpActionResult Get()
    {
        return Ok();
    }
}

And the following route configuration:

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "private/users",
            defaults: new { id = RouteParameter.Optional },
            constraints: null,
            handler: new TokenValidationHandler() { InnerHandler = new HttpControllerDispatcher(config) }
        );

And The MessageHandler looks like this:

public class TokenValidationHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        //some logic to validate token
        return base.SendAsync(request, cancellationToken);
    }
}

The TokenValidationHandler is never executed which seems to be because of the routeTemplate when configuring the route. Is it possible to achieve route specific configuration with a hardcoded routeTemplate like "private/users" instead of the default "{controller}/{id}" format?

What I want to do is have my TokenValidationHandler fire for all of my private api calls and have public api calls bypass the TokenValidationHandler.

Upvotes: 1

Views: 1358

Answers (1)

Nkosi
Nkosi

Reputation: 247068

Attribute routes a matched before convention-based routes. The action in question is tagged with an Route attribute. If attribute routing is enabled then it means that it will not reach the convention-based route and thus not invoke the handler.

Remove the route attribute

public class TestController : ApiController { 
    public IHttpActionResult Get() {
        return Ok();
    }
}

The order of route registration also plays a factor for convention-based routes so make sure that general routes are registered after more specific routes

config.Routes.MapHttpRoute(
    name: "PrivateApi",
    routeTemplate: "private/users",
    defaults: new { id = RouteParameter.Optional },
    constraints: null,
    handler: new TokenValidationHandler() { InnerHandler = new HttpControllerDispatcher(config) }
);

//more general route
config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional },
    //...
);

Otherwise if attribute routing is your preference you can consider using an action filter.

Based on stated intentions you would be better off using Authentication Filters in ASP.NET Web API 2

Upvotes: 2

Related Questions