So I've got a project using the default Route
of
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I just ran into a situation described 7 years ago at MVC Pro Tip: Don't use the "id" URL parameter in your routes.
The solution they have is great and all, but at this moment, I do not want to change my entire site. I was hoping to fix my issue with Attribute Routing.
However, I cannot seem to get this to work, and I receive a 404 Error
page. (just in case the link above does not work, I'll describe the code in detail here).
Details
In my project I use ViewModels
. The ViewModel
is (very simply) defined as:
public class Foo {
public int Id { get; set; }
...
}
My BarController
is as follows:
public ActionResult Create(string id) {
if (string.IsNullOrWhiteSpace(id)) {
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
...
}
[HttpPost]
public ActionResult Create(string id, Foo viewModel) {
if (string.IsNullOrWhiteSpace(id)) {
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
...
}
Error
When I navigate to /Bar/Create/abc123
, I see my form just fine. However, when I submit the form, Model.IsValid
is false
. Looking at Watch
window for the this.ModelState
object, I found the error message to say
The value 'abc123' is not valid for Id.'
I assume that's because the model binder is trying to bind abc123
to Id
on the ViewModel
which has an int
as the Id
property.
What I've Tried
Here's what I've attempted to do so far on my Controller
:
[Route("Bar/Create/{aid}", Name = "FooBarRouteName")]
public ActionResult Create(string aid) {
if (string.IsNullOrWhiteSpace(aid)) {
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
...
}
[HttpPost]
public ActionResult Create(string aid, Foo viewModel) {
if (string.IsNullOrWhiteSpace(aid)) {
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
...
}
The problem now is when I navigate to /Bar/Create/abc123
, I get a 404 Error
page and cannot even try to submit the form.
Can someone point me in the right direction or figure out what I'm doing wrong? Thanks!
First ensure that attribute routing is enabled before convention-based routes to avoid route conflicts.
//Attribute routing
routes.MapMvcAttributeRoutes();
//Convention-based routing
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
You are missing a route on the POST action.
If using attribute routing you have to decorate all actions on the controller
[HttpGet]
[Route("Bar/Create/{aid}", Name = "FooBarRouteName")] // GET Bar/Create/abc123
public ActionResult Create(string aid) {
if (string.IsNullOrWhiteSpace(aid)) {
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
...
}
[HttpPost]
[Route("Bar/Create/{aid}")] // POST Bar/Create/abc123
public ActionResult Create(string aid, Foo viewModel) {
if (string.IsNullOrWhiteSpace(aid)) {
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
...
}