System.Web.Routing命名空间代码解析(三) RouteCollection类2012-01-22 博客园 Andrew YinRouteCollection类继承于Collection<RouteBase>并且包装了一个Dictionary<string, RouteBase>,于是它提供了二者的功能。通过察看代码我们可以知道,Collection中和Dictionary中的数据并不完全相同。1.有Name的Route既存于D中又存于C中,并且可以通过索引属性通过Name检索(参看Add方法)2.没有Name的Route只存于C中3.删除Route的时候,如果D中也存在它,则从D中也删除(参看RemoveItem方法)4.设置Route的时候,如果D中也存在它,则从D中也删除(参看SetItem方法,这点需要特别注意)这个类中展现了一种很好的锁机制!请参看代码中的黄色高亮部分!本类中的其他方法以后会在 Route类(下)中讲。
using System;using System.Collections.Generic;using System.Collections.ObjectModel;using System.Globalization;using System.Security.Permissions;using System.Threading;using System.Web;using System.Web.Hosting; namespace System.Web.Routing{ [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] public class RouteCollection : Collection<RouteBase> { // Fields private Dictionary<string, RouteBase> _namedMap; private ReaderWriterLock _rwLock; private VirtualPathProvider _vpp; // Methods public RouteCollection() : this(HostingEnvironment.VirtualPathProvider) {} public RouteCollection(VirtualPathProvider virtualPathProvider) { this._namedMap = new Dictionary<string, RouteBase>(StringComparer.OrdinalIgnoreCase); this._rwLock = new ReaderWriterLock(); this._vpp = virtualPathProvider; } 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[name] = item; } protected override void ClearItems() { this._namedMap.Clear(); base.ClearItems(); } private RequestContext GetRequestContext(RequestContext requestContext) { if (requestContext != null) return requestContext; HttpContext current = HttpContext.Current; if (current == null) throw new InvalidOperationException(RoutingResources.RouteCollection_RequiresContext); return new RequestContext(new HttpContextWrapper(current), new RouteData()); } public RouteData GetRouteData(HttpContextBase httpContext) { if (httpContext == null) throw new ArgumentNullException("httpContext"); if (httpContext.Request == null) throw new ArgumentException(RoutingResources.RouteTable_ContextMissingRequest, "httpContext"); if (!this.RouteExistingFiles) { string appRelativeCurrentExecutionFilePath = httpContext.Request.AppRelativeCurrentExecutionFilePath; if (((appRelativeCurrentExecutionFilePath != "~/") && (this._vpp != null)) && (this._vpp.FileExists(appRelativeCurrentExecutionFilePath) || this._vpp.DirectoryExists(appRelativeCurrentExecutionFilePath))) return null; } using (this.GetReadLock()) foreach (RouteBase base2 in this) { RouteData routeData = base2.GetRouteData(httpContext); if (routeData != null) return routeData; } return null; } private static string GetUrlWithApplicationPath(RequestContext requestContext, string url) { string str = requestContext.HttpContext.Request.ApplicationPath ?? string.Empty; if (!str.EndsWith("/", StringComparison.OrdinalIgnoreCase)) str = str + "/"; return requestContext.HttpContext.Response.ApplyAppPathModifier(str + url); } public VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) { requestContext = this.GetRequestContext(requestContext); using (this.GetReadLock()) foreach (RouteBase base2 in this) { VirtualPathData virtualPath = base2.GetVirtualPath(requestContext, values); if (virtualPath != null) { virtualPath.VirtualPath = GetUrlWithApplicationPath(requestContext, virtualPath.VirtualPath); return virtualPath; } } return null; } public VirtualPathData GetVirtualPath(RequestContext requestContext, string name, RouteValueDictionary values) { RouteBase base2; bool flag; requestContext = this.GetRequestContext(requestContext); if (string.IsNullOrEmpty(name)) return this.GetVirtualPath(requestContext, values); using (this.GetReadLock()) flag = this._namedMap.TryGetValue(name, out base2); if (!flag) throw new ArgumentException( string.Format(CultureInfo.CurrentUICulture, RoutingResources.RouteCollection_NameNotFound, new object[] {name}), "name"); VirtualPathData virtualPath = base2.GetVirtualPath(requestContext, values); if (virtualPath == null) return null; virtualPath.VirtualPath = GetUrlWithApplicationPath(requestContext, virtualPath.VirtualPath); return virtualPath; } protected override void InsertItem(int index, RouteBase item) { if (item == null) throw new ArgumentNullException("item"); if (base.Contains(item)) throw new ArgumentException( string.Format(CultureInfo.CurrentUICulture, RoutingResources.RouteCollection_DuplicateEntry, new object[0]), "item"); base.InsertItem(index, item); } protected override void RemoveItem(int index) { this.RemoveRouteName(index); base.RemoveItem(index); } private void RemoveRouteName(int index) { RouteBase base2 = base[index]; foreach (KeyValuePair<string, RouteBase> pair in this._namedMap) if (pair.Value == base2) { this._namedMap.Remove(pair.Key); break; } } protected override void SetItem(int index, RouteBase item) { if (item == null) throw new ArgumentNullException("item"); if (base.Contains(item)) throw new ArgumentException( string.Format(CultureInfo.CurrentUICulture, RoutingResources.RouteCollection_DuplicateEntry, new object[0]), "item"); this.RemoveRouteName(index); base.SetItem(index, item); } // Properties public RouteBase this[string name] { get { RouteBase base2; if (!string.IsNullOrEmpty(name) && this._namedMap.TryGetValue(name, out base2)) return base2; return null; } } public bool RouteExistingFiles { get; set; } public IDisposable GetReadLock() { this._rwLock.AcquireReaderLock(-1); return new ReadLockDisposable(this._rwLock); } public IDisposable GetWriteLock() { this._rwLock.AcquireWriterLock(-1); return new WriteLockDisposable(this._rwLock); } // Nested Types private class ReadLockDisposable : IDisposable { // Fields private ReaderWriterLock _rwLock; // Methods public ReadLockDisposable(ReaderWriterLock rwLock) { this._rwLock = rwLock; } void IDisposable.Dispose() { this._rwLock.ReleaseReaderLock(); } } private class WriteLockDisposable : IDisposable { // Fields private ReaderWriterLock _rwLock; // Methods public WriteLockDisposable(ReaderWriterLock rwLock) { this._rwLock = rwLock; } void IDisposable.Dispose() { this._rwLock.ReleaseWriterLock(); } } }}