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();
}
}
}
}