由于MVC框架发展不久,还有很多不足的地方。其中关于路由规则配置这一块问题比较大。首先路由规则是在全局配置问价 Global.asax 的 Application_Start()事件中注册的。(文/
tandly)
- 01 public static void RegisterRoutes(RouteCollection routes)
- 02 {
- 03 routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
- 04
- 05 routes.MapRoute(
- 06 "User", // Route name
- 07 "{controller}/{action}/{id}", // URL with parameters
- 08 new { controller = "User", action = "Show", id = "0" } // Parameter defaults
- 09 );
- 10 }
- 11
- 12 protected void Application_Start()
- 13 {
- 14
- 15 RegisterRoutes(RouteTable.Routes);
- 16
- 17 }
复制代码默认硬编码的方式使得以后可维护程度大大降低。MVC 1.0 似乎没有提供很好的基于配置文件的路由规则设置。所以只好自己实现了。直到写这篇文章时,才找到了一个比较好的解决方案。
以下是 自定义的XML 格式
- 1 <?xml version="1.0" encoding="utf-8" ?>
- 2 <MapRoutes>
- view source
- print?
- 01 <!--默认规则-->
- 02 <MapRoute name="Default" url="{controller}/{action}">
- 03 <Params>
- 04 <Item key="controller" default="Article"/>
- 05 <Item key="action" default="Index"/>
- 06 </Params>
- 07 </MapRoute>
- 08
- 09 <!--显示新闻列表的路由规则 -->
- 10 <MapRoute name="ShowArticleList" url="{controller}/{action}/{typeId}/{pageIndex}/{pageSize}">
- 11 <Params>
- 12 <Item key="controller" default="Article"/>
- 13 <Item key="action" default="Index"/>
- 14 <Item key="typeId" default="1"/>
- 15 <Item key="pageIndex" default="1"/>
- 16 <Item key="pageSize" default="10"/>
- 17 </Params>
- 18 </MapRoute>
- 19
- 20 </MapRoutes>
复制代码以下是全部代码
- 001 /* ***********************************************
- 002 * 作者 :汤晓华/tension 任何转载请务必保留此头部信息 版权所有 盗版必究
- 003 * Email:tension1990@hotmail.com
- 004 * 描述 :
- 005 * 创建时间:2010-3-9 15:17:26
- 006 * 修改历史:
- 007 * ***********************************************/
- 008 using System;
- 009 using System.Collections.Generic;
- 010 using System.Linq;
- 011 using System.Text;
- 012 using System.Web.Routing;
- 013 using System.Web.Mvc;
- 014 using System.Xml.Linq;
- 015 using Microsoft.CSharp;
- 016 using System.CodeDom.Compiler;
- 017
- 018 namespace Tension.Mvc
- 019 {
- 020 public static class RouteHelper
- 021 {
- 022 /// <summary>
- 023 /// 从XML文件中注册路由规则
- 024 /// </summary>
- 025 /// <param name="routes"></param>
- 026 /// <param name="cfgFile"></param>
- 027 public static void Register(this RouteCollection routes, string cfgFile)
- 028 {
- 029
- 030 IList<Route> Routes = GetRoutes(cfgFile);
- 031
- 032 foreach (var item in Routes)
- 033 {
- 034 //路由规则对象
- 035 object obj = CreateObjectFormString(item.ToString(), item.Name);
- 036 routes.MapRoute(
- 037 item.Name, // Route name
- 038 item.Url, // URL with parameters
- 039 obj // Parameter defaults
- 040 );
- 041
- 042 }
- 043 }
- 044
- 045 /// <summary>
- 046 /// 从XML文件中注册路由规则 默认文件为网站根目录下MapRoute.config
- 047 /// </summary>
- 048 /// <param name="routes"></param>
- 049 public static void Register(this RouteCollection routes)
- 050 {
- 051 Register(routes, string.Format("{0}\\MapRoute.config", Tension.ServerInfo.GetRootPath()));
- 052 }
- 053
- 054
- 055 /// <summary>
- 056 /// 从string动态创建类对象
- 057 /// </summary>
- 058 /// <param name="codeString"></param>
- 059 /// <param name="className"></param>
- 060 /// <returns></returns>
- 061 private static object CreateObjectFormString(string codeString, string className)
- 062 {
- 063 CSharpCodeProvider ccp = new CSharpCodeProvider();
- 064 CompilerParameters param = new CompilerParameters(new string[] { "System.dll" });
- 065 CompilerResults cr = ccp.CompileAssemblyFromSource(param, codeString);
- 066 Type type = cr.CompiledAssembly.GetType(className);
- 067 return type.GetConstructor(System.Type.EmptyTypes).Invoke(null);
- 068 }
- 069
- 070 /// <summary>
- 071 /// 从XML文件中解析路由规则
- 072 /// </summary>
- 073 /// <param name="configFile"></param>
- 074 /// <returns></returns>
- 075 private static IList<Route> GetRoutes(string configFile)
- 076 {
- 077 StringBuilder sb = new StringBuilder();
- 078
- 079
- 080 Console.WriteLine(sb.ToString());
- 081 IList<Route> Routes = new List<Route>();
- 082
- 083 XElement xe = XElement.Load(configFile);
- 084
- 085 #region MyRegion
- 086 foreach (var item in xe.Elements("MapRoute"))
- 087 {
- 088
- 089 //名称属性
- 090 XAttribute xaName = item.Attribute("name");
- 091 if (xaName == null || string.IsNullOrEmpty(xaName.Value))
- 092 {
- 093 throw new ArgumentNullException("name!说明:路由配置文件中某规则缺少name属性或name属性的值为空字符串");
- 094 }
- 095
- 096 //URL 属性
- 097 XAttribute urlName = item.Attribute("url");
- 098 if (urlName == null || string.IsNullOrEmpty(urlName.Value))
- 099 {
- 100 throw new ArgumentNullException("url!说明:路由配置文件中某规则缺少url属性或url属性的值为空字符串");
- 101 }
- 102
- 103
- 104 Dictionary<string, string> DictParams = new Dictionary<string, string>();
- 105
- 106
- 107
- 108 #region MyRegion
- 109 foreach (var pItem in item.Element("Params").Elements("Item"))
- 110 {
- 111 XAttribute itemKey = pItem.Attribute("key");
- 112 if (itemKey == null || string.IsNullOrEmpty(itemKey.Value))
- 113 {
- 114 throw new ArgumentNullException("Item->key!说明:路由配置文件中某规则缺少Item->key属性或 Item->key属性的值为空字符串");
- 115 }
- 116
- 117 XAttribute itemDefault = pItem.Attribute("default");
- 118 if (itemDefault == null || string.IsNullOrEmpty(itemDefault.Value))
- 119 {
- 120 throw new ArgumentNullException("Item->default!说明:路由配置文件中某规则缺少Item->default属性或Item->default属性的值为空字符串");
- 121 }
- 122 DictParams.Add(itemKey.Value, itemDefault.Value);
- 123 }
- 124 #endregion
- 125
- 126 Routes.Add(new Route() { Name = xaName.Value, Url = urlName.Value, Params = DictParams });
- 127
- 128
- 129 }
- 130 #endregion
- 131
- 132 return Routes;
- 133 }
- 134 }
- 135
- 136
- 137 /// <summary>
- 138 /// 路由规则
- 139 /// </summary>
- 140 public class Route
- 141 {
- 142 public string Name { get; set; }
- 143 public string Url { get; set; }
- 144 public Dictionary<string, string> Params { get; set; }
- 145
- 146 /// <summary>
- 147 /// 重写ToString 方法 产生需要动态代码段
- 148 /// </summary>
- 149 /// <returns></returns>
- 150 public override string ToString()
- 151 {
- 152 StringBuilder sb = new StringBuilder();
- 153 sb.AppendFormat("public class {0}", Name);
- 154 sb.Append("{");
- 155 foreach (var item in Params)
- 156 {
- 157 sb.AppendFormat("public string {0}", item.Key);
- 158 sb.Append("{get{return \"");
- 159 sb.Append(item.Value);
- 160 sb.Append("\";}} ");
- 161 }
- 162
- 163 sb.Append("}");
- 164 return sb.ToString();
- 165 }
- 166 }
- 167 }
复制代码在实现过程中遇到的最大问题就是 参数列表的动态装载 看一下以下代码
- 1 routes.MapRoute(
- 2 "User", // Route name
- 3 "{controller}/{action}/{id}", // URL with parameters
- 4 new { controller = "User", action = "Show", id = "0" } // Parameter defaults
- 5 );
复制代码这是硬编码实现的路由规则注册
其中 第三个参数(new { controller = "User", action = "Show", id = "0" } ) 是一个匿名对象
该对象如何动态构建成了难题。(才疏学浅)
尝试着传入一个 Dictionary<K,T> 但是没有用,ASP.NET 解析这个参数的时候是以反射形式读取的对象属性。
后来想到了使用代码段 在运行时动态创建对象。
我们将类似代码段
- 1 public class Default{public string controller{get{return "Article";}} public str
- 2 ing action{get{return "Index";}} public string id{get{return "0";}} public strin
- 3 g page{get{return "1";}} public string size{get{return "10";}} }
复制代码传入方法
- 1 private static object CreateObjectFormString(string codeString, string className)
- 2 {
- 3 CSharpCodeProvider ccp = new CSharpCodeProvider();
- 4 CompilerParameters param = new CompilerParameters(new string[] { "System.dll" });
- 5 CompilerResults cr = ccp.CompileAssemblyFromSource(param, codeString);
- 6 Type type = cr.CompiledAssembly.GetType(className);
- 7 return type.GetConstructor(System.Type.EmptyTypes).Invoke(null);
- 8 }
复制代码即可有运行时动态的创建我们需要的参数对象。
以后就可以方便的在XML注册路由了。
public static void Register(this RouteCollection routes) 对 RouteCollection 对象添加了扩展方法
引入对应的命名空间后就方便的注册了。
改进后的注册方法
- 01 public static void RegisterRoutes(RouteCollection routes)
- 02 {
- 03 routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
- 04
- 05 }
- 06
- 07 protected void Application_Start()
- 08 {
- 09
- 10 RegisterRoutes(RouteTable.Routes);
- 11
- 12 //执行 RouteCollection的扩展方法 用来注册XML文件中的路由配置信息
- 13 RouteTable.Routes.Register();
- 14 }
复制代码 代码下载地址: