前言

插件化,其实也并不是什么新东西了,像nopCommerce等开源项目都有类似的机制,而且功能比较完善和齐全。

相信大家都对接过不少支付方式,支付宝、微信以及各大银行或第三方的支付公司。

我们可以把支付相关的操作抽象出来,无非就是支付,异步回调,退款,查询等几个重要的操作。

这个时候我们可以将各种支付方式都做为一个插件,这些插件都实现上面的操作,这样我们整合一个入口,去加载相应的插件即可。

这个入口常规情况就是MVC或者是WEB API。

下面来实现一个简单的例子。

简单的例子

首先建立一个公共的插件抽象类,简单起见,里面就包含一个无参的抽象方法Handle,这个方法就像上面提到的支付,退款等操作。

每一个新的插件都必须要继承这个抽象类并且实现这个抽象方法!

public abstract class BasePluginsService
{
public abstract string Handle();
}

假设现在有两个插件AA和BB,我们会把AA和BB各建一个类库。

其中,AA的就只是返回了AA相关的字符串。

public class PluginsService : Common.BasePluginsService
{
public override string Handle()
{
return "Plugins.AA";
}
}

BB的也同样只是返回了BB相关的字符串。

public class PluginsService : Common.BasePluginsService
{
public override string Handle()
{
return "Plugins.BB";
}
}

接下来,主要还是我们的入口,Web项目的处理。

在入口处的处理主要是利用反射去确实要调用那个插件里面的Handle方法。

下面是获取相应插件实例的方法。

private async Task<Common.BasePluginsService> GetPlugin(string type)
{
string cacheKey = $"plugin:{type}";
//先尝试从缓存中取
if (_cache.TryGetValue(cacheKey, out Common.BasePluginsService service))
{
return service;
}
else
{
var baseDirectory = Directory.GetCurrentDirectory();
var dll = $"Plugins.{type}.dll";
//Plugins的完整路径
var path = Path.Combine(baseDirectory, _options.PluginsPath, dll);
try
{
//预防无法更新dll
byte[] bytes = await System.IO.File.ReadAllBytesAsync(path);
var assembly = Assembly.Load(bytes);
//创建实例
var obj = (Common.BasePluginsService)assembly.CreateInstance($"Plugins.{type}.PluginsService"); if (obj != null)
{
_cache.Set(cacheKey, obj, DateTimeOffset.Now.AddSeconds(60));
} return obj;
}
catch (Exception)
{
return null;
}
}
}

这里主要有下面两个操作

一、 缓存反射结果

为了避免每次获取插件都去进行反射操作,这里引用了MemoryCache来缓存了反射的结果。

关于缓存,这里需要注意一个问题,缓存的时间!这个对新增加一个插件是没有什么影响,但是对修改一个已经存在的插件就影响比较大了!

缓存时候过长会导致没有办法实时出现修改的效果,可以考虑缓存比较短的时间。

二、 动态替换dll

为了避免出现对一个现存的插件修改之后,无法正常替换的情形,往往提示的是正常使用。需要做一些处理,避免一直占用这个资源!

最后就是Action的操作了。

[HttpGet]
public async Task<string> GetAsync(string type)
{
if (string.IsNullOrWhiteSpace(type))
{
return "type is empty";
} var plugin = await this.GetPlugin(type); if (plugin != null)
{
return plugin.Handle();
} return "default";
}

到这里,基本就完成了。

先来看看项目的大致框架:

我们是将所有的插件放到Plugins这个项目文件中的。Web项目并不直接引用Plugins下面的项目。

运行时是动态加载指定目录里面的dll,然后完成调用的。

下面简单来看看效果:

通过修改type达到选择不同插件的效果,然后对某个插件进行修改之后,也能正常替换和生效。

当然,实际中可能并没有那么直接就能拿type,而是是要根据传进来的参数去搜一下数据库,然后才能拿到type。这也完全取决于不同的设计。

总结

插件化机制,可以简单的认为是反射的一个实际应用,这个已经能满足不少常规性的要求了。

但是完整的插件化还有诸多要考量的东西,这个可以参考nop的实现。

它还是有不少好处的,个人认为,最主要的还是隔离了不同的插件,将它们之间相互影响的可能性降低。

最后附上本文的示例Demo:

PluginsDemo

在.NET Core中使用简单的插件化机制的更多相关文章

  1. Hangfire在ASP.NET CORE中的简单实现

    hangfire是执行后台任务的利器,具体请看官网介绍:https://www.hangfire.io/ 新建一个asp.net core mvc 项目 引入nuget包 Hangfire.AspNe ...

  2. Hangfire在ASP.NET CORE中的简单实现方法

    hangfire是执行后台任务的利器,具体请看官网介绍:https://www.hangfire.io/ 新建一个asp.net core mvc 项目 引入nuget包 Hangfire.AspNe ...

  3. [Songqw.Net 基础]WPF实现简单的插件化开发

    原文:[Songqw.Net 基础]WPF实现简单的插件化开发 版权声明:本文为博主原创文章,未经博主允许可以随意转载 https://blog.csdn.net/songqingwei1988/ar ...

  4. Python中实现简单的插件框架

    在系统设计中,经常我们希望设计一套插件机制,在不修改程序主体情况下,动态去加载附能. 我设想的插件系统: 1.通过类来实现 2.自动查找和导入 我们假设需要实现一个简单的插件系统,插件可以接收一个参数 ...

  5. ASP.NET MVC5 插件化机制简单实现

    一.前言 nopCommerce的插件机制的核心是使用BuildManager.AddReferencedAssembly将使用Assembly.Load加载的插件程序集添加到应用程序域的引用中.具体 ...

  6. .net core中的Options重新加载机制

    Options是.net core提出的一种辅助配置机制,即选项. 目前,我们可以使用的Options有五种(源码): IOptionsFactory<>:Options的创建工厂(Sin ...

  7. ASP.NET MVC 插件化机制

    概述 nopCommerce的插件机制的核心是使用BuildManager.AddReferencedAssembly将使用Assembly.Load加载的插件程序集添加到应用程序域的引用中.具 体实 ...

  8. ASP.NET:插件化机制

    概述 nopCommerce的插件机制的核心是使用BuildManager.AddReferencedAssembly将使用Assembly.Load加载的插件程序集添加到应用程序域的引用中.具体实现 ...

  9. 谈谈Circuit Breaker在.NET Core中的简单应用

    前言 由于微服务的盛行,不少公司都将原来细粒度比较大的服务拆分成多个小的服务,让每个小服务做好自己的事即可. 经过拆分之后,就避免不了服务之间的相互调用问题!如果调用没有处理好,就有可能造成整个系统的 ...

随机推荐

  1. 【面试题】Java实现String的IndexOf方法

    先说题后感:程序员这一行,很多时候,自驱学习能力是自我成长一个很重要的因素(当然技术最好的学习途径都是通过项目实践去学习.理解.掌握).而自学方法中,除了看官方文档.技术博客等途径之外,学习源码也是一 ...

  2. linux centos环境下,perl使用DBD::Oracle遇到报错Can't locate DBD/Oracle.pm in @INC 的解决办法

    前言 接手前辈的项目,没有接触.安装.使用过perl和DBD::Oracle,也没有相关的文档记录,茫茫然不知所措~~.一开始发现这个问题,就想着迅速解决,就直接在google上搜报错信息,搜索的过程 ...

  3. entOS7查看开放端口命令

    CentOS7的开放关闭查看端口都是用防火墙来控制的,具体命令如下: 查看已经开放的端口: firewall-cmd --list-ports 开启端口 firewall-cmd --zone=/tc ...

  4. jenkins安装配置

    一.下载Jenkins 官网地址:https://jenkins.io/,图如下所示,点击下载可下载最新版本. 点击下载之后,我们可以看到下面的图,我这边选择的Jenkins.war 文件. 下面,使 ...

  5. vue基于webpack说明

    1.文件build里的check-versions.js:检查node和npm版本, 此文件里的 (1)require('chalk')引入一个模块,定义输入终端样式 (2) require('sem ...

  6. 批量删除Excel里面的换行符

    关于批量删除excel里面的换行符,应该说写程序的遇上excel大体都会有这么个问题,在解决这个问题前,我的解决办法是把excel 的数据全部复制到txt里面, 因为操作txt比操作excel更为简单 ...

  7. 堆排序应用之topK问题

    题目:求海量数据(正整数)按逆序排列的前k个数(topK),因为数据量太大,不能全部存储在内存中,只能一个一个地从磁盘或者网络上读取数据,请设计一个高效的算法来解决这个问题. 第一行用户输入K,代表要 ...

  8. python-正则表达式练习

    1.匹配普通URL ^(http://)([a-z]+)\.([a-z]+)\.(com|cn|net|edu)(/(\w)+)+(.+) 2.匹配type返回的字符串中的类型 import re r ...

  9. IOS开发之尺寸

    在移动端或者前端开发中,UI图通常是带标注的,指定某个控件的长宽等属性,一般UI给的是68px,72px这样的样式,但是我们在开发过程中通常又并不是完全按照上面的标注去设置值,有时候需要将这个标注除以 ...

  10. github pages代码高亮highlighter

    github pages 一直想添加代码高亮 highlighter ,基于 jekyll 3.0 的 rouge 终于搞定了: 下载代码高亮库 在 cmd 中输入: rougify style mo ...