MvcSiteMapProvider如何使节点与当前url匹配

时间:2016-10-24 21:17:30

标签: mvcsitemapprovider

当前节点出现空值。在这种情况下,我无法弄清楚如何让MvcSiteMapProvider解析节点。

这是匹配所需的节点

<mvcSiteMapNode title="Policy" route="Details" typeName="Biz.ABC.ShampooMax.Policy" preservedRouteParameters="id" />

这是路线:

routes.MapRoute(
   "Details",
   "Details/{id}",
   new { Controller = "Object", Action = "Details" }
   ).RouteHandler = new ObjectRouteHandler();

点击的链接:

http://localhost:36695/MyGreatWebSite/Details/121534455762071

这是正确的路线。只有MvcSiteMapProvider.SiteMaps.Current.CurrentNode为空。

2 个答案:

答案 0 :(得分:2)

null的{​​{1}}结果表示传入请求与CurrentNode中的任何节点都不匹配。在您的情况下,有4个不同的问题可能导致此问题:

  1. 您输入的网址SiteMap不一定(必然)与您在路线http://localhost:36695/MyGreatWebSite/Details/121534455762071中指定的网址格式相匹配。如果您的站点作为"Details/{id}"下的IIS应用程序托管,则可能。
  2. 您的IISROOT/MyGreatWebSite/未指定匹配的mvcSiteMapNodecontrolleraction仅作为额外的标准(意味着在匹配中仅考虑命名的路线),但是还需要提供所有参数以便与路线匹配。 / LI>
  3. 您正在传递自定义route,这可能会改变路线与网址的匹配方式。如果没有看到RouteHandler中的代码,就无法判断这是否或如何影响路径与网址的匹配。
  4. 您的ObjectRouteHandler配置中有自定义属性typeName。除非您已指定ignore this attribute,否则网址中也需要匹配,即mvcSiteMapNode
  5. 我建议不要使用自定义http://localhost:36695/MyGreatWebSite/Details/121534455762071?typeName=Biz.ABC.ShampooMax.Policy来匹配网址。这样做的效果使您的传入路由(URL到MVC)的行为与传出路由(生成链接到其他页面的URL)不同。由于RouteHandler使用路由的两个部分,如果您只更改传入路由而不更改要匹配的传出路由,则会导致URL生成问题。相反,我建议您使用子类MvcSiteMapProvider,您可以在其中控制路线的两侧。有关自定义RouteBase子类的示例,请参阅this answer

    但是,请注意,传统路由非常强大,您可能不需要为此简单方案创建RouteBase子类。

答案 1 :(得分:0)

解决方案

我通过将mvc站点地图提供程序项目添加到我自己的解决方案中并逐步完成mvc站点地图提供程序代码来查看我的节点未匹配的原因。必须改变一些事情。我通过执行以下操作来修复它:

<强> Mvc.sitemap

<mvcSiteMapNode title="Policy" controller="Object" action="Details" typeName="Biz.ABC.ShampootMax.Policy" preservedRouteParameters="id" roles="*"/>

<强> RouteConfig.cs

  routes.MapRoute(
      name: "Details",
      url: "details/{id}",
      defaults: new { controller = "Object", action = "Details", typeName = "*" }
  ).RouteHandler = new ObjectRouteHandler();

现在起初它不想像这样工作,但我像这样修改了提供者:

RouteValueDictionary.cs (添加了通配符以匹配值)

    protected virtual bool MatchesValue(string key, object value)
    {
        return this[key].ToString().Equals(value.ToString(), StringComparison.OrdinalIgnoreCase) || value.ToString() == "*";
    }

SiteMapNode.cs (已更改requestContext.RouteData.Values

/// <summary>
/// Sets the preserved route parameters of the current request to the routeValues collection.
/// </summary>
/// <remarks>
/// This method relies on the fact that the route value collection is request cached. The
/// values written are for the current request only, after which they will be discarded.
/// </remarks>
protected virtual void PreserveRouteParameters()
{
  if (this.PreservedRouteParameters.Count > 0)
  {
    var requestContext = this.mvcContextFactory.CreateRequestContext();
    var routeDataValues = requestContext.HttpContext.Request.RequestContext.RouteData.Values;// requestContext.RouteData.Values;

我认为第二次修改并不是绝对必要的,因为我的请求上下文没有被缓存;如果是的话它会起作用。我不知道如何缓存它。

这是第一个使路由值符合使其工作的通配符(*)的修改。这似乎是一个黑客,也许有一个内置的方式。

注意

使用以下命令忽略typeName属性:

<强>的web.config

<add key="MvcSiteMapProvider_AttributesToIgnore" value="typeName" />

使另一个节点中断:

<强> Mvc.sitemap

<mvcSiteMapNode title="Policies" url="~/Home/Products/HarvestMAX/Policy/List" productType="HarvestMax" type="P" typeName="AACOBusinessModel.AACO.HarvestMax.Policy" roles="*">

这就是我不这样做的原因。