Если кто-то хочет знать, как я решил эту проблему.
Первое является расширенной 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;
}
}
}
Так что теперь он работает, почему любой случай строк запроса имен значений, однако генерироваться Картой сайта URL будет содержать строчные имена значений строки запроса.
FYI - эта проблема исправлена в [v4.6.18] (https://github.com/maartenba/MvcSiteMapProvider/releases/tag/v4.6.18), которая доступна на NuGet. – NightOwl888
Спасибо, это работает. И url генерируется с помощью оболочки из файла mvc.sitemap. –