ASP.NET MVC 路由规则XML化
很久没写文章了,不是懒得写,是写不出。。
最近由于工作关系,重新回顾了ASP.NET MVC 的 1.0 版本。2.0版本还没有研究。
由于MVC框架发展不久,还有很多不足的地方。其中关于路由规则配置这一块问题比较大。首先路由规则是在全局配置问价 Global.asax 的 Application_Start()事件中注册的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute( "{resource}.axd/{*pathInfo}" ); routes.MapRoute( "User" , // Route name "{controller}/{action}/{id}" , // URL with parameters new { controller = "User" , action = "Show" , id = "0" } // Parameter defaults ); } protected void Application_Start() { RegisterRoutes(RouteTable.Routes); } |
默认硬编码的方式使得以后可维护程度大大降低。MVC 1.0 似乎没有提供很好的基于配置文件的路由规则设置。所以只好自己实现了。直到写这篇文章时,才找到了一个比较好的解决方案。
以下是 自定义的XML 格式
1 2 | <?xml version= "1.0" encoding= "utf-8" ?> <MapRoutes> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <!--默认规则--> <MapRoute name= "Default" url= "{controller}/{action}" > <Params> <Item key= "controller" default = "Article" /> <Item key= "action" default = "Index" /> </Params> </MapRoute> <!--显示新闻列表的路由规则--> <MapRoute name= "ShowArticleList" url= "{controller}/{action}/{typeId}/{pageIndex}/{pageSize}" > <Params> <Item key= "controller" default = "Article" /> <Item key= "action" default = "Index" /> <Item key= "typeId" default = "1" /> <Item key= "pageIndex" default = "1" /> <Item key= "pageSize" default = "10" /> </Params> </MapRoute> </MapRoutes> |
一下是全部代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | /* *********************************************** * 作者 :汤晓华/tension 任何转载请务必保留此头部信息 版权所有 盗版必究 * Email:tension1990@hotmail.com * 描述 : * 创建时间:2010-3-9 15:17:26 * 修改历史: * ***********************************************/ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web.Routing; using System.Web.Mvc; using System.Xml.Linq; using Microsoft.CSharp; using System.CodeDom.Compiler; namespace Tension.Mvc { public static class RouteHelper { /// <summary> /// 从XML文件中注册路由规则 /// </summary> /// <param name="routes"></param> /// <param name="cfgFile"></param> public static void Register( this RouteCollection routes, string cfgFile) { IList<Route> Routes = GetRoutes(cfgFile); foreach ( var item in Routes) { //路由规则对象 object obj = CreateObjectFormString(item.ToString(), item.Name); routes.MapRoute( item.Name, // Route name item.Url, // URL with parameters obj // Parameter defaults ); } } /// <summary> /// 从XML文件中注册路由规则 默认文件为网站根目录下MapRoute.config /// </summary> /// <param name="routes"></param> public static void Register( this RouteCollection routes) { Register(routes, string .Format( "{0}\\MapRoute.config" , Tension.ServerInfo.GetRootPath())); } /// <summary> /// 从string动态创建类对象 /// </summary> /// <param name="codeString"></param> /// <param name="className"></param> /// <returns></returns> private static object CreateObjectFormString( string codeString, string className) { CSharpCodeProvider ccp = new CSharpCodeProvider(); CompilerParameters param = new CompilerParameters( new string [] { "System.dll" }); CompilerResults cr = ccp.CompileAssemblyFromSource(param, codeString); Type type = cr.CompiledAssembly.GetType(className); return type.GetConstructor(System.Type.EmptyTypes).Invoke( null ); } /// <summary> /// 从XML文件中解析路由规则 /// </summary> /// <param name="configFile"></param> /// <returns></returns> private static IList<Route> GetRoutes( string configFile) { StringBuilder sb = new StringBuilder(); Console.WriteLine(sb.ToString()); IList<Route> Routes = new List<Route>(); XElement xe = XElement.Load(configFile); #region MyRegion foreach ( var item in xe.Elements( "MapRoute" )) { //名称属性 XAttribute xaName = item.Attribute( "name" ); if (xaName == null || string .IsNullOrEmpty(xaName.Value)) { throw new ArgumentNullException( "name!说明:路由配置文件中某规则缺少name属性或name属性的值为空字符串" ); } //URL属性 XAttribute urlName = item.Attribute( "url" ); if (urlName == null || string .IsNullOrEmpty(urlName.Value)) { throw new ArgumentNullException( "url!说明:路由配置文件中某规则缺少url属性或url属性的值为空字符串" ); } Dictionary< string , string > DictParams = new Dictionary< string , string >(); #region MyRegion foreach ( var pItem in item.Element( "Params" ).Elements( "Item" )) { XAttribute itemKey = pItem.Attribute( "key" ); if (itemKey == null || string .IsNullOrEmpty(itemKey.Value)) { throw new ArgumentNullException( "Item->key!说明:路由配置文件中某规则缺少Item->key属性或Item->key属性的值为空字符串" ); } XAttribute itemDefault = pItem.Attribute( "default" ); if (itemDefault == null || string .IsNullOrEmpty(itemDefault.Value)) { throw new ArgumentNullException( "Item->default!说明:路由配置文件中某规则缺少Item->default属性或Item->default属性的值为空字符串" ); } DictParams.Add(itemKey.Value, itemDefault.Value); } #endregion Routes.Add( new Route() { Name = xaName.Value, Url = urlName.Value, Params = DictParams }); } #endregion return Routes; } } /// <summary> /// 路由规则 /// </summary> public class Route { public string Name { get ; set ; } public string Url { get ; set ; } public Dictionary< string , string > Params { get ; set ; } /// <summary> /// 重写ToString 方法 产生需要动态代码段 /// </summary> /// <returns></returns> public override string ToString() { StringBuilder sb = new StringBuilder(); sb.AppendFormat( "public class {0}" , Name); sb.Append( "{" ); foreach ( var item in Params) { sb.AppendFormat( "public string {0}" , item.Key); sb.Append( "{get{return \"" ); sb.Append(item.Value); sb.Append( "\";}} " ); } sb.Append( "}" ); return sb.ToString(); } } } |
在实现过程中遇到的最大问题就是 参数列表的动态装载 看一下以下代码
1 2 3 4 5 | routes.MapRoute( "User" , // Route name "{controller}/{action}/{id}" , // URL with parameters new { controller = "User" , action = "Show" , id = "0" } // Parameter defaults ); |
这是硬编码实现的路由规则注册
其中 第三个参数(new { controller = "User", action = "Show", id = "0" } ) 是一个匿名对象
该对象如何动态构建成了难题。(才疏学浅)
尝试着传入一个 Dictionary<K,T> 但是没有用,ASP.NET 解析这个参数的时候是以反射形式读取的对象属性。
后来想到了使用代码段 在运行时动态创建对象。
我们将类似代码段
1 2 3 | public class Default{ public string controller{ get { return "Article" ;}} public str ing action{ get { return "Index" ;}} public string id{ get { return "0" ;}} public strin g page{ get { return "1" ;}} public string size{ get { return "10" ;}} } |
传入方法
1 2 3 4 5 6 7 8 | private static object CreateObjectFormString( string codeString, string className) { CSharpCodeProvider ccp = new CSharpCodeProvider(); CompilerParameters param = new CompilerParameters( new string [] { "System.dll" }); CompilerResults cr = ccp.CompileAssemblyFromSource(param, codeString); Type type = cr.CompiledAssembly.GetType(className); return type.GetConstructor(System.Type.EmptyTypes).Invoke( null ); } |
即可有运行时动态的创建我们需要的参数对象。
以后就可以方便的在XML注册路由了。
public static void Register(this RouteCollection routes) 对 RouteCollection 对象添加了扩展方法
引入对应的命名空间后就方便的注册了。
改进后的注册方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute( "{resource}.axd/{*pathInfo}" ); } protected void Application_Start() { RegisterRoutes(RouteTable.Routes); //执行RouteCollection的扩展方法 用来注册XML文件中的路由配置信息 RouteTable.Routes.Register(); } |
代码下载地址
苏州 晴
汤晓华 QQ 1881597 MSN tension1990@hotmail.com
2010 03 10
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述