ASP.NET讀取DLL文件中的頁面和用戶控件(VirtualPathProvider VirtualFile)

這篇文章用來介紹一下如何通過VirtualPathProvider來獲取程序集中的頁面和用戶控件的內容。這樣做的好處是可以在項目中達到所有的文件路徑是統一的,不管你的頁面或者控件來自於任何一個程序集。

舉個例子,你的項目中所有的aspx頁面均存放在Website這個目錄下,那麼通常你可以使用相對路徑~/WebSite/WebPage.aspx來找到目錄下的WebPage頁面。

當你需要從某個程序集(DLL)中加載一個page到你的頁面上來。通常情況下必須要使用Assembly.load()方法來找到它,並且很有可能需要使用到反射來確定它的類型,並且將他返回給頁面,但是當你使用VirtualFile和VirtualPathProvider的時候,這時候對於父頁面來說,它只需要去讀取這個custom file的虛擬路徑即可,具體返回的stream由你自己來定義(例如你仍然可以使用Assembly.load來獲取文件)。那麼你可以自定義它的路徑來保證路徑的一致性。

舉個例子來看看如何來實現這個功能,能夠更清晰一些。

準備工作是建一個Web應用程序,創建一個頁面WebPage和一個用戶控件WebUserControl,同理新建一個另外一個項目也包含同名的這兩個文件,當然你最好在頁面上區分它們來自本項目還是其他項目。例如本項目的寫“I am from 本項目名”,其他項目則改爲其他項目的名字。

[本示例完整源碼下載(0分)] http://download.csdn.net/detail/aa466564931/4414671

首先我們創建一個CustomFile繼承自VirtualFile,這個類的作用是加載來自其他程序集的文件並且返回給VirtualFileProvider使用:

 

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


接着創建一個CustomVirtualProvider類繼承自VirtualPathProvider,這裏我們必須實現以下幾個方法(Assembly是我自定義的文件名,你以爲改爲任意名稱),注意AssemblyPathExist這個方法,在使用base.FileExists判斷之前先進行我們的自定義路徑的判斷,如果存在則使用VirtualFile來取代默認的方法:

 

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

OK, 接下來我們就可以使用我們自定義的path來加載程序集中的文件了,我們把一下代碼放在default頁面中:

注意~/WebSite/WebUserControl.ascx是本項目的文件, ~/Assembly/CSASPNETAssembly.dll/CSASPNETAssembly.WebUserControl.ascx是來自於CSASPNETAssembly.dll的文件:

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


 

好了接下來你可以debug看下結果了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章