白话ASP.NET MVC之一:Url 路由
?????? 好久没有写关于ASP.NET MVC的东西了,虽然《ASP.NET MVC4框架揭秘》已经完完整整的看完一遍,但是感觉和一锅粥差不多,没什么可写的,因为我自己不理解,也就写不出来。现在开始看《ASP.NET MVC5框架揭秘》,应该说第二遍了,每个代码都调试了,也看了很多的源代码,突然有一种清新的感觉,很多东西都连起来了,原来是这样啊,不不经意发出这样的感叹。既然有了一个好的理解,就整理一下,写出来,也就算巩固学习了。 一、简介 ????? Url路由:在ASP.NET MVC系统里,来自客户端的请求总是指向一个定义在某个Controller类型中的某个Action方法,并且目标Controller和Action的名称由请求的Url决定,既URL驱动的,所以必须采取某种机制根据请求的Url地址把目标的Controller和Action的名称解析出来,我们将这种机制就称为“路由(Routing)”。但是我们要说明的是这个路由系统是独立的,不是专属ASP.NET MVC的。独立的意思是可以在ASP.NET WEB FORMS里使用,可以在ASP.NET MVC里面使用,因为路由系统专门针对MVC的特点扩展了其原有的路由系统的实现。所以我把ASP.NET的路由系统分成两个部分,可能说法不太准确,我这样分是方便我更好的理解,大家可以自行分解,便于理解就好。 ???????? 第一:ASP.NET路由系统,定义在System.Web.dll程序集中,命名空间是System.Web.Routing,这个可以认为是针对ASP.NET WEB FORMS的,路由设置里面要写映射的物理.aspx文件,具体详情可以自行研究,就不多说了。 protected void Application_Start(object sender,EventArgs e) { var defaults = new RouteValueDictionary{ {"name",*" },{id" } }; RouteTable.Routes.MapPageRoute("",1)">employees/{name}/{id}~/Default.aspxtrue,defaults); } ???????? 第二:针对ASP.NET MVC扩展出来的新的路由系统,定义在System.Web.MVC.dll程序集里面。扩展类是定义在命名空间System.Web.Mvc下的RouteCollectionExtensions类型,路由注册的时候要写Controller和Action了。 public static void RegisterRoutes(RouteCollection routes) { routes.MapRoute( name: Default{controller}/{action}/{id}new { controller = EmployeesGetAllEmployees UrlParameter.Optional } ); } ?????? 我们知道ASP.NET MVC是通过扩展ASP.NET处理管道实现的,这里面有两个最重要的组件,一个是实现了IHttpModule接口的UrlRoutingModule,此组件用于截获请求,进行路由解析,并重新Remap到请求的处理程序上,这个处理程序就是第二个组件,实现了IHttpHandler的MvcHandler,此组件用于激活Controller和Action方法的执行。可以这样说,路由系统的解析操作就发生在UrlRoutingModule组件里面。我们先看看他的代码,然后我们按着请求的先后顺序一步一步的介绍所涉及到的对象。 1 namespace System.Web.Routing 2 { 4 class UrlRoutingModule : IHttpModule 5 { 6 private readonly object _contextKey = new (); 7 8 object _requestDataKey = 9 10 private RouteCollection _routeCollection; 11 12 public RouteCollection RouteCollection 13 { 14 get 15 { 16 if (this._routeCollection == null) 17 { 18 this._routeCollection = RouteTable.Routes; 19 } 20 return this._routeCollection; 21 } 22 set 23 24 value; 25 26 } 31 32 virtual Init(HttpApplication application) 33 34 if (application.Context.Items[UrlRoutingModule._contextKey] != 35 36 return; 37 38 application.Context.Items[UrlRoutingModule._contextKey] = UrlRoutingModule._contextKey; 39 application.PostResolveRequestCache += new EventHandler(.OnApplicationPostResolveRequestCache); 40 } 41 42 void OnApplicationPostResolveRequestCache( 43 44 HttpContextBase context = new HttpContextWrapper(((HttpApplication)sender).Context); 45 .PostResolveRequestCache(context); 46 47 53 PostResolveRequestCache(HttpContextBase context) 54 55 RouteData routeData = .RouteCollection.GetRouteData(context); 56 if (routeData == 57 58 59 60 IRouteHandler routeHandler = routeData.RouteHandler; 61 if (routeHandler == 62 63 throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,SR.GetString(UrlRoutingModule_NoRouteHandler"),1)">object[0])); 64 65 if (routeHandler is StopRoutingHandler) 66 67 68 69 RequestContext requestContext = RequestContext(context,routeData); 70 context.Request.RequestContext = requestContext; 71 IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); 72 if (httpHandler == 73 74 string.Format(CultureInfo.CurrentUICulture,1)">UrlRoutingModule_NoHttpHandler[] 75 76 routeHandler.GetType() 77 })); 78 79 if (!(httpHandler UrlAuthFailureHandler)) 80 81 context.RemapHandler(httpHandler); 82 83 84 if (FormsAuthenticationModule.FormsAuthRequired) 85 86 UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current,1)">); 87 88 89 new HttpException(401,1)">Assess_Denied_Description3)); 90 } ?? 二、路由解析的先后顺序 ???????? 路由规则注册-----》截获请求-----》路由解析并获得RouteData对象-----》根据RouteData的RouteHandler获得MvcRouteHandler对象-----》根据MvcRouteHandler获得MvcHandler对象-----》请求对象重新路由,HttpContext.Remap(MvcHandler)-----》MvcHandler接管请求处理-----》Controller激活-----》Action方法的执行-----》返回处理结果并结束 ?????? 上面是路由解析的全过程,我再用白话描述一遍:要想解析路由,必须先注册路由规则的对象吧,也就是Route对象,连注册都没有还解析个什么劲啊,我们一般在Global.asax文件的Application_Start方法里面注册Route对象。注册好了路由规则,启动系统,早已注册好的UrlRoutingModule截获请求,用当前的请求的Url和路由表【RouteTable】里面存储的路由对象【Route】进行比较,其实是Url地址和路由对象【Route】的路由地址模板Url进行匹配,没有匹配就返回空值,如果多个匹配,就选择第一个匹配路由对象【Route】,根据选择的路由对象【Route】生成路由数据【RouteData】。因为路由数据【RouteData】包含RouteHandler属性,RouteHandler属性用于提供最终处理请求的HttpHandler,ASP.NET MVC中RouteHandler的属性值就是MvcRouteHandler,MvcRouteHandler实现了IRouteHandler接口,这个接口有一个方法GetHttpHandler,这个方法就提供了用于处理最终请求的HttpHandler,这个HttpHandler就是MvcHandler,好了,该获取的对象都准备好了,那就把请求交给MvcHandler吧,交接是通过HttpContext.Remap方实现的,好了,大概就是这么一个过程。 ????? 我先简要的把路由解析所涉及到的类型说一下,我们是面向对象编程的,所以很多东西已经对象化了,说的不错。哈哈老王卖瓜了: ?????? 1、Route:路由规则抽象获得RouteBase类型,此类型是抽象类,他有唯一的一个子类就是Route对象,路由规则对象肯定要有路由模板的地址Url,要有路由的默认值了,路由的约束值了等等一些东西。也可以这样理解,我们注册的每一个规则就是一个Route对象,每一个Route对象实例就是代表一种路由的规则。 ?????? 2、UrlRoutingModule:我们有了Route路由规则对象,也注册好了,系统启动,我们要把请求截获,不截获请求,就没办法处理了,所以我们就是扩展了ASP.Net处理管道,实现了IHttpModule接口,定义了UrlRoutingModule类型,它用于截获请求,进行路由解析,我上面也提到过该类,并贴出了代码,下面会详细说的,非常核心的类,如果对ASP.NET处理管道不熟悉的可以去网上查找一些资料,很容易找的。 ?????? 3、RouteTable:ASP.NET MVC有一个代表全局的路由表,所有注册Route对象都存在RouteTable.Routes表示的集合里面,路由解析的时候就是和RouteTable.Routes表示的路由表里面的每一个Route对象进行匹配,如果RouteTable里面的所有Route对象所代表的路由规则和当前的Url都不匹配就返回Null值,如果有多个匹配就选择第一个匹配的Route对象,并根据Route对象生成RouteData对象。 ????? 4、RouteData:当请求的Url和RouteTable路由表中表示路由规则的Route相匹配的时候,会根据匹配的Route对象生成RouteData,它里面包含了根据Url解析所得到东西,如:controller的名字,Action的名字等信息。 ????? 5、MvcRouteHandler:MvcRouteHandler是MvcHandler对象的提供对象,RouteData的RouteHandler属性的值针对MVC来说就是MvcRouteHandler,如果是ASP.NET的路由系统,那就是PageRouteHandler对象了。 ????? 6、MvcHandler:既然我们获得了MvcHandler,通过HttpContext的Remap方法重新路由,把请求交给MvcHandler来处理,后面就是Controller激活和Action方法的解析了。 ????? 好了,简单的说了一下每个对象的用途,大家也许有了一个大概的印象了吧,我们下面就来详细的说说每一个对象的实际情况。 三、路由对象的详解 ???? 我们使用的是面向对象的语言,所操作的一切都是对象,路由规则经过抽象就是RouteBase对象,有了RouteBase对象,我们才可以注册路由对象,才有针对RouteBase的路由解析。接下来就让我们开始说我们的第一个对象吧,Route路由对象,刚才不是说要说RouteBase,咱们现在又要说Route对象了,怎么变了,其实没变,两个对象是一回事。RouteBase其实是 一个抽象类,我们所指的或者所说的Route路由对象,其实都是从RouteBase对象继承下来的。 ????? 1、RouteBase和Route ??????? 我们看看RouteBase的源代码吧,不看源代码,很多东西不能搞清楚的。 1 abstract RouteBase 2 { 3 bool _routeExistingFiles = 4 5 bool RouteExistingFiles 6 7 8 9 ._routeExistingFiles; 10 11 12 13 this._routeExistingFiles =14 15 16 17 abstract RouteData GetRouteData(HttpContextBase httpContext); 18 19 VirtualPathData GetVirtualPath(RequestContext requestContext,RouteValueDictionary values); 20 } ? RouteBase有两个抽象方法,第一个是返回的是RouteData类型的GetRouteData方法,RouteData说白了就是路由数据,在白点就是根据路由规则解析获得的数据,所以方法名是GetRouteData,该方法的参数是HttpContextBase对象,这个对象表示的当前请求。或者说这个方法就是根据当前的Url请求和路由规则对象进行比较,如果匹配就根据路由规则对象Route生成对象的RouteData路由数据对象。另外一个抽象方法就是,返回类型为VirtualPathData对象的GetVirtualPath方法,此方法的作用就是根据提供的数据和注册的路由规则生成相应的虚拟路径。RouteData稍后会将,让我们看看VirtualPathData是一个什么样的东西,源代码如下: VirtualPathData { string _virtualPath; private RouteValueDictionary _dataTokens = RouteValueDictionary(); 6 7 RouteValueDictionary DataTokens 9 11 ._dataTokens; 13 14 15 RouteBase Route 16 17 get18 set19 20 21 VirtualPath 22 23 24 25 this._virtualPath ?? .Empty; 26 27 28 29 this._virtualPath =30 31 32 33 public VirtualPathData(RouteBase route,1)"> virtualPath) 34 35 this.Route = route; 36 this.VirtualPath = virtualPath; 37 38 } 返回字符串类型VirtualPath属性就是生成虚拟路径,返回类型RouteBase的Route属性表示的匹配规则那个RouteBase对象。现在我想访问真实存在的一个物理文件怎么办呢?RouteBase有一个RouteExistingFiles属性,这个属性表示是否路由物理存在的文件,默认值是True,意味着我们想访问某个物理文件在不改变设置的情况下是不行的,因为已经按着路由规则发生了路由了。 ??? 我们在来看看Route对象吧,源码如下: Route : RouteBase 3 const string HttpMethodParameterName = httpMethod 4 5 _url; 6 7 ParsedRoute _parsedRoute; 8 9 RouteValueDictionary Constraints 10 11 12 14 15 16 17 18 20 21 RouteValueDictionary Defaults 22 23 24 26 27 IRouteHandler RouteHandler 28 29 30 31 32 33 Url 34 35 36 37 this._url ?? 38 39 41 this._parsedRoute = RouteParser.Parse(value); 42 this._url = 44 45 46 public Route( url,IRouteHandler routeHandler) 47 48 this.Url = url; 49 this.RouteHandler = routeHandler; 50 51 52 53 54 55 this.Defaults = defaults; 58 59 60 62 63 this.Constraints = constraints; 64 65 66 67 69 70 71 this.DataTokens = dataTokens; 73 74 75 76 override RouteData GetRouteData(HttpContextBase httpContext) 78 string virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo; 79 RouteValueDictionary routeValueDictionary = this._parsedRoute.Match(virtualPath,1)">.Defaults); 80 if (routeValueDictionary == 84 RouteData routeData = new RouteData(this,1)">.RouteHandler); 85 if (!.ProcessConstraints(httpContext,routeValueDictionary,RouteDirection.IncomingRequest)) 86 foreach (KeyValuePair<string,1)">object> current in routeValueDictionary) 91 routeData.Values.Add(current.Key,current.Value); 92 93 this.DataTokens != 94 95 object> current2 in .DataTokens) 96 97 routeData.DataTokens[current2.Key] = current2.Value; 98 99 100 routeData; 102 103 104 105 BoundUrl boundUrl = this._parsedRoute.Bind(requestContext.RouteData.Values,values,1)">this.Defaults,1)">.Constraints); 106 if (boundUrl == 107 108 109 110 .ProcessConstraints(requestContext.HttpContext,boundUrl.Values,RouteDirection.UrlGeneration)) 111 112 113 114 VirtualPathData virtualPathData = new VirtualPathData(115 116 117 118 119 virtualPathData.DataTokens[current.Key] = current.Value; 120 121 122 virtualPathData; 123 124 125 bool ProcessConstraint(HttpContextBase httpContext,1)">object constraint,1)"> parameterName,RouteValueDictionary values,RouteDirection routeDirection) 126 127 IRouteConstraint routeConstraint = constraint as IRouteConstraint; 128 if (routeConstraint != 129 130 return routeConstraint.Match(httpContext,parameterName,routeDirection); 131 132 string text = constraint as 133 if (text == 134 135 Route_ValidationMustBeStringOrCustomConstraint136 137 parameterName,138 .Url 139 140 141 142 values.TryGetValue(parameterName,1)">out value); 143 string arg_7C_0 = Convert.ToString(value,CultureInfo.InvariantCulture); 144 string pattern = ^(" + text + )$145 return Regex.IsMatch(arg_7C_0,pattern,RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); 146 147 148 ProcessConstraints(HttpContextBase httpContext,1)">149 150 this.Constraints != 151 152 .Constraints) 153 154 .ProcessConstraint(httpContext,current.Value,current.Key,routeDirection)) 155 { 156 false157 } 158 159 160 161 162 163 } ? 其实代码不复杂,大家也应该看的懂,Route对象直接继承RouteBase对象的,而且是唯一一个这样的对象,既然是路由规则对象,肯定包括,地址模板,默认值,约束条件和一些附加的数据,Constraints保存的就是约束条件,Defaults保存的就是默认值,Url属性就是地址模板了。他一定要实现GetRouteData方法和GetVirtualPath方法 ?2、RouteData ??? 我们有了路由规则了,也就是Route对象,我们也注册了,接下来就是路由解析,就是和Route对象的的Url进行比较,如果匹配就生成了RouteData对象,也就是Route对象GetRouteData方法返回结果了。大家一定要记住,RouteData是基于Route对象生成的,我们看看源码吧: RouteData IRouteHandler _routeHandler; private RouteValueDictionary _values = 8 9 18 19 20 21 22 23 25 27 ._routeHandler; 29 31 this._routeHandler =32 33 34 35 RouteValueDictionary Values 36 37 38 39 ._values; 40 41 42 43 RouteData() 44 45 46 47 RouteData(RouteBase route,1)">48 49 50 51 52 53 string GetRequiredString( valueName) 54 55 obj; 56 this.Values.TryGetValue(valueName,1)"> obj)) 57 58 string text = obj 59 .IsNullOrEmpty(text)) 60 61 text; 62 63 64 RouteData_RequiredValue65 66 valueName 67 })); 68 69 } ?? RouteData对象是规则匹配所要生成的东西,根据Url解析获得数据存在Values属性里面,DataTokens属性表示一些附加的数据,并且这个数据来源于Route对象的DataTokens属性,RouteData对象RouteHandler属性的值也是来源于Route对象的RouteHandler属性,这个RouteHandler在ASP.NET路由系统就是PageRouteHandler,在ASP.NET MVC中就是MvcRouteHandler,用于提供最终处理请求的HttpHandler。RouteData对象还有一个Route属性,此属性表示在路由解析的时候匹配的那个Route路由规则对象。 ??? 之所以说RouteData是基于Route对象产生了,因为RouteData对象里面的很多值来源于Routed对象,Route对象是基础。 3、RouteTable ???? 当我们了有了路由规则Route对象的时候,这些路由对象放在什么地方呢?答案就是放在了路由表RouteTable对象中,我们先看看他的源码吧: RouteTable static RouteCollection _instance = RouteCollection(); static RouteCollection Routes RouteTable._instance; 11 12 } ?RouteTable有一个静态属性是Routes,此属性的类型是RouteCollection,字面意思Route的Collection,就是路由对象的集合,类型如下: class RouteCollection : Collection<RouteBase> ReadLockDisposable : IDisposable 4 5 ReaderWriterLockSlim _rwLock; 7 ReadLockDisposable(ReaderWriterLockSlim rwLock) 8 9 this._rwLock = rwLock; IDisposable.Dispose() 14 ._rwLock.ExitReadLock(); 17 18 WriteLockDisposable : IDisposable 20 21 WriteLockDisposable(ReaderWriterLockSlim rwLock) 27 29 ._rwLock.ExitWriteLock(); 30 sealed IgnoreRouteInternal : Route public IgnoreRouteInternal(string url) : base(url,1)"> StopRoutingHandler()) 38 42 44 45 private Dictionary<new Dictionary<(StringComparer.OrdinalIgnoreCase); 46 47 VirtualPathProvider _vpp; 48 49 private ReaderWriterLockSlim _rwLock = ReaderWriterLockSlim(); 50 51 AppendTrailingSlash 52 53 55 56 57 LowercaseUrls 58 59 60 61 62 63 66 67 68 69 VirtualPathProvider VPP 70 72 73 this._vpp == 75 HostingEnvironment.VirtualPathProvider; 77 ._vpp; 81 this._vpp = 82 84 85 public RouteBase this[ name] 87 89 .IsNullOrEmpty(name)) 91 93 RouteBase result; 94 this._namedMap.TryGetValue(name,1)"> result)) 95 96 result; 97 98 100 101 102 RouteCollection() 103 105 106 RouteCollection(VirtualPathProvider virtualPathProvider) 108 this.VPP = virtualPathProvider; 110 111 void Add( name,RouteBase item) 112 113 if (item == 114 115 new ArgumentNullException(item117 string.IsNullOrEmpty(name) && ._namedMap.ContainsKey(name)) 119 new ArgumentException(RouteCollection_DuplicateName name 122 }),1)">124 base.Add(item); 125 127 this._namedMap[name] = item; 128 130 131 public Route MapPageRoute(string routeName,1)">string routeUrl,1)"> physicalFile) 132 this.MapPageRoute(routeName,routeUrl,physicalFile,1)">true,1)">null,1)">135 136 string physicalFile,1)"> checkPhysicalUrlAccess) 138 140 141 checkPhysicalUrlAccess,RouteValueDictionary defaults) 142 144 145 146 147 148 150 151 152 153 if (routeUrl == 154 155 routeUrl156 157 Route route = new Route(routeUrl,dataTokens,1)"> PageRouteHandler(physicalFile,checkPhysicalUrlAccess)); 158 .Add(routeName,route); 159 161 162 override ClearItems() 163 164 ._namedMap.Clear(); 165 .ClearItems(); 166 167 168 IDisposable GetReadLock() 169 170 ._rwLock.EnterReadLock(); 171 new RouteCollection.ReadLockDisposable(._rwLock); 172 173 174 RequestContext GetRequestContext(RequestContext requestContext) 175 176 if (requestContext != 177 178 179 180 HttpContext expr_0A = HttpContext.Current; 181 if (expr_0A == 182 183 new InvalidOperationException(SR.GetString(RouteCollection_RequiresContext184 185 new RequestContext(new HttpContextWrapper(expr_0A),1)"> RouteData()); 186 187 188 IsRouteToExistingFile(HttpContextBase httpContext) 189 190 string appRelativeCurrentExecutionFilePath = httpContext.Request.AppRelativeCurrentExecutionFilePath; 191 return appRelativeCurrentExecutionFilePath != ~/" && this.VPP != null && (this.VPP.FileExists(appRelativeCurrentExecutionFilePath) || .VPP.DirectoryExists(appRelativeCurrentExecutionFilePath)); 192 193 194 195 196 if (httpContext == 197 198 httpContext199 200 if (httpContext.Request == 201 202 new ArgumentException(SR.GetString(RouteTable_ContextMissingRequest203 204 base.Count == 205 206 207 208 bool flag = 209 bool flag2 = 210 .RouteExistingFiles) 211 212 flag = .IsRouteToExistingFile(httpContext); 213 flag2 = 214 (flag) 215 216 217 218 219 using (.GetReadLock()) 220 221 foreach (RouteBase current 222 223 RouteData routeData = current.GetRouteData(httpContext); 224 if (routeData != 225 226 RouteData result; 227 current.RouteExistingFiles) 228 { 229 flag2) 230 { 231 flag = 232 } 233 234 235 result = 236 237 238 } 239 result =240 241 242 243 244 245 246 247 string NormalizeVirtualPath(RequestContext requestContext,1)">248 249 string text = Util.GetUrlWithApplicationPath(requestContext.HttpContext,virtualPath); 250 this.LowercaseUrls || .AppendTrailingSlash) 251 252 int num = text.IndexOfAny(char253 254 '?'255 #' 256 }); 257 text2; 258 str; 259 if (num >= 260 261 text2 = text.Substring(262 str = text.Substring(num); 263 264 else 265 266 text2 =267 str = ""268 269 .LowercaseUrls) 270 271 text2 = text2.ToLowerInvariant(); 272 273 this.AppendTrailingSlash && !text2.EndsWith(/)) 274 275 text2 += 276 277 text = text2 +278 279 280 281 282 283 284 requestContext = .GetRequestContext(requestContext); 285 286 287 using (IEnumerator<RouteBase> enumerator = .GetEnumerator()) 288 289 while (enumerator.MoveNext()) 290 291 VirtualPathData virtualPath = enumerator.Current.GetVirtualPath(requestContext,values); 292 if (virtualPath != 293 294 virtualPath.VirtualPath = .NormalizeVirtualPath(requestContext,virtualPath.VirtualPath); 295 296 297 298 299 300 301 302 303 public VirtualPathData GetVirtualPath(RequestContext requestContext,1)">304 305 requestContext = 306 307 308 .GetVirtualPath(requestContext,1)">309 310 RouteBase routeBase; 311 flag; 312 313 314 flag = routeBase); 315 316 flag) 317 318 RouteCollection_NameNotFound319 320 321 }),1)">322 323 VirtualPathData virtualPath = routeBase.GetVirtualPath(requestContext,1)">324 325 326 virtualPath.VirtualPath = 327 328 329 330 331 332 IDisposable GetWriteLock() 333 334 ._rwLock.EnterWriteLock(); 335 new RouteCollection.WriteLockDisposable(336 337 338 void Ignore( url) 339 340 this.Ignore(url,1)">341 342 343 string url,1)"> constraints) 344 345 if (url == 346 347 url348 349 RouteCollection.IgnoreRouteInternal item = RouteCollection.IgnoreRouteInternal(url) 350 351 Constraints = RouteValueDictionary(constraints) 352 }; 353 354 355 356 void InsertItem(int index,1)">357 358 359 360 361 362 .Contains(item)) 363 364 RouteCollection_DuplicateEntry0]),1)">365 366 .InsertItem(index,item); 367 368 369 void RemoveItem( index) 370 371 .RemoveRouteName(index); 372 .RemoveItem(index); 373 374 375 void RemoveRouteName(376 377 RouteBase routeBase = [index]; 378 ._namedMap) 379 380 if (current.Value == routeBase) 381 382 ._namedMap.Remove(current.Key); 383 break384 385 386 387 388 void SetItem(389 390 391 392 393 394 395 396 397 398 399 .SetItem(index,1)">400 401 } ?RouteCollection类型直接继承Collection<RouteBase>,这个关系很明显,他就是用于存放Route路由规则对象的,用于注册Route路由对象的方法就是MapPageRoute方法,基于篇幅,其他方法就不细说了,大家可以细看。 ? 4、RouteHandler ???? 到此,我们有了路由规则对象Route,也通过RouteTable的Routes属性注册好了,系统启动了,我们要截获请求,截获请求的类文件就是UrlRoutingModule,在上面我已经贴出该类的全部源码了,这里就不写了,截获请求后,开始和RouteTable里面的每一个Route对象进行比较,如果匹配就获得RouteData对象了,有了RouteData对象,其实我们是为了获得RouteHandler的值,有了他的值我们才可以继续,我说了这么多就是这个方法所实现的: PostResolveRequestCache(HttpContextBase context) { RouteData routeData = .RouteCollection.GetRouteData(context); ) { ; } IRouteHandler routeHandler = routeData.RouteHandler; ])); } StopRoutingHandler) { ; } RequestContext requestContext = requestContext; IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); [] { routeHandler.GetType() })); } UrlAuthFailureHandler)) { context.RemapHandler(httpHandler); ; } (FormsAuthenticationModule.FormsAuthRequired) { UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current,1)">); )); } 有了RouteData对象,在和HttpContext对象一起封装为RequestContext对象, RequestContext requestContext =
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
interface IRouteHandler { IHttpHandler GetHttpHandler(RequestContext requestContext); } 最后,我们重新路由HttpHandler,在ASP.NET MVC终究是MvcHandler,他开始结果整个请求,进行Controlller激活和Action方法的执行。 context.RemapHandler(httpHandler); ? 四、结论 ??? 好了,做个总结吧,总体来说不是很难,只要大家理顺了,就好了,这些类的设计都是有因果关系的,理解这种因果关系,再把我前后顺序,理解起来就简单了。 ?? 今天就到这里,写的有点长,大家慢慢看,欢迎讨论,我要去赶火车了。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |