Pregunta

I'm trying to get a node.js app to interact with a .NET SDK fingerprint reader called U.are.U. The SDK provides .dll (win32 and x64), Java and .NET libraries. I decided to use .NET for the simple of use, having all the interfaces ready to use and all.

So, the current problem I'm facing is how to call those .NET functions and still preserve the asynchronous nature of node.js. The application flow (on the .NET example) is pretty straight forward, 3 calls on the library, and the fingerprint is done.

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;
    }
}

How can I change it so it can be usable in node.js, instead of a .NET gui program?

It also need to be noted that the node.js isn't always going to call a function on the .NET program to receive a function. The identification part of the program happens asynchronously and is set off when someone places a finger on the fingerprint reader, that means that the node.js part have no idea when that is going to happen. So I cannot rely on asking data on the .NET part all the time, it must call callbacks on the node.js without having been asked. So basically, it's a bidirectional communication, not only on request, since requesting using a webserver would be much easier.

I've found a node.js library that can close the gap between .NET and node.js called edge.js would this be of any help?


Basically, edge.js can make it work, along with node-webkit (which I'll be shipping my app), I can call the node APIs directly in the page, so I can update the DOM depending on the result from the library. I need to be able to register an async task that CAN notify from inside the CLR to the node.js counterpart either by emitting an event or calling a callback!

According to the edge.js author it can be done easily https://github.com/tjanczuk/edge/issues/54#issuecomment-17967082 I just don't have enough .NET skills to do so (from a full fledged module) with all the callbacks.

¿Fue útil?

Solución 2

After a long time since this question was posted, I can use edge.js easily to communicate IN and OUT my .NET UI (even control node.js within node-webkit from .NET UI), using node event emitter:

// 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')

And now you can call in/out from .NET using events, instead of calling native code (that might not be thread safe)

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;

can now call Emit('error', "My error") from anywhere my derived classes from Base, asynchronously. Just notice that I recently started dwelving in C#, and my code presented here might not be the best fit.

Otros consejos

Using this SDK's .NET library is not the appropriate solution for this problem.

Node.js itself is a C++ app, and trying to use a .NET library properly is just asking for a world of hurt, especially when the SDK also provides a native C/C++ library!

Of course, you can't just use the C++ library directly; you'll have to write a C++ wrapper. In the node world, these are known as addons. Writing an addon isn't exactly simple, but even someone with little C++ experience should be able to follow the examples in the documentation and get something working.

Getting a native addon built in Windows can also be a little tricky; here's some tips to help you get started.

Since the SDK you're using is behind a paywall, I can't provide any specific examples. However, I imagine your C++ wrapper object will expose a few methods, and you'll also write a JS wrapper around that to expose a clean API. For example:

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

Now your app can just:

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

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

This example obviously glosses over a lot, but should give you a good idea of what needs to happen on the JS end of things. As far as detecting when a finger is placed on the reader, again, I can't really say how you'll do that without access to the SDK. I'd bet that you'll end up polling somewhere. This should be done on a separate thread in your addon.


Bonus: going the native route means you'll probably also be compatible with the SDK's Linux version, so your app will also work on Linux!

Interesting problem. Would it be possible to just drop the function that you care about into an ASHX file (custom HTTP handler) and then post to that from your node application? Depending on what you want to return you might have to do some serializing/deserializing, but this seems like it might be the easiest way to fire a piece of C# code from a Node app....

Microsoft has a pretty good set of tutorials on custom HTTP handlers that can be found here.

The basic ASHX skeleton is below:

<%@ 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;
        }
    }

}

You would replace the contents of ProcessRequest with a modified version of your existing function.

I would create either self hosted WCF service ( ie windows service that has wcf endpoint) or use frameworks like OpenRasta or ServiceStack to replace WCF

In all three cases I would end up having json web service that return result of last call to CaptureAndExtractFmd

Then I would consume that service in node.js

If you need any further information with the way you decided to go, just create another question.

Sample code with WCF, C# part

[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 part

 var request = require("request");

 request.get("baseaddress/GetLastFeature", function (err, res, body) {
   if (!err) {
      var resultsObj = JSON.parse(body);         
      console.log(resultsObj);
   }
 });
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top