ASP.NET MVC 路由規則XML化
最近由于工作關系,重新回顧了ASP.NET MVC 的 1.0 版本。2.0版本還沒有研究。
由于MVC框架發展不久,還有很多不足的地方。其中關于路由規則配置這一塊問題比較大。首先路由規則是在全局配置問價 Global.asax 的 Application_Start()事件中注冊的。

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);
}
{
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 格式

<?xml version="1.0" encoding="utf-8" ?>
<MapRoutes>
view sourceprint?
<!--默認規則-->
<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>
<MapRoutes>
view sourceprint?
<!--默認規則-->
<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>
以下是全部代碼
/* ***********************************************
* 作者 :湯曉華/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.GetRoot
Path()));
}
/// <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();
}
}
}
* 作者 :湯曉華/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.GetRoot
Path()));
}
/// <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();
}
}
}
在實現過程中遇到的最大問題就是 參數列表的動態裝載 看一下以下代碼
routes.MapRoute(
"User", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "User", action = "Show", id = "0" } // Parameter defaults
);
"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 解析這個參數的時候是以反射形式讀取的對象屬性。
后來想到了使用代碼段 在運行時動態創建對象。
我們將類似代碼段
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";}} }
ing action{get{return "Index";}} public string id{get{return "0";}} public strin
g page{get{return "1";}} public string size{get{return "10";}} }
傳入方法
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);
}
{
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 對象添加了擴展方法 引入對應的命名空間后就方便的注冊了。
改進后的注冊方法
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
}
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
//執行RouteCollection的擴展方法 用來注冊XML文件中的路由配置信息
RouteTable.Routes.Register();
}
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
}
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
//執行RouteCollection的擴展方法 用來注冊XML文件中的路由配置信息
RouteTable.Routes.Register();
}
全站熱搜