10

我正在尝试让 node.js 应用程序与名为 U.are.U 的 .NET SDK 指纹读取器进行交互。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 技能来做到这一点(来自一个完整的模块) 与所有回调。

4

4 回答 4

2

使用此 SDK 的 .NET 库不是解决此问题的适当解决方案。

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 上运行!

于 2013-05-15T19:56:58.153 回答
2

自从发布这个问题很长时间后,我可以使用 node 事件发射器轻松地使用 edge.js 与我的 .NET UI 进行交流(甚至在 .NET UI 的 node-webkit 中控制 node.js):

// 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#,而我在这里展示的代码可能不是最合适的。

于 2014-01-23T19:50:25.003 回答
1

有趣的问题。是否可以将您关心的函数放入 ASHX 文件(自定义 HTTP 处理程序)中,然后从您的节点应用程序发布到该文件?根据您想要返回的内容,您可能需要进行一些序列化/反序列化,但这似乎是从 Node 应用程序触发一段 C# 代码的最简单方法......

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现有函数的修改版本。

于 2013-05-10T23:55:56.853 回答
0

我将创建自托管 WCF 服务(即具有 wcf 端点的 Windows 服务)或使用 OpenRasta 或 ServiceStack 等框架来替换 WCF

在所有三种情况下,我最终都会拥有 json web 服务,该服务返回最后一次调用的结果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);
   }
 });
于 2013-05-11T00:07:09.547 回答