Недавно мне пришлось интегрировать серверное приложение на базе Node.js с C # DLL. Наше программное обеспечение (веб-приложение) предоставляет возможность осуществлять платежи через POS-терминал. Эта последняя управляема через выделенную DLL, которая предоставляет такие интерфейсы, как ExecutePayment (операция, сумма) и так далее. Как я уже упоминал, существует сервер Node.js, который каким-то образом предоставляет функциональность POS (и некоторых других) в качестве REST API. (У выбора для использования Node.js были конкретные причины, которые я бы не хотел сейчас описывать).
Когда вы начинаете с такого начинания, тогда есть разные возможности. Одним из них является использование Edge.js, который позволяет встраивать, ссылаться и вызывать объекты .Net CLR из приложений, основанных на Node.js. Что-то вроде этого:
var hello = require('edge').func({ assemblyFile: 'My.Edge.Samples.dll', typeName: 'Samples.FooBar.MyType', methodName: 'MyMethod' // Func<object,Task<object>> }}); hello('Node.js', function (error, result) { ... });
Edge — очень интересный проект и имеет большой потенциал. На самом деле, я просто попробовал это быстро с простой DLL, и это сработало сразу. Однако при использовании его из моего Node-приложения в node-webkit это не сработало. Я еще не уверен, было ли это связано с node-webkit или самой POS DLL (потому что это может быть COM-доступ и т.д.). Однако, если вам нужны простые интеграции, это может сработать для вас.
Вызов процесса
Второй вариант , который пришел на мой взгляд , заключается в разработке DLL в качестве самодостаточного процесса и вызвать его с помощью Node.js в процессе апи . Оказывается, это довольно просто. Просто подготовьте свое приложение C #, чтобы прочитать его аргументы вызова st, вы можете сделать что-то вроде ..
IntegrationConsole.exe ExecutePayment 1 100
..в «ExecutePayment» с операцией № 1 и суммой 1 €. Консольное приложение C # должно передавать свои возвращаемые значения в STDOUT (вы можете использовать JSON для создания более структурированного формата протокола обмена информацией).
Получив это, вы можете просто выполнить процесс из Node.js и прочитать соответствующий STDOUT:
var process = require('child_process'); ... process.exec(execCmd, function (error, stdout, stderr) { var result = stdout; ... writeToResponse(stdout); });
execCmd содержит инструкции, необходимые для запуска EXE с необходимыми аргументами вызова.
При таком подходе вы выполняете процесс, он выполняет свою работу, возвращает ответ и завершается. Однако, если по какой-либо причине вам необходимо поддерживать работу процесса для более продолжительного, более интерактивного взаимодействия между двумя компонентами, вы можете обмениваться данными через STDIN / STDOUT процесса.
Ваше консольное приложение C # запускается и прослушивает STDIN.
static void Main(string[] args) { ... string line; do { line = Console.ReadLine(); try { // do something meaningful with the input // write to STDOUT to respond to the caller } catch (Exception e) { Console.WriteLine(e.Message); } } while (line != null); }
На стороне Node.js вы не исполняете свой процесс, а вместо этого порождаете дочерний процесс.
var spawn = require('child_process').spawn; ... var posProc = spawn('IntegrationConsole.exe', ['ExecutePayment', 1, 100]);
Чтобы получить ответы, вы просто регистрируетесь в STDOUT процесса …
posProc.stdout.once('data', function (data) { // write it back on the response object writeToResponse(data); });
… и вы также можете слушать, когда процесс умирает, чтобы в конечном итоге выполнить некоторую очистку.
posProc.on('exit', function (code) { ... });
Запись в STDIN процесса также проста:
posProc.stdin.setEncoding ='utf-8'; posProc.stdin.write('...');
Таким образом, вы получаете более интерактивное «взаимодействие с состоянием», когда вы отправляете в EXE-команду команду, которая отвечает (STDOUT) и на основании ответа вы снова реагируете и отправляете какую-то другую команду (STDIN).
Внедрение этого в шаблон запроса / ответа
Чтобы представить все как REST API (на узле), вам нужно обратить внимание на регистрацию обработчиков событий в STDOUT. Предположим, вы делаете что-то вроде
app.post('/someEndpoint',function(req, res){ posProc = spawn('IntegrationConsole.exe',['ExecutePayment',1,100]);... posProc.stdout.on('data',function(data){// return the result of this execution// on the response});}), app.post('/someOtherEndpoint',function(req, res){... posProc.stdout.on('data',function(data){// return the result of this execution// on the response});// write to the stdin of the before created child process posProc.stdin.setEncoding ='utf-8'; posProc.stdin.write('...');});
Я исключил правильную обработку крайних случаев, например, что происходит, если ваш процесс умер раньше и т. Д., Но ключевой момент здесь заключается в том, что вы не можете зарегистрировать свои события с помощью on (..), так как в противном случае вы получите несколько обработчиков событий данных на стандартный выход Таким образом, вы можете либо зарегистрировать и отменить регистрацию события, используя синтаксис removeListener (‘имя события’, обратный вызов), либо использовать более удобный механизм однократной регистрации (как я уже делал в моих примерах в начале статьи):
posProc.stdout.once('data',function(data){// write it back on the response object writeToResponse(data);});