System.Web.Routing命名空间代码解析(三) RouteCollection类
Posted on 2008-12-05 15:46 Andrew Yin 阅读(1865) 评论(1) 收藏 举报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();
}
}
}
}


浙公网安备 33010602011771号