0

Here is necessary code to reproduce a very strange problem with ASP.NET MVC 3.0 routing:

Route registration in Global.asax.cs:

routes.MapRoute("History", "Customer/History", new {controller = "User", action = "History", someParam = UrlParameter.Optional});
routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional });

Here we declare a route to the user's history. But in the URL we want "Customer" instead of "User". Also please note parameter someParam. Controller User does really exist and has action History.

Now usage in view:

<a href="<%= Url.Action("History", "User") %>">History</a>
<a href="<%= Url.Action("History", "User", new { someParam="qqq" }) %>">History with param</a>

I am using here Url.Action() instead of Html.ActionLink() only for clarity.

And here is the result - how this part of the view was rendered:

<a href="/Customer/History">History</a>
<a href="/User/History?someParam=qqq">History with param</a>

Now the problem is clear - URL without parameters was resolved correctly, while the URL with parameter starts with "/User" instead of "/Customer".

Questions:

  1. Is it a normal behavior? If yes, why does routing work that way?
  2. Is there any workaround for this? I mean is there any way to get the final result as:

    <a href="/Customer/History">History</a>
    <a href="/Customer/History?someParam=qqq">History with param</a>
    

1 Answer 1

1

I suspect it's getting confused because your route for Customer doesn't list that extra value, but the default one does. Try this:

routes.MapRoute("History", "Customer/History/{someParam}", new {controller = "User", action = "History", someParam = UrlParameter.Optional});

Or to preserive the query string link syntax, this:

routes.MapRoute("History", "Customer/History/{id}", new {controller = "User", action = "History", id = UrlParameter.Optional});

In the second case you don't supply a value for id when creating the link (your call to Url.Action shouldn't have to change).

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

5 Comments

Thanks for response. According to your suggestion the resulting URL will be /Customer/History/qqq. However what I need is /Customer/History?someParam=qqq. Is there any way to achieve this?
@Andrei - Well, you could put {id} on it instead of {someParam}, because you're not giving it an ID it's going to not put the value of someParam there. You don't have to add someParam to the route setup, just add it as a value when you actually create the link (as you're already doing). I've updated the answer with the second form.
thanks a lot, now it works exactly as expected. However I am still not sure how addition of a default parameter solved the problem. Why the original route did not fit? It has controller and action exactly as they are given in the Url.Action() method, someParam is declared to be optinal - everything seems OK... Could you please enlighten me what am I missing about those optinal parameters?
@Andrei - I honestly don't fully understand why it works that way myself. I just know it does. :) It seems to be that with the missing third parameter that route doesn't match when it should. It's not like you're using the {id} in this case, but having it there makes things happier. If I had to guess, I'd go with that it thinks someParam fits it even though it really doesn't. With that problem out of the picture it works as you'd expect.
Tridus, actually everything turned out to be even simpler. routes.MapRoute("History", "Customer/History", new {controller = "User", action = "History"}); does the job just as well - Url.Action("History", "User", new { someParam="qqq" }) gives an expected URL /Customer/History?someParam=qqq.

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.