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