首页 > 其他分享 >硬件管理平台-硬件网关-插件模块

硬件管理平台-硬件网关-插件模块

时间:2023-08-12 16:00:32浏览次数:50  
标签:hardwareInfo 插件 return 网关 Exception 硬件 public

硬件管理平台-硬件网关-插件模块

前言

硬件产品库最终导出了硬件及其相关的依赖项,接下来就需要将依赖项放入到网关项目中,放入后需要做两个动作,第一个是通过硬件配置软件将压缩包解压并放入指定位置,然后进行该硬件的具体操作,另一个是硬件网关服务启动后,将特定目录下的硬件添加到网关中,进而在进行下面的操作。本文将讲述的是后者,硬件网关如何将硬件添加到网关中,实际上添加方式与硬件产品库中的方式一致,都是通过反射来操作的。唯一的不同可能就是执行的环境不同,一个是在公司内部,出现错误可以马上解决,而硬件网关的插件模块是在客户现场操作的,调试和解决问题都需要必须快速精准,否则将将耗费大量的人力财力。

插件项目搭建

网关文件夹中创建一个名为HardwareGatewayPlugin的类库项目,并配置生成路径与HardwareGatewayService一致:..\bin\Debug\HardwareGateway\

准备工作

  1. 设置生成路径

    将该项目路径设置为与HardwareGatewayWebApi生成路径一致:..\bin\Debug\HardwareGateway\.

  2. 引用log4net

    无需AssemblyInfo.cs的配置,因为该类为类库,被引用时可配置项可通用。

    代码中可添加日志的引用代码

    readonly ILog _loginfo = LogManager.GetLogger("loginfo");
    readonly ILog _logerror = LogManager.GetLogger("logerror");
    
  3. 将引用的依赖包中属性“复制本地”设置为false。

Exception机制

因该项目客户现场使用,所以需要增加额外的日志和Exception机制,可以在报错时立马获取错误信息并解决。

  1. 在公共包的AssemblyLibrary项目AssemblyControl类中增加事件属性,在反射过程中如果出现错误可直接通过log文件获得错误信息

    public event AssemblyErrorEvent<AssemblyErrorEventArgs> ErrorEvent;
    

    AssemblyErrorEventArgs类型为

    public class AssemblyErrorEventArgs : EventArgs
    {
    
        /// <summary>
        /// 读取的dll文件路径
        /// </summary>
        public string DllFile { get; internal set; }
        /// <summary>
        /// 类加载失败的异常信息
        /// </summary>
        public Exception Exception { get; internal set; }
        /// <summary>
        /// 位置
        /// </summary>
        public string Seek { get; internal set; }
    }1
    
  2. 在插件项目中添加错误事件,包含组件的各流程中可能发生的错误,如组件加载前、组件加载后,组件加载错误时的相关异常

  3. 错误的相关描述信息,如dll未找到、构造函数问题-必须无参、未找到集成类等

反射模块

在插件项目中添加PluginManage.cs类,复用产品库的反射类代码即可,不过唯一的不同是需要将反射后的实例保存起来,以供后面的代码使用。

插件管理的流程是:

  1. 初始化反射类,并将Assembly_ErrorEvent赋值给事件委托ErrorEvent。
  2. 编写对外接口Load,主要作用是通过反射获得实例类,并保存到hardwareDic变量中。
  3. 添加异常机制,在主要代码处添加异常反馈,防止出现错误还不知的清空。
  4. 编写两个调用硬件项目中Execute的调用方法,分别为FunctionAsyncFunction
  5. 编写对外接口GetHardwareAbstracts,主要为获得当前反射的实例。
/// <summary>
/// 插件管理器
/// </summary>
/// <typeparam name="HardwareAbstract">插件方法的接口定义类,必须使用 abstract 修饰</typeparam>
public sealed class PluginManager : IDisposable
{
    readonly ILog _loginfo = LogManager.GetLogger("loginfo");
    readonly ILog _logerror = LogManager.GetLogger("logerror");
    #region 字段

    /// <summary>
    /// 设备类型的dll反射类,用于通过ke获得反射获得的硬件类
    /// </summary>
    readonly Dictionary<string, HardwareAbstract> hardwareDic = new Dictionary<string, HardwareAbstract>();
    /// <summary>
    /// 声明反射类
    /// </summary>
    readonly AssemblyControl assembly;
    /// <summary>
    /// 反射类的锁
    /// </summary>
    public Object DicLock = new object();
    #endregion

    #region 事件
    /// <summary>
    /// 插件实例创建前的事件
    /// </summary>
    public event PluginEvent<PluginInstanceCreatingArgs> OnInstanceCreating;
    /// <summary>
    /// 异步,没有返回值
    /// </summary>
    /// <param name="function"></param>
    /// <param name="hardwareInfo"></param>
    /// <param name="param"></param>
    private void FunctionAsync(String model, Function function, String hardwareInfo, string param = "")
    {
        Task<AjaxResult>.Run(() =>
        {
            AjaxResult result = AjaxResult.error("", "未找到");
            try
            {
                result = hardwareDic[model].Execute(function, hardwareInfo, param);
            }
            catch (Exception ex)
            {
                _logerror.Error($"FunctionAsync:Function:{function}, HardwareInfo:{hardwareInfo}, param:{param}", ex);
            }
            return result;
        }).ContinueWith(aj => {
            //后续的可以加这里 aj.Result
        });
    }

    public async Task<AjaxResult> AsyncResult(String model, Function function, String hardwareInfo, string param)
    {
        var task = await Task<AjaxResult>.Run(() =>
        {
            try
            {
                return hardwareDic[model].Execute(function, hardwareInfo, param);
            }
            catch (Exception ex)
            {
                _logerror.Error($"AsyncResult error:Function:{function}, HardwareInfo:{hardwareInfo}, param:{param}", ex);
                return AjaxResult.error("失败", "失败");
            }
        });
        return task;
    }

    public AjaxResult Function(Function function, String hardwareInfo, string param = "")
    {
        AjaxResult result = AjaxResult.error("", "未找到");
        try
        {
            HardwareInfo info = JSONUtils.DeserializeObject<HardwareInfo>(hardwareInfo);
            if (hardwareDic.ContainsKey(info.设备型号))
            {
                // 将获得状态修改为了异步
                FunctionAsync(info.设备型号, function, hardwareInfo, param);
                return AjaxResult.success("操作成功");
            }
            else
            {
                _logerror.Error($"运行的dll未找到 function{function} hardwareInfo{hardwareInfo}");
            }
        }
        catch (Exception ex)
        {
            _logerror.Error($"执行命令错误:Function:{function}, HardwareInfo:{hardwareInfo}, param:{param}", ex);
        }
        return result;
    }

    /// <summarydd
    /// 插件实例创建后的事件
    /// </summary>
    public event PluginEvent<PluginInstanceCreatedArgs<HardwareAbstract>> OnInstanceCreated;

    /// <summary>
    /// 加载插件失败的事件,具体的错误请通过参数<paramref name="e"/>的属性 ErrorType
    /// 错误类型参见 <see cref="PluginErrorTypes"/>
    /// </summary>
    public event PluginErrorEvent<PluginErrorEventArgs> one rror;

       
    #endregion

    /// <summary>
    /// 初始化插件管理器
    /// </summary>
    /// <param name="pluginFolder">插件所在目录,绝对路径或相对路径</param>
    public PluginManager()
    {
        assembly = new AssemblyControl();
        assembly.ErrorEvent += Assembly_ErrorEvent;
    }

    private void Assembly_ErrorEvent(AssemblyErrorEventArgs e)
    {
        EmitPluginErrorEvent(new PluginErrorEventArgs()
        {
            FileName = e.DllFile,
            Exception = e.Exception,
            ErrorType = PluginErrorTypes.InvalidDll,
            Seek = e.Seek
        });
        _logerror.Error($"ErrorEvent DllFile {e.DllFile} Seek {e.Seek}", e.Exception);
    }
      
    /// <summary>
    /// 加载插件目录下的所有插件
    /// </summary>
    /// <param name="filter">插件过滤器,返回false表示不加载这个插件</param>
    public void Load(Func<string, bool> filter = null)
    {
        string[] files = Directory.GetFiles(assembly.PluginsFolder, "*.dll", SearchOption.AllDirectories).Where(filename => filter == null || filter(filename)).ToArray();// 筛选dll文件
        //反射获得类
        List<HardwareAbstract> hardwares = LoadAssembly(files);
        bool acquired = false;
        try
        {
            Monitor.Enter(DicLock, ref acquired);
            hardwareDic.Clear();
            hardwares.ForEach(hardware =>
            {
                hardwareDic.Add(hardware.GetHardwareInfo().Model, hardware);
            });
        }
        catch (Exception ex)
        {
            _logerror.Error("Load dll error", ex);
        }
        finally
        {
            if (acquired) { Monitor.Exit(DicLock); }
        }
    }

    public List<HardwareAbstract> GetHardwareAbstracts()
    {
        List<HardwareAbstract> hardwares = new List<HardwareAbstract>();
        bool acquired = false;
        try
        {
            Monitor.Enter(DicLock, ref acquired);
            hardwares.AddRange(hardwareDic.Values);
        }
        finally
        {
            if (acquired) { Monitor.Exit(DicLock); }
        }
        return hardwares;
    }

    /// <summary>
    /// 加载程序集
    /// </summary>
    /// <param name="filenames"></param>
    /// <returns></returns>
    private List<HardwareAbstract> LoadAssembly(string[] filenames)
    {
        // 加载程序集
        try
        {
            // 创建实例前,发出事件
            EmitPluginEvent(OnInstanceCreating, new PluginInstanceCreatingArgs()
            {
                FileNames = filenames
            });

            // 加载
            List<HardwareAbstract> hardwareAbstracts = assembly.GetHardwareAbstracts();

            // 创建实例成功后,发出事件
            EmitPluginEvent(OnInstanceCreated, new PluginInstanceCreatedArgs<HardwareAbstract>()
            {
                FileNames = filenames,
                Instance = hardwareAbstracts.ToArray()
            });

            return hardwareAbstracts;
        }
        catch (Exception ex)
        {
            // 程序集加载失败
            EmitPluginErrorEvent(new PluginErrorEventArgs()
            {
                FileName = string.Join(",", filenames),
                Exception = ex,
                ErrorType = PluginErrorTypes.InvalidDll
            });
            _logerror.Error("DLL加载失败", ex);
            return null;
        }
    }

    /// <summary>
    /// 发出插件事件的公共函数
    /// </summary>
    /// <returns>返回true阻止插件继续加载</returns>
    private bool EmitPluginEvent<ArgType>(PluginEvent<ArgType> eventName, ArgType arg)
        where ArgType : PluginEventArgs
    {
        if (eventName == null)
        {
            return false;
        }

        eventName.Invoke(this, arg);

        return arg.Cancel;
    }

    /// <summary>
    /// 发出插件错误事件的公共函数
    /// </summary>
    private void EmitPluginErrorEvent(PluginErrorEventArgs arg)
    {
        if (OnError == null)
        {
            return;
        }

        one rror.Invoke(this, arg);
    }
    private ManualResetEvent mre;
    public void Dispose()
    {
        lock (this)
        {
            hardwareDic.Clear();
        }
    }
}

结束

自此一个很简单的 反射模块就写完了

标签:hardwareInfo,插件,return,网关,Exception,硬件,public
From: https://www.cnblogs.com/wanghun315/p/17624940.html

相关文章

  • 【Java】智慧工地源码-支持私有化部署,SaaS模式+全套硬件设备
    智慧工地硬件设备包括:AI识别一体机、智能广播音响、标养箱、塔机黑匣子、升降机黑匣子、吊钩追踪控制设备、扬尘监测设备、喷淋设备。1.什么是AI危险源识别AI危险源识别是指基于智能视频分析技术,对视频图像信息进行自动分析识别,以实时监测危险区域的人员闯入、靠近等危险行为,从......
  • idea实用插件推荐(1)-Grep Console
    1.简介GrepConsole可以根据日志等级设置不同的颜色,效果如下:安装点击File->Settings在搜索框里输入GrepConsole,点击install即可安装使用安装成功后,在idea控制台右键点击ShowGrepConsoleStatisticsinConsole,即可设置对应日志级别的颜色公众号:1号程序员,关注回复B0......
  • 使用pip安装pycharm插件时,要使用管理员权限打开cmd安装
    1.问题安装到一半报错报错1报错22.解决解决1原文:https://blog.csdn.net/weixin_44899752/article/details/128372969下面是收集的一些国内的pip源:阿里云http://mirrors.aliyun.com/pypi/simple/中国科技大学https://pypi.mirrors.ustc.edu.cn/simple/豆瓣(douban)h......
  • 视频获取缩略图使用ffmpeg插件
      stringmp4URL=Server.MapPath("~/Upload/")+"33.mp4";stringOutURL=Server.MapPath("~/Upload/")+DateTime.Now.ToString("yyyyMMddHHmmssfff")+".png";ffmpeg(mp4URL,OutURL,3); ......
  • vscode插件推荐
    原文链接:https://www.cnblogs.com/MrFlySand/p/17623887.htmlmarkdown预览【推荐文章】VsCode更换MarkDown样式到底能有多好看?博客园VSCode客户端将本地markdown发布到博客园博客园博文列表搜索博文将本地文件关联到博客园博文拉取远程博文内容更新本地文件Mark......
  • 传奇架设服务端传奇GOM引擎不加载插件,写入了不加载的解决方法
    vsftpd(verysecureFTPdaemon)是Linux下的一款小巧轻快、安全易用的FTP服务器软件。本教程介绍如何在Linux实例上安装并配置vsftpd。前提条件已创建ECS实例并为实例分配了公网IP地址。背景信息FTP(FileTransferProtocol)是一种文件传输协议,基于客户端/服务器架构,支持以下两种工作模......
  • 插件系列 vue2安装tailwindcss
    官方网址:https://www.tailwindcss.cn/docs/installation安装步骤:直接安装创建文件tailwindcss.cssmain.js全局引入文件tailwindcss.css在项目更目录下执行初始化配置文件指令第一步:直接安装npminstall-Dtailwindcss@npm:@tailwindcss/postcss7-compatpostcs......
  • 插件Rainbow Brackets插件使用
    插件RainbowBrackets1.自带花括号彩虹色2.高亮部分代码块command+右键代码块3.着重展示,其余都黑标alt+右键代码块4.取消代码高亮按esc......
  • 传奇架设服务端传奇GOM引擎不加载插件,写入了不加载的解决方法
    MirServer\Mir200下面的PlugList.txt文件里写入了插件dll名称,但是启动服务端时还是不加载,主要是因为是因为插件目录不正确,以下告诉大家解决方法。首先关掉M2,然后打开“D:\MirServer\Mir200\!Setup.txt”文件搜索该文件,搜索关键字是“Plugdir”把搜索到的那一行全部删除就可以了,如......
  • 使用Spring Cloud Gateway构建高性能的微服务网关
    在微服务架构中,微服务之间的通信可能会变得复杂,而且涉及到许多非功能性需求,如安全性、负载均衡、限流等。SpringCloudGateway是一个基于SpringBoot的轻量级网关服务,用于构建高性能的微服务网关,本文将深入探讨如何使用SpringCloudGateway搭建微服务网关,并提供代码示例。什么是......