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

WebApi 插件式构建方案:发现并加载程序集的更多相关文章

  1. WebApi 插件式构建方案:集成加载数据库连接字符串

    body { border: 1px solid #ddd; outline: 1300px solid #fff; margin: 16px auto; } body .markdown-body ...

  2. WebApi 插件式构建方案:重写的控制器获取工厂

    body { border: 1px solid #ddd; outline: 1300px solid #fff; margin: 16px auto; } body .markdown-body ...

  3. WebApi 插件式构建方案:IOC 容器初始化

    body { border: 1px solid #ddd; outline: 1300px solid #fff; margin: 16px auto; } body .markdown-body ...

  4. WebApi 插件式构建方案

    WebApi 插件式构建方案 WebApi 插件式构建方案 公司要推行服务化,不可能都整合在一个解决方案内,因而想到了插件式的构建方案.最终定型选择基于 WebApi 构建服务化,之所以不使用 WCF ...

  5. Winfom 插件式(Plugins)/模块化开发框架-动态加载DLL窗体-Devexpress

    插件式(AddIn)架构,不是一个新名词,应用程序采用插件式拼合,可以更好的支持扩展.很多著名的软件都采用了插件式的架构,如常见的IDE:Eclipse,Visual Studio,SharpDeve ...

  6. MVC中未能加载程序集System.Web.Http/System.Web.Http.WebHost

    ==================================== 需要检查项目的Microsoft.AspNet.WebApi版本是否最新,System.Web.Http 这个命名空间需要更新 ...

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

    分享JQuery动画插件Velocity.js的六种列表加载特效.在这款实例中给中六种不同的列表加载效果.分别为从上飞入.从右侧飞入.从左侧飞入.和渐显.一起看下效果图: 在线预览   源码下载 实现 ...

  8. .Net Core 通过依赖注入和动态加载程序集实现宿程序和接口实现类库完全解构

    网上很多.Net Core依赖注入的例子代码,例如再宿主程序中要这样写: services.AddTransient<Interface1, Class1>(); 其中Interface1 ...

  9. C#在使用Assembly加载程序集时失败

    错误现象: 进行插件读取时出现错误:"尝试从一个网络位置加载程序集,在早期版本的 .NET Framework 中,这会导致对该程序集进行沙盒处理.此发行版的 .NET Framework ...

随机推荐

  1. SQL 基础命令和函数

    [数据操作] SELECT --从数据库表中检索数据行和列 INSERT --向数据库表添加新数据行 DELETE --从数据库表中删除数据行 UPDATE --更新数据库表中的数据 [数据定义] C ...

  2. unicat,multicast,broadcast区别

    单播.多播和广播单播”(Unicast).“多播”(Multicast)和“广播”(Broadcast)这三个术语都是用来描述网络节点之间通讯方式的术语.那么这些术语究竟是什么意思?区别何在? 1.单 ...

  3. JS表单常见表达式(正则)

    整数或者小数:^[0-9]+\.{0,1}[0-9]{0,2}$ 只能输入数字:"^[0-9]*$". 只能输入n位的数字:"^\d{n}$". 只能输入至少n ...

  4. Linux下安装MATLAB

    Why do I see "Preparing installation files ... Installing ... Finished..." in the terminal ...

  5. VB指针操作和消息钩子

    二.VB怎么用指针       要想弄明白VB怎么使用指针,就必须要弄明白两件事,第一,如何取得数组的指针,第二,如何将指针所指向的数组取出来.       A.在讲解这两个问题之前,我们需要了解几个 ...

  6. 一劳永逸解决VLC播放中文字幕乱码问题

    VLC对于Mac/Ubuntu用户来说算得上是必备软件.其相当于PC机上的“暴风影音”,但Mac/Ubuntu的新手使用VLC播放avi时都会碰 到字幕乱码的问题.avi字幕的格式有多种,这里假设你使 ...

  7. Direcshow之视频捕捉<转>

    关于视频捕捉(About Video Capture in Dshow) 1. 视频捕捉Graph的构建 一个能够捕捉音频或者视频的graph图都称之为捕捉graph图.捕捉graph图比一般的文件回 ...

  8. css常用属性总结:文本属性中的text-indent

    在网页中的文本格式中最重要的效果之一就是段落的首行文本缩进,尤其在新闻类页面,使用text-indent,任何元素都可以让首行以给定的长度缩进, 长度甚至可以是负数,这一属性的最常用方式就是段落的首行 ...

  9. intellij idea运行Android程序时报错;Unable to locate adb within SDK

    环境:intellij idea15 问题:运行Android时报错Throwable:Unable to locate adb within SDK   解决方法:在SDK安装目录的\platfor ...

  10. sqlconnection dispose()与close()的区别

    区别: IDispose接口可以通过Using关键字实现使用后立刻销毁,因此,Dispose适合只在方法中调用一次SqlConnection对象,而Close更适合SqlConnection在关闭后可 ...