【问题标题】:Why is Mvc SiteMapProvider preservedRouteParameter case sensitive?为什么 Mvc SiteMapProvider reservedRouteParameter 区分大小写?
【发布时间】:2015-01-27 14:13:45
【问题描述】:

目前,我尝试了 MvcSiteMapProvider.MVC5 4.6.17 来生成面包屑。当我定义 reservedRouteParameters="id" (是的,在路由配置中它是 {id} 部分)时效果很好,但是当我将其更改为 reservedRouteParameters="Id" - url与该节点不匹配。

有什么理由让它区分大小写吗?有没有简单的方法绕过它?

背景:在“id”的情况下,用户不能在 url 中输入文字 'Id' 并不重要。但是我推出了一种使用查询字符串参数的方法,但问题是查询字符串值 name 必须遵循 xml 配置中定义的精确大小写,否则它与节点不匹配。

【问题讨论】:

  • 仅供参考 - 此问题现已在 v4.6.18 中修复,可在 NuGet 上使用。
  • 谢谢,它有效。并且 url 是使用 mvc.sitemap 文件中的一个大小写生成的。

标签: asp.net-mvc breadcrumbs mvcsitemapprovider


【解决方案1】:

如果有人想知道我是如何解决这个问题的。

第一件事是通过这样做扩展默认的 SiteMapNode(2 个更改是添加 ToLower()):

public class CustomSiteMapNode : RequestCacheableSiteMapNode
{
    public CustomSiteMapNode(ISiteMap siteMap, string key, bool isDynamic, ISiteMapNodePluginProvider pluginProvider, IMvcContextFactory mvcContextFactory, ISiteMapNodeChildStateFactory siteMapNodeChildStateFactory, ILocalizationService localizationService, IUrlPath urlPath) :
        base(siteMap, key, isDynamic, pluginProvider, mvcContextFactory, siteMapNodeChildStateFactory, localizationService, urlPath)
    {
    }

    protected override void PreserveRouteParameters()
    {
        if (this.PreservedRouteParameters.Count > 0)
        {
            var requestContext = this.mvcContextFactory.CreateRequestContext();
            var routeDataValues = requestContext.RouteData.Values;
            var queryStringValues = requestContext.HttpContext.Request.QueryString;

            foreach (var item in this.PreservedRouteParameters)
            {
                var preservedParameterName = item.Trim().ToLower();
                if (!string.IsNullOrEmpty(preservedParameterName))
                {
                    if (routeDataValues.ContainsKey(preservedParameterName))
                    {
                        this.routeValues[preservedParameterName] =
                            routeDataValues[preservedParameterName];
                    }
                    else if (queryStringValues[preservedParameterName] != null)
                    {
                        this.routeValues[preservedParameterName] =
                            queryStringValues[preservedParameterName];
                    }
                }
            }
        }
    }

    protected override IDictionary<string, object> MergeRouteValuesAndNamedQueryStringValues(IDictionary<string, object> routeValues, ICollection<string> queryStringKeys, HttpContextBase httpContext)
    {
        // Make a copy of the routeValues. We only want to limit this to the scope of the current node.
        var result = new Dictionary<string, object>(routeValues);

        // Add any query string values from the current context
        var queryStringValues = httpContext.Request.QueryString;

        // QueryString collection might contain nullable keys
        foreach (var key in queryStringValues.AllKeys.Select(x => x.ToLower()).ToList())
        {
            // Copy the query string value as a route value if it doesn't already exist
            // and the name is provided as a match. Note that route values will take
            // precedence over query string parameters in cases of duplicates
            // (unless the route value contains an empty value, then overwrite).
            if (key != null && queryStringKeys.Contains(key) && (!result.ContainsKey(key) || string.IsNullOrEmpty(result[key].ToString())))
            {
                result[key] = queryStringValues[key];
            }
        }

        return result;
    }
}

下一个问题是用这个替换默认实现。我能遇到的唯一解决方案是继承工厂/容器链并最终将其绑定在 ninject 中。

public class CustomSiteMapNodeFactory : ISiteMapNodeFactory
public class CustomSiteMapNodeFactoryContainer
internal class CustomSiteMapLoaderContainer

var configSettings = new ConfigurationSettings();
MvcSiteMapProvider.SiteMaps.Loader = new CustomSiteMapLoaderContainer(configSettings).ResolveSiteMapLoader();

最后是我用来从模型中提取属性值并将它们传递给父站点地图节点的属性。

public class SiteMapRouteValueAttribute : ActionFilterAttribute
{
    private readonly string _key;
    private readonly string[] _propertyParts;

    public SiteMapRouteValueAttribute(string key, string modelProperty = "")
    {
        _key = key.ToLower();
        _propertyParts = modelProperty.Split(new[] {'.'}, StringSplitOptions.RemoveEmptyEntries);
    }

    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        var viewResult = filterContext.Result as ViewResult;
        if (viewResult == null)
        {
            base.OnResultExecuting(filterContext);
            return;
        }
        var value = viewResult.Model;
        foreach (var property in _propertyParts)
        {
            var propertyInfo = value.GetType().GetProperty(property);
            value = propertyInfo.GetValue(value);
        }
        var currentNode = SiteMaps.Current.CurrentNode;
        while (currentNode != null)
        {
            currentNode.RouteValues[_key] = value;
            currentNode = currentNode.ParentNode;
        }
    }
}

所以现在它可以解释为什么任何情况下的查询字符串值名称,但是 siteMap 生成的 url 将包含小写的查询字符串值名称。

【讨论】:

  • 谢谢,我将其添加为a bug。但是,我将使用的解决方案是添加一个属性,该属性根据 PreservedRouteParameters 更正requestContext.HttpContext.Request.QueryStringNameValueCollection 中的值的大小写。然后PreserveRouteParameters() 和“MergeRouteValuesAndNamedQueryStringValues()”将使用此属性将大小写从原始 URL 更改为配置的内容。那么就不需要动作过滤器属性了。
猜你喜欢
  • 2011-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-28
  • 2011-11-14
  • 2013-10-31
  • 2013-11-07
相关资源
最近更新 更多