为什么Mvc SiteMapProvider保留了RouteParameter区分大小写?

时间:2015-01-27 14:13:46

标签: asp.net-mvc breadcrumbs mvcsitemapprovider

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

有什么理由说它区分大小写吗?是否有一种简单的方法来解决它?

背景:在" id"情况并不重要,因为用户无法输入文字“Id'进入网址。但是我推出了一种使用查询字符串参数的方法,但问题是查询字符串值名称必须遵循在xml配置中定义的确切大小写,否则它不匹配节点。

1 个答案:

答案 0 :(得分:0)

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

首先要做的是扩展默认的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将包含小写的查询字符串值名称。