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

        }

 

默认硬编码的方式使得以后可维护程度大大降低。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 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";}} }

 

传入方法

 

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

posted @ 2010-03-10 10:46  tandly  阅读(4554)  评论(13编辑  收藏