Asp.Net教程,WinForm教程,Asp.Net MVC,vs2008教程,vs2010教程,Silverlight技术,源码下载,Asp.Net视频教程
全站热门标签
vs2010 Silverlight 存储过程 水晶报表 ADO.NET JavaScript LINQ AjaxPro DataGridView 面向对象 Extjs GridView XML DevExpress HTML教程 Oracle jQuery 分页 GDI+ Visual C++2010 MySQL Office2010 WPF MVC Dojo WCF4.0 VB.NET Sql2005 textbox cookie WCF WinForm Discuz!NT SQL经典语句 T-SQL checkbox ASPxGridView F# asp.net SQL VS2008新特性 DropDownList Access TreeView Ajax VS2008 页面执行时间 Flex 字符串 回调 VB2005 DataSet C#时间 ASP.NET性能优化 用户在线检测 动画
当前位置: 主页 > Mvc技术 >

Asp.Net MVC实践 - 探索UrlRouting并分析UrlHelper (基于ASP.NET MVC Preview 3)

时间:2010-08-18 21:10来源:未知 作者:admin 点击:

用asp.net mvc以来,UrlRouting的处理就是一个非常关键的问题,由于使用的不小心,经常导致我们无法得到预期的结果,这的确是个很麻烦的问题,于是很多朋友推测是MVC框架的bug,到底事实如何呢?今天我便尽力探索系统中UrlRouting到底是如何工作的,希望能找出问题的关键.

总所周知,Asp.Net MVC框架一般使用Global.asax在程序第一次启动的时候初始化RouteCollection,Preview3,我们一般使用RouteCollection. MapRoute方法来添加新的规则.然后,系统理论上会非常听话执行我们给出的规则,然后我们直接或者间接在页面中使用UrlHelper提供的方法处理Url,UrlHelper使用路由而非路径的方式定义url,能给我们更大的方便,但是问题来了,很多朋友发现UrlHelper并不是那么听话的,可以说有时候会给出一个莫名其妙的地址.为了解开这个问题,我们得先看看系统到底怎么来处理这些规则的.

首先我们把这个MapRoute方法找出来,查询源代码:
 public static void MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints) {
            if (routes == null) {
                throw new ArgumentNullException("routes");
            }
            if (url == null) {
                throw new ArgumentNullException("url");
            }

            Route route = new Route(url, new MvcRouteHandler()) {
                Defaults = new RouteValueDictionary(defaults),
                Constraints = new RouteValueDictionary(constraints)
            };

            if (String.IsNullOrEmpty(name)) {
                // Add unnamed route if no name given
                routes.Add(route);
            }
            else {
                routes.Add(name, route);
            }
        }

 

这是一个扩展方法,我们看到这实际上是简化了PreView2中添加路由的方式.这儿仍然和以前一样使用routes.Add方法来添加路由,由于System.Web.Routing手上没有源码,只好使用反编译该程序集来研究,我们再看RouteCollection的关键定义:

public class RouteCollection : Collection<RouteBase>
{
    // Fields
private Dictionary<string, RouteBase> _namedMap;
xxx…

 

这表明实际上RouteCollection维护了两个容器,一个是Collection,一个是Dictionary

public void Add(string name, RouteBase item)
{
    if (item == null)
    {
        throw new ArgumentNullException("item");
    }
    if (!string.IsNullOrEmpty(name) && this._namedMap.ContainsKey(name))
    {
        throw new ArgumentException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.RouteCollection_DuplicateName, new object[] { name }), "name");
    }
    base.Add(item);
    if (!string.IsNullOrEmpty(name))
    {
        this._namedMap.set_Item(name, item);
    }
}

如果未提供name参数,则直接使用Collection提供的Add方法添加Route,这时并没有向_ namedMap添加route,只有提供了name,且提供的name满足!IsNullOrEmpty参数才会向_namedMap添加规则.ok,这下明白了RouteCollection是如何存储路由规则了,我们继续看UrlHelper部分和Url有关的主要提供了Action, Content和RouteUrl3个方法,而RouteUrl和Action方法则都是调用了UrlHelper.GenerateUrl方法,至于其他和Url有关的部分,如HtmlHelper也都是直接或者间接调用UrlHelper.GenerateUrl方法.我们一个个查看.

首先看Action,该方法会给出一个连接到所提供的action的url,有好几个重载,但是总结起来都是调用return GenerateUrl(null /* routeName */, actionName,xxx,xxx)的模式,也就是说前面所有Action间接调用GenerateUrl时候前两个参数固定,一个是null,一个是actionName,而在RouteUrl中则不同,会根据不同的重载模式来,既有需要routeName的,也有不需要routeName的.现在关键就是GenerateUrl方法了,该方法代码如下:


        private string GenerateUrl(string routeName, string actionName, string controllerName, RouteValueDictionary valuesDictionary) {
            return GenerateUrl(routeName, actionName, controllerName, valuesDictionary, RouteCollection, ViewContext);
        }

        internal static string GenerateUrl(string routeName, string actionName, string controllerName, RouteValueDictionary valuesDictionary, RouteCollection routeCollection, ViewContext viewContext) {
            if (actionName != null) {
                if (valuesDictionary.ContainsKey("action")) {
                    throw new ArgumentException(
                        String.Format(
                            CultureInfo.CurrentUICulture,
                            MvcResources.Helper_DictionaryAlreadyContainsKey,
                            "action"),
                        "actionName");
                }
                valuesDictionary.Add("action", actionName);
            }
            if (controllerName != null) {
                if (valuesDictionary.ContainsKey("controller")) {
                    throw new ArgumentException(
                        String.Format(
                            CultureInfo.CurrentUICulture,
                            MvcResources.Helper_DictionaryAlreadyContainsKey,
                            "controller"),
                        "controllerName");
                }
                valuesDictionary.Add("controller", controllerName);
            }
VirtualPathData vpd;
            if (routeName != null) {
                vpd = routeCollection.GetVirtualPath(viewContext, routeName, valuesDictionary);
            }
            else {
                vpd = routeCollection.GetVirtualPath(viewContext, valuesDictionary);
            }

            if (vpd != null) {
                return vpd.VirtualPath;
            }
            return null;
        }

关键是第二个,分析下这个方法,它要求必须唯一提供action,且不能重复提供controller,然后,对于路径的查找,如果提供了routeName,则系统会使用GetVirtualPath(viewContext, routeName, valuesDictionary);否则使用routeCollection.GetVirtualPath(viewContext, valuesDictionary);

(责任编辑:admin)

Tags:ASP.NET MVC MVC asp.net
责任编辑:admin
返回顶部
------分隔线----------------------------
推荐内容
骆驼户外男 真皮磨砂日常休闲鞋 低帮 2011秋冬新款 专柜正品特价 骆驼户外男 真皮磨砂日常休闲鞋 低帮 2011秋冬新款 专柜正品特价