在.NET Core中使用简单的插件化机制

在.NET Core中使用简单的插件化机制,第1张

概述前言插件化,其实也并不是什么新东西了,像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{//预防无法更新dllbyte[] 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

<h2 ID="前言">前言

插件化,其实也并不是什么新东西了,像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 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 != n<a href="https://m.jb51.cc/tag/ul/" target="_blank" >ul</a>l)        {            _cache.Set(cacheKey,obj,DateTimeOffset.<a href="https://www.jb51.cc/tag/Now/" target="_blank" >Now</a>.AddSeconds(60));        }        return obj;    }    catch (Exception)    {        return n<a href="https://m.jb51.cc/tag/ul/" target="_blank" >ul</a>l;    }}

}

这里主要有下面两个 *** 作

一、 缓存反射结果

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

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

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

二、 动态替换dll

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

最后就是Action的 *** 作了。

[httpGet]public async Task GetAsync(string type){    if (string.IsNullOrWhiteSpace(type))    {        return "type is empty";    }
var plugin = await this.GetPlugin(type);if (plugin != n<a href="https://m.jb51.cc/tag/ul/" target="_blank" >ul</a>l){    return plugin.Handle();}return "defa<a href="https://m.jb51.cc/tag/ul/" target="_blank" >ul</a>t";

}

到这里,基本就完成了。

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

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

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

下面简单来看看效果:

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

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

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

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

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

最后附上本文的示例Demo:

href="https://github.com/catcherwong/Demos/tree/master/src/PluginsDemo">PluginsDemo

总结

以上是内存溢出为你收集整理的在.NET Core中使用简单的插件化机制全部内容,希望文章能够帮你解决在.NET Core中使用简单的插件化机制所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1256019.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-07
下一篇 2022-06-07

发表评论

登录后才能评论

评论列表(0条)

保存