插件式的 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()); } }