Working with an event handler - but not always.. (How do i...) - c#

I'm quite new to C# and certainly OOP concepts.. so forgive the stupidity of my question.
I have a system I wish to communicate with, It has a number of commands that can be called with an associated response. (Communication is done via TCP/IP or Serial) (I implemented an Interface with SendMessage so that I can use multiple transport mechanisms)
I want to create a method for each command and then expose these, which is simple enough. The device also lets say 'broadcasts' messages as well which I want to act on, so I was using an event handler for this which works well..
At the moment in the event handler I catch OK and ERROR style messages, but ideally I would like to also be able to send the command from the above method and catch an error and return a bool value based on the command.
Can anyone think of a way I can do something like this and point me in the right direction?
Thanks
David

You can use helper to wait for event. Some ugly code from past:
public class ComWait
{
ManualResetEvent _waitEvent;
SomeEvent _eventHandler;
public ComWait()
{
_waitEvent = new ManualResetEvent(false);
_eventHandler = new SomeEvent(Watch);
}
void Watch()
{
_waitEvent.Set();
}
public bool Wait(int time = 3000)
{
_waitEvent.Reset();
SomeEvent += _eventHandler;
bool result = _waitEvent.WaitOne(time, false);
SomeEvent -= _eventHandler;
return result;
}
}
Usage is
ComWait wait = new ComWait();
if(!wait.Wait())
return; // timeout
// process
It will simply block synchronous method until event is rised or timeout occurs. It should be easy to add parameters: to unblock on specific event and to pass event handler parameters back to caller.
Otherwise I would simply have method inside communication class to use as a blocker:
readonly object _waitLock = new object();
public void Wait()
{
lock (_waitLock)
if (!Monitor.Wait(_waitLock, 3000))
throw new TimeoutException("No communications");
}
Signal at same time as you rise event:
lock (_waitLock)
Monitor.PulseAll(_waitLock);

Related

Action Delegation in C#

I am reviewing some code from a sample application for an API, and need some help better understanding the Action<T> delegation throughout the sample app. I have put several questions throughout the code. Any help is appreciated
The API is implemented in the Client.cs class, and when I make requests from the application, the API sends the responses to the functions in Client.cs that have been implemented.
/***** Client.cs *****/
public event Action<int, int, int> TickSize;
void tickSize(int tickerId, int field, int size)
{
var tmp = TickSize;
//What is the point of tmp, and why do we check if it is not null?
if (tmp != null)
//This invokes the Action? ie - fires the TickSize Action event?
tmp(tickerId, field, size);
}
Then the UI.cs class handles the UI interactions and feeding the information back into the UI so the user can see what data is returned
/***** UI.cs *****/
//Delegate to handle reading messages
delegate void MessageHandlerDelegate(Message message);
protected Client client;
public appDialog(){
InitializeComponent();
client = new Client();
.
.
//Subscribes the client_TickSize method to the client.TickSize action?
client.TickSize += client_TickSize;
}
void client_TickSize(int tickerId, int field, int size){
HandleMessage(new Message(ticketID, field, size));
}
public void HandleMessage(Message message){
//So, this.InvokeRequired checks if there is another thread accessing the method?
//Unclear as to what this does and its purpose
//What is the purpose of the MessageHandlerDelegate callback
// - some clarification on what is going on here would be helpful
if (this.InvokeRequired)
{
MessageHandlerDelegate callback = new MessageHandlerDelegate(HandleMessage);
this.Invoke(callback, new object[] { message });
}
else
{
UpdateUI(message);
}
}
private void UpdateUI(Message message) { handle messages }
From the docs
Events are a special kind of multicast delegate that can only be invoked from within the class or struct where they are declared (the publisher class). If other classes or structs subscribe to the event, their event handler methods will be called when the publisher class raises the event
So in Client.cs you have a multicast delegate called TickSize. This delegate enables other classes to subscribe to the event it is associated with. So in your function void tickSize(int tickerId, int field, int size), you want to let all the other subscribers know that a tick event has happened.
To do this, you first see if you have any subscribers. This is where the null check happens in if (tmp != null). Having tmp is not needed, you could have done if(TickSize != null) If you have any eventhandlers registered, it would fire and subscribers will receive that call. In your case, you do have subscribers because you are subscribing to the event in public AppDialog with this code : client.TickSize += client_TickSize;
So whenever void tickSize(...) is called in Client.cs, the code in void client_TickSize(...) will run. This will call HandleMessage which will check if it needs to be called by an Invoke function because calling code is not on UI thread. If it does need to be called using Invoke, it will then call the same message using current Control's Invoke function (Not sure which control, could be Form). The HandleMessage will then see that Invoke is not required because caller is on UI thread and then it will call UpdateUi which will update controls.

Ensure event can never have more than one subscriber

I want to ensure that the particular event can never have more than one subscriber. In my particular case it does not make sense to have multiple subscribers, and some sneaky problems might occur if it will.
Side note: Particularly, my handler (subscriber) has to be async and I have to await it when raising the event. The reason is that this is a network-socket-wrapping class, where I raise the TextReceived event, and I don't want to read any more data from the socket, before the user (subscriber) has finished processing last TextReceived event (because user usually writes some reply to the socket, and multiple in-flight callbacks will cause collision). Maybe this case can better be solved another way (without async events), and I'm trying to solve the wrong problem. If so, how?
Here is the solution that I've come up with, but I wonder whether it is the only option, or if it can be simplified any further.
This is my code:
private TextReceivedAsyncHandler _textReceivedAsync;
public event TextReceivedAsyncHandler TextReceivedAsync
{
add
{
if (_textReceivedAsync != null)
throw new MultipleSubscribersNotAllowedException(eventName: nameof(TextReceivedAsync));
_textReceivedAsync = value;
}
remove
{
_textReceivedAsync = null;
}
}
Is this the proper shortest way to restrict multiple subscribers, or can you propose more elegant solution? I thought of using public delegate property instead of an event, but that does not solve any problems because delegates are multicast anyway.
I would still suggest to expose delegate itself. Yes, delegates are multicast and it still might reference to multiple methods. However, semantics of event assumes possibility of multiple subscribers, and restricting this is very confusing to the users of your code. However, if you expose delegate it's very clear only one "subscriber" is expected. To prevent using += syntax, you can do it like this:
private Func<YourEventArgs, Task> _callback;
public Func<YourEventArgs, Task> Callback
{
set { _callback = value; }
}
It's true that user might still pass delegate with multiple methods:
Func<YourEventArgs, Task> delegateA = ...;
Func<YourEventArgs, Task> delegateB = ...;
Callback = delegateA + delegateB;
But the same is true for your TextReceivedAsync event too, and I think that's a problem of subscriber himself.
One more options, if you really want to prevent multicast delegates, is:
private Func<YourEventArgs, Task> _callback;
public Func<YourEventArgs, Task> Callback
{
set
{
if (value != null && value.GetInvocationList().Length > 1) {
throw new Exception("...");
}
_callback = value;
}
}

c# .net WCF Eventhandler completion

How do I determine when a Eventhandler for a WCF is complete?
I have two static variables that don't get set until the loop I am using to check the status is complete.
Create the variables and call the WCF using the Asynch functions created
static var globalResults;
static bool myEventComplete;
main()
{
globalResults = null;
myEventComplete = false;
WCFClient wcf = new WCFClient();
//create event handler for the WCF asynch call
wcf.MyFuncCompleted += new EventHandler<MyFuncCompletedEventArgs>wcf_MyFuncCompleted);
wcf.MyFuncAsync(wcfParameter.ToString());
int counter = 1;
//Need to determine when the event handler is complete to then use the data returned from the WCF
while (myEventComplete == false && globalResults == null && counter < 10000)
{
counter++;
}
}
//Eventhandler
public static void wcf_MyFuncCompleted(object sender, MyFuncCompletedEventArgs e)
{
globalResults = e.Result;
myEventComplete = true;
}
The eventhandler eventually updates the variables after the loop has completed.
If I duplicate the loop into two sections - the variables get updated in between the two loops - it seems that the event handler isn't running until after the loop (which I don't think is the case) - I just don't know how to get the update values from within the loop.
What's probably happening is that loop is running almost instantly (counting to 10,000 takes practically no time at all). And I'd actually expect the compiler to optimize away the loop unless you use the counter further down.
If the goal is to just do something when the event fires - just call the method you want to run when it completes from within the event itself. There isn't any need for the loop. Are you just attempting to "block" the code until the event fires/completes? I probably wouldn't since it's not needed - just continue the rest of your code that is called by the event itself.
I agree with #Paul Mrozowski.
However, if you have to block the thread, you can block it by defining a static AutoResetEvent object, and in your main call WaitOne() method to block the thread and unblock it with Set()
I do not recommend this if you don't badly need it. You usually can call whatever you want in your wcf_MyFuncCompleted
your main will probably look like this:
// You may reduce its accessibility if needed
public static AutoResetEvent SignalMyThread=new AutoResetEvent(false);
main()
{
WCFClient wcf = new WCFClient();
//create event handler for the WCF asynch call
wcf.MyFuncCompleted += new EventHandler<MyFuncCompletedEventArgs>wcf_MyFuncCompleted);
wcf.MyFuncAsync(wcfParameter.ToString());
// wait for one minute at most, you can specify no time to make it wait indefinitely
SignalMyThread.WaitOne(60000);
}
And just call set in your event handler:
public static void wcf_MyFuncCompleted(object sender, MyFuncCompletedEventArgs e)
{
SignalMyThread.Set();
}

How can I use EventWaitHandle to create an event?

I'm writing a program that listens on a Serial Port. I already have code that utilizes the VCP drivers (Virtual COM Port) to open a serial connection and then add an event handler for any time data is received. That code roughly looks like this:
public void OpenPort(string portNumber)
{
_port = new SerialPort(
portName: portNumber,
baudRate: 9600,
parity: Parity.None,
dataBits: 8,
stopBits: StopBits.One
);
_port.DataReceived += ReadData;
}
private void ReadData(object sender, SerialDataReceivedEventArgs e)
{
string data = _port.ReadExisting().Trim();
Console.WriteLine("Received: " + data);
}
This works great. It's very easy for me to understand how to set up events using the += notation. But I'm trying to switch over from using the VCP drivers to instead using the D2XX drivers provided by FTDI. I have most of the equivalent code that I need written, with the notable exception of being able to read data whenever a "data received" event occurs.
The D2XX driver includes one method for setting up event handlers whenever data is received, called SetEventNotification. Here's what the method signature looks like:
SetEventNotification(UInt32 eventMask, EventWaitHandle eventHandle);
The first parameter is straight-forward enough (they have some predefined uints you can pass in to determine when the event should trigger), but I've never worked directly with EventWaitHandles before, and I found the documentation difficult to grasp, so I'm having trouble getting started.
At the end of the day... I would like to have an event listener method which performs a read task, and which I can assign using the += operator, as I did above with the VCP driver.
Based on what I was reading, it looks like I'll have to create a new Thread that essentially polls continuously for the EventWaitHandle's signal? Or something like that? Any examples or sample code to get me started (or finished!) would be appreciated.
Here's what I have so far:
public void OpenPort(string portNumber)
{
_port = new FTDI();
var status = _port.OpenBySerialNumber(portNumber);
if (FTDI.FT_STATUS.FT_OK != status) throw new Exception();
status = _port.SetBaudRate((UInt32) 9600);
if (FTDI.FT_STATUS.FT_OK != status) throw new Exception();
status = _port.SetDataCharacteristics(
DataBits: FTDI.FT_DATA_BITS.FT_BITS_8,
StopBits: FTDI.FT_STOP_BITS.FT_STOP_BITS_1,
Parity: FTDI.FT_PARITY.FT_PARITY_NONE
);
if (FTDI.FT_STATUS.FT_OK != status) throw new Exception();
var evHandle = new EventWaitHandle(false, EventResetMode.AutoReset, "");
_port.SetEventNotification(FTDI.FT_EVENTS.FT_EVENT_RXCHAR, evHandle);
// ... now what?
}
public void ReadData(object sender, EventArgs e)
{
UInt32 bytesAvailable = 0;
_port.GetRxBytesAvailable(ref bytesAvailable);
string data;
UInt32 bytesRead = 0;
_port.Read(out data, bytesAvailable, ref bytesRead);
data = data.Trim();
Console.WriteLine("Received: " + data);
}
I'll have to create a new Thread that essentially polls continuously for the EventWaitHandle's signal
Polls, no. But waits, yes. All that an event handle can do is let a thread sleep until the event is signaled. Note that "event" here means something completely different from a C# "event", though of course you can use the former as part of an implementation of the latter.
Frankly, it's not clear at all why you are headed down this part. Are you dealing with data transmitted over the standard serial port? If so, then there should never be any need to use some third-party API; Windows and .NET provide all you need, and you should stick with that. What does using this third-party API gain you that you are unable to accomplish using the standard SerialPort class?
As far as the event itself goes, without more context (and no, it's unlikely anyone would sift through the PDF you linked to figure out how to produce a turn-key solution for you), all one can offer is a general outline of how you can use the event handle to implement an event:
public event EventHandler DataReceived;
private bool _done;
private void PortListener(EventWaitHandle waitHandle)
{
while (true)
{
waitHandle.WaitOne();
if (_done)
{
break;
}
EventHandler handler = DataReceived;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
public void StartListening(EventWaitHandle waitHandle)
{
_done = false;
new Thread(() => PortListener(waitHandle)).Start()
}
public void StopListening(EventWaitHandle waitHandle)
{
_done = true;
waitHandle.Set();
}
The above provides a DataReceived C# event that is raised any time the wait handle is signaled. It assumes an auto-reset event. You can also use manual reset, simply by (of course) manually resetting the event handle any time it's signaled and you've raised the C# event.
To do this, it simply maintains an internal flag _done indicating whether the thread should be running or not, and provides the Start... and Stop... methods, which clear the flag and start the thread with its loop, and set the flag and signal the event, respectively.

How to use data receive event in Socket class?

I have wrote a simple client that use TcpClient in dotnet to communicate. In order to wait for data messages from server i use a Read() thread that use blocking Read() call on socket. When i receive something i have to generate various events. These event occur in the worker thread and thus you cannot update a UI from it directly. Invoke() can be use but for end developer its difficult as my SDK would be use by users who may not use UI at all or use Presentation Framework. Presentation framework have different way of handling this. Invoke() on our test app as Microstation Addin take a lot of time at the moment. Microstation is single threaded application and call invoke on its thread is not good as it is always busy doing drawing and other stuff message take too long to process.
I want my events to generate in same thread as UI so user donot have to go through the Dispatcher or Invoke.
Now i want to know how can i be notified by socket when data arrive? Is there a build in callback for that. I like winsock style receive event without use of separate read thread. I also do not want to use window timer to for polling for data.
I found IOControlCode.AsyncIO flag in IOControl() function which help says
Enable notification for when data is
waiting to be received. This value is
equal to the Winsock 2 FIOASYNC
constant.
I could not found any example on how to use it to get notification. If i am right in MFC/Winsock we have to create a window of size(0,0) which was just used for listening for the data receive event or other socket events. But i don't know how to do that in dotnet application.
Ok I got it up and running. What I was really looking to was how to seamlessly post events to an UI thread, in which my connection is created. After going through framework code I came up with following proof of concept. SynchronizationContext can be use to bind my component to the UI thread that created it. Then I can post events to that UI thread directly, without using Invoke.
In the following example I created a ThreadUISafeTimer which uses a seperate thread, just like my socket client that uses one for reading and raising events. In this case, context is used to post the event if not null, otherwise the event is raised using the worker thread.
[DefaultEvent("Tick")]
public class ThreadUISafeTimer : Component
{
private const int True = 1;
private const int False = 0;
private int enabled = False;
private SynchronizationContext context;
public event EventHandler Tick = delegate { };
[DefaultValue(false)]
public ushort Interval { get; set; }
public ThreadUISafeTimer() {
Interval = 100;
this.Events.AddHandler("Tick", Tick);
//If this class is created by a UI thread it will always post the Tick event to it.
//otherwise it would be null and Tick would occur in a seperate thread.
context = SynchronizationContext.Current;
}
protected override bool CanRaiseEvents {
get {
return true;
}
}
[DefaultValue(false)]
public bool Enabled {
get {
return enabled == True;
}
set {
int newval = value ? True : False;
if (enabled != newval) {
if (newval == False)
Thread.VolatileWrite(ref enabled, False);
else {
enabled = True;
ThreadPool.QueueUserWorkItem(
new WaitCallback(delegate(object o) {
try {
do {
try {
Thread.Sleep(Interval);
if (Thread.VolatileRead(ref enabled) == True) {
var callback = new SendOrPostCallback(delegate(object arg) {
try {
Tick(this, EventArgs.Empty);
}
catch (Exception exp) {
Application.OnThreadException(exp);
return;
}
});
//If context is null raise Tick event from current thread
if (context == null)
callback(null);
else
//otherwise post it to the UI thread that owns this timer.
context.Post(callback, null);
}
}
catch (ThreadInterruptedException) {
}
} while (Thread.VolatileRead(ref enabled) == True);
}
catch (ThreadAbortException) {
}
}), null);
}
}
}
}
Take a look at this question which is roughly the same and solved by using the Event Broker pattern.
Sending instructions to a thread which is waiting for TCP?
Basically you would have one object with an event that all your threads subscribe to. It will also have a method that can be called which will invoke the event. It maybe sounds complicated, but its fairly simple.
Example code is here http://msforge.net/blogs/paki/archive/2007/11/20/EventBroker-implementation-in-C_2300_-full-source-code.aspx.

Categories