4

Lets say we have this route:

routes.MapRoute(
"Library",
"Lib/{id}/{lang}",
New With {.controller = "MyLibrary", .action = "ShowItem", .id= 0, .lang = "en"}
)

And lets say we request this url:

http://localhost/Lib/10/de

so now we have this route values: id = 10 & lang = de

Here is the problem:

This code:

<%= Url.Action("ShowItem", New With {.id = 45})%>

returns:

http://localhost/Lib/45/de

It changes id but preserves lang.

But this code:

<%= Url.RouteUrl("Library", New With {.id = 45})%>

returns:

http://localhost/Lib/45

It changes id but removes lang!

Is this a bug or what? I know how to fix this, but this different behavior is very confusing. Am I right? Or just imagining this?

One quick fix would be:

<%= Url.RouteUrl("Library", New With {.id = 45},.lang = RouteData.Values("lang"))%>
Afshin Gh
  • 7,918
  • 2
  • 26
  • 43

3 Answers3

3

This is basically the same as How to ignore current route values when generating links?.

Try something like this:

<%= Url.Action("ShowItem", New With {.id = 45, .lang=UrlParameter.Optional})%>

Sorry, I'm not too familiar with VB syntax so it may not be 100% correct, but the key is to pass UrlParameter.Optional so it doesn't preserve the route value.

Update: I should add that the behavior you get is not expected. From a new MVC app, I added a basic MyLibrary controller with ShowItem action, with this code (sorry, it's C#):

@Url.Action("ShowItem", new {id = 45})<br />
@Url.RouteUrl("Library", new {id = 45})<br />
@Url.Action("ShowItem", new {lang = "fr"})<br />
@Url.RouteUrl("Library", new { lang = "fr" })<br />

And when I go to /Lib/10/de, it displays:

/Lib/45
/Lib/45
/Lib/10/fr
/Lib/10/fr

So note that:

  • There is no difference between the two methods
  • Current route values are only preserved if there are no changing values before then in the URL. Hence '10' is preserved but 'de' is not.

I don't know why you see something different, but I suggest testing from a clean app to isolate from other things that may be going on in your app.

Community
  • 1
  • 1
David Ebbo
  • 42,443
  • 8
  • 103
  • 117
  • Well, my question is: Why 2 different behaviors in these 2 methods? By the way, in my project, my desired route is defined, as you said, using: UrlParameter.Optional, and it's the same behavior. – Afshin Gh Oct 19 '11 at 08:00
  • I'm talking about passing UrlParameter.Optional to Url.Action, not when you set up the route. This is an entirely different thing. – David Ebbo Oct 19 '11 at 16:52
  • I'll try it ASAP and will comment back about it. but as i said, the problem is the different behavior between these 2 similar methods. And +1 for kindly posts & comments in this thread. – Afshin Gh Oct 20 '11 at 01:52
  • Sorry for responding late. As you suggested i started a clean project and every thing works fine, so i suspect that the problem was with other routes defined. You deserve the bounty for commenting back and updating your answer. Thanks again for forcing me to test it in a clean app :) – Afshin Gh Oct 24 '11 at 18:33
  • I'm going to give bounty points to David & answer point to Dan. You both helped me a lot. David's answer was complete and I found out that the problem was because of defined routes. Dan's answer made sure that other defined routes caused this problem. – Afshin Gh Oct 24 '11 at 18:36
3

Ok so the theoretically correct expected mvc behaviour here is that it shouldn't reuse variables from the current request if they occur in a later segment than one you specify. So I'm wondering if you have some other routes defined as what you are describing isn't quite right so could it be matching something else. If not it may be a bug.

Regardless because this above behaviour (when its working!) is pretty confusing, best practice is to supply all the segment variables when creating links, using UrlParameter.Optional as described above. Then you don't have to worry about this ambiguity.

For what it is worth, the second result you are seeing (i.e. RouteUrl) is the correct behaviour. The Action should be behaving the same.

DanH
  • 3,772
  • 2
  • 27
  • 31
  • Thanks DanH for your answer & sorry that i responded late. As you said I think this is because of other routes. After David's answer and suggestion I created a new project and found out that every things works fine. I really wish to give a part of the bounty to you, but David's answer looks better. Thanks again & +1 – Afshin Gh Oct 24 '11 at 18:31
  • I'm going to give bounty points to David & answer point to Dan. You both helped me a lot. David's answer was complete and I found out that the problem was because of defined routes. Dan's answer made sure that other defined routes caused this problem. – Afshin Gh Oct 24 '11 at 18:37
1

Looks like that is the expected action. http://msdn.microsoft.com/en-us/library/dd492912.aspx indicates "Generates a fully qualified URL to an action method for the specified action name and route values." meaning that it will populate the other fields with the route values?

Kind of just guessing...

endyourif
  • 2,186
  • 19
  • 33
  • No. It means for the routevalues you pass to this method. http://msdn.microsoft.com/en-us/library/dd504960.aspx this link says nothing about routevalues, but it will preserve them too. – Afshin Gh Oct 17 '11 at 05:01