Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to deal the .NET's event with the nodejs event's handler. #330

Open
gentlecolder opened this issue Oct 12, 2015 · 24 comments
Open

How to deal the .NET's event with the nodejs event's handler. #330

gentlecolder opened this issue Oct 12, 2015 · 24 comments

Comments

@gentlecolder
Copy link

the problem code is bellow:
/the edge code bellow: edged.js/
var stractData = edge.func(function () {/*

async (dynamic input) => {
       Box.DataMonitorValueChanged +=input.DataChangedHandler;
}   

*/});

module.exports.stractData=stractData;

/the nodejs code bellow:/
var databox=require('edged.js');

var util = require('util');

var input = {
DataChangedHandler: function (object sender, IList e) {
foreach (DataMonitorValueChangedArgs monitorValue in e)
{

              Console.log(monitorValue.ToString()+";"+monitorValue.Uid.ToString() + ':' +                     monitorValue.Value + '\n');
            }
}

};

databox.stractData(input);

is there any good solution ?

@gentlecolder
Copy link
Author

I tried many times as read the instruction:
Func<object, Task> dataChanged=(Func<object, Task>)input.DataChangedHandler;
Box.DataMonitorValueChanged +=await dataChanged;
does it is not suport eventhandler since its delegate is async method?

@gentlecolder
Copy link
Author

delegate tag can not submit above "Func<object, Task>"

@gentlecolder
Copy link
Author

the erro is cannot wait System.Func<object,System.
Threading.Tasks.Task>
i donot know why?i hope there is a solution which can trans the event result from the .NET to node.js method.

@gentlecolder
Copy link
Author

I and i saw .net can handle node events, but node can not handle .net events, that's not fair.

@tjanczuk
Copy link
Owner

@gentlecolder The functions Edge.js can marshal from JavaScript to C# must have the following signature:

function (data, callback) {
  // ...
  callback(error, result);
}

These functions will then have the shape of the following delegate on the C# side:

Func<object, Task<object>>

If you plan to hook up JavaScript function as a .NET event handler, you will need to provide a wrapper event handler implementation around the marshaled Func<object,Task<object>> in C#.

@gentlecolder
Copy link
Author

The debug complied error is:
System.Func<ob
tem.Threading.Tasks.Task >” can not implicit casting “System.EventHandler<System.Collections.Generic.IList >

then i changed the Func<object,Task > to Func<object,Task<System.Collections.Generic.IList > the debug give me the message is "Invalid expression term".
So is there and type need to attention when hook up JavaScript function as a .NET event handler

@gentlecolder
Copy link
Author

20151013094003

@gentlecolder
Copy link
Author

node Code
nodecode
C# CODE
c code

@gentlecolder
Copy link
Author

it seamed that the node function can not changed to Eventhandler implicitly, why? doest that means Eventhandler is not a function in C#. I am not good at C#

@tjanczuk
Copy link
Owner

Edge.js does not marshal arbitrary functions between JavaScript and .NET, the functions must be of appropriate signature. It means that in most cases you will need to write an adapter code or class that changes the intended signature of the function: https://github.com/tjanczuk/edge#how-to-integrate-c-code-into-nodejs-code.

In your case, I believe you need to write a wrapper around *EventHandler type expected in your C# code and the Func<object,Task<object>> exposed by Edge.

@gentlecolder
Copy link
Author

above code i have showed wrapped still cannot pass complie

@colceagus
Copy link

@tjanczuk Could you please provide a simple example of EdgeJS code (Node.JS) code handling .NET events properly?

I want to start an ID Card Reader application (for 3M CR100 SwipeReader) and I want my (edgejs + nodejs) code to listen to the DocumentReadEvent and DocumentReadErrorEvent from my C# code.

I hope you see this asap.

Please reply to this comment just to see you have seen it and if you can apply some action to this issue commented here.

With all due respect,
Daniel.

@colceagus
Copy link

@gentlecolder have you been able to assign a javascript event handler to a C# event?

@tjanczuk
Copy link
Owner

@danielmihai Are you writing .NET application or a Node.js application (i.e. is Node hosted in CLR or vice versa)?

@tjanczuk
Copy link
Owner

Have a look at https://github.com/tjanczuk/edge/blob/master/samples/209_websocket.js, specifically at how the sendImpl (https://github.com/tjanczuk/edge/blob/master/samples/209_websocket.js#L79) is set up and used to call back to Node.js when something happens in CLR. This example assumes you write a Node.js app and host CLR in it, but the pattern is also applicable if the reverse is true.

@colceagus
Copy link

@tjanczuk I want to send a function from JavaScript that acts as an event handler to
the c# dll. In c# the invoke function receives a dynamic input as a
JavaScript object with the javascript handler function
{
handleCSeventEventHandler: function(data, callback) {
// do something with data (i don't know what data is in this case, most
probably the event)
callback(error, result);
}
}

In c# on Invoke, I'll assign the EventHandler to the Event:

public EventHandler DocumentReadEvent;
public SwipeReader swipeReader;

.... Invoke (dynamic input) {

this.swipeReader = new SwipeReader();
this.swipeReader.Start();

this.DocumentReadEvent += input.handleCSeventEventHandler;

}

The scenario I'm in : I've written a library that initializes a 3M
CR100 SwipeReader, starts listening for SwipeReader events, it uses a
Control to invoke event processing (if _threadHelperControl.invokeRequired
then _threadHelperControl.invoke(ProcessEvent), I'll post the code below:

private void ProcessEventThreadHelper(MMM.Readers.FullPage.EventCode
aEventCode)
{
try
{
if (_threadHelperControl.InvokeRequired)
{
_threadHelperControl.Invoke(
new
MMM.Readers.FullPage.EventDelegate(ProcessEvent),
new object[] {aEventCode}
);
}
else
{
ProcessEvent(aEventCode);
}
}
catch (Exception )
{
Console.Out.Write("thread helper control failed to invoke
ProcessEvent");
}
}

private void ProcessEvent(MMM.Readers.FullPage.EventCode aEventCode)
{
InsertRow((int)aEventCode, aEventCode.ToString(), 0,
string.Empty, RowType.Event);

        if (aEventCode == EventCode.DATA_READ)
        {
            if (DocumentReadEvent != null)
            {
                this.DocumentReadEvent(this.resultStr);
            }
        }
    }

In InitializeSwipeAPI i have
private int InitialiseSwipeAPI()
{
MMM.Readers.ErrorCode lErrorCode =
MMM.Readers.ErrorCode.NO_ERROR_OCCURRED;

        // Initialise logging and error handling first. The error

handler callback
// will receive all error messages generated by the 3M Page
Reader SDK
MMM.Readers.Modules.Reader.SetErrorHandler(
new MMM.Readers.ErrorDelegate(ProcessErrorThreadHelper),
IntPtr.Zero
);
lErrorCode = MMM.Readers.Modules.Reader.InitialiseLogging(
true,
3,
-1,
"SwipeReader.Net.log"
);

        if (lErrorCode == MMM.Readers.ErrorCode.NO_ERROR_OCCURRED)
        {
            // Next load the settings for the Swipe Reader from the ini

files. You can
// also modify and save settings back to the ini files
using
// MMM.Readers.Modules.Reader.SaveSwipeSettings()
lErrorCode = MMM.Readers.Modules.Reader.LoadSwipeSettings(
ref swipeSettings
);

        }

        if (lErrorCode == MMM.Readers.ErrorCode.NO_ERROR_OCCURRED)
        {
            // Initialise the Swipe Reader. Data and events will be

sent back in a
// non-blocking fashion through the callbacks provided
//
// Thread helper delegates are used to avoid thread-safety
issues,
// particularly with .NET framework 2.0
lErrorCode = MMM.Readers.Modules.Swipe.Initialise(
swipeSettings,
new
MMM.Readers.Modules.Swipe.DataDelegate(ProcessDataThreadHelper),
new
MMM.Readers.FullPage.EventDelegate(ProcessEventThreadHelper)
);
}

        if (lErrorCode != MMM.Readers.ErrorCode.NO_ERROR_OCCURRED)
        {
            InsertRow(
                (int)lErrorCode,
                lErrorCode.ToString(),
                0,
                "Failed to initialise Swipe Reader API",
                RowType.Error
            );
            return (int)lErrorCode;
        }

return 1;
}

How can I keep the DLL alive in nodejs so that it continually runs and
listens for event triggering from the CR100 SwipeReader?
How can I assign a function from nodejs to c# eventhandler to handle the
event?
How can the CLR communicate with v8 to send the event to my nodejs module?

Kind Regards,
Daniel.

On 21 ian. 2016, at 22:27, Tomasz Janczuk [email protected] wrote:

Have a look at
https://github.com/tjanczuk/edge/blob/master/samples/209_websocket.js,
specifically at how the sendImpl (
https://github.com/tjanczuk/edge/blob/master/samples/209_websocket.js#L79)
is set up and used to call back to Node.js when something happens in CLR.
This example assumes you write a Node.js app and host CLR in it, but the
pattern is also applicable if the reverse is true.


Reply to this email directly or view it on GitHub
#330 (comment).

@tjanczuk
Copy link
Owner

This line of code will require some extra work:

this.DocumentReadEvent += input.handleCSeventEventHandler;

The input.handleCSeventEventHandler is of type Func<object,Task<object>> and as such will need to be wrapped in an adapter class that is of type expected by DocumentReadEvent. Within this wrapper class you will also likely need to covert the actual event data into a structure that can be passed as an object to handleCSeventEventHandler. It can be an anonymous object. You may also find out that passing the event directly works, but I would not count on that.

@colceagus
Copy link

Hi @tjanczuk ,

I managed to get it working by integrating this example https://github.com/tjanczuk/edge/blob/master/samples/209_websocket.js and sending the function to the DLL.

public abstract class NetWebSocket
    {
        private Func<object, Task<object>>  SendImpl { get; set; }

        protected NetWebSocket(Func<object, Task<object>> sendImpl)
        {
            this.SendImpl = sendImpl;
        }

        protected abstract Task ReceiveAsync(string message);

        public Func<object, Task<object>> ReceiveImpl
        {
            get
            {
                return async (input) =>
                {
                    Console.Out.WriteLine(input);
                    await this.ReceiveAsync((string) input);
                    return Task.FromResult<object>(null);
                };
            }
        }

        protected async Task SendAsync(string message)
        {
            await this.SendImpl(message);
            return;
        }
    }

    public class MyNetWebSocketImpl : NetWebSocket
    {
        public CHello module;
        private string JSONCodelineDataRepr = "not set";

        public MyNetWebSocketImpl(Func<object, Task<object>> sendImpl) : base(sendImpl)
        {
            // do other stuff after calling the super class constructor  
            module = new CHello();
            module.DocumentReadEvent += this.DocumentReadEventHandler;
            module.DocumentReadErrorEvent += this.DocumentReadErrorEventHandler;
            // uncomment after the websocket communication works
            module.Start();
        }

        protected override async Task ReceiveAsync(string message)
        {
            // not really needed because only the NodeJS Server listens to C# .NET Server messages
            Console.WriteLine(message);
            if (message.Equals("shutdown"))
            {
                module.Close();
            }
            // not necessary (can comment the send function call)
            // if I eventually receive a message, respond with the JSON representation of the Patient ID Card
            await this.SendAsync("I received a message from you, but I'll ignore it and send you the Patient" +
                                 " ID Card Data instead.. I'm a fish, so start phishing! PersonData = " +
                                 JSONCodelineDataRepr);
            return;
        }

        private async void DocumentReadEventHandler(string args)
        {
            this.JSONCodelineDataRepr = args;
            await this.SendAsync(args);
        }

        private async void DocumentReadErrorEventHandler(string args)
        {
            await this.SendAsync(args);
        }
    }

    public class Startup
    {

        public static MyNetWebSocketImpl ws;

        public async Task<object> Invoke(Func<object, Task<object>> sendImpl)
        {
            ws = new MyNetWebSocketImpl(sendImpl);

            return ws.ReceiveImpl;
        }
    }
(function(e,d,g,e){

    var edge = require('edge'),
        http = require('http'),
        WebSocketServer = require('ws').Server,
        swipe = edge.func('./dlls/ActiveXCOM.dll');

    var server = http.createServer(function(req,res){
        res.writeHead(200, {'Content-Type' : 'text/html'});
        res.end((
            function () { /*
                <!DOCTYPE html>
                <html>
                <head>
                </head>
                <body>
                    <div id='jsonOutput'>
                    </div>
                    <script>
                        var ws = new WebSocket('ws://' + window.document.location.host);

                        ws.onmessage = function (event) {
                            console.log(event.data);
                            var div = document.getElementById('jsonOutput');
                            div.innerHTML = event.data;
                        }

                        ws.onopen = function (event) {
                            // send something to the server
                            ws.send('I am the client from the browser calling you, the NodeJS WebSocketServer!');
                        }

                        ws.onclose = function (event) {
                            alert('websocket closing');
                        }

                        window.onbeforeunload = function myonbeforeUnload() {
                            return "Are you sure?";
                        }

                        window.onunload = function myonunload() {
                            confirm('Are you really sure?');
                            ws.close();
                            return "Are you really sure?";
                        }
                    </script>
                </body>
                </html>
            */}).toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1]);
    });

    var wss = new WebSocketServer({server: server});

    wss.on('connection', function(ws) {
        var sendImpl = function (message, callback) {
            console.log(message);
            ws.send(message);
            callback();
        };

        var receiveHandler = swipe(sendImpl, true); 

        ws.on('message', function (message) {
            receiveHandler(message);
        });

        ws.on('close', function close(){
            console.log('****************************The client disconnected!');
            receiveHandler('shutdown');
            delete receiveHandler;
        });
    });

    server.listen(process.env.PORT || 8080);
    module.exports = this;
})();

This kind of does what it should. Thank you very very much!
My new question arises if this can be done without this abstractified websocket connection, just by giving the invoke a function(input, callback) { //do something; callback(error, result); } and the edgejs func returns a Func<object, Task> function as a ReceiveImpl on the clientside node application (in this case, client is the node app, server is the C# DLL, but both are server and client at the same time <=> C# is a client-server, Node App is a client-server as well).

^:)^ There are no words to thank you enough!

Would you like to include this example of handling C# events in Javascript (Node) to the samples folder? I would be glad to offer the full implementation to have a mini contribution to EdgeJS (Samples only, for now, who knows what might happen in the future), if you agree :D.

@colceagus
Copy link

@tjanczuk Another question popped into my mind, if it's possible to convert this into a client-side javascript module and have things packed like nw.js does ? What do you think?

Thank you again for your support, examples and wonderful library! ^:)^ 🙇

@colceagus
Copy link

@tjanczuk Any news?

@skybedy
Copy link

skybedy commented Nov 15, 2016

Hi @danielmihai , can I ask, if you solved this your situation? I deal with a similar problem as you, only I need to handle C# events from RFID reader.
Thanks for a reaction.

@colceagus
Copy link

If you keep the same pattern as in the example I've written, it doesn't matter what you expose.
Keep the same pattern.

@darylltee
Copy link

darylltee commented Apr 20, 2017

@danielmihai , Hi, how did you get your swipe reader working. I'm working with my fingerprint scanner but no luck in listening for events.
Thanks for you responce.
` // Activate capture handler

currentReader.On_Captured += new `Reader.CaptureCallback(OnCaptured);

`

@colceagus
Copy link

colceagus commented Apr 20, 2017 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants