我已经在SO中多次看过这个问题,但没有一个问题可以接受:
ASP.NET MVC @Url.Action includes current route data
ASP.NET MVC implicitly adds route values
基本上我有一个名为Group的动作方法的Controller,它有一个不接收任何参数的重载,显示一个元素列表,另一个接收一个id并显示该组的详细信息。
如果我这样做:
Url.Action("Group", "Groups");
从网站的主页面(/)返回一个这样的网址:
"mysite.com/Groups/Group"
没关系 现在,如果站点的当前地址是/ Groups / Group / 1 我称之为相同的方法
Url.Action("Group", "Groups");
返回的网址是:
"mysite.com/Groups/Group/1"
生成URL时,它会自动为当前页面添加路由值。 即使我这样生成URL:
Url.Action("Group", "Groups", null);
因此明确指定我不想要任何路由值,生成的URL是相同的。 要获取我想要的地址,我必须将路由值显式设置为空字符串,如下所示:
Url.Action("Group", "Groups", new {id=""});
这将生成以下网址:
"mysite.com/Groups/Group"
我的问题是,为什么会这样?如果我没有设置任何路由值,则不应将它们添加到生成的URL中。
答案 0 :(得分:50)
如果您没有明确设置它们,Url.Action将重用当前的请求参数。它是出站网址匹配算法的设计。在生成URL的过程中查找路径数据参数时,参数取自:
1)明确提供值
2)来自当前请求的值
3)默认
按照我上面指定的顺序。
路由的出站匹配算法很复杂,因此最好为请求显式设置所有参数,就像在示例中所做的那样
答案 1 :(得分:2)
我的应用程序显式设置路由值,不需要当前请求的神奇值。我希望完全掌控。
我制作了一个与我的路线库集合共存的扩展程序。 因此单个RouteValueDictionary参数。 (请参阅底部的路线库评论)
在此,我会在生成网址之前从请求中删除所有路由值。
(注意:对于array.contains ignorecase部分,请参阅: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);
}
}
我有使用RemoveRoutes方法的Form和ActionLink扩展方法。我的mvc库中没有帮助器使用的方法不是我创建的扩展方法。因此,在生成URL之前清理所有routedata。
作为参考,我使用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;
}
答案 2 :(得分:2)
所以当我读到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+" }
);
答案 3 :(得分:2)
简单示例:
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
。 Id参数是从url读取的,尽管我们只写了Url.Action(methodName, controller)
- 没有指定参数。另外,没有id的方法细节没有意义。
为了使下一行的属性工作,必须添加到RouteConfig.cs
:
public static void RegisterRoutes(RouteCollection routes)
{
...
routes.MapMvcAttributeRoutes();
...
}
答案 4 :(得分:1)
这是一种不需要属性路由的解决方法,也不会改变请求中的当前路由值。这个想法来自http://notherdev.blogspot.ca/2013/10/aspnet-mvc-current-values-used-by-url-action.html,我在没有MvcFutures的情况下略微改变了。
我在UrlHelper上构建了我自己的Action
扩展程序,其中包含一个额外的bool,允许您选择忽略当前路由值(以免与UrlHelper上的现有Action方法冲突。)
它的作用是使用当前路由从当前路由构建一个全新的RequestContext,但不当前路由值。然后我们将它传递给基础助手。这样,当基本帮助者在请求上下文中查看路由值时,它将找不到,因此在生成URL时不会使用它们。
public static string Action(this UrlHelper urlHelper, string actionName, string controllerName, object routeValues, bool ignoreCurrentRouteValues=false) {
var routeValueDictionary = new RouteValueDictionary(routeValues);
var requestContext = urlHelper.RequestContext;
if (ignoreCurrentRouteValues) {
var currentRouteData = requestContext.RouteData;
var newRouteData = new RouteData(currentRouteData.Route, currentRouteData.RouteHandler);
requestContext = new RequestContext(requestContext.HttpContext, newRouteData);
}
return UrlHelper.GenerateUrl(null, actionName, controllerName, routeValueDictionary,
urlHelper.RouteCollection, requestContext, includeImplicitMvcValues: false);
}
答案 5 :(得分:0)
一个简单的解决方法是首先调用
Url.Action("dummy", new { ... })
然后将结果字符串中的dummy重命名为正确的操作名称。
答案 6 :(得分:0)
一个愚蠢的解决方法我发现它可以处理当前页面路由数据,包括根据您的偏好更改页面参数
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
tools:context="sslwireless.com.testfullscreen.MainActivity">
<!--RePresent Toolbar-->
<LinearLayout
android:orientation="horizontal"
android:background="@drawable/gradient"
android:layout_width="match_parent"
android:layout_height="100dp">
<ImageView
android:layout_gravity="center_vertical"
android:src="@drawable/ic_arrow_back_white_24dp"
android:layout_marginLeft="10dp"
android:layout_width="35dp"
android:layout_height="35dp" />
<TextView
android:layout_gravity="center_vertical"
android:textSize="25sp"
android:gravity="center_horizontal"
android:textColor="#fff"
android:text="Test Title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>