ASP.Net MVC处理具有路由

时间:2015-09-09 09:47:52

标签: asp.net asp.net-mvc routes action asp.net-mvc-routing

我是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();
}

当我点击网址时,我总是在类别参数

中获取null
http://localhost:50877/Home/CategoryProducts/c_50_ShowcasesDisplays

我收到此错误

Object reference not set to an instance of an object

我该如何解决这个问题。我需要从段中提取id并使用它。同样,我也需要处理制造商和属性字符串。

还有一件事

如何使我的函数至少获得一个参数而不管顺序如何?我的意思是我想制作类似的功能,我可以处理类别或制造商或属性或类别+制造商和所有组合/

1 个答案:

答案 0 :(得分:4)

占位符(例如{category})的作用类似于变量 - 它可以包含任何值。框架必须能够理解URL中的参数含义。您可以通过以下三种方式之一完成此任务:

  1. 按特定顺序和特定数量的细分提供
  2. 将它们放在查询字符串中,这样就可以使用名称/值对来标识它们是什么
  3. 使用文字段制作一系列路线,以提供名称以识别参数
  4. 以下是选项#3的示例。与使用查询字符串参数相比,它有点涉及,但只要您为每个路段提供某种标识符,它肯定是可能的。

    IEnumerable Extensions

    这增加了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 Extensions

    我们扩展了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 }
            );
        }
    }
    

    这会添加一组完整的路由以匹配网址格式:

    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
    

    将调用CategoryProducts上的操作HomeController。您的类别参数值将为c_50_ShowcasesDisplays

    当您使用ActionLinkRouteLinkUrl.ActionUrlHelper时,它还会构建相应的网址。

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