原文地址:http://code.msdn.microsoft.com/CSASPNETAccessResourceInAss-6725d61a
你可以在原文中下载源代码,我在文章中不再提供下载链接。
本项目举例说明了如何通过虚拟路径访问类库中的用户控件和页面,我们继承了VirtualPathProvider和VirtualFile类创建了一个自定义路径提供程序,这个虚拟文件系统能够提供一类像似的文件路径,供不同的程序访问文件或代码。例如,我们可以将相同类型但在不同程序集(a.dll, b.dll)中的文件(a.mp3, b.mp3)使用统一的虚拟路径,像 http://localhost/mp3/a.mp3 和 http://localhost/mp3/b.mp3。通过这种方法,我们的网站变得更加清晰和易于交互。
跟着示例的步骤:
第一步:打开CSASPNETAccessResourceInAssembly.sln,展开CSASPNETAccessResourceInAssembly Web应用程序,按CTRL+ F5浏览Default.aspx。
第二步:我们将会在页面上看到两个用户控件和两个连接,红色边框部分和它下面的连接来自CSASPNETAssembly项目,蓝色边框部分和WebSite/WebPage连接来自本项目。
第三步:你可以点击两个连接来查看两个不同程序集中的页面,Assembly/WebPage 是CSASPNETAssembly项目的页面,Website/WebPage是当前项目的页面。
来自CSASPNETAssembly的页面:
来自本项目的页面:
第四步:完成
代码逻辑:
第一步:在Visual Studio 2010 或 Visual Web Developer 2010中创建一个空的Web应用程序,命名为“CSASPNETAccessResourceInAssembly”。这个程序需要新建两个项目:“CSASPNETAccessResourceInAssembly”和“CSASPNETAssembly”。
第二步:在项目CSASPNETAssembly中,创建一个用户控件也Web页面,这个项目是目标项目,另外一个会访问它的资源。为了使页面和用户控件看上去和别的不同,我们需要为他们加入一些文字和特殊颜色的边框。
第三步:像第二步一样为CSASPNETAccessResourceInAssembly添加页面和用户控件,同样需要添加一些文字和边框。然后我们需要添加一个模板页来显示这些资源,新增一个名字为default.aspx的页面,在后台代码中添加加载用户控件和连接。常规的web页面和用户控件,我们可以用相对路径直接访问,但对于程序中的资源,我们需要在url中加入一些特殊的信息。
使用一下代码为default.aspx添加控件和链接:
public partial class Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { // Add relative web pages and user controls in assembly and this application. DataTable tab = this.InitializeDataTable(); if (tab != null && tab.Rows.Count != 0) { for (int i = 0; i < tab.Rows.Count; i++) { Control control = Page.LoadControl(tab.Rows[i]["UserControlUrl"].ToString()); UserControl usercontrol = control as UserControl; Page.Controls.Add(usercontrol); HyperLink link = new HyperLink(); link.NavigateUrl = tab.Rows[i]["WebPageUrl"].ToString(); link.Text = tab.Rows[i]["WebPageText"].ToString(); Page.Controls.Add(link); } } } /// <summary> /// Initialize a DataTable variable for storing URL and text properties. /// </summary> /// <returns></returns> protected DataTable InitializeDataTable() { DataTable tab = new DataTable(); DataColumn userControlUrl = new DataColumn("UserControlUrl",Type.GetType("System.String")); tab.Columns.Add(userControlUrl); DataColumn webPageUrl = new DataColumn("WebPageUrl", Type.GetType("System.String")); tab.Columns.Add(webPageUrl); DataColumn webPageText = new DataColumn("WebPageText", Type.GetType("System.String")); tab.Columns.Add(webPageText); DataRow dr = tab.NewRow(); dr["UserControlUrl"] = "~/Assembly/CSASPNETAssembly.dll/CSASPNETAssembly.WebUserControl.ascx"; dr["WebPageUrl"] = "~/Assembly/CSASPNETAssembly.dll/CSASPNETAssembly.WebPage.aspx"; dr["WebPageText"] = "Assembly/WebPage"; DataRow drWebSite = tab.NewRow(); drWebSite["UserControlUrl"] = "~/WebSite/WebUserControl.ascx"; drWebSite["WebPageUrl"] = "~/WebSite/WebPage.aspx"; drWebSite["WebPageText"] = "WebSite/WebPage"; tab.Rows.Add(dr); tab.Rows.Add(drWebSite); return tab; } }
第四步:万事俱备,现在我们可以创建自定义虚拟文件系统了。首先,创建一个继承自VirtualPathProvider 的类,重写一些必要的方法,例如FileExists、GetFile、GetCacheDependency,这个类用来接收和解析来自web请求,以获得正确的资源。
public class CustomPathProvider : VirtualPathProvider { public CustomPathProvider() { } /// <summary> /// Make a judgment that application find path contains specifical folder name. /// </summary> /// <param name="path"></param> /// <returns></returns> private bool AssemblyPathExist(string path) { string relateivePath = VirtualPathUtility.ToAppRelative(path); return relateivePath.StartsWith("~/Assembly/", StringComparison.InvariantCultureIgnoreCase); } /// <summary> /// If we can find this virtual path, return true. /// </summary> /// <param name="virtualPath"></param> /// <returns></returns> public override bool FileExists(string virtualPath) { if (this.AssemblyPathExist(virtualPath)) { return true; } else { return base.FileExists(virtualPath); } } /// <summary> /// Use custom VirtualFile class to load assembly resources. /// </summary> /// <param name="virtualPath"></param> /// <returns></returns> public override VirtualFile GetFile(string virtualPath) { if (AssemblyPathExist(virtualPath)) { return new CustomFile(virtualPath); } else { return base.GetFile(virtualPath); } } /// <summary> /// Return null when application use virtual file path. /// </summary> /// <param name="virtualPath"></param> /// <param name="virtualPathDependencies"></param> /// <param name="utcStart"></param> /// <returns></returns> public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart) { if (AssemblyPathExist(virtualPath)) { return null; } else { return base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart); } } }
第五步:然后创建一个虚拟文件类,用来从CustomPathProvider获取路径,并检查url是否合法,并返回相对于程序集的文件流。
public class CustomFile: VirtualFile { string path { get; set; } public CustomFile(string virtualPath) : base(virtualPath) { path = VirtualPathUtility.ToAppRelative(virtualPath); } /// <summary> /// Override Open method to load resource files of assembly. /// </summary> /// <returns></returns> public override System.IO.Stream Open() { string[] strs = path.Split('/'); string name = strs[2]; string resourceName = strs[3]; name = Path.Combine(HttpRuntime.BinDirectory, name); Assembly assembly = Assembly.LoadFile(name); if (assembly != null) { Stream s = assembly.GetManifestResourceStream(resourceName); return s; } else { return null; } } }
第六步:最后,你需要在Application_Start 事件中注册CustomPathProvider 类,这个提供者会随着程序一起运行。
protected void Application_Start(object sender, EventArgs e) { HostingEnvironment.RegisterVirtualPathProvider(new CustomPathProvider()); }
第七步:编译并调试。