ASP.NET MVC Url.Action将当前路由值添加到生成的URL

我在这里几次看到这个问题,但没有一个可以接受的答案:

ASP.NET MVC @ Url.Action包含当前的路由数据
ASP.NET MVC隐式添加路由值

基本上,我有一个名为组的操作方法的控制器,它有一个重载没有参数,并显示一个元素的列表,另一个接收一个ID和显示该组的详细信息。

如果我做这样的事情:

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

从网站的主页(/)返回一个像这样的url:

 "mysite.com/Groups/Group" 

这是好的现在,如果该网站的当前地址是/ Groups / Group / 1而且我调用的方法相同

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

返回的url是这样的:

 "mysite.com/Groups/Group/1" 

它会在生成URL时自动为当前页面添加路由的值。 即使我这样生成URL:

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

因此明确指定我不需要任何路由值,生成的URL是相同的。 为了得到我想要的地址,我必须明确地设置路由值为空string,如下所示:

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

这将生成以下url:

 "mysite.com/Groups/Group" 

我的问题是,为什么会发生这种情况? 如果我不设置任何路由值,则不应将它们添加到生成的URL中。

Url.Action将重用当前的请求参数,如果你没有明确地设置它们。 这是出站url匹配algorithm的devise。 在生成url的过程中查找路由数据参数时,参数取自:

1)明确提供的价值

2)来自当前请求的值

3)默认

按照上面指定的顺序。

对于路由的出站匹配algorithm很复杂,因此最好像所有示例一样,为请求显式设置所有参数

我的应用程序显式设置路由值,并不想从当前的请求魔法值。 我想完全控制。

我做了一个扩展,与我的路由库集合共存。 因此,单个RouteValueDictionary参数。 (见我的路线库评论在底部)

这里我在生成一个url之前从请求中删除任何路由值。

(注意:对于array.contains ignorecase部分,请参阅: 如何使Array.Contains在string数组上不区分大小写? )

 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); } } 

我有使用RemoveRoutes方法的Form和ActionLink扩展方法。 我的mvc库中没有任何助手使用的方法不是我创build的扩展方法。 因此,在生成URL之前,所有路由数据都会被清除。

为了参考我使用AttributeRouting。 以下是我的路线库中的一条路线的示例。

 public static RouteValueDictionary DisplayNews(int newsId) { RouteValueDictionary route = new RouteValueDictionary(); route["Area"] = _area; route["Controller"] = _controller; route["Action"] = "DisplayNews"; route["newsId"] = newsId; return route; } 

所以当我阅读objectbox的答案时,我想我将不得不修改我的代码中的几个链接。 然后我尝试添加一个默认路由,省略了解决问题的默认参数:

 routes.MapRoute( "ArtistArtworkDefPage", "Artist/{username}/Artwork", new { controller = "Artist", action = "Artwork", page = 1 } ); routes.MapRoute( "ArtistArtwork", "Artist/{username}/Artwork/{page}", new { controller = "Artist", action = "Artwork", page = 1 }, new { page = @"\d+" } ); 

简单的例子:

 public class ProductController : Controller { public ActionResult Edit(int id) { return View(); } [Route("Product/Detail/{id:int}")] public ActionResult Detail(int id) { return View(); } } 

编辑视图只包含这个:

 @{ Layout = null;} @Url.Action("Detail", "Cmr") 

所以当你运行你的站点时,例如localhost:randomPort/Product/Edit/123你会得到下一个响应: /Product/Detail/123

为什么? 因为Route属性需要参数id 。 虽然我们只写了Url.Action(methodName, controller) ,但是没有指定参数,我们从url中读取了Id参数。 也没有意义,有一个没有身份证的方法的细节。

为了下一行的属性必须被添加到RouteConfig.cs

 public static void RegisterRoutes(RouteCollection routes) { ... routes.MapMvcAttributeRoutes(); ... } 

首先要调用一个简单的解决方法

 Url.Action("dummy", new { ... }) 

然后将结果string中的哑元重命名为正确的操作名称。

我发现一个愚蠢的解决方法,处理当前的页面路由数据,包括根据您的喜好更改页面参数

 @{ var current_route_1 = new RouteValueDictionary(Url.RequestContext.RouteData.Values); var current_route_2 = new RouteValueDictionary(Url.RequestContext.RouteData.Values); //If you want to customize the routing values current_route_1["controller"] = "Controller1"; current_route_2["controller"] = "Controller2"; } @Url.RouteUrl(current_route_1); @Url.RouteUrl(current_route_2);