需求背景:公司产品是餐饮POS,使用的技术栈是 nw.js(一个带node执行环境的chrome壳子),需要对接很多硬件,但是很多硬件是只提供dll驱动,如果用nodejs的话是很难对接的,所以就引出这样的需求
-
使用Edgejs
网上一般提供的方案一般是使用Edgejs,直接在js里执行C#代码 Edgejs 确实强大,示例代码如下:
var edge = require('edge');
var helloWorld = edge.func(function () {
/* async (input) => { return ".NET Welcomes " + input.ToString(); } */
});
helloWorld('JavaScript', function (error, result) {
if (error) throw error;
console.log(result);
});
可以直接在js中写C#代码,也可以像这样,调用C#写的dll
function loadDll(dllName){
var dllImport = null;
if(typeof(require) != 'undefined'){
var edge = require('edge');
dllImport = edge.func(dllName);
}
return dllImport;
};
对于dll有些要求,例如,我们的dll名称为 demo.dll,那么必须有个demo的namespace,然后这个namespace下必须有个Startup类,这个类还得有个 invoke公开方法 示例如下
namespace demo
{
public class Startup
{
public async Task Invoke(dynamic data)
{
return await dosomething();
}
}
}
一切都很完美,直到有一天,来了个新需求,需要我们支持XP系统(很无奈,很多小店的确还在用XP的系统),注意上面的C#代码,使用了 async await,这个只在 .net4.5 开始支持,而 .net 4.5已经放弃对XP的支持,XP下最高只能安装 .net 4.0,心塞…
-
使用子进程
这么好的解决方案用不了,只能想其他的办法了,首先想到的就是子进程,而且真的解决了我的问题,下面是自己的一点收获
- 初级版
nodejs使用子进程的方式一般是这样的
var spawn = require("child_process").spawn;
var exepath = 'exe地址';
var args=[];
var childprocess = spawn(exepath, args);
信息传递的话,就是通过 上面的 args参数;那么C#中怎么获取参数呢?新建一个空的控制台项目,打开 Program.cs 对的,就是通过 Main函数的参数获取 我们可以通过传递不同的参数来控制C#执行不同的代码,那么执行完成后怎么把结果返回呢 很简单 直接Console.WriteLine 标准输出,那对于输出的结果又怎么获取呢? 也很简单,只要监听 子进程的 stdout的data事件,如下
childprocess.stdout.on('data', function (data) {
console.log(data);
});
- 高级版
上面是在程序运行之前就要确定需要传递的参数,所以功能有限,不够灵活,如果在exe已经运行的情况下,怎么进行数据交换呢? 先来看看,在nodejs中启动exe子进程后的对象是什么样的
我们上面监听子进程输出用的是 stdout 这个Socket对象,这是一个只读的Socket,另外子进程对象还有个stdin,这是个只写的Socket,作用就是输入,对于这样的输入,C#中怎么获取呢? 上面C#输出用的是 Console.WriteLine 标准输出,所以,我们用标准输入就可以了,C#标准输入 是 Console.ReadLine
- 终极版
至此,我们已经具备了所有与exe双向通讯的条件,但是如果只是简单的标准输入输出,很难与js配合处理复杂的业务场景,我们需要对这样的虚拟通道进行包装 以我们使用nw下的一个场景,node将sql语句发送给子进程exe,子进程执行sql,完成后将结果返回给node.
通过上面的方法,我们可以完成 node发送 -> C#处理 -> 返回结果 主要流程都没有问题,但是我们的sql语句发送是连续的,就是node会一直发送,exe进行多线程处理,但是完成后返回的结果就懵逼了,谁跟谁啊,完全不知道执行的结果是谁需要的
针对这个问题,我们可以抽象下,以我们熟悉的 浏览器->服务器 来类比下,node中每个发送给子进程的sql就相当于一个 浏览器,子进程就相当于服务器,只要我们给每个请求都给一个令牌,在子进程处理后,包装结果,把令牌也同时返回,node这边根据令牌找到相应的方法回调,至此所有问题解决,exe具备了作为node的服务的能力 相关解决方案及代码已开源
详见GitHub NodeSharp