2015-09-09 151 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(); 
} 

當我打的網址我總是得到空的類別參數

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

我得到這個錯誤

Object reference not set to an instance of an object

我怎樣才能解決這個問題。我需要從段中提取ID並使用它。同樣我也需要處理製造商和屬性字符串。

一件事

我怎樣才能讓我的功能得到至少一個參數,無論順序?我的意思是我想製作這樣的功能,我可以處理類別或製造商或屬性或類別+製造商和所有組合/

+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模式匹配:當您使用以下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} 

現在:

Home/CategoryProducts/category/c_50_ShowcasesDisplays 

行動將調用HomeController上的。您的類別參數值將爲c_50_ShowcasesDisplays

它也將在您使用ActionLinkRouteLinkUrl.Action,或UrlHelper建立相應的URL。

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

// Generates URL /Home/CategoryProducts/category/c_50_ShowcasesDisplays