Welcome 微信登录

首页 / 网页编程 / ASP.NET / System.Web.Routing命名空间代码解析(三) RouteCollection类

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