2

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.

3
  • I'm not sure exactly what's causing the error off the top of my head, but your nomenclature for step type is inconsistent between what you're doing in the ActionLink method and in the route ("step" versus "stepType"). Whatever you named the parameter in your Action is what you need to call it in both the route and the ActionLink method. Commented Feb 6, 2010 at 0:54
  • Ahh, good point. I've fixed that but still getting an exception. Geez this routing takes some getting used to! Commented Feb 6, 2010 at 0:57
  • Looking at that again, and this is where my knowledge is lacking a little bit, but you may want to change that second parameter in your Advance Action to a string instead of what it is. I don't know that that will work with a GET request unless you have some sort of model binding in place. I could be quite mistaken, however it may be worth a try. Commented Feb 6, 2010 at 1:00

4 Answers 4

2

Custom route catching too much at the moment

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:

http://localhost/Website

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.

Keep your custom route in front of default one

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.

Sign up to request clarification or add additional context in comments.

Comments

2

Yes, if there is no route such as "{controller}/{action}/{id}/{step}" then the ActionLink method will simply pass "step" as a querystring parameter.

1 Comment

Hmm, I've tried adding a new route (before and after the default one) and either I get an exception or it makes no difference. Where can I find out what the route definition should look like?
1

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!!

1 Comment

Thanks - I've fixed that (I'm an idiot) but unfortunately still getting an exception if the new (more specific) route is registered first.
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.