Считыватель отпечатков пальцев на node.js через .NET SDK

Я пытаюсь заставить приложение node.js взаимодействовать со считывателем отпечатков пальцев .NET SDK под названием U.are.U. SDK предоставляет библиотеки .dll (win32 и x64), Java и .NET. Я решил использовать .NET для простоты использования, имея готовые к использованию интерфейсы и все такое.

Итак, текущая проблема, с которой я сталкиваюсь, заключается в том, как вызывать эти функции .NET и при этом сохранять асинхронную природу node.js. Поток приложения (на примере .NET) довольно прямолинейный, 3 вызова в библиотеке, и отпечаток пальца сделан.

private IEnumerable<Fmd> CaptureAndExtractFmd()
{
    while (!reset)
    {
        DataResult<Fmd> resultConversion;

        try
        {
            if (count >= 8)
            {
                SendMessage("Enrollment was unsuccessful.  Please try again.");
                count = 0;
                break;
            }

            Fid fid = null;
            if (!_sender.CaptureFinger(ref fid))
                break;

            if (fid == null)
                continue;

            count++;

            resultConversion = FeatureExtraction.CreateFmdFromFid(fid, Constants.Formats.Fmd.ANSI);

            SendMessage("A finger was captured.  \r\nCount:  " + (count));

            if (resultConversion.ResultCode != Constants.ResultCode.DP_SUCCESS)
                break;
        }
        catch (Exception)
        {
            break;
        }

        yield return resultConversion.Data;
    }
}

Как я могу изменить его, чтобы его можно было использовать в node.js вместо программы .NET gui?

Также необходимо отметить, что node.js не всегда будет вызывать функцию в программе .NET для получения функции. Идентификационная часть программы происходит асинхронно и срабатывает, когда кто-то прикладывает палец к считывателю отпечатков пальцев, а это означает, что часть node.js понятия не имеет, когда это произойдет. Поэтому я не могу постоянно запрашивать данные в части .NET, она должна вызывать обратные вызовы в node.js без запроса. По сути, это двусторонняя связь, а не только по запросу, поскольку запрос с использованием веб-сервера был бы намного проще.

Я нашел библиотеку node.js, которая может сократить разрыв между .NET и node.js, под названием edge.js поможет ли это?


По сути, edge.js может заставить его работать вместе с node-webkit (которым я буду поставлять свое приложение), я могу вызывать API-интерфейсы узлов непосредственно на странице, поэтому я могу обновлять DOM в зависимости от на результат из библиотеки. Мне нужна возможность зарегистрировать асинхронную задачу, которая МОЖЕТ уведомлять из среды CLR аналогу node.js либо отправив событие, либо вызвав обратный вызов!

По словам автора edge.js, это легко сделать https://github.com/tjanczuk/edge/issues/54#issuecomment-17967082 У меня просто недостаточно навыков работы с .NET (из полноценного модуля) со всеми обратными вызовами.


person pocesar    schedule 08.05.2013    source источник
comment
Можете ли вы объяснить, почему вы толкаете себя с помощью node.js здесь?   -  person vittore    schedule 13.05.2013
comment
Я использую node-webkit, который может поставлять браузер вместе с node.js внутри, и я могу вызывать API-интерфейсы узлов непосредственно из тегов script, между ними существует бесшовный мост, и поскольку я буду подключать каждое приложение к каждому другое (стиль P2P), обязательно   -  person pocesar    schedule 15.05.2013
comment
Возможно, вы захотите взглянуть на Reactive.NET (Rx.NET). Я использовал его раньше, чтобы запускать обратные вызовы, когда что-то происходит, что возможно с его концепцией подписки, аналогичной событиям.   -  person Chris    schedule 15.05.2013
comment
У меня нет опыта работы с .NET, но у меня есть опыт работы с узлом. Как мне закрыть пробел с помощью reactive.net?   -  person pocesar    schedule 15.05.2013


Ответы (4)


Использование библиотеки .NET этого пакета SDK не является подходящим решением этой проблемы.

Node.js сам по себе является приложением C++, и попытка правильно использовать библиотеку .NET просто напрашивается на мир боли, особенно, когда SDK также предоставляет нативную библиотеку C/C++!

Конечно, вы не можете просто использовать библиотеку C++ напрямую; вам придется написать оболочку C++. В мире узлов они известны как дополнения. Написание надстройки не совсем просто, но даже человек с небольшим опытом работы с C++ должен быть в состоянии следовать примерам в документации и получить что-то работающее.

Получить собственный аддон, встроенный в Windows, также может быть немного сложно; вот несколько советов, которые помогут вам начать работу.

Поскольку SDK, который вы используете, защищен платным доступом, я не могу привести конкретных примеров. Однако я предполагаю, что ваш объект-оболочка C++ будет предоставлять несколько методов, и вы также напишете JS-оболочку вокруг этого, чтобы предоставить чистый API. Например:

var uareu = require('./uareu.node') // the native C++ addon dll
    , events = require('events')
    , util = require('util');

function FingerprintReader() {
    events.EventEmitter.call(this); // initialize the EventEmitter

    // do stuff with the native module

    // whenever a finger is placed on the reader:
    this.emit('finger', { id: idFromSdk });
}

util.inherits(FingerprintReader, events.EventEmitter); // we want this module
                                                       // to be an EventEmitter

module.exports = FingerprintReader; // export for require()ing in your app

Теперь ваше приложение может просто:

var FingerprintReader = require('fingerprint')
    , fp = new FingerprintReader();

fp.on('finger', function(d) {
    // do something with `d.id`
});

Этот пример, очевидно, многое замалчивает, но должен дать вам хорошее представление о том, что должно произойти в конце JS. Что касается обнаружения, когда палец помещается на ридер, опять же, я не могу сказать, как вы это сделаете без доступа к SDK. Могу поспорить, что вы где-нибудь проголосуете. Это должно быть сделано в отдельном потоке в вашем аддоне.


Дополнительный бонус: выбор собственного пути означает, что вы, вероятно, также будете совместимы с версией SDK для Linux, поэтому ваше приложение также будет работать в Linux!

person josh3736    schedule 15.05.2013
comment
В любом случае я не могу вызывать код узла из оболочки C++. Это представляется возможным с помощью внедрения кода edge.js и .NET. - person pocesar; 17.05.2013
comment
@pocesar: Конечно, можешь. См. пример обратного вызова. - person josh3736; 17.05.2013
comment
это кажется действительно сложным по сравнению с решением edge.js... кажется, требует продвинутых знаний C++, которых мне не хватает. - person pocesar; 17.05.2013
comment
Я также на Windows, и он будет поставляться только для ОС Windows. - person pocesar; 17.05.2013

Спустя долгое время после публикации этого вопроса я могу легко использовать edge.js для связи IN и OUT моего пользовательского интерфейса .NET (даже для управления node.js в node-webkit из пользовательского интерфейса .NET), используя эмиттер событий узла:

// demo basic code in node.js

var 
  edge = require('edge'), 
  Bridge = edge.func('../path/to/compiled.dll'),
  callback,
  ev = new require('events').EventEmitter();

ev.on('acquire', function(fingerdata){
  console.log(fingerdata);
});

ev.on('error', function(){
}); 

callback = function(event, report){
  // report the result of the event emitter back to .NET
  // you can even pass the "report" to the event handler, so you can return anything you want back to .NET, not just a boolean
  report(null, ev.emit(event.name, event.data));
  //ev.emit(event.name, {data: event.data, report: report});
};

var bridge = Bridge(callback, true);

// calling bridge(null, true); "releases" my device, should be called on process.on('exit')

И теперь вы можете вызывать/исходить из .NET, используя события, вместо того, чтобы вызывать собственный код (который может быть не потокобезопасным).

namespace Bridge
{
    public class Startup
    {
        public async Task<object> Invoke(Func<object, Task<object>>callback)
        {
            Bridge.Base.setCallback(callback);

            MainForm mainForm = new Bridge.MainForm();

            Task.Run(async () =>
            {
                Application.Run(mainForm);
            });

            return (Func<object, Task<object>>)(async (i) => { Bridge.Base.release(); return null; });
        }
    }
}

// inside Bridge.Base


static public void setCallback(Func<object, Task<object>> cb)
{
    if (callback == null)
    {
        callback = cb;
    }
}

static public async void Emit(string name, object data)
{
    return await Task.Run(async () =>
    {
        return await callback(new {
            name = name,
            data = data
        });
    });
}

static public Func<object, Task<object>> callback = null;

теперь я могу асинхронно вызывать Emit('error', "My error") из любого места мои производные классы от Base. Просто заметьте, что недавно я начал углубляться в C#, и мой код, представленный здесь, может не подойти.

person pocesar    schedule 23.01.2014
comment
У меня точно такая же ситуация, как вы... пытаетесь поговорить с некоторым оборудованием с помощью .NET sdk из узла... Ваше решение приносит мне 95% пути... Мне просто интересно, есть ли у вас еще код чтобы показать фактическую реализацию функции .NET Emit. А также, где в .NET вы получаете события, испускаемые узлом? - person Rastographics; 09.05.2019

Интересная проблема. Можно ли просто поместить интересующую вас функцию в файл ASHX (настраиваемый обработчик HTTP), а затем опубликовать ее из приложения вашего узла? В зависимости от того, что вы хотите вернуть, вам, возможно, придется выполнить некоторую сериализацию/десериализацию, но похоже, что это может быть самый простой способ запустить фрагмент кода С# из приложения Node....

У Microsoft есть довольно хороший набор руководств по пользовательским обработчикам HTTP, которые можно найти здесь.

Базовый скелет ASHX приведен ниже:

<%@ WebHandler Language="C#" Class="NodeHandler" %>

using System;
using System.Web;

public class NodeHandler : IHttpHandler {

    public void ProcessRequest (HttpContext context) {

        //Handle fingerprint stuff!!!

        context.Response.ContentType = "text/plain";
        context.Response.Write("Hello World");
    }

    public bool IsReusable {
        get {
            return false;
        }
    }

}

Вы замените содержимое ProcessRequest модифицированной версией вашей существующей функции.

person Abe Miessler    schedule 10.05.2013

Я бы создал либо самостоятельную службу WCF (т.е. службу Windows с конечной точкой wcf), либо использовал такие фреймворки, как OpenRasta или ServiceStack, для замены WCF.

Во всех трех случаях у меня будет веб-служба json, которая возвращает результат последнего вызова CaptureAndExtractFmd

Затем я бы использовал эту службу в node.js.

Если вам нужна дополнительная информация о том, как вы решили пойти, просто создайте еще один вопрос.

Пример кода с WCF, частью C#

[ServiceContract]
public interface IFingerprintContrat {

   [OperationContract]
   Fmd[] GetLastFeature(); 

}

public class FingerprintService {
  Fmd[] GetLastFeature() {
     return CaptureAndExtractFmd().ToArray()
  }
}

using (ServiceHost host = new ServiceHost(typeof(FingerprintService), baseAddress))
{
// Enable metadata publishing.
  ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
  smb.HttpGetEnabled = true;
  smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
  host.Description.Behaviors.Add(smb);
  host.Open();

  Console.WriteLine("The service is ready at {0}", baseAddress);
  Console.WriteLine("Press <Enter> to stop the service.");
  Console.ReadLine();

  // Close the ServiceHost.
  host.Close();
}

Часть Node.js

 var request = require("request");

 request.get("baseaddress/GetLastFeature", function (err, res, body) {
   if (!err) {
      var resultsObj = JSON.parse(body);         
      console.log(resultsObj);
   }
 });
person vittore    schedule 11.05.2013