Reputation: 111
The goal is to allow these four endpoints:
POST v1/invoices<br/>
POST v1/invoices/12345<br/>
POST v1/invoices/12345/attachment<br/>
POST v1/invoices/12345/image
Routing entries:
routes.MapHttpRoute(
name: "InvoiceAttachments",
routeTemplate: "v1/invoices/{id}/attachments",
defaults: new { controller = "invoices", action = "PostAttachment" }
);
routes.MapHttpRoute(
name: "InvoiceImages",
routeTemplate: "v1/invoices/{id}/images",
defaults: new { controller = "invoices", action = "PostImage" }
);
These are my four function definitions in the controller:
[HttpPost]
[ActionName("PostAttachment")]
public HttpResponseMessage PostAttachment(int id)
[HttpPost]
[ActionName("PostImage")]
public HttpResponseMessage PostImage(int id)
[HttpPost]
public HttpResponseMessage Post(int id)
[HttpPost]
public HttpResponseMessage Post()
Yet when I post an invoice using the first URI, the route that gets recognized is the attachments route. How do i have endpoints with different sections after the ID variable?
Upvotes: 3
Views: 5838
Reputation: 111
Got it!
Route:
routes.MapHttpRoute(
name: "InvoiceStuff",
routeTemplate: "v1/invoices/{id}/{*action}",
defaults: new { controller = "invoices", action = "" }
);
Function definitions:
[HttpPost]
[ActionName("Attachments")]
public HttpResponseMessage Attachments([FromUri]int id)
[HttpPost]
[ActionName("Images")]
public HttpResponseMessage Images([FromUri]int id)
[HttpPost]
public HttpResponseMessage Post()
[HttpPost]
[ActionName("")]
public HttpResponseMessage Post([FromUri]int id)
Works perfectly. Note that in the route I specified a default action of "" because of a defect in webAPI routing with wildcards. Had i not done the default, a null reference exception would have been thrown. More information on the defect can be found here: http://aspnetwebstack.codeplex.com/workitem/718 - slated to be fixed in ASP.NET v5.
Thanks for all your help!
Upvotes: 7
Reputation: 4063
Have you tried using constraints rather than defaults?
routes.MapHttpRoute(
name: "InvoiceAttachments",
routeTemplate: "v1/invoices/{id}/attachments",
defaults: new { controller = "invoices" },
constraints: new { action = "PostAttachment" }
);
routes.MapHttpRoute(
name: "InvoiceImages",
routeTemplate: "v1/invoices/{id}/images",
defaults: new { controller = "invoices" },
constraints: new { action = "PostImage" }
);
routes.MapHttpRoute(
name: "Default",
routeTemplate: "v1/invoices/{id}",
defaults: new { controller = "invoices" }
);
UPDATE:
You could probably sort of hack it by making the action a url part:
routes.MapHttpRoute(
name: "InvoiceAttachments",
routeTemplate: "v1/invoices/{id}/{action}",
defaults: new { controller = "invoices" },
constraints: new {action = "attachments|images"}
);
routes.MapHttpRoute(
name: "default",
routeTemplate: "v1/invoices/{id}",
defaults: new { controller = "invoices", id = RouteParameter.Optional },
constraints: new {action = "attachments|images"}
);
and the controller methods:
[HttpPost]
[ActionName("attachments")]
public HttpResponseMessage PostAttachment(int id)
[HttpPost]
[ActionName("images")]
public HttpResponseMessage PostImage(int id)
public HttpResponseMessage Post(int id)
public HttpResponseMessage Post()
Upvotes: 0
Reputation: 336
Try having a single route
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}/{action}",
defaults: new { id = RouteParameter.Optional, action = "DefaultAction" }
);
Then decorate functions like
[HttpPost]
[ActionName("DefaultAction")]
public HttpResponseMessage Post()
[HttpPost]
public HttpResponseMessage PostImage(int id)
Upvotes: 0
Reputation: 4244
I think you must have another route defined, because the first URI should not be matching the InvoiceAttachments route, because it does not have "/attachments" on the end
Upvotes: 1