您的位置:首页 > 编程语言 > ASP

从零开始学习 ASP.NET MVC 1.0 (二) 识别URL的Routing组件

2011-02-18 14:48 639 查看

一.摘要

本篇文章从基础到深入的介绍ASP.NETMVC中的Routing组件.Routing翻译过来是"路由选择",负责ASP.NETMVC的第一个工作:识别URL,将一个Url请求"路由"给Controller.

二.承上启下

第一篇文章中我们已经学会了如何使用ASP.NETMVC,虽然其中还有很多的细节没有深入了解,但是对基本的处理流程已经有了认识:来了一个Url请求,从中找到Controller和Action的值,将请求传递给Controller处理.Controller获取Model数据对象,并且将Model传递给View,最后View负责呈现页面.

而Routing的作用就是负责分析Url,从Url中识别参数,如图:





这一讲就让我们细致的了解System.Web.Routing及其相关的扩展知识.

三.Routing的作用

第一讲中实例的首页地址是:localhost/home/index

我们发现访问上面的地址,最后会传递给HomeController中名为index的action(即HomeController类中的index方法).

当然服务器端不会自己去实现这个功能,关键点就是在Global.asax.cs文件中的下列代码:

publicstaticvoidRegisterRoutes(RouteCollectionroutes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapRoute(
"Default",//Routename
"{controller}/{action}/{id}",//URLwithparameters
new{controller="Home",action="Index",id=""}//Parameterdefaults
);

}

protectedvoidApplication_Start()
{
RegisterRoutes(RouteTable.Routes);
}


回来看我们的Url:localhost/home/index

localhost是域名,所以首先要去掉域名部分:home/index

对应了上面代码中的这种URL结构:{controller}/{action}/{id}

因为我们建立了这种Url结构的识别规则,所以能够识别出Controller是home,action是index,id没有则为默认值"".

这就是Routing的第一个作用:

1.从Url中识别出数据.比如controller,action和各种参数.

如果跟踪程序,接下来我们会跳转到HomeController中的Index()方法.这是Routing内部为实现的第二个作用:

2.根据识别出来的数据,将请求传递给Controller和Action.

但从实例中我们并不知道Routing如何做的这部份工作.第五部分我做了深入讲解.

四.Routing的使用

在分析Routing的实现原理前,先学习如何使用Routing为ASP.NETMVC程序添加路由规则.

1.使用MapRoute()方法.

这是最简单的为ASP.NETMVC添加识别规则的方法.此方法有如下重载:

MapRoute(stringname,stringurl);
MapRoute(stringname,stringurl,objectdefaults);
MapRoute(stringname,stringurl,string[]namespaces);
MapRoute(stringname,stringurl,objectdefaults,objectconstraints);
MapRoute(stringname,stringurl,objectdefaults,string[]namespaces);
MapRoute(stringname,stringurl,objectdefaults,objectconstraints,string[]namespaces);



name参数:

规则名称,可以随意起名.当时不可以重名,否则会发生错误:
路由集合中已经存在名为“Default”的路由。路由名必须是唯一的。

url参数:

url获取数据的规则,这里不是正则表达式,将要识别的参数括起来即可,比如:{controller}/{action}

最少只需要传递name和url参数就可以建立一条Routing(路由)规则.比如实例中的规则完全可以改为:

routes.MapRoute(
"Default",
"{controller}/{action}");


defaults参数:

url参数的默认值.如果一个url只有controller:localhost/home/

而且我们只建立了一条url获取数据规则:{controller}/{action}

那么这时就会为action参数设置defaults参数中规定的默认值.defaults参数是Object类型,所以可以传递一个匿名类型来初始化默认值:

new{controller="Home",action="Index"}


实例中使用的是三个参数的MapRoute方法:

routes.MapRoute(
"Default",//Routename
"{controller}/{action}/{id}",//URLwithparameters
new{controller="Home",action="Index",id=""}//Parameterdefaults
);


constraints参数:

用来限定每个参数的规则或Http请求的类型.constraints属性是一个RouteValueDictionary对象,也就是一个字典表,但是这个字典表的值可以有两种:

用于定义正则表达式的字符串。正则表达式不区分大小写。

一个用于实现IRouteConstraint接口且包含Match方法的对象。

通过使用正则表达式可以规定参数格式,比如controller参数只能为4位数字:

new{controller=@"\d{4}"}



通过第IRouteConstraint接口目前可以限制请求的类型.因为System.Web.Routing中提供了HttpMethodConstraint类,这个类实现了IRouteConstraint接口.我们可以通过为RouteValueDictionary字典对象添加键为"httpMethod",值为一个HttpMethodConstraint对象来为路由规则添加HTTP谓词的限制,比如限制一条路由规则只能处理GET请求:

httpMethod=newHttpMethodConstraint("GET","POST")



完整的代码如下:

routes.MapRoute(
"Default",//Routename
"{controller}/{action}/{id}",//URLwithparameters
new{controller="Home",action="Index",id=""},//Parameterdefaults
new{controller=@"\d{4}",httpMethod=newHttpMethodConstraint("GET","POST")}
);

当然我们也可以在外部先创建一个RouteValueDictionary对象在作为MapRoute的参数传入,这只是语法问题.

namespaces参数:

此参数对应Route.DataTokens属性.官方的解释是:

获取或设置传递到路由处理程序但未用于确定该路由是否匹配URL模式的自定义值。

我目前不知道如何使用.请高手指点

2.MapRoute方法实例

下面通过实例来应用MapRoute方法.对于一个网站,为了SEO友好,一个网址的URL层次不要超过三层:

localhost/{频道}/{具体网页}

其中域名第一层,频道第二层,那么最后的网页就只剩下最后一层了.如果使用默认实例中的"{controller}/{action}/{其他参数}"的形式会影响网站的SEO.

假设我们的网站结构如下:





下面以酒店频道为例,是我创建的Routing规则:

publicstaticvoidRegisterRoutes(RouteCollectionroutes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

#region酒店频道部分
//hotels/list-beijing-100,200-3
routes.MapRoute(
"酒店列表页",
"hotels/{action}-{city}-{price}-{star}",
new{controller="Hotel",action="list",city="beijing",price="-1,-1",star="-1"},
new{city=@"[a-zA-Z]*",price=@"(\d)+\,(\d)+",star="[-1-5]"}
);

//hotels/所有匹配
routes.MapRoute(
"酒店首页",
"hotels/{*values}",
new{controller="Hotel",action="default",hotelid=""}
);
#endregion

//网站首页.
routes.MapRoute(
"网站首页",
"{*values}",
new{controller="Home",action="index"}
);
}



实现的功能:

(1)访问localhost/hotels/list-beijing-100,200-3会访问酒店频道的列表页,并传入查询参数

(2)访问localhost/hotels下面的任何其他页面地址,都会跳转到酒店首页.

(3)访问localhost下面的任何地址,如果未匹配上面2条,则跳转到首页.

简单总结:

(1)Routing规则有顺序(按照添加是的顺序),如果一个url匹配了多个Routing规则,则按照第一个匹配的Routing规则执行.

(2)由于上面的规则,要将具体频道的具体页面放在最上方,将频道首页和网站首页放在最下方.

(3){*values}表示后面可以使任意的格式.

3.使用Route类

MapRoute方法虽然简单,但是他是本质也是通过创建Route类的实例,为RouteCollection集合添加成员.

下载最新版本的MSDN-VisualStudio20008SP1,已经可以找到Route类的说明.

创建一个Route类实例,最关键的是为以下几个属性赋值:

属性名称说明举例
Constraints获取或设置为URL参数指定有效值的表达式的词典。{controller}/{action}/{id}
DataTokens获取或设置传递到路由处理程序但未用于确定该路由是否匹配URL模式的自定义值。newRouteValueDictionary{{"format","short"}}
Defaults获取或设置要在URL不包含所有参数时使用的值。new{controller="Home",action="Index",id=""}
RouteHandler获取或设置处理路由请求的对象。newMvcRouteHandler()
Url获取或设置路由的URL模式。new{controller=@"[^\.]*"}
这些属性除了RouteHandler以外,
其他的都对应MapRoute方法的参数.RouteHandler是实现了IRouteHandler接口的对象.关于此接口的作用在第五部分Routing深入解析中做讲解.

五.Routing深入解析

对于一个一般开发人员来说,上面的知识已经完全足够你使用ASP.NETMVC时使用Routing了.

接下来的部分我将深入Routing的机制讲解Routing的高级应用.但是因为是"高级应用",加上这篇文章已经太长了,再加上马上今天就过去了,
"每日一篇"的承诺一定要兑现的,所以不会对所有细节进行讲解.或者也可以略过此部分.

Routing如何将请求传递给Controller?上面讲解Routing作用的时候,我们就分析出Routing会将请求传递给Controller,
但是Routing如何做的这部份工作我们却看不到.关键在于MapRoute()这个方法封装了具体的细节.

虽然MapRoute方法是RouteCollection对象的方法,但是却被放置在System.Web.Mvc程序集中,
如果你的程序只引用了System.Web.Routing,那么RouteCollection对象是不会有MapRoute方法的.
但是如果你同又引用了System.Web.Mvc,则在mvc的dll中为RouteCollection对象添加了扩展方法:

publicstaticvoidIgnoreRoute(thisRouteCollectionroutes,stringurl);
publicstaticvoidIgnoreRoute(thisRouteCollectionroutes,stringurl,objectconstraints);
publicstaticRouteMapRoute(thisRouteCollectionroutes,stringname,stringurl);
publicstaticRouteMapRoute(thisRouteCollectionroutes,stringname,stringurl,objectdefaults);
publicstaticRouteMapRoute(thisRouteCollectionroutes,stringname,stringurl,string[]namespaces);
publicstaticRouteMapRoute(thisRouteCollectionroutes,stringname,stringurl,objectdefaults,objectconstraints);
publicstaticRouteMapRoute(thisRouteCollectionroutes,stringname,stringurl,objectdefaults,string[]namespaces);
publicstaticRouteMapRoute(thisRouteCollectionroutes,stringname,stringurl,objectdefaults,objectconstraints,string[]namespaces);

RouteCollection是一个集合,他的每一项应该是一个Route对象.但是我们使用MapRoute时并没有创建这个对象,这是因为当我们将MapRoute方法需要的参数传入时,在方法内部会根据参数创建一个Route对象:

publicstaticRouteMapRoute(thisRouteCollectionroutes,stringname,stringurl,objectdefaults,objectconstraints,string[]namespaces){
if(routes==null){
thrownewArgumentNullException("routes");
}
if(url==null){
thrownewArgumentNullException("url");
}

Routeroute=newRoute(url,newMvcRouteHandler()){
Defaults=newRouteValueDictionary(defaults),
Constraints=newRouteValueDictionary(constraints)
};

if((namespaces!=null)&&(namespaces.Length>0)){
route.DataTokens=newRouteValueDictionary();
route.DataTokens["Namespaces"]=namespaces;
}

routes.Add(name,route);

returnroute;
}

上面就是MapRoute方法的实现,至于在创建Route对象时第二个参数是一个MvcRouteHandler,它是一个实现了IRouteHandler接口的类.IRouteHandler十分简单只有一个方法:

IHttpHandlerGetHttpHandler(RequestContextrequestContext);


参数是一个RequestContext类实例,这个类的结构也很简单:

publicclassRequestContext
{
publicRequestContext(HttpContextBasehttpContext,RouteDatarouteData);

publicHttpContextBaseHttpContext{get;}
publicRouteDataRouteData{get;}
}


其中的一个属性RouteData就包含了Routing根据Url识别出来各种参数的值,其中就有Controller和Action的值.

归根结底,ASP.NETMVC最后还是使用HttpHandler处理请求.ASP.NETMVC定义了自己的实现了IHttpHandler接口的Handler:MvcHandler,因为MvcRouteHandler的GetHttpHandler方法最后返回的就是MvcHandler.

MvcHandler的构造函数需要传入RequestContext对象,也就是传入了所有的所有需要的数据,所以最后可以找到对应的Controller和Action,已经各种参数.

六.测试Routing

因为一个Url会匹配多个routing规则,最后常常会遇到规则写错或者顺序不对的问题.于是我们希望能够看到Url匹配Routing的结果.

其中最简单的办法就是使用RouteDebug辅助类.这个类需要单独下载dll组件,我将此组件的下载放在了博客园上:

http://files.cnblogs.com/zhangziqiu/RouteDebug-Binary.zip

解压缩后是一个DLL文件,将这个DLL文件添加到项目中并且添加引用.

使用方法很简单,只需要在Application_Start方法中添加一句话:

RouteDebug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes);


比如下面是我的示例中的代码:

protectedvoidApplication_Start()
{
RegisterRoutes(RouteTable.Routes);
RouteDebug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes);
}


现在你访问任何URL,都会出现RouteDebug页面,如下:





其中不仅有你的所有Routing规则,还显示了是否匹配.并且按照顺序列出.还有识别的参数列表.

当你不想测试Routing规则的时候则注释掉这一段,即可回复跳转到View对象上.

七.总结

本文讲解了ASP.NETMVC中一个关键的组件:Routing的使用.System.Web.Routing在Framework3.5
SP1中已经集成,也就是说虽然我们还没有ASP.NETMVC的正式版,但是Routing组件却已经提早发布了.因为Routing是一个相对独立的组件,
不仅能和ASP.NETMVC配额使用,也可以用于任何需要URL路由的项目.另外Routing的作用和Url重写(UrlRewrite)是有区别的,
你会发现Routing和UrlRewrite相比其实很麻烦,
无论是添加规则还是传递参数.对UrlRewite感兴趣的可以去寻找UrlRewrite.dll这个组件,很简单很强大,
有关两者的异同以及如何使用UrlRewrite这里不在多说了.

本文的示例下载地址:

http://files.cnblogs.com/zhangziqiu/Demo-2.rar
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: