首页 > 其他分享 >Natasha 插件化之dll

Natasha 插件化之dll

时间:2023-05-20 17:46:34浏览次数:36  
标签:插件 List FruitFunction using dll public Natasha

调用外部dll来实现组件化

场景

  1. 有一个设备管理控制系统,主要作用是控制设备及收集相关设备的信息,目前只集成了门禁和监控,后期期望添加更多设备时,一般都是在公司编写完后现场实施并调试,代码一般也是每个设备创建独立的项目,供总项目调用;慢慢的可能会演变出所有设备都继承一个公共的接口类,接口类中实现获取能力集和发送命令,以此来减少对于总控模块的修改,而此时只需要维护好能力集即可;可是这样每次也需要运行一整个解决方案,如果其他地方也需要这个系统,只能通过卸载项目来减少引用进行实时,这时就可以通过将项目分拆出去,通过Natasha进行组件化的管理。这样子的好处是通过约定的接口和能力集进行通信,主程序和设备耦合度低,如果遇到其他项目需要该系统,只需要将所需的dll放入特定文件夹即可。
  2. 任何可以分拆成模块的系统都可以按照组件化的逻辑进行开发,例如有业务流程的项目,每个步骤可有多个组件选项,可执行一个或者多个;或者说通过获得的插件来动态配置那一步应执行那个插件,通过插件的反馈判断是否应执行下一步操作。

好处

  1. 低耦合,业务分拆,插件只需要关心插件接口及反馈即可,不需要关心核心系统的业务逻辑
  2. 分工明确,每个人只需关注插件代码即可,项目整合后出现问题也好排查,未调用插件,则主系统有问题,调用插件结果与实际不符则插件有问题。
  3. 维护方便,学习成本低,对于某一个特定插件,代码量会远远低于整个项目的代码量,而且每个业务都可以进行分拆。

实现

  1. 获得Assembly

主要使用NatashaDomain类实例化的方法(源码位置:src\Natasha.Domain\Extension\NatashaDomainExtension.cs)

相关方法:

LoadPluginUseDefaultDependency 如果加载的dll已经被加载过了,则跳过

LoadPluginWithAllDependency 不会判断高低版本,源码中的解释是默认的,感觉和Default类似

LoadPluginWithHighDependency 使用高版本的dll

LoadPluginWithLowDependency 使用低版本的dll

参数说明:

string path 必填,dll所在路径

Func<AssemblyName, bool>? excludeAssembliesFunc = null 选填,需要排除的dll,返回true为排除引用,例如共同引用某个公用的dll(例如Utils.dll),此时可以选择使用哪个版本的dll

  1. 找到clas类并且实例化

找到class类(默认所有插件的实现类为*Controller),也可以按照下面例子来

var type = assembly.GetTypes().Where(item => item.Name.IndexOf("Controller")!=-1).First();

实例化

var plugin = (IPluginClass)(Activator.CreateInstance(type)!);

例子

  1. 创建两个底层项目

    1. IPluginBase项目:用于创建插件使用的接口

      using PluginUtil;
      
      namespace IPluginBase
      {
          public interface IPluginClass
          {
              /// <summary>
              /// 初始化方法
              /// </summary>
              public void initialize();
              /// <summary>
              /// 获得插件特有的方法
              /// </summary>
              /// <returns></returns>
              public List<FruitFunction> getFunction();
              /// <summary>
              /// 获得需要定时方法
              /// </summary>
              /// <returns></returns>
              public List<FruitFunction> getTimeFunc();
              /// <summary>
              /// 通过方法执行插件代码
              /// </summary>
              /// <param name="function">FruitFunction</param>
              /// <param name="param">可能输入的数值</param>
              /// <returns></returns>
              public String execute(FruitFunction function, String param);
          }
      }
      
    2. PluginUtil项目,用于声明FruitFunction

      using System.ComponentModel;
      
      namespace PluginUtil
      {
          public enum FruitFunction
          {
              [Description("硬度")]
              hardness = 01,
              [Description("苹果特有功能")]
              appleAttr = 02,
              [Description("切")]
              cut = 03
          }
      }
      
  2. 创建两个插件项目

    1. PluginApple项目

      using IPluginBase;
      using PluginUtil;
      
      namespace PluginApple
      {
          public class PluginAppleClass : IPluginClass
          {
              public string execute(FruitFunction function, string param)
              {
                  switch (function) {
                      case FruitFunction.cut:
                          Console.WriteLine("切苹果");
                          break;
                      case FruitFunction.hardness: 
                          Console.WriteLine("苹果很脆");
                          break;
                      case FruitFunction.appleAttr:
                          Console.WriteLine("苹果特有属性");
                          break;
                  }
                  return "结束";
              }
      
              public List<FruitFunction> getFunction()
              {
                  Console.WriteLine("返回苹果的现有功能");
                  return new List<FruitFunction>() { FruitFunction.appleAttr, FruitFunction.cut, FruitFunction.hardness }; 
              }
      
              public List<FruitFunction> getTimeFunc()
              {
                  Console.WriteLine("返回苹果的定时功能");
                  return new List<FruitFunction>() { FruitFunction.cut};
              }
      
              public void initialize()
              {
                  Console.WriteLine("苹果初始化完成");
              }
          }
      }
      
    2. PluginBanana项目

      using IPluginBase;
      using PluginUtil;
      
      namespace PluginBanana
      {
          public class PluginBananaClass : IPluginClass
          {
              public string execute(FruitFunction function, string param)
              {
                  switch (function)
                  {
                      case FruitFunction.cut:
                          Console.WriteLine("切香蕉");
                          break;
                      case FruitFunction.hardness:
                          Console.WriteLine("香蕉很软");
                          break;
                  }
                  return "结束";
              }
      
              public List<FruitFunction> getFunction()
              {
                  Console.WriteLine("返回香蕉的现有功能");
                  return new List<FruitFunction>() { FruitFunction.cut, FruitFunction.hardness };
              }
      
              public List<FruitFunction> getTimeFunc()
              {
                  Console.WriteLine("返回香蕉的定时功能");
                  return new List<FruitFunction>() { FruitFunction.cut };
              }
      
              public void initialize()
              {
                  Console.WriteLine("香蕉初始化完成");
              }
          }
      }
      
  3. 使用Natasha实现两个插件项目的方法

    前置条件:将PluginApple.dll和PluginBanana.dll放到NatashaStudyConsole.exe同级下的plugins文件夹中

    using IPluginBase;
    using PluginUtil;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace NatashaStudyConsole
    {
        internal class PluginDemo
        {
            public void PluginMethod() {
                //获得dll存放路径
                string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory+ "plugins");
                //实例化NatashaDomain
                NatashaDomain domain = new(Guid.NewGuid().ToString());
                List<IPluginClass> assemblies = new List<IPluginClass>();
                //通过获得所有的dll来进行实例化
                Directory.GetFiles(path, "*.dll").ToList().ForEach(dll =>
                {
                    //加载dll
                    var assembly = domain.LoadPluginWithAllDependency(dll);
                    // 本例子中项目名称为"A",需要实例化的类为"AClass",因此使用IndexOf方法
                    // 获得项目名称
                    var asmName = assembly.GetName().Name!;
                    // 根据项目名称判断应该实例那个class
                    var type = assembly.GetTypes().Where(item => item.Name.IndexOf(asmName)!=-1).First();
                    // 实例化
                    var plugin = (IPluginClass)(Activator.CreateInstance(type)!);
                    if (plugin != null) {
                        // 保存
                        assemblies.Add(plugin);
                    }
                });
                assemblies.ForEach(assembly => {
                    // 实现相关方法
                    List<FruitFunction> functions = assembly.getFunction();
                    if(functions != null && functions.Count > 0)
                    {
                        assembly.execute(functions[0], "");
                    }
                });
            }
        }
    }
    
    

    代码结构示意图:

    执行结果:

标签:插件,List,FruitFunction,using,dll,public,Natasha
From: https://www.cnblogs.com/wanghun315/p/17417520.html

相关文章

  • Intellij IDEA 如何删掉插件
    在IntellijIDEA的配置中,找到插件选项。在插件选项中,选择需要删除的插件,然后在右侧的对话框中选择uninstall就可以了。  卸载以后,可能不会要求重启,为了安全起见,还是重启下你的IDE吧。 https://www.ossez.com/t/intellij-idea/14436......
  • 浏览器好用插件
    1.消除广告,广告拦截器AdGuard  2.解除网页复制限制 3.解除网页下载限制    ......
  • Cookie的使用(js-cookie插件)
    1.js-cookie一个简单,轻巧的JavaScriptAPI,用于处理Cookie2.安装npminstalljs-cookie--save3.引用importCookiesfrom'js-cookie'Vue.prototype.$Cookies=Cookies;4.创建<!--作者:zhangfan页面名称:Cookie的使用(js-cookie插件)--><template><divid="produc......
  • dll防止卸载,以及阻止crt释放,等
    部分dll有时需要在进程中永久有效,如hook,正常的dll在程序退出时会释放dll,然后导致dll中的对象被释放(CRT清理)跟踪源码,可以看到在__DllMainCRTStartup中有调用_CRT_INIT释放资源,中间不可控,但是有一个异常捕获,尝试生成一个异常,但是简单异常的过滤条件无法满足改......
  • 网站指纹扫描插件(WhatRuns、Wappalyzer)
    我使用的是Chrome浏览器,需要到应用商店搜索下载WhatRunsWappalyzer......
  • Chrome浏览器好用的插件(批量保存所有选项卡网址、批量打开粘贴板网址插件)
    转自:https://www.cnblogs.com/nmap/p/6557883.html 1、Chrome批量保存所有选项卡网址+批量打开复制网址小插件批量保存所有选项卡网址插件:CopyAllUrls经常搜索一些东西,下班时无法处理完所有网页内容,比如做笔记什么的,又不舍得关闭网页。每个页面关闭前复制链接保存太麻烦......
  • PLSQL Developer 无法找到OCI dll
    运行PL/SQLDeveloper14(64bit)时,提示 Initializationerror 无法找到OCI.dll OracleHomeKey:OracleHomeDir: 解决方式: 1、从oracle 官方网站下载数据库瘦客户端链接工具   instantclient-basic-windows.x64-21.9.0.0.0dbru.zip  ,解压在“D:\instantclien......
  • 插件:Verilog Language Support
    https://mp.weixin.qq.com/s/oSkF98uSqvdpBb2-Fwa5TA开发了一个基于IntellijIDEA的Verilog语言插件:VerilogLanguageSupport。可以基于IntellijIDEA社区版2023.1版本进行安装,安装方法如下:该插件目前是免费的,正在申请付费插件,先分享出来给需要的同学。该插件目前仅支持词法......
  • quasar [email protected] ssr Meta插件 使用 title无法reactive的bug
    为了使自己的网站SEO更友好,在项目里启用了quasar的Meta插件。但实际使用下来发现文档里的描述不正确。为了动态的更新title和meta信息,文档https://quasar.dev/quasar-plugins/meta里介绍ReactiveInthesectionabove,younoticedallofthemetapropsare“static”.But......
  • 【一步步开发AI运动小程序】二、引入插件
    随着人工智能技术的不断发展,阿里体育等IT大厂,推出的“乐动力”、“天天跳绳”AI运动APP,让云上运动会、线上运动会、健身打卡、AI体育指导等概念空前火热。那么,能否将这些在APP成功应用的场景搬上小程序,分享这些概念的红利呢?本系列文章就带您一步一步从零开始开发一个AI运动小程序......