【问题标题】:Generate a URL From Route Data ONLY仅从路由数据生成 URL
【发布时间】:2011-12-30 14:17:09
【问题描述】:

我正在尝试在 ASP.NET MVC 中做一些简单的事情:

RouteValuesDictionary routeValues = GetMyRouteData();
var url = new UrlHelper(Html.ViewContext.RequestContext);
return url.RouteUrl(routeValues);

问题是无论我做什么,url 都包含来自当前请求上下文的路由数据。我想仅基于来自GetMyRouteData() 的路由值生成一个 URL。

谢谢

【问题讨论】:

  • 这段代码是什么上下文(控制器?)?
  • 只是一个观察:不同的路由可能包含相同的标记,并映射到相同的控制器操作,因此在任何情况下您都可能无法获得您正在寻找的 url(因为它们不一定独一无二)。

标签: asp.net-mvc asp.net-mvc-3 routes


【解决方案1】:

问题是不管我做什么,url都包含路由数据 从当前请求上下文中

这是设计使然。您必须将原始请求中存在且您不希望在结果 url 中的路由值显式设置为 null:

    var routeValues = GetMyRouteData();
    // remove values that you want to exclude from the resulting url
    // by setting their values to null
    routeValues["id"] = null;
    var url = new UrlHelper(Html.ViewContext.RequestContext);
    return url.RouteUrl(routeValues);

【讨论】:

  • @Paul,太好了,那么你做对了。你还有什么需要知道的吗?
  • 就像在这个例子中一样,routeValues 不包含 ID(它已被删除),但由于它是当前路由的一部分,它会包含在返回的 URL 中。
  • @Paul,是的,这很正常。这就是 ASP.NET MVC 团队设计的诸如 RouteUrl 之类的 url 助手的方式。所以我重复我的问题:还有什么你需要知道的吗?
  • 只是......原来的问题!我知道它从当前上下文中提取路由信息,我正在查看描述优先顺序的 MSDN 文档。这就是我问这个问题的原因,只是想找一个简单的方法来解决它。
  • @Paul,绕过它的方法是手动从 RouteValueDictionary 集合中删除路由值,否则助手会使用请求中的原始值。我已经回答了您的问题:您有两种可能性:编写您自己的自定义 Url 助手,它的行为如您所愿,不要使用 RouteUrl 助手,因为它就是这样设计的,或者删除您不使用的值想要从你传递给它的论点。有什么不清楚的地方吗?看起来很简单。
【解决方案2】:

这不是特定于 ASP.NET MVC,而是由于 ASP.NET Routing 的路由解析。这个入口点是RouteCollection.GetVirtualPath,它有两个签名。

第一个采用RequestContextRouteValueDictionary。这用于默认路由解析,它依赖于模式匹配来查找路由。路线搜索包含来自RequestContextRouteValueDictionary 的所有标记;换句话说,将两组路由标记组合起来形成路由搜索的基础。存在一种特殊情况,即RouteValueDictionary 中的空参数从搜索中删除该参数。但是,如果此类空值参数在RequestContext 中有值,则该值仍将作为查询字符串值出现在生成的 URL 中。

另一个签名还接受一个路由名称。这有点奇怪,因为它改变了路由解析以及查询字符串的创建。显然,使用名称解析可以找到路线。找到命名路由后,只有在路由的 URL 模式中指定的那些参数的标记才会出现在生成的 URL 中。

为什么会这样?这是 ASP.NET MVC 对 Ruby on Rails 的参数处理约定的解释。

所以默认路由解析和“回退”令牌解析是混合的。如果您不希望令牌回退到 RequestContext,(并且您仍想使用 ASP.NET 路由),则必须使用命名路由解析。

【讨论】:

    【解决方案3】:

    这可能有助于澄清。使用源,卢克!

    RouteUrl 助手调用这个静态方法来生成 URL:

    public static string GenerateUrl(string routeName, string actionName, string controllerName, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, bool includeImplicitMvcValues) {
            if (routeCollection == null) {
                throw new ArgumentNullException("routeCollection");
            }
    
            if (requestContext == null) {
                throw new ArgumentNullException("requestContext");
            }
    
            RouteValueDictionary mergedRouteValues = RouteValuesHelpers.MergeRouteValues(actionName, controllerName, requestContext.RouteData.Values, routeValues, includeImplicitMvcValues);
    
            VirtualPathData vpd = routeCollection.GetVirtualPathForArea(requestContext, routeName, mergedRouteValues);
            if (vpd == null) {
                return null;
            }
    
            string modifiedUrl = PathHelpers.GenerateClientUrl(requestContext.HttpContext, vpd.VirtualPath);
            return modifiedUrl;
    }
    

    注意这一行:

    RouteValueDictionary mergedRouteValues = RouteValuesHelpers.MergeRouteValues(actionName, controllerName, requestContext.RouteData.Values, routeValues, includeImplicitMvcValues);
    

    这是在幕后合并当前 requestcontext 值。因此,您可以创建自己的助手,只调用此静态方法并传递空集合以避免合并当前路由上下文值。在 MVC 代码中进行试验和调试,您应该能够看到需要哪些值核弹。

    【讨论】:

    • RouteValuesHelpers.MergeRouteValues 被标记为内部,不幸的是。
    • 太棒了。不确定这在旧 MVC 版本中是否有所不同,或者我只是错过了它。该方法是公共的,但它挂起的静态类是内部的。源代码是开放的,因此如果没有公共替代方案,您可以挑选一些代码来做您想做的事情。顺便说一句,正在讨论 MergeRouteValues 的代码在这个文件中:aspnetwebstack.codeplex.com/SourceControl/changeset/view/…
    • 是的。将他们的代码复制到我的代码库中的缺点是,如果 ASP.NET MVC 中的内容在以后的版本中发生变化,我没有测试覆盖率或保护。
    • 这是错误RouteValuesHelpers.MergeRouteValues 中的“合并”仅指“必需”值:“动作”和“控制器”。当前请求路由值的使用发生在 ASP.NET Routing 的虚拟路径解析中,在对RouteCollection.GetVirtualPath(RequestContext, RouteValueDictionary) 的更深层次调用中。
    猜你喜欢
    • 2013-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-17
    • 2012-02-03
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    相关资源
    最近更新 更多