Capture Third Party DLL events in WCF - c#

I’ve been supplied with a DLL by a third party which processes the data it’s supplied and returns its results through an event as below.
private IBlackbox blackbox;
// Capture the processed data from the BlackBox
public void blackbox_Processed(object sender, BlackBoxEventArgs e)
{
string returndata = e.ReturnData;
// Do something with the data
}
public void blackbox_Run(string datavalues)
{
blackbox.Processed += new EventHandler(blackbox_Processed);
blackbox = BlackBox.Create(datavalues);
blackbox.Start();
}
This implementation works fine when called from a Windows form with the blackbox.Processed event firing in less than a second. However, when I implement this in a WCF method the blackbox.Processed event is never trapped.
Can anyone help?

It's hard to say for certain since you haven't provided code for your service but my guess is that the call to your service method is returning before your blackbox component fires the event. One thing you could look at would be using a WCF duplex service which would allow you to publish an event from the server to the client.
WCF Duplex Services

Related

Show dialog from non UI dll

I'm building a dll that will be used from wpf and other kind of framework (windows form, asp...). For this reason I don't want to use Messagebox. Which is the best way to send notification from dll to app and each decide the way to show the message to user (and wait an answer from user)? Somebody can help me to find the correct way?
Unless the library (.dll) is only intended to work with a particular UI, the library shouldn't "decide" how or if notifications get displayed. It's a separation of concerns. If a library determined that it should show a MessageBox then you wouldn't be able to use that same library with a web app or some out-of-sight service.
Here are two ways (not exhaustive) that we might get information from a separate library, including our own:
We call a function and the library returns a response. For example, it might indicate that an action succeeded or failed. The library doesn't know what type of app it's being called from or whether anyone needs to see the response. It just returns it. Your app can then receive that result and display a message.
A class within the library raises an event which indicates that something has happened. Same thing - it doesn't know what is listening for that even or what will happen as a result. It just raises the notification. Our app determines that in response to that event it should display a message.
When our libraries work that way they are easier to test using automated tests like unit tests and integration tests. It's easy to write a test which verifies that calling a method returns a certain result. It's much harder to verify that a MessageBox pops up.
And, as mentioned, it makes it more likely that we can use more of our code with different types of user interfaces. For those reasons it's beneficial to write as much of our code as possible in isolation from any UI, which means not including input/output behaviors that are specific to one type of UI.
You could expose an event that the consumers can subscribe to. Here is the general pattern to do this kind of thing:
You can create your own class to carry the data about the event:
public class NotificationEventArgs : EventArgs
{
public NotificationEventArgs(string message)
{
Message = message;
}
public string Message { get; }
}
You then create a delegate to represent the signature of the event:
public delegate void OnNotificationEventHandler(SomeClass sender, NotificationEventArgs args);
Your class or classes can then expose this delegate as an event:
public class SomeClass
{
private OnNotificationEventHandler _notificationEventHandler;
public event OnNotificationEventHandler OnNotification
{
add { _notificationEventHandler += value; }
remove { _notificationEventHandler -= value; }
}
protected void RaiseNotificationEvent(NotificationEventArgs args)
{
_notificationEventHandler?.Invoke(this, args);
}
public void SomeMethod()
{
//Your class does something that requires consumer notification
var args = new NotificationEventArgs("Something happened!");
//Raise the event for the consumers who are listening (if any)
RaiseNotificationEvent(args);
}
}
Finally, your consuming classes will subscribe to this event:
SomeClass obj = new SomeClass();
obj.OnNotification += Obj_OnNotification;
private static void Obj_OnNotification(SomeClass sender, NotificationEventArgs args)
{
//Handle the notification from the class here.
Console.WriteLine(args.Message);
}
The general idea is that consumers of your class only need to know that something has happened as well as details of what happened. How that event is consumed, handled or displayed is not the responsibility of your component.

SignalR OnConnected not called, connecting from .NET client

I'm using SignalR and have a Hub where I've overwritten the OnConnected method. The reason is, the server publishes data every 60 seconds. But when a new client connects, I want to publish the data immediately.
In a simplified form:
public class CustomerPublisher : Hub
{
public void Publish(Customer customer)
{
Clients.All.receive(customer);
}
public override Task OnConnected()
{
return base.OnConnected();
}
}
The OnConnected method is never called (I tested by debugging). I've read in several places (like here) that the client needs to have a connected handler, like:
$.connection.onlineHub.client.connected = function(){...}
However, I have a WPF client, so in .NET I tried adding this, on top of the event I was already handling:
hubProxy.On<object>("receive", OnCustomerReceived); // this line was already present
hubProxy.On<object>("connected", OnConnected); // I added this
This didn't help. But I do have a connection, because after some time, I start receiving data.
Is there anything I'm missing? How can I get SignalR to call the OnConnected method when my .NET client connects?
You can try to use StateChanged event like this :
Connection.StateChanged += Connection_StateChanged;
void Connection_StateChanged(StateChange obj)
{
if (obj.NewState == ConnectionState.Connected)
{
//do somethign here
}
}
You ll receive Connecting and Connected states
In my case, the problem was Autofac. I had set it up in my own way (due to the way I had set up WCF duplex before using SignalR). But it is important to follow the docs. Even though a connection was made, and my client received data, I never entered the OnConnected method. After following the documentation, I the method was called.

How to communicate Server to Client with SignalR in Nancy with ASP.NET Hosting?

Most of the examples I've found for SignalR are assuming ASP.NET (MVC or not). I'm using NancyFX. I'm having just one problem, so I'm hoping there's something I'm overlooking or some thing I need to do in Nancy to compensate for not being ASP.NET.
My one goal is to be able to notify the client browsers when a server event happens. I don't plan on replacing my Nancy routes with hub methods. But I would like the ability to call into the browser from my routes (actions).
I have very simple Hub that I created following the example in the SignalR Wiki. I'm not even sure I need it, since I don't plan on calling client to server.
public interface IUserNotifier
{
void Start();
void Notify(object #event);
}
I used an interface in hopes that I would be able to inject the same hub later on to use in my nancy routes... I'm not sure that is in the cards.
[HubName("userNotifier")]
public class UserNotifier : Hub, IUserNotifier
{
public void Start()
{
Notify(new {Status = "Started"});
}
public void Notify(object #event)
{
Clients.notification(#event);
}
}
When I have the following code in my html file, I can see that it executes the Start() method, and then the Notify() method, delivering content to my client.
var communicator = $.connection.userNotifier;
$.extend(communicator, {
Notification: function(event) {
alert("notification received from server!");
console.log(event);
}
});
$.connection.hub.start()
.done(function() {
communicator.start();
});
Like I said, "starting" the hub works and sends a notification to the client. Very cool. But, then, my primary goal hasn't been accomplished yet. I need to initiate these notifications from other places in my code where they might not be directly associated with a "request".
I tried injecting my IUserNotifier in my nancy modules for use in the routes, but when the Notify() is fired, I get:
That's because the Clients property on the Hub base class is null (hasn't been initialized). So, I switched gears. I tried to follow multiple examples, including the example from the wiki page about hubs in the section called "Broadcasting over a Hub from outside of a Hub":
public class NotifierModule : NancyModule
{
public NotifierModule(){
Get["/notify/{message}"] = p => {
var context = GlobalHost.ConnectionManager.GetHubContext<UserNotifier>();
context.Clients.notification(new { Message = p.message });
};
}
}
My Nancy route executes without throwing errors. Except my browser never receives the message. If I set a breakpoint in the route, I can see that Clients is initialized. Maybe the collection of clients is initialized but empty. Who knows? Maybe you do. :)
Again, my main goal is to be able to send events/notifications to the browser from anywhere in my code, any time. Is that too much to ask? What should I be doing here?
I'm sure you must have found the answer already. However, I figured I could try and help out in case anyone else runs into a similar problem. In order for your server on the .NET side to send messages to clients, it would also need to have a connection made to the hub.
var connection = new HubConnection("http://localhost/");
connection.Start();
connection.Notify("Hello");
Check out an official example at:
https://github.com/SignalR/SignalR/blob/master/samples/Microsoft.AspNet.SignalR.Client.Samples/Program.cs

C# Equivalent events in Java

I have developed a PC based API in C# to communicate with an embedded electronic device. This API reads the PC COM port, decodes packets, constructs packets and raises events. Now I need to develop the same API in Android mobile. As there are differences between C# and Java Events, I'm quite confused how to achieve the same in Java.
The following C# code rises events:
public class MARGserial
{
dataObject = BT_DeconstructPacket(encodedPacket);
if (dataObject != null) // if packet successfully deconstructed
{
OnMARGdataReceived(dataObject);
if (dataObject is RawMARGdata)
{
OnRawMARGdataReceived((RawMARGdata)dataObject);
PacketsReadCounter.RawMARGdataPackets++;
}
}
public delegate void onRawMARGdataReceived(object sender, RawMARGdata e);
public event onRawMARGdataReceived RawMARGdataReceived;
protected virtual void OnRawMARGdataReceived(RawMARGdata e)
{
if (RawMARGdataReceived != null)
RawMARGdataReceived(this, e);
}
}/*End of MARGserial class */
The following code is for subscribing to Event OnRawMARGdataReceived in windows console application.
public static MARG_api.MARGserial MARGserial = new MARG_api.MARGserial("COM44");
MARGserial.RawMARGdataReceived += new MARG_api.MARGserial.onRawMARGdataReceived(MARGserial_RawMARGdataReceived);
static void MARGserial_RawMARGdataReceived(object sender, MARG_api.RawMARGdata e)
{
Console.WriteLine("Data : " + e.Accelerometer[0].ToString() + " "+e.Accelerometer[1].ToString()+ " "+e.Accelerometer[2].ToString());
}
In case of Android Java application, Main Activity class in the application itself has to subscribe for events which are fired inside of another class thread ( this thread reads Bluetooth buffer & constructs packets)
You could use Design Patterns here, notably Observer:
In Observer you have an interface called IObserver with a method called update() that you make all your interested objects implement. Then the master object stores a set of s and when something happens it calls .update() on every object in that collection (the callback in essence). This is common in MVC architectures too if you want to go that way for GUI, when the model state changes and the view needs to be updated.
You could also achieve Delegate style first order functions using the Command design pattern, which is very useful in Java given there is no native support for this concept.
I'm not sure if the above will help in your specific context, but Design Patterns are usually a good way to go and solve all manner of problems.
If you are not using a GUI-Toolkit like "Swing" then in Java the Listener Pattern is quite common for this kind of task.
That is you have a listener that registers itself at the host, which in turn holds a list of listeners. If the event corresponding to the listener happens, the listeners then get notified.
It is pretty similar to the Observer Pattern.
Maybe this SO question is helpful.
I successfully developed android application which can connect to my bluetooth device using the BluetoothChat sample provided by Google. The bluetooth module of device has SPP (serial port profile) which is from RovingNetworks (RN-41).
Please check out -
http://v-lad.org/projects/gnu.io.android/

How to enable user GUI response in wcf service to trigger duplex callback to client

Maybe I am trying the impossible...
I have created a wpf application to start a wcf service with the following service contract:
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IRejectCallback))]
public interface IRejectService
{
[OperationContract(IsOneWay = true)]
void SubmitNewRejectInfo();
[OperationContract(IsOneWay = true)]
void SendRejectCallback();
}
My service behavior:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = true)] //(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.Single, UseSynchronizationContext = true)]
public class RejectService : IRejectService, IPostRejectEvent
I create my duplex channel and call the SubmitNewRejectInfo service method:
InstanceContext ic = new InstanceContext(new RejectCallbackHandler());
tcpFactory = new DuplexChannelFactory<IRejectService>(ic, "netTcp");
IRejectService _rejectService = tcpFactory.CreateChannel();
_rejectService = _tcpFactory.CreateChannel();
_rejectService.SubmitNewRejectInfo();
The SubmitNewRejectInfo method is run on the service side. Normally, I would add my callback method like this:
public void SubmitNewRejectInfo(RejectInformation rejectInformation)
{
// Do something here...
callback.RejectCallback();
}
However, when the SubmitNewRejectInfo method is run from the client (using IsOneWay = true), I do not want to callback to the client at that time. I would like to wait for the user to click a button on my WPF GUI which will transmit the signal to callback to the client. ** Is it possible to postpone the callback, or send a callback via a different operation contract? **
How could the client invoke the service via an operation contract method and then receive a callback after user interaction happens on the service side? I saw one duplex example where someone used a reentrant service with Thread.Sleep() as follows:
public void Register()
{
OperationContext ctxt = OperationContext.Current;
IClientCallback callBack = ctxt.GetCallbackChannel<IClientCallback>();
Thread.Sleep(3000);
callBack.TempUpdate(10);
}
In my case, I would need to trigger the callback in the Register method after a user clicks a button on a gui that is hosting the service. Would this be possible? Any ideas?
UPDATE **
I have discovered my main issue:
I make a call from my wcf client to my operation service contract method:
InstanceContext ic = new InstanceContext(new RejectCallbackHandler());
_tcpFactory = new DuplexChannelFactory<IRejectService>(ic, "netTcp");
_rejectService = _tcpFactory.CreateChannel();
_rejectService.SubmitNewRejectInfo();
The wcf service operation is invoked here:
public void SubmitNewRejectInfo(RejectInformation rejectInformation)
{
// Throw event to notify MainViewModel that new reject information is available.
OnSubmitNewRejectInfo(new RejectInfoArgs(rejectInformation));
callback.RejectCallback();
}
The event is fired to notify my MainViewModel that some data has been updated and refresh some properties. Then problem begins... I do not want the callback.RejectCallback(); to fire just yet. I need the user to click a button on my Mainwindow GUI associated to the view model to "authorize" the duplex callback to return a message to the wcf client.
Any ideas how to "pause" the callback long enough for a user to click a button to authorize the duplex callback to deliver a message to the wcf client? Perhaps my OnSubmitNewRejectInfo event can return some event argument before the callback is invoked? Could a new delegate be triggered to return information from my MainViewModel before the callback is invoked?
I hope this describes my problem a little better. Any help is VERY much appreciated.
Update number 2 **
More information... :)
The WCF service was created as a WCF service class library. The WCF client was also created as a WCF service class library. This makes it easy for other applications or class objects to host the service and client. This was done in order for human interaction via a GUI on the service side, and other software interaction on the wcf client side. The WCF service and client are hosted on separate machines.
The WCF service is hosted by a WPF application, and communication is event driven between the two. The service class is created as a singleton in the MainViewModel of the WPF application.
The WCF service class must talk via duplex communication with the wcf client. The client invokes an operation contract to update information in the service, which is displayed on the WPF GUI. After the information is displayed on the GUI, then the user must click a button to invoke the callback to the client indicating that the service has completed it's task.
So, WPF app hosts a wpf service class library. There is communication between the WPF app and service class via events. The service class is consumed by a wcf client via duplex channel communication. The wcf client is also hosted by another class object with a service reference to the wcf service. The client communicates with it's host via events.
WCF CLIENT CODE:
InstanceContext ic = new InstanceContext(new RejectCallbackHandler());
_tcpFactory = new DuplexChannelFactory<IRejectService>(ic, "netTcp");
_rejectService = _tcpFactory.CreateChannel();
_rejectService.SubmitNewRejectInfo(); // This is where I invoke a service operation from my client.
WCF SERVICE CODE:
// This service operation is consumed by the client.
public void SubmitNewRejectInfo(RejectInformation rejectInformation)
{
// Create event to notify MainViewModel that new reject info is available.
OnSubmitNewRejectInfo(new RejectInfoArgs(rejectInformation));
// **** I need something to happen here in order to halt the duplex callback to the client until a human creates a button click event in my MainViewModel, which indicates the duplex callback may be sent back to the client. ****
callback.RejectCallback();
}
Sorry this question has become very detailed. I never should have fallen asleep during my technical writing class in college... :)
Update number 3 **
I tried running the code that degorolls mentioned below. His example code is perfect for my needs!! (Thanks degorolls!) However I get a null reference exception: "Object reference not set to an instance of an object".
First the action executes in this part of degoroll's demo code:
if (pendingNotifications.TryGetValue(rejectInformation, out action))
{
try
{
action(rejectInformation); // This is invoked
Then this part of the demo code is called -> callback.RejectCallback(new RejectCallbackMessage())); :
public void SubmitNewRejectInfo(RejectInformation rejectInformation)
{
// Throw event to notify MainViewModel that new reject information is available.
OnSubmitNewRejectInfo(new RejectInfoArgs(rejectInformation));
pendingNotifications.Add(rejectInformation, info => callback.RejectCallback(new RejectCallbackMessage())); // **** the action returns to callback.RejectCallback here ****
This is where I get my null exception error.
Here is my code to get the callback channel:
IRejectCallback callback
{
get { return OperationContext.Current.GetCallbackChannel<IRejectCallback>(); }
}
My guess is that I am not returning null instead of the original callback channel...
Is there a way I can obtain the correct channel at this point in the code?
If I'm understanding things correctly it seems that the server simply needs to be keep a list of things it is waiting to do. How you implement will be tied closely to the instancing of the server. If you stick with singleton, you can simply hold a map of pending notification in the server class. E.g.:
public class RejectService
{
Dictionary<RejectInformation, Action<RejectInformation>> pendingNotifications = new Dictionary<RejectInformation, Action<RejectInformation>>();
public void SubmitNewRejectInfo(RejectInformation rejectInformation)
{
OnSubmitNewRejectInfo(new RejectInfoArgs(rejectInformation));
pendingNotifications.Add(rejectInformation, info => callback.RejectCallback(info));
}
public void SendRejectCallback(RejectInformation rejectInformation)
{
Action<RejectInformation> action;
if (pendingNotifications.TryGetValue(rejectInformation, out action))
{
acion(rejectInformation);
pendingNotifications.Remove(rejectInformation);
}
}
}
If you want to make this reentrant you may need to think about locks... This is a really simplistic approach but gives a starting point.

Categories

Resources