William Scalf
William Scalf

Reputation: 422

Using attribute routing and a global route for the same controller action

So, we're developing a webapi-heavy application that serves multiple types of clients (including a website that's a JavaScript client and multiple C# clients), and we'd like to use attribute routing to make friendlier urls. Something like this:

[RoutePrefix(Constants.RoutePrefixes.Api + "foo")]
[HttpPut]
FooController : ApiController
{
     [Route("{fooId}/sub/{subFooId}")]
     [HttpPut]
     public HttpResponseMessage UpdateAFoo(int fooId, int subFooId)
     {
         return Request.CreateResponse(HttpStatusCode.OK);
     }
}

And a request to /api/foo/1/sub/2 would hit this controller, as expected.

However, we have a message handler built into one of our default routes for processing identity tokens, and requests coming from clients that require that special behavior still have to use that route, or at least something that runs the appropriate message handler, and the following request (which uses that other route):

/integration/foo?fooId=1&subFooId=2

..gives me an error that no suitable controller could be found to handle the request. If I remove the route attribute, this second request hits my action method as expected.

I've read in several places that you can use both default and attribute routes, and I have both working in the application, but I haven't been able to use both for a specific action.

My route config looks like this:

public static void RegisterHttpRoutes(HttpConfiguration configuration)
{
        var routes = configuration.Routes;

        configuration.MapHttpAttributeRoutes();

        routes.MapHttpRoute(
            name: Constants.RouteNames.Api,
            routeTemplate: Constants.RoutePrefixes.Api + "{controller}/{id}/{p}",
            defaults: new { id = RouteParameter.Optional, p = RouteParameter.Optional }
        );

        routes.MapHttpRoute(
            name: Constants.RouteNames.IntegrationApi,
            routeTemplate: Constants.RoutePrefixes.IntegrationApi + "{controller}/{id}/{p}",
            defaults: new { id = RouteParameter.Optional, p = RouteParameter.Optional },
            constraints: null,
            handler: new SuperDuperAuthenticationHandler())
        );
    }

Is that just how it works? Do I need a separate action without the route attribute? Is there a way to specify message handlers for attribute routes? Can I have both attribute and convention routing apply to the same action method? I'm not really clear on what my options are.

Upvotes: 1

Views: 1643

Answers (1)

Kiran
Kiran

Reputation: 57939

Controllers/Actions which are decorated with attribute routes cannot be reached via routes matched by conventional routing...so the behavior that you are seeing is expected...

Per-route message handlers are not supported for attribute routes.

Can you use AuthenticationFilterAttribute for your scenario?...if you need this filter for a set of controllers, then you could probably create a base controller decorated with this filter and let all these set of controller derive from it...

Upvotes: 2

Related Questions