Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC Url.Action adds current route values to generated url

I have seen this question a couple of times here in SO but none of them with any acceptable answer:

ASP.NET MVC @Url.Action includes current route data
ASP.NET MVC implicitly adds route values

Basically I have Controller with an action method called Group, it has an overload that receives no parameters and displays a list of elements and another one that receives an id and displays details for that group.

If I do something like this:

Url.Action("Group", "Groups"); 

From the main page of the site (/) it returns an url like this:

"mysite.com/Groups/Group" 

which is alright Now, if the current address of the site is /Groups/Group/1 And I call the same method

Url.Action("Group", "Groups"); 

the returned url is this:

"mysite.com/Groups/Group/1" 

It automatically adds the value of the route for the current page when generating the URL. Even if I generate the URL this way:

Url.Action("Group", "Groups", null); 

Thus explicitly specifying that I don't want any route values, the generated URL is the same. To get the address I want I have to explicitly set the route value to an empty string, like so:

Url.Action("Group", "Groups", new {id=""}); 

This will generate the following url:

"mysite.com/Groups/Group" 

My question is, why does this happen? If I don't set any route values it shouldn't add them to the generated URL.

like image 213
willvv Avatar asked Aug 20 '11 16:08

willvv


People also ask

What does URL action do?

Generates a fully qualified URL to an action method for the specified action name and route values. Generates a fully qualified URL to an action method by using the specified action name, controller name, and route values.

How can add route in ASP.NET MVC?

In this tutorial, you learn how to add a custom route to an ASP.NET MVC application. You learn how to modify the default route table in the Global. asax file with a custom route. For many simple ASP.NET MVC applications, the default route table will work just fine.

Can we map multiple URLs to the same action?

Yes, We can use multiple URLs to the same action with the use of a routing table. foreach(string url in urls)routes. MapRoute("RouteName-" + url, url, new { controller = "Page", action = "Index" });


2 Answers

Url.Action will reuse the current request parameters, if you do not explicitly set them. It is by design in outbound url-matching algorithm. When looking for the route data parameters in a process of generating url, parameters are taken from:

1) explicitly provided values

2) values from the current request

3) defaults

In the order I specified above.

Outbound matching algorithm for routes is complicated, so it is good practice to explicitly set all parameters for request, as you did in your example

like image 54
objectbox Avatar answered Sep 16 '22 12:09

objectbox


My application explicitly sets route values and does not want a magical value from the current request. I want to be in full control.

I have made an extension which coexists with my route library collection. Hence the single RouteValueDictionary param. (See my Route library comment at the bottom)

Here I remove any routevalues from the request prior to generating a url.

(note: for the array.contains ignorecase part, see: How can I make Array.Contains case-insensitive on a string array?)

public static string Action(this UrlHelper helper,                              RouteValueDictionary routeValues) {     RemoveRoutes(helper.RequestContext.RouteData.Values);      string url = helper.Action(routeValues["Action"].ToString(), routeValues);     return url; }  public static void RemoveRoutes(RouteValueDictionary currentRouteData) {     List<string> keyList = new List<string>(currentRouteData.Keys);      string[] ignore = new[] { "Area", "Controller", "Action" };     foreach (string key in keyList)     {         if (!ignore.Contains(key, StringComparer.CurrentCultureIgnoreCase))             currentRouteData.Remove(key);     } } 

I have Form and ActionLink extension methods that uses the RemoveRoutes method. No helper in my mvc library uses a method that is not an extension method i have created. Thereby, all routedata is cleaned up before generating urls.

For reference I use AttributeRouting. Here is an example of one route from my route library.

public static RouteValueDictionary DisplayNews(int newsId) {     RouteValueDictionary route = new RouteValueDictionary();     route["Area"] = _area;     route["Controller"] = _controller;     route["Action"] = "DisplayNews";     route["newsId"] = newsId;     return route; } 
like image 35
Valamas Avatar answered Sep 17 '22 12:09

Valamas