Reputation: 43
I'm using a custom HTTP controller selector to version my API.
config.Services.Replace(typeof(IHttpControllerSelector), new NamespaceSelector(config));
Below is my controller with actions:
[RoutePrefix("api/v1/messages")]
public class MessagesController : ApiController
{
[Route("unreadall")] // api/v1/messages/unreadall
public IEnumerable<long> UnreadAll()
{
// Return value;
}
[Route("{type}/unreadall")] // api/v1/messages/{type}/unreadall
public IEnumerable<long> UnreadAll(string type)
{
// Return value;
}
[Route("unreadnext")] // api/v1/messages/unreadnext
public long UnreadNext()
{
// Return value;
}
[Route("{type/}unreadnext")] // api/v1/messages/{type}/unreadnext
public long UnreadNext(string type)
{
// Return value;
}
[Route("{id:long}/markasread")] // api/v1/messages/123/markasread
[HttpPut]
public string MarkAsRead(long id)
{
// Return value;
}
[Route("{id:long}")] // Default Action
public string Get(long id) // api/v1/messages/123
{
// Return value;
}
[Route("")] // Default Action
[HttpPost]
public long Post(string message) // api/v1/messages
{
// Return value;
}
}
Below is my route config:
config.Routes.MapHttpRoute(
name: "DefaultApi1",
routeTemplate: "api/{version}/{controller}/{id}/{action}"
);
config.Routes.MapHttpRoute(
name: "DefaultApi2",
routeTemplate: "api/{version}/{controller}/{action}"
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{version}/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
When I test my routes, the following work.
/api/v1/messages/unreadall
/api/v1/messages/unreadnext
/api/v1/messages/123/markasread
But the below routes, also point to the same actions.
/api/v1/messages/type/unreadall
/api/v1/messages/type/unreadnext
And I get errors for the rest of my routes.
/api/v1/messages/123
Error:
{
"Message": "No HTTP resource was found that matches the request URI 'http://localhost:59411/api/v1/messages/123'.",
"MessageDetail": "No action was found on the controller 'MessagesController' that matches the name '123'."
}
POST: /api/v1/messages
Error:
{
"Message": "The requested resource does not support http method 'POST'."
}
Can someone please tell what I'm doing wrong with my route configuration ? or can someone please post working route configuration for my scenarios above ?
Appreciate your help !
Cheers,
Upvotes: 4
Views: 2615
Reputation: 20033
What you are getting it's the expected behavior: the routes defined in route config works, while the attribute routes does not.
This happens because request.GetRouteData()
is not taking into account attribute routes. This makes sense of course because there is no specific controller that a route points to as attributed routes are related to methods, not controllers.
When you use attribute routing, all the route attributes get added to a common route without a name. This is a special route that is an instance of an internal class called RouteCollectionRoute
. This route has a collection of sub-routes that you can query for that includes all the attribute routes. But if you just want the selected route for your call, you can simple ask for it using the RouteData.Values
:
var routeData = request.GetRouteData();
var subroutes = (IEnumerable<IHttpRouteData>)routeData.Values["MS_SubRoutes"];
var route = subroutes.First().Route;
Source: http://wildermuth.com/2013/11/12/Web_API_2_s_Attribute_Routing_Looking_Deeper
Upvotes: 3