硬件管理平台-硬件网关-插件模块
前言
硬件产品库最终导出了硬件及其相关的依赖项,接下来就需要将依赖项放入到网关项目中,放入后需要做两个动作,第一个是通过硬件配置软件将压缩包解压并放入指定位置,然后进行该硬件的具体操作,另一个是硬件网关服务启动后,将特定目录下的硬件添加到网关中,进而在进行下面的操作。本文将讲述的是后者,硬件网关如何将硬件添加到网关中,实际上添加方式与硬件产品库中的方式一致,都是通过反射来操作的。唯一的不同可能就是执行的环境不同,一个是在公司内部,出现错误可以马上解决,而硬件网关的插件模块是在客户现场操作的,调试和解决问题都需要必须快速精准,否则将将耗费大量的人力财力。
插件项目搭建
在网关文件夹中创建一个名为HardwareGatewayPlugin的类库项目,并配置生成路径与HardwareGatewayService一致:..\bin\Debug\HardwareGateway\
。
准备工作
-
设置生成路径
将该项目路径设置为与HardwareGatewayWebApi生成路径一致:
..\bin\Debug\HardwareGateway\
. -
引用log4net
无需AssemblyInfo.cs的配置,因为该类为类库,被引用时可配置项可通用。
代码中可添加日志的引用代码
readonly ILog _loginfo = LogManager.GetLogger("loginfo"); readonly ILog _logerror = LogManager.GetLogger("logerror");
-
将引用的依赖包中属性“复制本地”设置为false。
Exception机制
因该项目客户现场使用,所以需要增加额外的日志和Exception机制,可以在报错时立马获取错误信息并解决。
-
在公共包的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
-
在插件项目中添加错误事件,包含组件的各流程中可能发生的错误,如组件加载前、组件加载后,组件加载错误时的相关异常
-
错误的相关描述信息,如dll未找到、构造函数问题-必须无参、未找到集成类等
反射模块
在插件项目中添加PluginManage.cs类,复用产品库的反射类代码即可,不过唯一的不同是需要将反射后的实例保存起来,以供后面的代码使用。
插件管理的流程是:
- 初始化反射类,并将Assembly_ErrorEvent赋值给事件委托ErrorEvent。
- 编写对外接口Load,主要作用是通过反射获得实例类,并保存到hardwareDic变量中。
- 添加异常机制,在主要代码处添加异常反馈,防止出现错误还不知的清空。
- 编写两个调用硬件项目中Execute的调用方法,分别为FunctionAsync和Function。
- 编写对外接口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