Reproducing a bug
Create new ASP.Net MVC application:
Create an action that take non nullable argument called 'id':
[HandleError] public class HomeController : Controller { public ActionResult Index() { ViewData["Title"] = "Home Page"; ViewData["Message"] = "Welcome to ASP.NET MVC!"; return View(); } public ActionResult Test(int id) { return Content(id.ToString()); } public ActionResult About() { ViewData["Title"] = "About Page"; return View(); } }
Go to home/index.aspx and add the following before the final </asp:Content> tag:
<% using(Html.BeginForm("Test","Home")){ %> <%=Html.Hidden("id",2) %> <input type="submit" value="test" /> <%} %>
Visit the site and see that you indeed have a test button on the page. Click the button.
Get an exception:
I am going to assume this is a bug.
This is on the ASP.Net MVC beta bits.
Comments
Submit to codeplex?
I guess this is related to your previous post: in this case the action invoker takes the parameter that comes from the url parameter list, which should be (if u are using the default routes) and empty string. So it cannot find an valid int for the Test action.
Well... at least it's my guess without doing more tests... try removing the "id" parameter from the route and see what happens
I think this is purely because the routing isn't looking into form values to resolve parameters.. generally routing is resolved from url defined parameters or query string values.
@Stephen: the route must look only in the url... it's the action invoker that should probably be smarter to detect which id (the default one retrieved by the url parameter or the one that comes from the HttpRequest) is the right one
Actually your issue on codeplex explains this more, for whatever reason, the routing obviously isn't looking at the default values last: one would think:
url parameters,
qs parameters,
form parameters,
default parameter (if its convertable)
Thanks! This is a much better bug report than your last one. ;) I confirmed this behavior and it definitely doesn't seem right. I'll circle back with my dev/QA team and figure it out. Thanks!
Ok, it turns out this is by design right now. By convention, if you have a parameter name defined in your route with a default and you specify a parameter name to an action method with the same name, we assume you want us to populate that with the route value.
The easy fix is to change your default route from id to something else (routeID for example) so that there's no conflict. Otherwise the id in your action method has two meanings.
The first one wasn't a bug report :-)
I would say that this is a wrong by design choice to make.
Especially when it took me a really long while to figure out what was going on.
The route doesn't have an ID parameter, so it should fall back to looking at the request params.
Only if it can't find anything, should it try to use the default.
As you noted yourself, this doesn't look right. It also mean that something that I do in one place can adversely and non obviously affect in a completely different place.
Ayende - The team noticed that you opened a bug report on CodePlex <<a rel="nofollow external" href="http://www.codeplex.com/aspnet/WorkItem/View.aspx?WorkItemId=2549" title="http://www.codeplex.com/aspnet/WorkItem/View.aspx?WorkItemId=2549">www.codeplex.com/.../View.aspx?WorkItemId=2549
Agreed, we'll take a look at it in our next triage meeting. I mentioned it's currently by design, but we will re-evaluate the design.
@Phil,
See my comment in Ayende's previous post. I could have sworn this wasn't the way it worked before. In the initial releases if the route didn't have a default value, but it was supplied in the query string then it would take that. Also renaming the parameter isn't always an option.
I have seen this behavior in past previews as well. I usually get around it by changing my form values to not conflict with route values, but that get's aggravating after a while.
Just curious as to why the ID is a hidden input value rather than a parameter in the URL. I started putting IDs in hidden inputs, but soon realized they really belong in the form's action attribute as part of the action path, since that's how you originally came to the resource.
Example:
GET:
/employee/123/edit
POST:
/employee/123/do-edit
Comment preview