很久沒寫文章了,不是懶得寫,是寫不出。。
最近由於工作關係,重新回顧了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); }
預設硬式編碼方式使得以後可維護程度大大降低。MVC 1.0 似乎沒有提供很好的基於設定檔的路由規則設定。所以只好自己實現了。直到寫這篇文章時,才找到了一個比較好的解決方案。
以下是 自訂的XML 格式
<?xml version="1.0" encoding="utf-8" ?><MapRoutes>
<!--預設規則--> <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.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(); } }}
在實現過程中遇到的最大問題就是 參數列表的動態裝載 看一下以下代碼
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 解析這個參數的時候是以反射形式讀取的對象屬性。
後來想到了使用程式碼片段 在運行時動態建立對象。
我們將類似程式碼片段
public class Default{public string controller{get{return "Article";}} public string action{get{return "Index";}} public string id{get{return "0";}} public string 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); }
即可有運行時動態建立我們需要的參數對象。
以後就可以方便的在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(); }
代碼
/tandly/MvcRouteHelper.rar
蘇州 晴
湯曉華 QQ 1881597 MSN tension1990@hotmail.com
2010 03 10