Reputation: 42125
Why does the following Html.ActionLink
call:
Html.ActionLink("Approve", "Advance", new { id = Model.ID, step = StepType.Approve })
generate a URL with query parameters rather than a "restful" URL, i.e.:
http://localhost/Website/Case/Advance/1?step=Refer
I only have the default route registered, do I need additional routes that can understand what the "StepType" parameter is?
I've tried adding this route in after the default route:
routes.MapRoute(
"CaseAdvance",
"{controller}/{action}/{id}/{step}",
new {controller = "Case", action = "Advance", id = "", step = StepType.Refer});
but it had no effect. Adding the new route registration before the default gave me an error:
The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int64' for method 'System.Web.Mvc.ActionResult Advance(Int64, Website.Core.StepType)' in 'Website.Controllers.CaseController'. To make a parameter optional its type should be either a reference type or a Nullable type.
Upvotes: 2
Views: 2547
Reputation: 105029
Your exception only tells you that your custom route is catching something that you didn't intend it to catch. So if there would be a request to your application root URL:
your custom route would catch it. And set it's defaults. And call your CaseController.Advance()
action. And of course throw an exception, because id
is not defined.
But you will have to change your custom route or add route constraints to it so it will actually catch only those requests that it's meant to catch.
But which change should you do? If there's only going to be a single controller that needs it than change it to:
routes.MapRoute(
"CaseAdvance",
"Case/{action}/{id}/{step}",
new { controller = "Case", action = "Advance", id = "", step = StepType.Refer});
If there are other controllers a well, you can keep it as it was, just add constraints:
routes.MapRoute(
"CaseAdvance",
"{controller}/{action}/{id}/{step}",
new { controller = "Case", action = "Advance", id = "", step = StepType.Refer},
new { controller = "Case|Other" });
If there can be any controller, you can make a requirement for your id to be numeric:
routes.MapRoute(
"CaseAdvance",
"{controller}/{action}/{id}/{step}",
new { controller = "Case", action = "Advance", id = "", step = StepType.Refer},
new { id = @"\d+" })
In this case this route will only catch those requests that actually have an id defined. As a number of course.
You will know which one suits you best.
Upvotes: 2
Reputation: 40863
Try using RouteLink and see if that works for you.
Html.RouteLink("Approve", "CaseAdvance", new { controller = "Case", action = "Advance", id = Model.ID, step = StepType.Approve })
If calling RouteLink produces a valid link it will at least mean your route is setup correctly.
Upvotes: 1
Reputation: 150
In your route you have specified a parameter of stepType but your passing a parameter called step.
Your actionlink parameters names must match the route parameter names or you will get exactly what your seeing.
EDIT: Ok, you changed your code while I was typing this answer!!
Upvotes: 1
Reputation: 1885
Yes, if there is no route such as "{controller}/{action}/{id}/{step}" then the ActionLink method will simply pass "step" as a querystring parameter.
Upvotes: 2