zoukankan      html  css  js  c++  java
  • WebApi 插件式构建方案:发现并加载程序集

    插件式的 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 配置文档的含义:

    • enabled="true" 表示当前插件的可用性,只有值为 true 的模块才会进行后续操作;否则不做任何操作。
    • description 子元素表示当前模块的自然语义名称,在程序上没有任何含义,面向自然人说明当前模块的作用。
    • assemblies 子元素表示当前模块下需要加载的程序集列表。
      • add 元素表示添加一个程序集文件:目前有且只有一个 add 元素受支持。
      • type 表示内含程序集路径的类型:
        • relative 表示相对路径,为程序集文件相对于当前配置文件的路径:比如第一个文件就是在当前目录的子目录 bin 目录下。
        • absolute 表示绝对路径,表示程序不必做额外工作就可以根据路径信息找到文件:此处没有栗子
      • 内含文本表示程序集的路径信息。

    BuildManager 程序集加载规则

    在实现程序集加载之前,我们有必要大概了解一下 BuildManager 类加载程序集的规则。

    首先,是项目引用,被网站项目引用的 GAC 程序集,都会列入到引用列表中;其次,就是这个类很强大,只要你将程序集放入网站,它就能知道网站运行需要加载这个程序集;最后,还有个不常用的设置,Web.config 文件的 runtime 配置节点中引进的目录,也会被加载。所以我们要加载的程序集,必须是这三个地方所没有的程序集。

    另外,就是程序集多版本的问题。这里我们约定更新的版本完全兼容老版本,否则就需要升级代码以适配这个功能。在网站运行出现多个版本存在的情况下,我们约定如下原则:

    • bin 目录是最先加载的路径,后续插件加载的程序集版本必须小于等于 bin 目录下程序集的版本。
    • 非 .Net 框架库自带的程序集,一律要拷贝到网站 bin 目录下:请使用 NuGet 管理第三方程序集。
    • 不要使用 Web.config 文件的 runtime 配置节点加载个性目录。

    这样,我们可以定义包含这些元数据的类:配置文件信息、加载的程序集列表,在 PreApplicationStartMethodAttribute 程序集特性设定的方法内,将我们的程序集加到 BuildManager 管理的 程序集列表中。在程序运行时,.Net 就可以找到我们的这些程序集了。

    部分源代码:自然语义

    代码是在 Mac 下用文本编辑器写出来的,请自行脑补。

    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());
      }
    }
    
  • 相关阅读:
    Entity Framework+SQLite+DataBaseFirst
    接口的实现方式(显示和隐示)及协变和逆变
    C#线程
    UIScrollView放大缩小图片偏移的问题
    SQL Server 2008在添加用户时弹出错误提示:此版本的 Microsoft Windows 不支持 MUST_CHANGE 选项
    jmeter的正则表达式的使用
    Linux下安装jmeter
    系统测试方案
    [ASP.NET].NET逻辑分层架构总结
    [C#]C#时间日期操作
  • 原文地址:https://www.cnblogs.com/lenic/p/4137161.html
Copyright © 2011-2022 走看看