Wind-Eagle

No pain,no gain!
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

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 getset; }

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

        }

    }

}