在Asp.Net的開發(fā)過程中頁面文件等都是放在當前網(wǎng)站目錄下的,其實我們可以利用.Net2.0新增的虛擬文件系統(tǒng)(VirtualPathProvider)將頁面、圖片等信息保存到數(shù)據(jù)庫或其他目錄中去,達到靈活配置。
以前開發(fā)Asp.Net的web用戶控件時,需要把用戶控件和當前項目作為同一個項目時才能正常使用,而且發(fā)布時需要把dll文件和所有的ascx文件都發(fā)布才能使用;另外也不方便作為公用類給其他人使用 利用虛擬文件系統(tǒng)后可以把ascx文件作為資源打包到dll中,下次只要有這個dll就可以使用了,不需要ascx文件,很方便。 具體實現(xiàn)步驟如下: 一、開發(fā)web用戶控件 這一步和以前的開發(fā)沒有區(qū)別。 1、首先新建一個web應用程序(需要VS2005 sp1支持) 2、然后在里面開發(fā)幾個web用戶控件 3、在ascx文件上右鍵-〉屬性-〉生成操作選擇嵌入的資源 4、生成dll就可以了(dll的名字為:Test.Control.dll,后面會用到) 二、開發(fā)一個虛擬文件系統(tǒng)提供類 這一步是最重要的一步。 具體思路就是:在系統(tǒng)中注冊這個類,然后在每訪問一個文件/資源的時候會自動調(diào)用這個類,在這個類中判斷文件的路徑是否是我們定義的,如果是就用我們的邏輯來處理,即從dll中取出資源。 首先把類的代碼貼出來,我想可能許多人應該和我一樣,喜歡直接先看代碼:) DllVirtualPathProvider public class DllVirtualPathProvider : System.Web.Hosting.VirtualPathProvider { public DllVirtualPathProvider() { } public override string CombineVirtualPaths(string basePath, string relativePath) { if (IsAppResourcePath(basePath)) { return null; }
return Previous.CombineVirtualPaths(basePath, relativePath); }
public override System.Runtime.Remoting.ObjRef CreateObjRef(Type requestedType) { return Previous.CreateObjRef(requestedType); }
public override bool DirectoryExists(string virtualDir) { if (IsAppResourcePath(virtualDir)) { return true; } else { return Previous.DirectoryExists(virtualDir); }
}
public override string GetCacheKey(string virtualPath) { if (IsAppResourcePath(virtualPath)) { return null; } else { return Previous.GetCacheKey(virtualPath); } }
public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies) { if (IsAppResourcePath(virtualPath)) { return null; } else { return Previous.GetFileHash(virtualPath, virtualPathDependencies); } }
private bool IsAppResourcePath(string virtualPath) { String checkPath = VirtualPathUtility.ToAppRelative(virtualPath); return checkPath.StartsWith("~/MyUserControl/Test.Control.dll/", StringComparison.InvariantCultureIgnoreCase); }
public override bool FileExists(string virtualPath) { return (IsAppResourcePath(virtualPath) || Previous.FileExists(virtualPath)); }
public override VirtualFile GetFile(string virtualPath) { if (IsAppResourcePath(virtualPath)) { return new AssemblyResourceVirtualFile(virtualPath); } else { return Previous.GetFile(virtualPath); } }
public override System.Web.Caching.CacheDependency GetCacheDependency(string virtualPath, System.Collections.IEnumerable virtualPathDependencies, DateTime utcStart) { if (IsAppResourcePath(virtualPath)) { string path = HttpRuntime.AppDomainAppPath + virtualPath.Substring(1);
return new System.Web.Caching.CacheDependency(path); } else { return Previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart); } } }重點有以下幾個: 1、必須從VirtualPathProvider類繼承 2、IsAppResourcePath方法是用來判斷是否為我們定義的路徑格式:~/MyUserControl/Test.Control.dll/,下面調(diào)用的時候就使用這個路徑 3、注意GetCacheKey方法: public override string GetCacheKey(string virtualPath) { if (IsAppResourcePath(virtualPath)) { return null; } else { return Previous.GetCacheKey(virtualPath); } }這里當符合條件時一定要返回null,如果返回"",會導致所有的用戶控件都使用一個key值,從而所有的用戶控件都顯示同樣的內(nèi)容了。如果返回其他非空字符,會報異常(它會去查找cache,我們是沒有的) 另外所有的方法當不符合我們的條件時一定要調(diào)用 Previous.**** 因為系統(tǒng)中可能有多個虛擬文件提供程序的。
4、GetCacheDependency方法: if (IsAppResourcePath(virtualPath)) { string path = HttpRuntime.AppDomainAppPath + virtualPath.Substring(1);
return new System.Web.Caching.CacheDependency(path); }這個方法是用來決定Cache的使用的,如果返回null,會導致性能嚴重下降,每次調(diào)用用戶控件時都會重新編譯,這里返回的當前路徑(需要在網(wǎng)站目錄下再建立子目錄:MyUserControl\Test.Control.dll),這個目錄下是空的,這樣當每次取Cache時都會認為我們的ascx沒有修改,不需要重新編譯。
5、在GetFile方法中我們返回的是一個AssemblyResourceVirtualFile類: class AssemblyResourceVirtualFile : VirtualFile { string path; public AssemblyResourceVirtualFile(string virtualPath) : base(virtualPath) { path = VirtualPathUtility.ToAppRelative(virtualPath); }
public override System.IO.Stream Open() { string[] parts = path.Split('/'); string assemblyName = parts[2]; string resourceName = parts[3]; assemblyName = Path.Combine(HttpRuntime.BinDirectory, assemblyName); System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFrom(assemblyName); if (assembly != null) { return assembly.GetManifestResourceStream(resourceName); } return null; } }這個類的目的就是從我們的dll中讀出資源文件。 三、注冊這個虛擬文件提供程序 這一個很簡單,在global.asax中注冊: protected void Application_Start(object sender, EventArgs e) { System.Web.Hosting.HostingEnvironment.RegisterVirtualPathProvider(new DllVirtualPathProvider()); } 四、調(diào)用dll中的用戶控件 Control control1 = this.LoadControl("/MyUserControl/Test.Control.dll/Test.Control.Sample.List.ascx"); Control control2 = this.LoadControl("/MyUserControl/Test.Control.dll/Test.Control.Sample.Sample.ascx");
form1.Controls.Add(control1); form1.Controls.Add(control2);比較簡單,就是路徑要和前面的一致。 后記: 首先感謝 Leepy 同志認真踏實的精神,找出了我這篇文章中的一個BUG。 原來我的第四步:調(diào)用dll中的用戶控件,是一個web應用程序,如果是一個web站點的話就會出現(xiàn)問題。因為在VS2005中調(diào)試時這兩種方式呈現(xiàn)出來的Url是不一樣的: web應用程序:http://localhost:****/Default.aspx web站點 :http://localhost:****/WebSite1/Default.aspx 也就是說我原來的程序沒有考慮到非根目錄部署的情況,針對這個BUG要修改的地方有(為了BUG的原始記錄,我就不在原文中修改了,把修改點列在下面): 1、GetCacheDependency方法: GetCacheDependency public override System.Web.Caching.CacheDependency GetCacheDependency(string virtualPath, System.Collections.IEnumerable virtualPathDependencies, DateTime utcStart) { if (IsAppResourcePath(virtualPath)) { string path = HttpRuntime.BinDirectory;
return new System.Web.Caching.CacheDependency(path); } else { return Previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart); } }這里改成直接改成當前網(wǎng)站的bin目錄還可以省掉建空目錄的步驟了, 軟件開發(fā)網(wǎng)
2、在調(diào)用的地方修改成以下方式: Control control1 = this.LoadControl("~/MyUserControl/MyWebApplication.dll/MyWebApplication.Sample1.ascx"); Control control2 = this.LoadControl("~/MyUserControl/MyWebApplication.dll/MyWebApplication.Sample2.ascx"); form1.Controls.Add(control1); form1.Controls.Add(control2);
|