Subscribe only once to event in multithreaded environment - c#

I'm currently implementing a SignalR application to send a message to several clients when an external library I've written fire an event.
I want to attach a unique handler to my event for every instance of my hub, so I could send the messages only once when it is fired; but as SignalR instanciate many hubs on every request, I end up with more than one event handler attached every time. So my question is: what can I do to attach only once on my event ?
Here is my code:
public class MyHub : Hub
{
private static ExternalClass staticObject = new ExternalClass();
public MyHub()
{
staticObject.MyEvent += staticObject_MyEvent;
}
private void staticObject_MyEvent(object sender, EventArgs e)
{
//Some irrelevant code which send messages to clients
}
}
I know my question is pretty the same than this one and a lot of others, but I never found a satisfying anwser for multi-threaded or multi-instance environment - which is definitly my case.

Here is the code replacing my old event declaration in my library :
private bool isEventAlreadyRegistered = false;
private static readonly object verrou = new object();
private System.EventHandler myEvent = delegate { };
public event System.EventHandler MyEvent
{
add
{
if(!isEventAlreadyRegistered)
{
lock(verrou)
{
//Double check as multiple add can be made simultaneously
if(!isEventAlreadyRegistered)
{
isEventAlreadyRegistered = true;
myEvent += value;
}
}
}
}
remove
{
myEvent -= value;
}
}
It works magnificently. My only doubt was about the performances with the lock; but as it is used only on the first call, it's negligible.
Of course, this solution only works when you have access to the source code of your event.

Hubs live in transient life. Meaning it will be created for each type of transaction (connected, on client message, dissconnected etc).
Never, ever have anything else then SignalR logic in the hub. Move your code somewhere else and invoke the client method when you want to upate. Or use a library that already have abstracted that for your. For example this library (I'm the author)
https://github.com/AndersMalmgren/SignalR.EventAggregatorProxy/wiki
Live demo:
http://malmgrens.org/signalR/

Related

inheritance and event handlers c#

Ok guys I'm totally new to stackoverflow, let me know if I stuff something up.
I am making a class library for sockets and then using the class library to make a server. The issue I've run into is this:
In the class library I have a class called sockets that has event handlers (you know like connection made, closed so on) and in the server I'm making, I have a class named player which inherits from sockets.
The problem pretty much comes down to this.
I use the OnConnectionMade event handler to create my player, but because I cant do instanceOfInheritedClass = intanceOfBaseClass, even when I make use of use of the event handlers, the event handlers wont trigger because instanceOfInheritedClass isn't pointing to intanceOfBaseClass event, if I pass through the parameters.
void hostManager_OnConnectionMade(object source, ConnectionArgs e)
{
Player socket = new Player(e.GetSocket());
socket.OnDataRecivedPostConvert += Socket_OnDataRecivedPostConvertLogin;
}
public Player(DDSocket socket)
{
this.Host = socket.Host;
this.Socket = socket.Socket;
//this.OnConnectionClosed += socket.OnConnectionClosed;
//this.OnDataRecivedPostConvert += socket.OnDataRecivedPostConvert;
//this.OnDataRecivedPostConvertHost += socket.OnDataRecivedPostConvertHost;
}
One of the solutions I came up with was that instead of inheriting, I can just make it a intanceOfBaseClass parameter in the player class. But that will prevent me from making proper use of object source from my event handlers which will mean I'll need to use linq or something to find the player from the socket or something like that.
The other thing I thought about doing was somehow passing the event handlers over, which you can see I tried, but don't know how to do.
Now after hours of looking it up I'm stuck. Any help is greatly appreciated
and any answer that solves this issue is fine. I'm not picky with how its solved.
Despite that your Player class is inherited from DDSocket, but in this scenario, it acts as the wrapper class of DBSocket, so there is one hack to achieve that, I think you have to do some further steps:
class DDSocket
{
public event Action OnConnectionClosed;
public void Raise()
{
if (OnConnectionClosed != null)
{
OnConnectionClosed();
}
}
}
class Player :DDSocket
{
// make new event look as the same base class
public new event Action OnConnectionClosed;
public Player(DDSocket socket)
{
socket.OnConnectionClosed += Socket_OnConnectionClosed;
}
private void Socket_OnConnectionClosed()
{
if (OnConnectionClosed != null)
{
OnConnectionClosed();
}
}
}
// test those 2 classes
static void Main()
{
DDSocket d = new DDSocket();
Player pl = new Player(d);
pl.OnConnectionClosed += () => MessageBox.Show("test");
d.Raise();
}

Getting a class to 'inform' another class that it needs to change (Events?)

Okay, I've been searching on the site and Google and can't quite get my head around where things need to be in terms of delegates and eventhandlers and the like so hopefully someone here can help/explain what I need to do.
So, I am writing a simple database application (using SQLite). There is a mainform that is the MDI parent (that's basically a big window with menus at the top). The menus launch other windows that allow view, edit and insert into various tables of the database.
One of those windows is a LOG window which shows my log table.
At the moment, if a user changes something in the window showing the data in TABLE. The operation also writes into the log table. If the Log window is open, however, the log view doesn't update.
So, I've figured out I probably need to 'fire' an event from my TABLE UPDATE code that my LOG window 'subscribes' to (so it can update the DataGridView).
What I can't figure out is where the different 'bits' of the event go.
Should the MdiParent have the public delegate void EventHandler();? If not where?
which class gets the public static event EventHandler logGoneStale;?
The only bit I'm reasonably sure about is that the Window that displays the log (which has a method called public void UpdateLogDataGridView() - which calls the database object/methods to (re-)populate the datagridview) needs to have:
something like logGoneStale += new EventHandler(UpdateLogDataGridView); in it. Is that at least right?
Totally befuddled - it seems none of the event examples/tutorials on MSDN are trying to do what I want to achieve.
You need to define an event in the class that is sending the event, and append an event handler in the class that should receive the event. To make things slightly easier, starting with C# 3.5 you can forget about the delegate keyword altogether and use a lamba expression as event handler. Also note that it in most cases it makes no sense to make an event static, since usually events are fired by an instance, not by a class.
Example:
class SendsEvent
{
public event EventHandler MyEvent;
public void FireEvent()
{
if(MyEvent != null) // MyEvent is null if no handlers have been attached
{
MyEvent(this, new EventArgs()); // event fired here
}
}
}
class ReceivesEvent
{
private SendsEvent eventSource;
public ReceivesEvent(SendsEvent eventSource)
{
this.eventSource = eventSource;
// Attach event handler - can be a lambda expression
// or method with signature
// "void HandleEvent(object sender, EventArgs e)"
this.eventSource.MyEvent += (sender, args) =>
{
// do something when event was fired
Console.Out.WriteLine("Hello. Event was fired.");
};
}
}
class Program
{
public static void Main()
{
var eventSource = new SendsEvent();
var eventReceiver = new ReceivesEvent(eventSource);
eventSource.FireEvent();
}
}
I hope this helps you.
Working with events requires you to have both an event publisher and an event subscriber.
#chris' answer is correct.
Besides, you need to raise the event on the closest point where the action for which you want to be notified takes place.
For example, implementing the INotifyPropertyChanged interface.
public class Customer : INotifyPropertyChanged {
public string Name { get; set; }
public string Address {
get { return address; }
set {
address = value;
if (thereArePropertyChangedEventSubcribers())
raisePropertyChangedEventFor("Address");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void raisePropertyChangedEventFor(string propertyName) {
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private bool thereArePropertyChangedEventSubcribers() {
return PropertyChanged != null;
}
private string address;
}
So here, the Customer class allows for the publishment of its change of address. So, whenever anyone is interested to be notified when the address has changed, it subscribes to the event like so:
Customer.PropertyChanged += new PropertyChangedEventHandler(customerPropertyChanged);
Or else like so:
Customer.PropertyChanged += customerPropertyChanged;
You might even have noticed that the closest point where the address has changed in directly after it has actually changed. The only requirement is that the method used as the event handler has the same signature as the event itself. If you take a look at the PropertyChangedEventHandler Delegate, one may notice that it signature awaits an object as the first parameter, that is, the object that fired the event, and a PropertyChangedEventArgs instance to notify about the property that has changed.
To come back to your example, you wish to be noticed whenever a log has been inserted into the underlying database so that a refresh of your Log window may occur. There are two questions that need to be answered whenever you want to use events.
What shall my publisher be?
What shall my subscriber be?
What shall my publisher be?
Should the MdiParent have the public delegate void EventHandler();?
Short answer: No!
If not where?
The event declaration best fits the publisher. Should you have a class responsible for logging, then this is where the public delegate void EventHandler(); should reside, as it is it that is responsible to raise the event whenever there are subscribers.
Whenever there is a successful Log inserted, it shall notify whatever subscriber interested to know about the new Log Entry.
public class Log {
public void UpdateLog(string description) {
// insert the new Log line into your database.
if (thereIsAtLeastOneNewLogEntryAddedSubscriber())
raiseTheNewLogEntryAddedEvent();
}
public event EventHandler NewLogEntryAdded;
private raiseTheNewLogEntryAddedEvent() {
NewLogEntryAdded(this, EventArgs.Empty);
}
private bool thereIsAtLeastOneNewLogEntryAddedSubscriber() {
return NewLogEntryAdded != null;
}
}
What shall my subscriber be?
This question can be answered through another question:
What do you need to do when the event fires?
In your case, you wish to update a Log window whenever it is opened.
The only bit I'm reasonably sure about is that the Window that displays the log (which has a method called public void UpdateLogDataGridView() - which calls the database object/methods to (re-)populate the datagridview) needs to have:
something like logGoneStale += new EventHandler(UpdateLogDataGridView); in it. Is that at least right?
Yes, you're right! =D
You actually subscribe to the event per this line. So, it tells the application that the window that displays the log is interested to know about log changes in your database.
public class WindowThatDisplaysTheLog : Form {
public WindowThatDisplaysTheLog() {
InitializeComponent();
log = new Log();
log.NewLogEntryAdded += UpdateLogDataGridView;
}
private void UpdateLogDataGridView(object sender, EventArgs e) {
// Reload your Log entries from the underlying database.
// You now shall see the LogDataGridView updating itself
// whenever a new log entry is inserted.
}
private Log log;
}

Why does my custom event throw an exception?

I'm writing a program that logs user idle time, however when I attempt to run the program it throws a Stack Overflow Exception.
These are my custom events
public void OnInactive(EventArgs e)
{
this.OnInactive(new EventArgs());
do
{
var idle2 = GetIdleTime();
GetIdleTime();
System.Diagnostics.Debug.WriteLine(idle2);
}
while (timer.Interval > 5000);
}
public void OnActive(EventArgs e)
{
this.OnActive(new EventArgs());
if (timer.Interval < 5000)
{
var idle3 = GetIdleTime();
System.Diagnostics.Debug.WriteLine(idle3);
}
}
I've breakpointed the code to try and locate the source of the issue, which appears to lie within this.OnInactive(new EventArgs());, However I'm pretty stumped on how to resolve this issue as I'm a beginner to Custom Events and haven't been coding in C# for long.
Any and all help with this issue would be greatly appreciated!
Thanks in Advance =]
Your handler method is calling itself immediately on entry:
this.OnInactive(new EventArgs());
this leads to a sequence of calls:
OnInactive -> OnInactive -> OnInactive -> ... ->
which will continue until you run out of stack space and the StackOverflowException is thrown by the runtime.
It's not clear what you're trying to achieve with the recursive call, but you should be able to just remove it.
You have the same issue in your OnActive handler.
EDIT: In response to the comments, it seems you're trying to raise the event itself at the beginning of your method. Assuming your event declaration looks like:
public event EventHandler InActive;
then you can raise it with:
EventHandler inactiveEvent = this.InActive;
if(inactiveEvent != null)
{
inactiveEvent(this, e);
}
and similarly for your Active event.
I gues you are trying to call the base method, but in fact you are now calling OnInactive when hitting OnInactive. This behaviour is recursive and will finaly stop due StackOverflow exception.
You can call the base function with base.<function name>.
For example:
class SpecialDerived : Base
{
public override void Say()
{
Console.WriteLine("Called from Special Derived.");
base.Say();
}
}
More info: http://msdn.microsoft.com/en-us/library/hfw7t1ce(v=vs.71).aspx
I think what you need is a bit more understanding about events. Let me explain the same through a sample code.
Class A{
public event OnInactive;
public event OnActive;
}
when any changes occur in classA you want to update things in ClassB. So you will implement events of class A in ClassB.
this link will describe you the same in detail.
My understanding says that there is no use of events when you are triggering it from the same class and listening in the same class.
these aren't event handlers, these are the methods that are going to
be called in order to raise the active and inactive events – Reece
Cottam
You need to actually call the event.
public class ReecesWatcher
{
public event EventHandler ActiveEvent;
public event EventHandler InactiveEvent;
protected virtual void OnInactive(EventArgs e)
{
// Fire the event using the () syntax. Fire it through
// a test variable so that we can reliabilty test for null,
// if there are no subscribers.
EventHandler inactiveEventTest = InactiveEvent;
if (inactiveEventTest != null)
{
inactiveEventTest(this, new EventArgs());
}
do
{
var idle2 = GetIdleTime();
GetIdleTime();
System.Diagnostics.Debug.WriteLine(idle2);
}
while (timer.Interval > 5000);
}
protected virtual void OnActive(EventArgs e)
{
// Fire the event using the () syntax. Fire it through
// a test variable so that we can reliabilty test for null,
// if there are no subscribers.
EventHandler activeEventTest = ActiveEvent;
if (activeEventTest != null)
{
activeEventTest(this, new EventArgs());
}
if (timer.Interval < 5000)
{
var idle3 = GetIdleTime();
System.Diagnostics.Debug.WriteLine(idle3);
}
}
// ... the rest of your class, where you call OnActive and OnInactive to
// cause the events to be fired.
}
I recommend not making your OnActive and OnInactive methods public, otherwise you're exposing too much of the implementation to the rest of your program. If you expect the class to be inherited from, then make them protected, otherwise I usually make them entirely private, since they're basically wrapper functions called by the rest of the class.

Are there pitfalls to using static class/event as an application message bus

I have a static generic class that helps me move events around with very little overhead:
public static class MessageBus<T> where T : EventArgs
{
public static event EventHandler<T> MessageReceived;
public static void SendMessage(object sender, T message)
{
if (MessageReceived != null)
MessageReceived(sender, message);
}
}
To create a system-wide message bus, I simply need to define an EventArgs class to pass around any arbitrary bits of information:
class MyEventArgs : EventArgs
{
public string Message { get; set; }
}
Anywhere I'm interested in this event, I just wire up a handler:
MessageBus<MyEventArgs>.MessageReceived += (s,e) => DoSomething();
Likewise, triggering the event is just as easy:
MessageBus<MyEventArgs>.SendMessage(this, new MyEventArgs() {Message="hi mom"});
Using MessageBus and a custom EventArgs class lets me have an application wide message sink for a specific type of message. This comes in handy when you have several forms that, for example, display customer information and maybe a couple forms that update that information. None of the forms know about each other and none of them need to be wired to a static "super class".
I have a couple questions:
fxCop complains about using static methods with generics, but this is exactly what I'm after here. I want there to be exactly one MessageBus for each type of message handled. Using a static with a generic saves me from writing all the code that would maintain the list of MessageBus objects.
Are the listening objects being kept "alive" via the MessageReceived event?
For instance, perhaps I have this code in a Form.Load event:
MessageBus<CustomerChangedEventArgs>.MessageReceived += (s,e) => DoReload();
When the Form is Closed, is the Form being retained in memory because MessageReceived has a reference to its DoReload method? Should I be removing the reference when the form closes:
MessageBus<CustomerChangedEventArgs>.MessageReceived -= (s,e) => DoReload();
Well, yes, you should, but if you use the lambda syntax as you've done in your example I think it won't work (by which I mean, the handler will not be de-registered successfully).
Someone correct me if I'm wrong, but I believe this is true because using the lambda syntax effectively creates a new EventHandler<CustomerChangedEventArgs> object, with its own place in memory. When you try to remove this handler, using the lambda syntax again, this creates yet another new EventHandler<CustomerChangedEventArgs> object, which is not equal to the first one you created; and so the first one never gets de-registered.
Sadly, I think you'll need to actually define a method like this:
DoReload(object sender, CustomerChangedEventArgs e) {
DoReload(); // your original overload, which doesn't actually care
// about the sender and e parameters
}
This way you can do:
MessageBus<CustomerChangedEventArgs>.MessageReceived += DoReload;
And later:
MessageBus<CustomerChangedEventArgs>.MessageReceived -= DoReload;
Yes, there are problems. Your event handlers will cause the form object to stay referenced, you have to explicitly unregister the event handlers. The lambdas make this impossible, you'll have to write an explicit handler.
This pattern has a name, "Event Broker service". It is part of the Composite UI Application Block, published by Microsoft's Pattern and Practices team. Beg, borrow and steal (if not use) what you can from this.
You could use weak references to store the event handlers. That way, unhooked handlers won't prevent garbage collection of the objects.
public static class MessageBus<T> where T : EventArgs
{
private static List<WeakReference> _handlers = new List<WeakReference>();
public static event EventHandler<T> MessageReceived
{
add
{
_handlers.Add(new WeakReference(value));
}
remove
{
// also remove "dead" (garbage collected) handlers
_handlers.RemoveAll(wh => !wh.IsAlive || wh.Target.Equals(value));
}
}
public static void SendMessage(object sender, T message)
{
foreach(var weakHandler in _handlers)
{
if (weakHandler.IsAlive)
{
var handler = weakHandler.Target as EventHandler<T>;
handler(sender, message);
}
}
}
}

C# pattern to prevent an event handler hooked twice [duplicate]

This question already has answers here:
How to ensure an event is only subscribed to once
(8 answers)
Closed 8 years ago.
Duplicate of: How to ensure an event is only subscribed to once
and Has an event handler already been added?
I have a singleton that provides some service and my classes hook into some events on it, sometimes a class is hooking twice to the event and then gets called twice.
I'm looking for a classical way to prevent this from happening. somehow I need to check if I've already hooked to this event...
How about just removing the event first with -= , if it is not found an exception is not thrown
/// -= Removes the event if it has been already added, this prevents multiple firing of the event
((System.Windows.Forms.WebBrowser)sender).Document.Click -= new System.Windows.Forms.HtmlElementEventHandler(testii);
((System.Windows.Forms.WebBrowser)sender).Document.Click += new System.Windows.Forms.HtmlElementEventHandler(testii);
Explicitly implement the event and check the invocation list. You'll also need to check for null:
using System.Linq; // Required for the .Contains call below:
...
private EventHandler foo;
public event EventHandler Foo
{
add
{
if (foo == null || !foo.GetInvocationList().Contains(value))
{
foo += value;
}
}
remove
{
foo -= value;
}
}
Using the code above, if a caller subscribes to the event multiple times, it will simply be ignored.
I've tested each solution and the best one (considering performance) is:
private EventHandler _foo;
public event EventHandler Foo {
add {
_foo -= value;
_foo += value;
}
remove {
_foo -= value;
}
}
No Linq using required. No need to check for null before cancelling a subscription (see MS EventHandler for details). No need to remember to do the unsubscription everywhere.
You really should handle this at the sink level and not the source level. That is, don't prescribe event handler logic at the event source - leave that to the handlers (the sinks) themselves.
As the developer of a service, who are you to say that sinks can only register once? What if they want to register twice for some reason? And if you are trying to correct bugs in the sinks by modifying the source, it's again a good reason for correcting these issues at the sink-level.
I'm sure you have your reasons; an event source for which duplicate sinks are illegal is not unfathomable. But perhaps you should consider an alternate architecture that leaves the semantics of an event intact.
You need to implement the add and remove accessors on the event, and then check the target list of the delegate, or store the targets in a list.
In the add method, you can use the Delegate.GetInvocationList method to obtain a list of the targets already added to the delegate.
Since delegates are defined to compare equal if they're linked to the same method on the same target object, you could probably run through that list and compare, and if you find none that compares equal, you add the new one.
Here's sample code, compile as console application:
using System;
using System.Linq;
namespace DemoApp
{
public class TestClass
{
private EventHandler _Test;
public event EventHandler Test
{
add
{
if (_Test == null || !_Test.GetInvocationList().Contains(value))
_Test += value;
}
remove
{
_Test -= value;
}
}
public void OnTest()
{
if (_Test != null)
_Test(this, EventArgs.Empty);
}
}
class Program
{
static void Main()
{
TestClass tc = new TestClass();
tc.Test += tc_Test;
tc.Test += tc_Test;
tc.OnTest();
Console.In.ReadLine();
}
static void tc_Test(object sender, EventArgs e)
{
Console.Out.WriteLine("tc_Test called");
}
}
}
Output:
tc_Test called
(ie. only once)
Microsoft's Reactive Extensions (Rx) framework can also be used to do "subscribe only once".
Given a mouse event foo.Clicked, here's how to subscribe and receive only a single invocation:
Observable.FromEvent<MouseEventArgs>(foo, nameof(foo.Clicked))
.Take(1)
.Subscribe(MyHandler);
...
private void MyHandler(IEvent<MouseEventArgs> eventInfo)
{
// This will be called just once!
var sender = eventInfo.Sender;
var args = eventInfo.EventArgs;
}
In addition to providing "subscribe once" functionality, the RX approach offers the ability to compose events together or filter events. It's quite nifty.
Create an Action instead of an event. Your class may look like:
public class MyClass
{
// sender arguments <----- Use this action instead of an event
public Action<object, EventArgs> OnSomeEventOccured;
public void SomeMethod()
{
if(OnSomeEventOccured!=null)
OnSomeEventOccured(this, null);
}
}
have your singleton object check it's list of who it notifies and only call once if duplicated. Alternatively if possible reject event attachment request.
In silverlight you need to say e.Handled = true; in the event code.
void image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true; //this fixes the double event fire problem.
string name = (e.OriginalSource as Image).Tag.ToString();
DoSomething(name);
}
Please tick me if this helps.

Categories