ASP.NET Web Froms开发模式中实现程序集的延迟加载
延遲加載是一個很大的誘惑,可以達到一些比較好的效果,比如:
1、在實體框架中,由于關聯數據的數量和使用時機是不確定的,通過延遲加載,僅在使用的時候去執行關聯數據的查詢操作,減少無謂的數據查詢操作,可以降低單次數據查詢執行的時間,提升系統的性能。
2、在一個插件平臺中啟動平臺時只加載必需的程序集,當執行到具體插件時再加載插件相關的程序集,僅在需要的時候加載資源,可以減少插件平臺的啟動時間,使內存的占用更合理些。
延遲加載可以使資源的占用更加合理,并提升一定的性能,當然也有一些例子來說明延遲加載的壞處,這就需要根據實際的情況去考量,不是這篇文章的目的。
?
言歸正傳,在ASP.NET Web Forms開發模式中,程序集一般都放到bin目錄下,或者在web.config中通過配置codebase或者probing節點指定程序集目錄,應用程序啟動時會從這些位置自動加載程序集。我們要使用延遲加載,就不能將程序集放到這些地方,將需要延遲加載的程序集放到一些有規則可循的目錄是一種比較好的方式。比如:
root
|–bin
|–lazyload
| ? ?|–bin1
| ? ?|–bin2
將這些程序集都放到一個lazyload的目錄中,然后在其中根據程序集的劃分建立不同的子目錄,根據需要去不同的目錄中加載程序集。
?
那么使用什么方法加載程序集呢?
Assembly類提供了幾個靜態方法:Load、LoadFile、LoadFrom,可以通過這幾個方法將dll文件加載到當前應用程序域的程序集中。
關于這幾個方法如何選擇,網上有一些總結,這里不做討論。以下是一些總結:
http://www.cnblogs.com/xuqingfeng/archive/2012/05/22/assembly-load-loadfrom-loadfile-details.html
http://msdn.microsoft.com/zh-cn/library/dd153782(v=vs.110).aspx
?
實現程序集的延遲加載需要擴展兩個地方:
1、依賴程序集的延遲加載
通過訂閱當前應用程序域的AssemblyResolve事件,應用程序域在加載依賴程序集時如果找不到就會觸發這個事件。
在這個事件中我們可以通過一些規則找到需要加載的程序集文件,然后通過Assembly的加載方法加載到內存,并返回。
| AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; |
| ? |
| private?Assembly CurrentDomain_AssemblyResolve(object?sender, ResolveEventArgs args) |
| { |
| Assembly assembly =?null; |
| ? |
| //加載程序集部分省略 |
| ? |
| return?assembly; |
| } |
2、頁面動態編譯所需程序集的延遲加載
aspx頁面在首次訪問時會進行編譯,編譯時需要頁面綁定的類所在的程序集。默認情況下這些程序集是在程序啟動的時候自動加載的,從.net4開始,微軟提供了一個應用程序啟動的擴展支持System.Web.PreApplicationStartMethod,也可以在這里通過程序加載程序集,但還是達不到延遲加載的效果。
aspx頁面的編譯是通過BuildManager實現的,調用BuildManager.AddReferencedAssembly方法可以添加程序集,但是這個方法只能在上邊提到的擴展支持中調用,程序啟動后再調用就會拋出異常(可能是.net4.0還有些東西沒協調好),此路不通。既然不能通過方法添加,那是不是可以直接加入到BuildManager的程序集集合中,很不幸全是私有的,有興趣的可以自己反編譯看看。
私有的其實也不是沒有辦法可以獲取,使用反射,還好BuildManager有一個靜態的屬性TheBuildManager,通過反射獲取這個屬性的值就可以得到內部的BuildManager實例,修改程序集的集合就不成問題了。
| // 獲取BuildManager的實例 |
| PropertyInfo buildmanagerProperty = Type.GetTypeFromHandle(typeof(BuildManager).TypeHandle).GetProperty("TheBuildManager", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.GetProperty); |
| BuildManager buildmanager = buildmanagerProperty.GetValue(null,?null)?as?BuildManager; |
| ? |
| // 獲取TopLevelReferencedAssemblies |
| PropertyInfo topLevelReferencedAssembliesProperty = Type.GetTypeFromHandle(typeof(BuildManager).TypeHandle).GetProperty("TopLevelReferencedAssemblies", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetProperty); |
| IList assemblies = topLevelReferencedAssembliesProperty.GetValue(buildmanager,?null)?asIList; |
| ? |
| // 添加程序集 |
| Assembly assembly =?null; |
| ? |
| //加載程序集部分省略 |
| ? |
| assemblies.Add(assembly); |
這段程序要在頁面編譯之前調用,比如PageHandlerFactory的GetHandler方法中。
?
通過這兩個擴展基本上就可以實現程序集的延遲加載了,能用來干什么就要看自己了。博客園有個人搞了個OSGI.NET,就用到文中的兩個方法。
當然上邊只是初步給出了解決問題的方法,如果要實際使用,可能要考慮更多的問題,比如多線程同步問題、程序集多版本問題等等,有興趣的可以寫寫看。
?
本人獨立博客地址:http://blog.bossma.cn/dotnet/asp-net-how-to-lazy-load-assembly/
轉載請注明出處。
?
轉載于:https://www.cnblogs.com/bossma/p/3457903.html
總結
以上是生活随笔為你收集整理的ASP.NET Web Froms开发模式中实现程序集的延迟加载的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: xposed 修改手机定位
- 下一篇: ASP.Net中实现中英文复合检索文本框