Title: ASP.NET MVC 4 - API Routing - Specifying Action in the URL
Tags: asp.net-mvc;asp.net-mvc-4;asp.net-web-api
Question: I have a web service written in the ASP.NET MVC 4 framework. Its basic CRUD operations map well to REST verbs, but I have one action that I need to add that does not.
What is the correct way to specify the ability to sometimes pass an ID at the end of the URL that you know will be an Integer type and sometimes have it be an "action" a String type followed by a slash and an int ID? Need help with correct Router map.
Thoughts? Note: I'm more concerned with WebAPI then being 100% REST.
example URLs
// GET list of widgets
http://somedomain.com/api/widget
// GET specific widget
http://somedomain.com/api/widget/1
// POST - take special action on a specific widget - promote
http://somedomain.com/api/widget/promote/1
Would this be the correct way to handle it?
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapHttpRoute(
name: "DefaultApiExtended",
routeTemplate: "api/{controller}/{action}/{id}"
);


Here is another answer: Take a look at http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api - specifically section "Routing by Action Name"
Slight change recomended from
http://somedomain.com/api/widget/promote/1
http://somedomain.com/api/widgets/1/promote
(Use the plural if possible widget*s*)
Your Controller will need to look like this:
public class WidgetsController : ApiController
[HttpPost]
/// POST api/widgets/1/promote
public void Promote(int id)
// GET api/widgets/1
public string Get(int id)
return "value";
And the routes:
public static void RegisterRoutes(RouteCollection routes)
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapHttpRoute(
name: "DefaultPromoteActionApi",
routeTemplate: "api/{controller}/{id}/{action}",
defaults: new { action = "Promote" }
);
Comment for this answer: @brun sorry I don't fully understand... like api/widgets/promote ?
Comment for this answer: +1 - slight varation - how would you handle something like a dequeue where you do want to specify the action but won't have the ID? Thanks.

Here is another answer: Take a look at AttributeRouting; it should be able to accomplish this with ease.

Here is another answer: I'd try putting the second pattern (an "action" a String type followed by a slash and an int ID) in at a higher priority than (pass an ID at the end of the URL that you know will be an Integer type).
routes.MapHttpRoute(
name: "ActionWithId",
routeTemplate: "api/widget/{action}/{id}"
);
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Your action and your ID are not optional as you're always expecting them. If there is no match, the DefaultApi rule should take over processing.
Just thought, if you do want it to be "RESTy" then you could always switch the ID, so for this widget, with this id, perform this action.
routes.MapHttpRoute(
name: "ActionWithId",
routeTemplate: "api/widget/{id}/{action}"
);

{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 3, 'CommentCount': 0, 'ContentLicense': 'CC BY-SA 3.0', 'CreationDate': '2012:00:08/23/12', 'FavoriteCount': 0.0, 'PostTypeId': 1, 'Tags': '<asp.net-mvc><asp.net-mvc-4><asp.net-web-api>', 'Title': 'ASP.NET MVC 4 - API Routing - Specifying Action in the URL', 'ViewCount': 2246, 'id': 12093182, 'user_AboutMe': '<p>I like to code C# and work with the web. Still learning.<br /></p>\n', 'user_AccountId': 16675.0, 'user_DisplayName': 'BuddyJoe', 'user_Reputation': 67977.0, 'user_Views': 2364.0, 'user_id': 36590.0}}