2015-01-27 4 views
0

В настоящее время я попробовал MvcSiteMapProvider.MVC5 4.6.17 для создания панировочных сухарей. Он хорошо работает, когда я определяю сохраненныеRouteParameters = «id» (да, в конфигурации маршрута это часть {id}), но когда я меняю его на сохраненныйRouteParameters = "Id" - url не соответствует этому узлу.Почему Mvc SiteMapProvider сохраненRouteParameter чувствителен к регистру?

Есть ли причина, почему он чувствителен к регистру? Есть ли простой способ обойти это?

Фон: в случае «id» это не имеет значения, так как пользователь не может ввести буквальный «Id» в url. Но я выбрал способ использования параметров запроса, но проблема в том, что значение querystring имя должно соответствовать точной оболочке, которая определена в xml-конфигурации, иначе она не соответствует узлу.

+0

FYI - эта проблема исправлена ​​в [v4.6.18] (https://github.com/maartenba/MvcSiteMapProvider/releases/tag/v4.6.18), которая доступна на NuGet. – NightOwl888

+0

Спасибо, это работает. И url генерируется с помощью оболочки из файла mvc.sitemap. –

ответ

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; 
     } 
    } 
} 

Так что теперь он работает, почему любой случай строк запроса имен значений, однако генерироваться Картой сайта URL будет содержать строчные имена значений строки запроса.

+0

Спасибо, я добавил это как [ошибка] (https://github.com/maartenba/MvcSiteMapProvider/issues/380). Тем не менее, решение, которое я хотел бы использовать, было бы добавить свойство, которое исправляет оболочку значений в 'requestContext.HttpContext.Request.QueryString' NameValueCollection на основе PreservedRouteParameters. Это свойство затем будет использоваться как «PreserveRouteParameters()», так и «MergeRouteValuesAndNamedQueryStringValues ​​()», чтобы изменить оболочку с необработанного URL на то, что настроено. Тогда не требуется атрибут фильтра действий. – NightOwl888

Смежные вопросы