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

 

代码下载地址

/tandly/MvcRouteHelper.rar

 

苏州 晴

汤晓华 QQ 1881597 MSN tension1990@hotmail.com

2010 03 10

posted @   tandly  阅读(4605)  评论(13编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述
点击右上角即可分享
微信分享提示