【译】All-In-One:加载嵌入资源中的用户控件

原文地址:http://code.msdn.microsoft.com/CSASPNETAccessResourceInAss-6725d61a

你可以在原文中下载源代码,我在文章中不再提供下载链接。

 

介绍

  本项目举例说明了如何通过虚拟路径访问类库中的用户控件和页面,我们继承了VirtualPathProvider和VirtualFile类创建了一个自定义路径提供程序,这个虚拟文件系统能够提供一类像似的文件路径,供不同的程序访问文件或代码。例如,我们可以将相同类型但在不同程序集(a.dll, b.dll)中的文件(a.mp3, b.mp3)使用统一的虚拟路径,像 http://localhost/mp3/a.mp3http://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());
        }

第七步:编译并调试。

posted @ 2012-06-13 17:35  拓荒者FF  阅读(651)  评论(0编辑  收藏  举报