I have a class ChatManager, which has a ChatServer and a ChatClient(WCF) class inside of them.
I want my controller which instantiates the ChatManager to be able to subscribe to the UserConnected, UserDisconnected and MessageReceived events that are on the ChatClient.
What is the most elegant and logical way to do this? Is it silly for me to define the events in the ChatClient like I have, and then redefine the events in the ChatManager solely to pass the events up to the Controller without it having to deal with or know about the ChatClient? The ChatManager would subscribe to the events of the ChatClient, and then fire off its own events which the ChatController would be listening to.
I know WPF has the concept of bubbling up of events, but I don't know if that is for this type of scenario, since nothing is part of a user interface.
I'd start by questioning whether both ChatManager and ChatController can both justify their own existence. Generally whenever you find yourself creating a "Manager" class, it really isn't necessary, especially if part of what it is doing consists of merely relaying messages.
Controller classes can struggle against SRP since their "responsibility" is quite broad. In cases where you want to delegate responsibility for certain behaviour then leave the responsibility for the ChatClient with the controller, and initialize a subordinate controller with the ChatClient (through a contract interface) so that it can interact with the client as needed. Just make sure that when you start registering for events that you de-register those events before discarding subordinates or the client, otherwise you'll be looking at managed memory leaks.
It is not bubbling events you are looking for. You can easily subscribe to these events by calling an instance of the child class in your parent (ChatManager) and subscribing to the Events like so :
chatManager.UserConnected += (param1, param2) => {
//your code here
};
Unless you have a need for an event to only conditionally reach the things that would subscribe to it (or to be processed sequentially by multiple handlers), "bubbling" isn't really something you should need. Using an event aggregator would probably be the best way to go.
Related
I have an application architecture like this:
When UDP servers inside the UDP service receive different types of messages it publishes Prism events to managers. Those UDP servers have their own threads so when the events published they sometimes cause multithreading issues inside the managers.
To prevent that I want to create an event handler and queue inside the subscribing managers. When subscriber receives an event, its only job is to try to Enqueue the event payload to ConcurrentQueue inside the managers and return (I think this is called store and forward). Then I will have a worker that will read this queue and send the event parameters to related methods.
Every manager will have its own event queue, event handler and worker.
My "event queue":
But when I try to implement this I couldn't get past some issues:
1- When you subscribe to an event, public class TestEvent1 : PubSubEvent<Class1>, like this, GetEvent<TestEvent1>().Subscribe(OnTestEvent1), callback method(OnTestEvent1) must have same type of parameters of the event, in this case Class1, OnTestEvent1(Class1 class1). I need a type to store every received data and event type.
How can I use the same callback method for all my events inside the subscriber manager that have different types?
Example:
// Events
public class TestEvent1 : PubSubEvent<Class1>
{
}
public class TestEvent2 : PubSubEvent<Class2>
{
}
public class TestEvent3 : PubSubEvent<List<Class3>>
{
}
// Subscriptions
_eventAggregator.GetEvent<TestEvent1>().Subscribe(EventHandler, true);
_eventAggregator.GetEvent<TestEvent2>().Subscribe(EventHandler, true);
_eventAggregator.GetEvent<TestEvent3>().Subscribe(EventHandler, true);
// Callback
private void EventHandler("What's inside here?")
{
_eventQueue.Enqueue(payload);
return;
}
2- Since I want to store all of the received events for a manager inside a single queue, the same type problem applies to this too, what should be my T when creating ConcurrentQueue?
3- Is this viable? Are there any other approaches, patterns(I found mediator but I didn't research it deeply enough) that I can use like this?
What I tried:
1- I tried to use object or dynamic type but then I will lose compile-time security.
2- I thought of creating an interface and implementing it on all of my custom classes so I can use it for general type but what to do about events with built-in types?
PS: I had another question about this but I felt like I didn't explain myself clearly so I tried my best again.
How can I use the same callback method for all my events inside the subscriber manager that have different types?
You don't. The event aggregator isn't designed that way. The type of the event is used to distinguish subscriptions and to distribute the event to the subscribers that actually want it, so you can only ever subscribe to an individual event type.
As said before, you shouldn't be using the event aggregator here at all, because there are much better tools for what you're trying to achieve.
Since I want to store all of the received events for a manager inside a single queue
If, for example, the manager was an dataflow ActionBlock it would come with a fully functional queue preinstalled.
In a WPF application I'm working on I came across following code snippet;
public int SomeInteger
{
get { return _someInteger; }
set
{
_someInteger= value;
OnPropertyChanged("SomeInteger");
SomeIntegerChanged();
}
}
As you can see, inside the property setter a method is called. Is this approach correct or is there any better way to do in MVVM pattern WPF?
As above code snippet is a sample, actually the property setter might load a DataTable when the property changes which might be time consuming. I tried to make the application asynchronous using async and await but above scenarios causes problems since async and await doesn't have asynchronous property concept.
I also got across a way to bind a event to INotifyPropertyChanged and by checking which property triggers the event and call the method. But looking for any other alternatives.
Is this approach correct or is there any better way to do in MVVM pattern WPF?
This is, unfortunately, the common and accepted MVVM pattern across all of C#. I say "unfortunately" because this pattern does run into problems. It is based on events - which are problematic just on their own - and it also causes an immediate update, which in many cases is not desired.
For one example, sometimes it's desirable to have two properties that are mutually dependent - when the user changes one, the other one changes in relation to it - and this can cause problems since there's no way to distinguish "user changes" from "code changes".
For another example, sometimes you can end up with a whole tree of dependent properties, and it can take some time for all the changes to propagate through and stop interfering with each other.
More modern MVVM approaches like the atomically-updated single source of truth with single-directional data flow (as popularized by Redux) avoid the above problems. There is a C# Redux implementation; I don't know how easy it is to use. In my own CalculatedProperties library, I built my own "invalidation queue" to work around this, which defers all PropertyChanged updates until after the entire system's new steady-state is calculated.
I tried to make the application asynchronous using async and await but above scenarios causes problems since async and await doesn't have asynchronous property concept.
True. In particular, you can't "asynchronously get" a property. And this makes sense in the MVVM world; when WPF is updating the screen, and it asks your VM for a data value, then your VM can't say "hold on, I'll get it in a minute". WPF needs to know that value now so it can update the screen now.
Hooking up an asynchronous event handler is one way of kicking off asynchronous work when the value changes; that approach is fine. Usually, the presence of SomeIntegerChanged implies that there is a "changed" event specifically for that property, so hooking into PropertyChanged with string comparisons is probably the harder way to do it.
For more on asynchronous properties with MVVM, see my article on the subject.
In this case, calling the methods in the Setter is okay. Using INotifyPropertyChanged for property change notifications in WPF is the correct way, and adding the call to the Setter is the default way to implement it.
The call to SomeIntegerChanged(); depends a bit on what the method does (and if it's even required given you already implemented INotifyPropertyChanged).
Using properties as a consumer should have as little side-effects as possible, and generally should be simple operations. There's a nice guide on MSDN about that topic.
You should also avoid using strings of property names as parameters, in your case the call to OnPropertyChanged should look like this: OnPropertyChanged(nameof(SomeInteger));
A property setter shouldn't kick off a long-running operation. It should simply set the value of a backing field and perhaps call a fast synchronous method that returns just almost immediately. Please refer to #Stephen Cleary's blog post for more information.
If you need to call an asynchronous whenever SomeInteger gets set, you could for example hook up an async event handler for the PropertyChanged event, e.g.:
this.PropertyChanged += async (s, e) =>
{
if (e.PropertyName == nameof(SomeInteger))
{
await SomeAsyncMethod();
}
};
I would caution against premature optimisation.
Don't complicate your solution any more than is necessary.
If the change is immediate then there's no problem putting what you like in a setter.
Dependent property changes are an occasional requirement but also not usually a big deal.
If you have a long process needs to start then that sounds like it should be something discrete. You should initiate that processing on a separate thread and or decouple the processing. You could just start up a fire and forget thread ( not terribly elegant ).
You can decouple processing using service calls, message queues like msmq or RabbitMQ or pub sub. There are many pub sub approaches - a simple implementation being mvvmlight's messenger or prism's eventaggregator. More sophisticated would be NServiceBus or even Windows Workflow. If events are involved then weak events are preferable.
It is obvious that firing events inside of a lock (i.e. critical section) is prone to deadlocks due to the possibility that the event handler may block on some asynchronous operation that also needs to acquire the same lock. Now, design-wise there are two possible solutions that come to my mind:
If it is needed to fire an event inside a lock, then always fire the event asynchronously. This can be performed by using ThreadPool, for example, if the firing order of the events does not matter. If the order of the events must be preserved, then a single event firing thread can be used to fire the events in order, but asynchronously.
The class/library that fires the events does not need to take any necessary precautions to prevent the deadlock and just fire the event inside the lock. In this case it is the event handler's responsibility to process the event asynchronously if it performs locking (or any other blocking operation) inside the event handler. If the event handler does not conform to this rule, then it should suffer the consequences in case a deadlock occurs.
I honestly think that the second option is better in terms of separation of concerns principle as the event-firing code should not guess what the event handler may or may not do.
However, practically, I am inclined to take the first route since the second option seems to converge to the point that every event handler must now run all event-handling code asynchronously, since most of the time it is not clear whether some series of calls performs a blocking operation or not. For complex event-handlers, tracing all possible paths (and, moreover, keeping track of it as the code evolves) is definitely not an easy task. Therefore, solving the problem in one place (where the event is fired) seems to be preferable.
I am interested in seeing if there are other alternative solutions that I may have overlooked and what possible advantages/disadvantages and pitfalls can be attributed to each possible solution.
Is there a best practice for this kind of situation?
There is a third option: Delay raising the event until the lock is released. Normally, locks are taken for a short time. It is usually possible to delay raising the event till after lock (but on the same thread).
The BCL almost never calls user code under a lock. This is an explicit design principle of theirs. For example ConcurrentDictionary.AddOrUpdate does not call the factory while under a lock. This counter-intuitive behavior causes many Stack Overflow questions because it can lead to multiple factory invocations for the same key.
I honestly think that the second option is better in terms of separation of concerns principle as the event-firing code should not guess what the event handler may or may not do.
I don't think the first option violates separation of concerns. Extract an AsyncEventNotifier class and have your event-generating object delegate to it, something like (obviously not complete):
class AsyncEventNotifier
{
private List<EventListener> _listeners;
public void AddEventListener(EventListener listener) { _listeners.add(listener); }
public void NotifyListeners(EventArgs args)
{
// spawn a new thread to call the listener methods
}
....
}
class EventGeneratingClass
{
private AsyncEventHandler _asyncEventHandler;
public void AddEventListener(EventListener listener) { _asyncEventHandler.AddEventListener(listener); }
private void FireSomeEvent()
{
var eventArgs = new EventArgs();
...
_asyncEventhandler.NotifyListeners(eventArgs);
}
}
Now your original class isn't responsible for anything it wasn't responsible for before. It knows how to add listeners to itself and it knows how to tell its listeners that an event has occurred. The new class knows the implementation details of "tell its listeners that an event has occurred". Listener order is also preserved if it's important. It probably shouldn't be, though. If listenerB can't handle an event until listenerA has already handled it then listenerB is probably more interested in an event generated by listenerA than by the object it was listening to. Either that or you should have another class whose responsibility is to know the order that an event needs to be processed in.
Modify the sender's state in events (aside from being a mutable object), is this considered bad practice?
All event examples I've found are very simple and only do something like Console.WriteLine("event!")
Simple code:
public void HandleEvent(object sender, EventArgs args)
{
ClassA a = (ClassA)sender;
a.doSomething(this.makeSomething());
}
It's not bad practice as such, you need to be careful though.
For instance would it be relevant if dosomething was called from the eventhandler, or directly.
Or because you can't rely on when the eventhandler gets triggered, you are asynchronous, so you can't assume dosomething has been executed before you call dosomethingelse.
E.g dosomething should change state to 2 only if it's 1. If it's not 1 or already 2 more logic is required.
If you start disappearing into that hole, might be better to queue a request to do a dosomething, and then have an engine which deals with the current state and the request queue.
So have a think about how dosomething to a relates to any other methods you call on a. If it's self contained, you are ok, if dependencies start proliferating, than it's bad idea as opposed to a bad practice.
I would not consider it bad practice, as far as you do not make assumptions about the order followed by the runtime to call the event handlers registered with your events. In fact, being that order not guaranteed, you should not rely on that to change the state of your objects, including the sender one.
I have custom event that has several different subscribers who will all use the data passed in my CustomEventArgs and potentially change it for their own use. What is considered the best practice in this scenario to prevent one subscriber from polluting the data that another subscriber is using? Should the publisher create clones of the data and invoke each of the subscribers' delegates separately? Should the subscriber be responsible for cloning the data if it is to be modified?
Thanks in advance.
Typically, I would recommend making the EventArgs derived class immutable. The publisher can then set a single instance up and call all delegates normally without worry.
Subscribers can always make their own class based on this data as needed.
The one exception to this would be situations where you want to have some form of Handled property within the argument, in which case, you want subscribers to be able to overwrite this value. This is one case where proper documentation is typically enough to handle this correctly.
I would rarely recommend calling subscriber delegates separately.