你的位置:首页 > ASP.net教程

[ASP.net教程]MVC路由配置为何如此麻烦


 


首先我用MVC4新增一个订单查看的功能


1.创建控制器OrderController

namespace MvcApplication3.Controllers{  public class OrderController : Controller  {    public ActionResult OrderView()    {      return View();    }  }}

 

2.创建视图 OrderView

@{  ViewBag.Title = "OrderView";}<h2>OrderView</h2>

 

3.Global配置路由

 public static void RegisterRoutes(RouteCollection routes)    {      routes.IgnoreRoute("{resource}.axd/{*pathInfo}");      routes.MapRoute(       "OrderView",        "Order/OrderView.html",       new { controller = "Order", action = "OrderView" },       new string[] { "MvcApplication3" }       );    }

 

 

我们在做MVC项目时,每次我们新增功能时,都要在golbal文件里注册下该视图的路由,当项目有10个,100个功能,那我们不配置死,而且都在一个文件里global里修改配置,维护起来非常费劲,有没有好的办法来解决这个问题尼,不用再修改global文件,就可自由的配置路由地址。

让我们接下来一步步分析

首先我们看MVC路由类RouteCollection的扩展方法 MapRoute 的参数属性

    //    // 摘要:    //   Maps the specified URL route and sets default route values and namespaces.    //    // 参数:    //  routes:    //   A collection of routes for the application.    //    //  name:    //   The name of the route to map.    //    //  url:    //   The URL pattern for the route.    //    //  defaults:    //   An object that contains default route values.    //    //  namespaces:    //   A set of namespaces for the application.    //    // 返回结果:    //   A reference to the mapped route.    //    // 异常:    //  System.ArgumentNullException:    //   The routes or url parameter is null.    public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, string[] namespaces);

 

再看下我们在Golbal里调用此方法

routes.MapRoute(       "OrderView", --对应name       "Order/OrderView.html", --对应url       new { controller = "Order", action = "OrderView" }, --对应object       new string[] { "MvcApplication3" } --对应namespaces       );

看第三个参数 defaults 它包含了路由的Controller名称,Action名称,第四个参数namespaces表示这个Controller所在的命名空间,我们看看我们之前新建的控制器OrderController它的类型是class,而它下面的Action是一个返回类型是ActionResult的方法,再想到命名空间,由此我们是否可以利用反射技术来来循环读取当前应用程序下所有Controller,每个Controller的所有方法Action以及每个Controller所在命名空间

下面我们写下面一段伪代码来分析我们的思路:

 var 控制器类集合=读取当前所有控制器类(); foreach (var 控制器 in 控制器类集合) {    var action方法数组=获取控制器所有Action方法();    var namespance=获取当前控制器所在命名空间;    var controllerName=获取控制器名称();    foreach(var action in action方法数组)    {      var actionName=获取action名称();         var routerUrl="Order/OrderView.html";           //注册      routes.MapRoute(         actionName,          routerUrl,         new { controller =controllerName, action = actionName },         new string[] { namespance }         );    } } 

 

这段伪代码算是解决我们今天讲的主题问题的一部分,为什么尼,因为第二个参数url 我们无法识别或知道每个Controller路由的地址,这样问题还没有解决,我们继续苦逼的维护这我们的golbal路由文件,新增一个功能,来加个配置,如果每个Controller有个属性URL,我们可以设置这个属性,那问题不就解决了嘛,那如何给Controller添加属性尼,这里我们可以利用到C# 特性 Attribute

关于特性MSDN给的定义: 

特性提供功能强大的方法,用以将元数据或声明信息与代码(程序集、类型、方法、属性等)相关联。特性与程序实体关联后,即可在运行时使用名为“反射”的技术查询特性。

特性具有以下属性:

  • 特性可向程序中添加元数据。元数据是有关在程序中定义的类型的信息。所有的 .NET 程序集都包含指定的一组元数据,这些元数据描述在程序集中定义的类型和类型成员。可以添加自定义特性,以指定所需的任何附加信息。。

  • 可以将一个或多个特性应用到整个程序集、模块或较小的程序元素(如类和属性)。

  • 特性可以与方法和属性相同的方式接受参数。

  • 程序可以使用反射检查自己的元数据或其他程序内的元数据。有关更多信息。

所以我们定义一个特性类

 

 [AttributeUsage(AttributeTargets.All, Inherited = true)]  public class RouteAddressAttribute : Attribute  {    public RouteAddressAttribute()     { }    public RouteAddressAttribute(string name, string address)    {      this.Name = name;      this.Address = address;    }    /// <summary>    /// 地址 【正是我们想要的URL】    /// </summary>    public string Address { get; set; }    /// <summary>    /// 名称    /// </summary>    public string Name { get; set; }  }

定义了特性类,看我们怎么用它,此时我们再看我的Controller

namespace MvcApplication3.Controllers{  public class OrderController : Controller  {    [RouteAddress(Name = "订单查看", Address = "Order/OrderView.html")]    public ActionResult OrderView()    {      return View();    }  }}

再把我们之前的伪代码编程成真实代码,代码实现如下

namespace MvcApplication3{  public class RouteMap  {    public static void Redirection(RouteCollection routes, string assemblyName)    {      Assembly assembly = Assembly.Load(assemblyName);      Type[] types = assembly.GetTypes();      List<string> ListAdress = new List<string>();      foreach (Type type in types)      {        #region 读取所有Controller        if (type.Name.Contains("Controller"))        {          string nameSpace = type.Namespace;          string controller = type.Name.Replace("Controller", "");          MemberInfo[] memberInfos = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);          #region 读取每个Controller的Action          foreach (var item in memberInfos)          {            var objAttr = item.GetCustomAttributes(typeof(RouteAddressAttribute), false);            if (objAttr != null && objAttr.Length > 0)            {              //获取特性RouteAdress              RouteAddressAttribute temp = (RouteAddressAttribute)objAttr.First();              if (temp != null)              {                string action = item.Name;                string address = temp.Address;                string routeName = type.Name + action;                if (!ListAdress.Contains(address))                {                  //实现注册                  routes.MapRoute(routeName, address, new { controller = controller, action = action }, new string[] { nameSpace });                  ListAdress.Add(address);                }                else                  throw new Exception("存在相同路由地址:" + address);              }            }          }           #endregion        }         #endregion      }    }   }}

 

这样Golbal文件里我们添加一行代码就行了。

 public static void RegisterRoutes(RouteCollection routes)    {      routes.IgnoreRoute("{resource}.axd/{*pathInfo}");      //调用      RouteMap.Redirection(routes, "MvcApplication3");    }

 

综上所述,利用特性,利用反射,解决了开发人员繁琐的路由配置工作。

关于特性和反射技术,大家可以看下MSDN,本文不做详细介绍。