WebApi 插件式构建方案:发现并加载程序集

By | 12月02日
Advertisement

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

Similar Posts:

  • Android插件化完美实现代码资源加载及原理讲解 附可运行demo

    我们通过前4篇的分解,分别将插件化设计到的知识点全部梳理了一遍,如果没有看过的,建议先看前面4篇 Binder机制 插件化知识详细分解及原理 之代理,hook,反射, 类加载及dex加载 应用启动过程及类加载过程 好了上面介绍了之前准备的知识点后今天我们做一个真正的可运行的启动插件demo,要知道一个插件可能是随时从网上下载下来的,那么也就是说其实这个apk不会被安装,那么如果不被安装,怎么能被加载呢, 又如何管理插件中四大组件的生命周期呢,没有生命周期的四大组件是没有意义的.而且Activit

  • 分享JQuery动画插件Velocity.js的六种列表加载特效

    分享JQuery动画插件Velocity.js的六种列表加载特效.在这款实例中给中六种不同的列表加载效果.分别为从上飞入.从右侧飞入.从左侧飞入.和渐显.一起看下效果图: 在线预览 源码下载 实现的代码. html代码: <h1> Velocity.js <i>slice + sequence</i></h1> <pre>Only anim X number with FX#1, animate Y number with FX#2 etc /

  • 关于c#中 的动态加载程序集

    最近在写一个解析分析程序,需要动态加载卸载程序集(其实就是一个简单的插件框架),我的 思路是在主程序的目录下,创建一个assemblis目录,用来存放插件目录,如果加载插件时将其复制到 此目录,然后主程序从此目录中加载程序集.其实还有一个更简单的方法,也是在网上找到的.代码如下: AppDomainSetup setup = new AppDomainSetup(); setup.ApplicationBase = functionDirectory; setup.PrivateBinPath

  • Prism框架中加载类库中时其中第三方类dll提示无法加载程序集

    Prism框架是采用一种依赖注入的方式动态加载程序集,能够在程序需要加载的时候将程序集注入到里面去,实现程序的热插拔效果,而且采用这种框架能够让我们进行一个大项目的独立开发,在最近的一个项目中在独立开发的一个模块中,引用了第三方的一个控件DateTimePicker,在我们的项目中引用了该程序集xceed.wpf.toolkit.dll,但是在我们启动整个项目的时候总是找不到xceed.wpf.toolkit.dll,我们开发的项目是放在Apps文件夹下面的,但是在该文件夹下面明明已经放置了该d

  • 未能加载程序集或者命名空间

    命名空间加载上之后仍然报错"未能加载程序集或者命名空间". 1.引用上dll之后将每个项目进行编译 不通过 2.重新引用然后关闭vs 不通过 3.查看项目属性的framework是否和dll的相匹配 再不行就没办法了.

  • .NET 动态加载程序集 (三)

    .NET 动态加载程序集(三) 来源: CSDN 作者: dragonsuc 我们先看看一般的反射的动态方法查找 下面为ms自带的例子ms-help://MS.VSCC/MS.MSDNVS.2052/cpref/html/frlrfsystemreflectionmethodbaseclassinvoketopic.htm public class A { public virtual int method () {return 0;} } public class B { public vir

  • Android插件化开发 第二篇 [动态加载apk优化]

    引言 上篇文章我们有提到过ClassLoader类加载器,通过学习了解到系统提供的类加载器有* PathClassLoader*和* DexClassLoader*两种.它们的不同之处是: * PathClassLoader只能加载系统/data/data/包名目录下的apk: * DexClassLoader可以加载jar/apk/dex,可以从SD卡中加载的apk: 当Android应用开启的时候会创建一个PathClassLoader用来加载自己apk中的类,上篇文章中我们使用的insta

  • Jquery Mobile插件的使用-页面的预加载和缓存

    通常,把不同的page存储在多个html文档是要比用一个大的保存多个page容器的文档要好.这样每个页面的dom会少一些. 当使用单一page的文档时,你可以把page预加载到dom中,这样用户在访问时可以立即打开.要预加载一个页面,给指向这个页面的链接添加data-prefetch属性.jQueryMobile会在加载完当前页面之后在后台自动加载目标页面,pagecreate事件会被触发.例如: <a href="prefetchThisPage.html" data-pref

  • C#利用反射来加载程序集,并调用程序集中有关类的方法

    此文章来自博客园,因为原文已经打不开,我是在百度快照中看到的,所以贴在这里做个备份. -------------------------------------------------------------------------------------------------------------------------------------- 假设在C盘根目录下有个Dog的Dll程序集文件,该程序集文件中包含类Dog 该类中有个狗叫几声的方法,如何通过反射来加载这个C:\Dog.dll

  • 加载程序集时设置特定的权限(Appdomain.ExecuteAssembly())

    通常,当我们需要加载外部程序集(例如加载第三方控件)时,为了避免由于第三方控件程序漏洞或希望安全访问该程序集, 我们需要利用System.Security.Policy.Evidence 来创建一个Evidence来限制访问该程序集的权限. Code static void Main(string[] args) { object[] hostEvidences = { new Zone(System.Security.SecurityZone.Internet) }; Evidence int

Tags: