2015-09-09 2 views
2

Я новичок в ASP.Net MVC и столкнулся с проблемой. Вот.ASP.Net MVC Обработка сегментов с помощью маршрута

routes.MapRoute(
    "SearchResults",// Route name 
    "{controller}/{action}/{category}/{manufacturer}/{attribute}", 
    new { 
     controller = "Home", 
     action = "CategoryProducts", 
     category = UrlParameter.Optional, 
     manufacturer = UrlParameter.Optional, 
     attribute = UrlParameter.Optional 
    } 
); 

И вот мой метод управления.

public ActionResult CategoryProducts(string category, string manufacturer, string attribute) 
{ 
    string[] categoryParameter = category.Split('_'); 
    . 
    . 
    . 
    return View(); 
} 

, когда я ударил URL я всегда получить нуль в категории параметра

http://localhost:50877/Home/CategoryProducts/c_50_ShowcasesDisplays 

Я получаю эту ошибку

Object reference not set to an instance of an object

Как я могу исправить эту проблему. Мне нужно извлечь идентификатор из сегмента и использовать его. Точно так же мне нужно также обрабатывать строки производителя и атрибута.

Еще одна вещь

Как я могу сделать свою функцию получить по крайней мере один параметр, независимо от того? Я имею в виду, что я хочу выполнять такие функции, которые я могу использовать для категории или производителя или атрибутов или производителя категории +, и все комбинации/

+0

Только последний параметр может быть помечен как «UrlParameter.Optional» (иначе механизм маршрутизации не может совпадать с каким). Для того, чтобы ваша текущая реализация работала, вам нужно будет использовать http: // localhost: 50877/Home/CategoryProducts? Category = c_50_ShowcasesDisplays' –

+0

спасибо за ответ, но я хочу использовать сегмент вместо строки запроса –

+0

Тогда вы будете требуется несколько маршрутов и методов. –

ответ

4

Заполнитель (такой как {category}) действует как переменная - он может содержать любое значение. Структура должна быть в состоянии понять, что означают параметры в URL. Вы можете сделать это один из трех способов:

  1. Предоставлять их в определенном порядке, и для определенного числа сегментов
  2. поместить их в строке запроса, так что вы имеете имя пар/значение, чтобы определить, что они
  3. сделать ряд маршрутов с буквальным сегментов предоставить имена, чтобы определить, какие параметры

Вот пример опции # 3. Это немного связано с использованием параметров строки запроса, но это, безусловно, возможно, если вы предоставляете какой-то идентификатор для каждого сегмента маршрута.

IEnumerable Расширение

Это добавляет поддержку LINQ для возможности получить все возможные перестановки значений параметров.

using System; 
using System.Collections.Generic; 
using System.Linq; 

public static class IEnumerableExtensions 
{ 
    // Can be used to get all permutations at a certain level 
    // Source: http://stackoverflow.com/questions/127704/algorithm-to-return-all-combinations-of-k-elements-from-n#1898744 
    public static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<T> elements, int k) 
    { 
     return k == 0 ? new[] { new T[0] } : 
      elements.SelectMany((e, i) => 
      elements.Skip(i + 1).Combinations(k - 1).Select(c => (new[] { e }).Concat(c))); 
    } 

    // This one came from: http://stackoverflow.com/questions/774457/combination-generator-in-linq#12012418 
    private static IEnumerable<TSource> Prepend<TSource>(this IEnumerable<TSource> source, TSource item) 
    { 
     if (source == null) 
      throw new ArgumentNullException("source"); 

     yield return item; 

     foreach (var element in source) 
      yield return element; 
    } 

    public static IEnumerable<IEnumerable<TSource>> Permutations<TSource>(this IEnumerable<TSource> source) 
    { 
     if (source == null) 
      throw new ArgumentNullException("source"); 

     var list = source.ToList(); 

     if (list.Count > 1) 
      return from s in list 
        from p in Permutations(list.Take(list.IndexOf(s)).Concat(list.Skip(list.IndexOf(s) + 1))) 
        select p.Prepend(s); 

     return new[] { list }; 
    } 
} 

RouteCollection Расширение

Продолжим метод MapRoute расширения, добавив возможность добавить набор маршрутов, чтобы соответствовать всем возможным перестановкам URL.

using System; 
using System.Collections.Generic; 
using System.Web.Mvc; 
using System.Web.Routing; 

public static class RouteCollectionExtensions 
{ 
    public static void MapRoute(this RouteCollection routes, string url, object defaults, string[] namespaces, string[] optionalParameters) 
    { 
     MapRoute(routes, url, defaults, null, namespaces, optionalParameters); 
    } 

    public static void MapRoute(this RouteCollection routes, string url, object defaults, object constraints, string[] namespaces, string[] optionalParameters) 
    { 
     if (routes == null) 
     { 
      throw new ArgumentNullException("routes"); 
     } 
     if (url == null) 
     { 
      throw new ArgumentNullException("url"); 
     } 
     AddAllRoutePermutations(routes, url, defaults, constraints, namespaces, optionalParameters); 
    } 

    private static void AddAllRoutePermutations(RouteCollection routes, string url, object defaults, object constraints, string[] namespaces, string[] optionalParameters) 
    { 
     // Start with the longest routes, then add the shorter ones 
     for (int length = optionalParameters.Length; length > 0; length--) 
     { 
      foreach (var route in GetRoutePermutations(url, defaults, constraints, namespaces, optionalParameters, length)) 
      { 
       routes.Add(route); 
      } 
     } 
    } 

    private static IEnumerable<Route> GetRoutePermutations(string url, object defaults, object constraints, string[] namespaces, string[] optionalParameters, int length) 
    { 
     foreach (var combination in optionalParameters.Combinations(length)) 
     { 
      foreach (var permutation in combination.Permutations()) 
      { 
       yield return GenerateRoute(url, permutation, defaults, constraints, namespaces); 
      } 
     } 
    } 

    private static Route GenerateRoute(string url, IEnumerable<string> permutation, object defaults, object constraints, string[] namespaces) 
    { 
     var newUrl = GenerateUrlPattern(url, permutation); 
     var result = new Route(newUrl, new MvcRouteHandler()) 
     { 
      Defaults = CreateRouteValueDictionary(defaults), 
      Constraints = CreateRouteValueDictionary(constraints), 
      DataTokens = new RouteValueDictionary() 
     }; 
     if ((namespaces != null) && (namespaces.Length > 0)) 
     { 
      result.DataTokens["Namespaces"] = namespaces; 
     } 

     return result; 
    } 

    private static string GenerateUrlPattern(string url, IEnumerable<string> permutation) 
    { 
     string result = url; 
     foreach (string param in permutation) 
     { 
      result += "/" + param + "/{" + param + "}"; 
     } 

     System.Diagnostics.Debug.WriteLine(result); 

     return result; 
    } 

    private static RouteValueDictionary CreateRouteValueDictionary(object values) 
    { 
     IDictionary<string, object> dictionary = values as IDictionary<string, object>; 
     if (dictionary != null) 
     { 
      return new RouteValueDictionary(dictionary); 
     } 
     return new RouteValueDictionary(values); 
    } 
} 

Использование

public class RouteConfig 
{ 
    public static void RegisterRoutes(RouteCollection routes) 
    { 
     routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

     routes.MapRoute(
      url: "Home/CategoryProducts", 
      defaults: new { controller = "Home", action = "CategoryProducts" }, 
      namespaces: null, 
      optionalParameters: new string[] { "category", "manufacturer", "attribute" }); 

     routes.MapRoute(
      name: "Default", 
      url: "{controller}/{action}/{id}", 
      defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
     ); 
    } 
} 

Это добавляет полный набор маршрутов, чтобы соответствовать модели URL:

Home/CategoryProducts/category/{category}/manufacturer/{manufacturer}/attribute/{attribute} 
Home/CategoryProducts/category/{category}/attribute/{attribute}/manufacturer/{manufacturer} 
Home/CategoryProducts/manufacturer/{manufacturer}/category/{category}/attribute/{attribute} 
Home/CategoryProducts/manufacturer/{manufacturer}/attribute/{attribute}/category/{category} 
Home/CategoryProducts/attribute/{attribute}/category/{category}/manufacturer/{manufacturer} 
Home/CategoryProducts/attribute/{attribute}/manufacturer/{manufacturer}/category/{category} 
Home/CategoryProducts/category/{category}/manufacturer/{manufacturer} 
Home/CategoryProducts/manufacturer/{manufacturer}/category/{category} 
Home/CategoryProducts/category/{category}/attribute/{attribute} 
Home/CategoryProducts/attribute/{attribute}/category/{category} 
Home/CategoryProducts/manufacturer/{manufacturer}/attribute/{attribute} 
Home/CategoryProducts/attribute/{attribute}/manufacturer/{manufacturer} 
Home/CategoryProducts/category/{category} 
Home/CategoryProducts/manufacturer/{manufacturer} 
Home/CategoryProducts/attribute/{attribute} 

Теперь, когда вы используете следующий URL:

Home/CategoryProducts/category/c_50_ShowcasesDisplays 

Действие CategoryProducts на HomeController. Значение параметра вашей категории будет c_50_ShowcasesDisplays.

Он также будет строить соответствующий URL при использовании ActionLink, RouteLink, Url.Action или UrlHelper.

@Html.ActionLink("ShowcasesDisplays", "CategoryProducts", "Home", 
    new { category = "c_50_ShowcasesDisplays" }, null) 

// Generates URL /Home/CategoryProducts/category/c_50_ShowcasesDisplays 
Смежные вопросы