[仅作学习,切莫多鸠余.由头到尾模仿一遍]
目的:创建一个模块基于C#调用的封装.能够被nodejs调用
----------------坑坑坑坑坑坑坑-------------
首先,根据度娘的发现能够实现此功能的第三方依赖模块为edge.但实际测试会报错.于是发现有个electron-edge-js,但发现这个需要安装electron.所以觉得太不存粹了.最后发现可怜的有个edge-js.网友说是edge的修复版,最终通过测试.可是还有一个坑,就是发现require的每个函数都会生成一个DLL的内存.问了同事说electron-edge-js不会.
哎,没办法.只能想办法了.
因为考虑到以上三个包都需要c#那边的函数以Func
}
如果按照这样的逻辑.也就是每次第三方的DLL都需要封装一层c#DLL.(PS.多么的麻烦,或者我理解错了?但是看GitHub好像是这个意思呀)
最后,想到通过中间一个负责反射的DLL,就可以实现一个C#DLL中转所有的第三方DLL.这样的话.就不用nodejs也封装一次,C#这边也要封装一次了
----------------坑坑坑坑坑坑坑-------------
创建C#中间通用模块
根据以上的想法,需要创建一个通用的中间DLL作为使用.同时中间DLL的指定会 被封装在模块中,这样其他人调用只需要知道目标DLL是什么和函数接口参数等信息就可以了.省去中间的require等操作.
//C# 创建一个DLL项目 DynamicJSProxy.dll 其中的核心代码
public async Task JSProxyInvoke(dynamic args) {
JSProxyResult proxyResult = new JSProxyResult();
BindingAssemblyResolveEvent();//用于反射时缺依赖DLL时加载
string AssemblyFile = "";
string TypeName = "";
AssemblyFile=(string)args.AssemblyFile;//Dll的名字
TypeName = (string)args.TypeName;//类名
if (!AssemblyCreateInstance(AssemblyFile, TypeName)) return proxyResult;
MethodInfo method = AssemblyObject.GetType().GetMethod((string)args.MethodName, BindingFlags.Instance | BindingFlags.Public);
ParameterInfo[] pis = method.GetParameters();
object[] invoteParams = new object[pis.Length];
if (pis.Length == 0)
{
proxyResult.RESULT = 0;
proxyResult.MSG = "成功";
dynamic dynamicOut= method.Invoke(AssemblyObject, invoteParams);//没参数的情况传递
proxyResult.DATA = new
{
IN = invoteParams,
OUT = dynamicOut
};
return proxyResult;
}
if (args.Parameters is ExpandoObject)
{
IDictionary ParameterDictionary = (IDictionary)(args.Parameters);
for (int i = 0; i < pis.Length; i++) //复制数据进去
{
invoteParams[i] = ParameterDictionary.Values.ElementAt(i);
}
proxyResult.RESULT = 0;
proxyResult.MSG = "成功";
dynamic dynamicOut = method.Invoke(AssemblyObject, invoteParams);//没参数的情况传递
proxyResult.DATA = new
{
IN = invoteParams,
OUT = dynamicOut
};
return proxyResult;
}
return proxyResult;
}
public JSProxy() {
string EnvironmentPATH = Environment.GetEnvironmentVariable("PATH");
AssemblySearchBaseDir = System.IO.Path.GetDirectoryName(this.GetType().Assembly.Location);//获取DLL所在地址
string p = AssemblySearchBaseDir;
string newPath = string.Join(System.IO.Path.PathSeparator.ToString(), EnvironmentPATH, p);
Environment.SetEnvironmentVariable("PATH", newPath);
}
class JSProxyResult
{
public int RESULT { get; set; } = -1;
public string MSG { get; set; } = "失败";
public dynamic DATA { get; set; }
}
这个DynamicJSProxy.dll作为中转使用
初始化项目
接下来需要创建一个跟这个中转DLL配合使用的模块
创建空白文件夹DynamicJSProxy
根据流程创建了一个模块项目DynamicJSProxy模块,用于调用C# DLL DynamicJSProxy.dll来实现功能.
在DynamicJSProxy中使用命令行进行模块的初始化
//初始化生成package.json
cnpm init
//也可以使用cnpm init --yes 直接默认过去.
//输入相应的package.json的信息
安装依赖
然后使用cnpm install 安装edge-js模块.
----------------坑坑坑坑坑坑坑-------------
注意:这个坑坑了我不少.如果是使用模块可以直接cnpm install edge-js就可以了
但是如果后面还要作为第三方依赖的库的话.这样安装依赖的包就不会记录到package.json中的dependencies中,之后引用这个包就会报没有相应的依赖项.很是麻烦
解决办法就是记住要后面加--save
----------------坑坑坑坑坑坑坑-------------
安装edge-js包
cnpm install edge-js --save
安装完成后package.json就会如下这样有依赖信息
创建入口
接下来创建入口
打开vscode使用打开目录的功能
添加index.js文件
var edge = require("edge-js");
//var url = require('url');
//var util = require('util');
//定义通用的调用函数中转站代理通用不用更改
//此处有个坑,assemblyFile如果直接使用.Lib/DynamicJSProxy.DLL会导致作为安装包时,报错,因为找的目录时当前目录而不是我们自己创建的dynamic_jsproxy目录,所以使用__dirname就时用来获取js代码所在的路径.这样就准确了
var JSProxyInvoke=edge.func({
assemblyFile:__dirname+"/Lib/DynamicJSProxy.Dll",
typeName:"DynamicJSProxy.JSProxy",
methodName: "JSProxyInvoke"
})
//引出函数JSPorxy作为调用
module.exports.JSProxy= function(MethodInfo,callback){
if (process.platform != 'win32'){
this.$notify.error({
title: '错误',
message: '此功能为windows专属功能,mac无法使用'
});
return;
}
JSProxyInvoke(MethodInfo, callback);//加载成功
};
测试
添加测试文件 app.js文件
var DynamicJSProxy=require('./index');
var MethodInfo = {
AssemblyFile:'CardLibDp.dll',
TypeName:'CardLibDp',
MethodName: 'JKE700A_SerialNumber',
Parameters:{
prtName:'700A'
}
}
DynamicJSProxy.JSProxy(MethodInfo, function (err, val) {
if (err) throw err
console.log(val)
});
可以直接vscode使用F5进行直接调试.不过,如果调试app.js就会报错.暂时没由仔细去解决.
我直接使用命令运行,去到app.js目录
>node app.js
{ RESULT: -1, MSG: '失败', DATA: null }
到此模块创建和测试完毕
上传模块
使用命令进行私有npm仓库上传
//使用login登录
>npm login --registry=http://X.X.X.208:1000
Username: XXX
Password:
Email: (this IS public) [email protected]
Logged in as hrf on http://X.X.X.208:1000/.
//看到这句,说明成功了
上传
>npm publish --registry=http://X.X.X.208:1000
npm notice
npm notice package: [email protected]
npm notice === Tarball Contents ===
npm notice 303B package.json
npm notice 342B app.js
npm notice 610B index.js
npm notice 13.8kB Lib/DynamicJSProxy.dll
npm notice === Tarball Details ===
npm notice name: dynamic_jsproxy
npm notice version: 0.0.3
npm notice package size: 7.4 kB
npm notice unpacked size: 15.1 kB
npm notice shasum: 4c2f1566aadf6c6db3043a0a9aa553e935d895a6
npm notice integrity: sha512-b/zr265Ue3q7V[...]5KhQ1Q6Uv0JwA==
npm notice total files: 4
npm notice
+ [email protected]
以上为上传到私有仓库中的模块.使用时只需要在使用的模块中使用
>npm install dynamic_jsproxy --registry=http://X.X.X.208:1000
在node_model中就会看到dynamic_jsproxy.这样就可以直接使用
使用方式
var DynamicJSProxy=require('dynamic_jsproxy');
var MethodInfo = {
AssemblyFile:'CardLibDp.dll',
TypeName:'CardLibDp',
MethodName: 'JKE700A_SerialNumber',
Parameters:{
prtName:'AISINO JKE700A'
}
}
DynamicJSProxy.JSProxy(MethodInfo, function (err, val) {
if (err) throw err
console.log(val)
});