插件式的 WebApi 開發,首要面對的問題就是程序集的發現。由於開發的過程當中,都是在各自的解決方案下進行開發,部署後是分模塊放在一個總體的的運行時網站下。框架
這裏我根據上一節的設定,把插件打包完成後的文件夾,放入網站 bin
目錄下。重複一下這樣作的好處:在插件的配置或者程序集發生變更後,網站會直接從新啓動。編輯器
這是 IIS 的機制,和 WebApi 無關。網站
00_Name
的形式,能夠更方便的按照咱們的要求排列插件。PluginConfig.xml
文件<?xml version="1.0" encoding="UTF-8"?> <configuration enabled="true"> <description>受權支持插件</description> <assemblies> <add type="relative">bin/Intime.AuthorizationService.dll</add> <add type="relative">bin/Intime.AuthorizationService.Services.dll</add> <add type="relative">bin/Intime.AuthorizationService.Data.dll</add> <add type="relative">bin/Intime.AuthorizationService.Data.Repository.dll</add> </assembiles> </configuration>
解釋一下 XML
配置文檔的含義:ui
true
的模塊纔會進行後續操做;不然不作任何操做。add
元素受支持。bin
目錄下。在實現程序集加載以前,咱們有必要大概瞭解一下 BuildManager
類加載程序集的規則。插件
首先,是項目引用,被網站項目引用的 GAC 程序集,都會列入到引用列表中;其次,就是這個類很強大,只要你將程序集放入網站,它就能知道網站運行須要加載這個程序集;最後,還有個不經常使用的設置,Web.config
文件的 runtime
配置節點中引進的目錄,也會被加載。因此咱們要加載的程序集,必須是這三個地方所沒有的程序集。code
另外,就是程序集多版本的問題。這裏咱們約定更新的版本徹底兼容老版本,不然就須要升級代碼以適配這個功能。在網站運行出現多個版本存在的狀況下,咱們約定以下原則:orm
bin
目錄是最早加載的路徑,後續插件加載的程序集版本必須小於等於 bin
目錄下程序集的版本。bin
目錄下:請使用 NuGet 管理第三方程序集。Web.config
文件的 runtime
配置節點加載個性目錄。這樣,咱們能夠定義包含這些元數據的類:配置文件信息、加載的程序集列表,在 PreApplicationStartMethodAttribute
程序集特性設定的方法內,將咱們的程序集加到 BuildManager
管理的 程序集列表中。在程序運行時,.Net 就能夠找到咱們的這些程序集了。xml
代碼是在 Mac 下用文本編輯器寫出來的,請自行腦補。ip
public class DynamicModule { public static DynamicModule Instance { get{ return Instance == null ? (Instance = new DynamicModule()) : Instance; } } public string BaseDirectory { get; set; } public ModuleMetadata[] BaseDirectory { get; set; } ctor() { BaseDirectory = Path.Combine(App.BaseDirectory, "bin"); var modules = Directory.GetFiles(BaseDirectory, "PlugConfig.xml", AllDirectory) .Where(p => p.Configuration.Enabled); bar baseAssemblies = AssemblyName.GetAssemblyNames(BaseDirectory, "*.dll", TopDirectory); var data = baseAssemblies.Intersect(modules.LoadedAssemblyNames) .Where(p => p.CodeBase != BaseDirectory); if(data.Any()) throw new ModuleConfiguration(string.Format("程序集 {0} 裝載出現異常!", string.Join(data))); modules.Foreach(p => p.LoadAssemblies()); } }