[转载]ASP.NET MVC 路由规则XML化 - 汤家大院 - 博客园

[转载]ASP.NET MVC 路由规则XML化 – 汤家大院 – 博客园.

很久没写文章了,不是懒得写,是写不出。。

最近由于工作关系,重新回顾了ASP.NET MVC 的 1.0 版本。2.0版本还没有研究。

由于MVC框架发展不久,还有很多不足的地方。其中关于路由规则配置这一块问题比较大。首先路由规则是在全局配置问价 Global.asax 的 Application_Start()事件中注册的。

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>
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 }

代码下载地址

/tandly/MvcRouteHelper.rar

苏州 晴

汤晓华 QQ 1881597 MSN tension1990@hotmail.com

2010 03 10

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏