RouteCollection類繼承於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(); } } } }