RouteCollectiond的RouteExistingFiles屬性一看這個名字,我想大家就能猜出來它的意思,對靜態資源是否啟用路由。我在Asp.net Web.config文件讀取路徑你真的清楚嗎? 里面做demo時遇到這樣一個問題:
項目結構如下:
我原本是用來讓程序讀views/channel/men/web.config文件,當我添加了men文件夾后,整過路由都出錯了。
我的路由代碼:
routes.MapRoute("channelDefault", "{ChannelName}/{action}", new
{
controller = "Channel",
action = "Default"
});
controller代碼:
public ActionResult Default()
{
string channelName = RouteData.Values["ChannelName"].ToString().Trim();
string actionName = RouteData.Values["action"].ToString().Trim();
string viewName = string.Format("{0}/{1}", channelName, actionName);
return View(viewName);
}
整個代碼是不是都很簡單啊。當我添加了men文件夾后路由出錯,移除men路由就對了。那么問題也就找到了 routes.RouteExistingFiles = true;我對RouteExistingFiles樹立的理解是:對已存在文件是否啟用路由,其實這個理解有點不對啊。
讓我們來看看RouteCollection的GetRouteData方法,里面有這么一段:
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; } } }
它檢查文件和文件目錄是否存在。例如我的請求路徑是http://localhost:11286/men,那么httpContext.Request.AppRelativeCurrentExecutionFilePath的取值是~/men/, 而men這個路徑樹存在的。所以及返回null了。我們知道在UrlRoutingModule的PostResolveRequestCache方法中 會調用this.RouteCollection.GetRouteData(context)獲取RouteData,如果返回值不為null才會調用 context.RemapHandler(httpHandler),那么如果這里返回為null也就表示路由失敗,那么也就找不到對應的 handler來處理此次請求了。
現在讓我們來看看你HostingEnvironment.VirtualPathProvider是如果查找文件和路徑的,首先我們要知道HostingEnvironment.VirtualPathProvider其實是一個MapPathBasedVirtualPathProvider實例,
public override bool DirectoryExists(string virtualDir)
{
return this.CacheLookupOrInsert(virtualDir, false);
}
public override bool FileExists(string virtualPath)
{
return this.CacheLookupOrInsert(virtualPath, true);
}
從DirectoryExists和FileExists方法來看,它主要是調用了一個CacheLookupOrInsert方法。
private bool CacheLookupOrInsert(string virtualPath, bool isFile) { string physicalPath = HostingEnvironment.MapPathInternal(virtualPath); bool doNotCacheUrlMetadata = CachedPathData.DoNotCacheUrlMetadata; string key = null; if (!doNotCacheUrlMetadata) { key = this.CreateCacheKey(isFile, physicalPath); bool? nullable = HttpRuntime.CacheInternal[key] as bool?; if (nullable.HasValue) { return nullable.Value; } } bool flag2 = isFile ? File.Exists(physicalPath) : Directory.Exists(physicalPath); if (!doNotCacheUrlMetadata) { CacheDependency dependencies = null; string filename = flag2 ? physicalPath : FileUtil.GetFirstExistingDirectory(AppRoot, physicalPath); if (filename != null) { dependencies = new CacheDependency(filename); TimeSpan urlMetadataSlidingExpiration = CachedPathData.UrlMetadataSlidingExpiration; HttpRuntime.CacheInternal.UtcInsert(key, flag2, dependencies, Cache.NoAbsoluteExpiration, urlMetadataSlidingExpiration); } } return flag2; }
這里其中有string physicalPath = HostingEnvironment.MapPathInternal(virtualPath);這句,就是把虛擬路徑轉化為物理路徑的。例如我實驗 的時候virtualPath=~/men/,而physicalPath=C:\Users\majiang\Documents\Visual Studio 2010\Projects\System.Configuration\MvcApp\men\,這個文件沒有但是目錄卻是有的。順便提一下默認情況下 CachedPathData.DoNotCacheUrlMetadata是false,在這里它主要用來控制是否使用緩存。真正查找文件和目錄是否存 在是在這句代碼完成的:
bool flag2 = isFile ? File.Exists(physicalPath) : Directory.Exists(physicalPath);不過大家一定要注意這里默認是有緩存的,我當時做實驗的時候見 了 routes.RouteExistingFiles = true;這句也沒起到作用,就知道緩存的存在,知道這里在明白緩存是怎么搞的啊。
總結一下吧:RouteCollectiond的RouteExistingFiles屬性是:對已存在的文件和文件夾是否啟用路由,大家千萬不要忘記還有文件夾這個檢查,同時文件和文件夾的檢查結果默認是啟用了緩存的。