Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
I read that people use event dispatching libraries for domain events in their domain-driven design.
The C# language have built-in support for events using the event keyword together with the EventHandler<> class. Is it feasible to use this instead of a event dispatcher library (such as MediatR)?
I know that domain events are often dispatched when persisted, not when the method on the aggregate is called. But by adding the events to a List<Action> you can defer the raising of events.
Event declaration:
public event EventHandler<InvoiceCreatedEventArgs> InvoiceCreated;
Deferred event raising:
private ICollection<Action> _events = new List<Action>();
public void AddDomainEvent(Action action)
{
_events.Add(action);
}
protected virtual void OnInvoiceCreated(InvoiceCreatedEventArgs e)
{
AddDomainEvent(() => { InvoiceCreated?.Invoke(this, e); });
}
If the events are exposed as public members of the root aggregate then the application would have to resubscribe for every new instance of the root aggregate whenever a root aggregate was fetched from the repository.
Wouldn't that be a bit of a undesirable trait to have to resubscribe for every instance? Would the application have to unsubscribe too?
Unless the events were declared as static, but I have heard bad things about static events and memory leaks. Would this be a concern?
If C# events were used, would they belong in the root aggregate or would they belong in the repository?
If the events were declared in the repository (which could be a Entity Framework Core DbContext) then when registered with the ASP.NET Core dependency handler using the .AddDbContext method it would be registered with the "Scoped" lifetime (once per client request), so unless the events were to be declared as static then the application would have to resubscribe on every new instance of the repository which would occur at every new incoming HTTP request.
Is using C# events for domain events in a application employing domain-driven design feasible or is it just an non-viable ill-fated idea?
Without distinguishing between C# Events and Domain Events it’s difficult to follow your narrative. However, if I understand your proposal correctly, you’re envisioning a C# component that listens to the Entity Event stream, then publishes those incoming domain events via C# events to listeners in the app. If that’s what you’re proposing then you would have to work hard to make it work, and it wouldn’t work well.
If we look at Mediatr, it subscribes to an event source and creates new command processors to process incoming domain events. The key is that it creates new command processors so it is able to call a method on them. Also, there is a one-to-one correspondence between a domain event and a command processor, and nothing is required at system startup other than Mediatr itself.
With C# Events the command processor is created by something, then registers itself to receive C# events of a particular type. The command processor initiates the link, not the event source subscriber. In order to process all kinds of events, at startup you would have to create at least one of each type of command processor and let it register itself as the receiver of the C# messages which carries the Domain Event as a payload.
Then what happens when you start to scale? Mediatr scales well because it creates a command processor for each Domain Event. Your proposal would not scale because to process 2 of the same event type you would need to manually create 2 command processors, and each of those command processors would receive BOTH of the incoming Domain Events because they are both subscribed to the same C# Event.
It is possible to code around all this mess, but that’s what Jimmy Bogard has already done. Instead of rewriting all that just fire up NuGet, pull down Mediatr, and then go play with your kids with all the time you saved.
It depends on the type of application.
If the application is a web application then it have a DbContext scoped to the life time of the HTTP request, and all the aggregates have a short life time too that lasts for the duration of the HTTP request. Hence registering the C# event handlers is cumbersome, also since you would have to do it after you fetch get the DbContext or the aggregate it would have to be inside the controller, repeatedly, everywhere. So for web applications using C# for events is a poor choice, and it a much better idea to delegate it to a singleton class as is done with MediatR.
If the application maintains a persistent DbContext that survives for the lifetime of the application and a root aggregate that survives for the lifetime of the application then you can could use C# events and just register the event handlers once. Such an application could be a command-line application, a background service, or a desktop application with a UI.
Related
Say I have a console application or Windows service, and am using dependency injection with an IOC container (in my specific case, I'm using Autofac).
One of the classes that my IOC container resolves is a WorkDoer class, which has a long running DoWork(Args args) method. When DoWork(Args args) completes, a custom event is raised (WorkDone). In my case, DoWork is triggered as messages with parameters are taken off of a message queue.
I also have a Notifier class that I'd like to have subscribe to my WorkDone event.
Concretely
public class Notifier
{
public void Subscribe(WorkDoer w)
{
w.WorkDone += new WorkDoer.WorkDoneHandler(Notify);
}
private void Notify(WorkDoer w, EventArgs e)
{
//do some kind of notification decoupled from my WorkDoer
//concretely I'd like to push a SignalR message or something.
}
}
So now I have my WorkDoer which is responsible for running some long running business logic and raises an event. Then I in theory have my Notifier that can listen for that event and run some logic decoupled from my business logic, such as pushing a notification to an MVC page in that solution, or maybe publishes another message queue message, or something like that.
The projects in my solution are
App.WorkerService -- this contains my WorkDoer console app and my DependencyConfig
App.BusinessLogic -- this is a library that contains all of the business logic that WorkDoer uses
App.Notification -- this is where I'd like my Notifier(s) to live
So here's my problem:
In my WorkerService Program.cs, I have my WorkDoer registered with Autofac's Single Instance Scope. This means that it's a transient instance and can disappear. As such, I'm not sure how I can subscribe to it's WorkDone event effectively in my Program.cs's Main method, since it will eventually get disposed of. I could make it use a singleton scope to avoid this, but then I've captured all of WorkDoer's dependencies within that long running scope, which I don't want to do.
I have my Notifier in a singleton scope so that I don't lose existing subscriptions -- I'm not sure if that's bad practice or not, and I'm happy to change it.
Basically, the big picture is that I want to have my business logic in a separate project than my notification logic to avoid leaking notification code into my business logic. I'd also like to have the ability to easily add/remove/change notifier types (SignalR, log file, MQ, etc.). I'd like to use the C# event and delegate system for this (seems reasonably relevant here), but I'm not sure how to manage my dependency scopes.
I did see this question but I'd like to avoid the suggestions of OnActivated or the delegate registration because of the aforementioned captured dependency concerns.
Currently, you are using an observer design pattern for your notifications. You register the event handlers directly. That results in a tight coupling of the components.
For your requirements above, the publish/subscribe design pattern, using an event aggregator, would be better. The publisher and subscriber are only loosely coupled. Both know only the event aggregator. The event aggregator is injected into both and works as a mediator/facade/adapter.
There are many possible implementations. See:
https://www.codeproject.com/Articles/812461/Event-Aggregator-Pattern
https://www.martinfowler.com/eaaDev/EventAggregator.html
https://www.c-sharpcorner.com/UploadFile/pranayamr/publisher-or-subscriber-pattern-with-event-or-delegate-and-e/
I am using prism event aggregators to trigger and associate events (publish and subscribe). The service is only instantiated if there is a request for it. Either from a client (through a channel) or from another service (as a class object).
Issue:
If an event is not subscribed (registration and instantiation) then even if it is published nothing
happens i.e no handler will be called.
Scenario:
If I am using lets say WCF services that act as our subscribers and also publishers and the service subsriber instance has not yet been created and the events get triggered,what can be done to handle this since as at this point the subscriber instance has not been created. (Registration has been done though).
Note: I am subscribing to events in the ctor of the service.
So , in short, I am looking to make sure all subscribers are instanstiated before the publish (event trigger call).
Possible Solution: I was looking at Unity application Block to resolve this dependency but wanted to find that if this is the right direction. For this purpose I was thinking of doing something like this in global.asax.cs application start method:
IUnityContainer container = new UnityContainer();
container.RegisterType<ISubscribeEvent ,EventSubsriber>();
and then I could
EventPublisher = container.Resolve<EventPublisher>();
where the ctor of EventPublisher class is
public EventPublisher(ISubscribeEvent obj)
{
}
where ISubscribeEvent will be an interface that every subscriber will implement. So that whenever an event is raised the class implementing ISubscribeEvent interface will be instantiated.
Does this approach make sense? Are there any alternatives?
EDIT:
The events would occur at the server and the subscribers would also be services on the server i.e the service to service call will not be going through the channel but as normal class call.
Update:
I have also looked at the IInstanceProvider here as it can provide an interface ,which can be used to control the instantiation of WCF service instances using Unity.WCF.
That won't work.
Event aggregators assume long-living objects, objects that first subscribe to events and then live long enough to get notifications.
WCF service instances are short-living objects. An instance is activated once the request begins and is deleted once the request completed.
The probability that your publisher and subscriber both live in the very same moment of time is low, as you have noticed, the subscriber is not yet created.
I believe your issue stems from the fact that you are misusing event aggregator there. A wcf service can publish events but there is no point in a wcf service being a subscriber registered in an event aggregator. A wcf service already is a subscriber - it can be called by other beings that "notify" it just by calling it.
If you want your services to "notify" other services, just call these other services as you'd normally call them.
I'm writing an application for WPF in MVC pattern. The purpose of application is to display some data in the database and these data are being updated asynchronously.
I'm thinking about how to design the architecture, such that it will be thread-safe. In particular:
Each page (or its viewmodel) must be able to subscribe and unsubscribe from the service, which updates the database.
The service updating the database informs all subscribers, that new data arrived and that they should refresh their views.
Obviously, the page, which is just being closed should unsubscribe from the service and the page, which just appears, should (or may) subscribe.
I could put subscription inside a critical section, as well as broadcast about new data, but then imagine the following scenario (page ~= its viewmodel, that does not matter much here):
Service enters critical section to broadcast information about new data (in separate thread)
Page tries to enter critical section to unsubscribe (in main thread)
Service informs page about new data (in separate thread).
Page populates its fields and raises PropertyChange event (in separate thread).
PropertyChange event is marshalled to the main thread. Which waits for the critical section.
And it looks like a deadlock to me.
How can I safely design this architecture to avoid such deadlocks? Maybe pages should never unsubscribe? Or is there another way to secure threads such that they won't deadlock?
Given that the post is tagged WPF and WP-8.1 and the clarification in the comments, i would do the following:
Have the base Model class (the one with properties holding relevant data) implement INotifyPropertyChanged
Have the Model for ALL pages as ObservableCollection<BaseModel>. The model should also implement a mutex/lock property instantiated in the constructor.
Share the model across all viewmodels (e.g. share the instance of the model).
In the 'Service' performing async operation, i would only lock the section of the code that would Add or Remove items from the Model ObservableCollection using the lock object from the Model itself. This section MUST be placed in the Dispatcher.Invoke() or equivalent platform call. This ensures that it is only UI thread that is waiting to update the collection.
I would bind all the UI in the relevant pages to the model reference in the viewmodel.
This way the UI and viewmodels are careless to the specific service events thus eliminating the overhead of subscribing, and you also limit the duplication of the data if you share the model - even with 20 pages on screen, your service will perform a single update that is propagated to the UI and viewmodels by the powers of the framework (binding).
A simple solution could be: Do not do the unsubscribe operation in the UI thread. (In general do not block the UI thread.) Do it in async way, fire and forget.
Alternatively you may take a look to Rx (Reactive Extensions) what are exactly for this purpose: Implementing the observer pattern in multithreaded way.
Silently "just not unsubscribe" is probably not a good idea. Although I do not know your implementation details, if the event handlers are instance methods, then a reference to that instance implicitly will be kept by the service, and depending the reference chain maybe your page or other instances will be prevented to garbage collected.
"Or is there another way to secure threads such that they won't deadlock?" Currently in .NET framework there is no magic trick what automatically prevents deadlock. Other multithreaded environments may or may not provide an automatic deadlock resolution (note: not prevention) service what can detect a deadlock (after it happen) and automatically choose a victim. In .NET it could be an exception what occurs while your are waiting to a resource. (again this is not implemented yet)
I have a .NET library which, as part of an Object Model will emit notifications of certain occurrences.
It would seem to me that the main pros of events are approachability for beginners (and simplicity in certain consumption contexts) with the main negative being that they are not composable and hence are immediately forced into an Observable.FromEvent* if you want to do anything interesting without writing a code thicket.
The nature of the problem being solved is such that the event traffic won't be particularly frequent or voluminous (it's definitely not screaming RX), but there is definitely no requirement to support .NET versions prior to 4.0 [and hence I can use the built-in IObservable interface in System.Reactive without forcing any significant dependencies on consumers]. I'm interested in some general guidelines some specific concrete reasons to prefer IObservables over events from an API design perspective though - regardless of where my specific case might sit on the event - IObservable spectrum.
So, the question:
Is there anything concrete I'm making dramatically more difficult or problematic for API consumers if I go with the simplest thing and expose an event instead of an IObservable
Or, restated: Aside from the consumer having to do an Observable.FromEvent* to be able to compose events, is there really not a single reason to prefer an IObservable over an event when exposing a notification in an API?
Citations of projects that are using IObservable for not-screaming-RX stuff or coding guidelines would be ideal but are not critical.
NB as touched on in the comments with #Adam Houldsworth, I'm interested in concrete things wrt the API surface of a .NET 4+ library, not a survey of opinions as to which represents a better 'default architecture' for our times :)
NB this question has been touched on in IObserver and IObservable in C# for Observer vs Delegates, Events and IObservable vs Plain Events or Why Should I use IObservable?. The aspect of the question I'm asking has not been addressed in any of the responses due to SRP violations. Another slightly overlapping question is Advantages of .NET Rx over classic events?. Use of IObservable instead of events falls into that same category.
In the comments of this answer, OP refined his question as:
[Is it] indeed definitely the case that each and every event can
always be Adapted to be an IObservable?
To that question, the answer is basically yes - but with some caveats. Also note that the reverse is not true - see the section on reverse transformation and the conclusion for reasons why observables might be preferred to classic events because of the additional meaning they can convey.
For strict translation, all we need to do is map the event - which should include the sender as well as arguments - on to an OnNext invocation. The Observable.FromEventPattern helper method does a good job of this, with the overloads returning IObservable<EventPattern<T>> providing both the sender object and the EventArgs.
Caveats
Recall the Rx grammar. This can be stated in EBNF form as:
Observable Stream = { OnNext }, [ OnError | OnCompleted ] - or 0 or more OnNext events optionally followed by either an OnCompleted or an OnError.
Implicit in this is the idea that from the view of an individual subscriber events do not overlap. To be clear, this means that a subscriber will not be called concurrently. Additionally, it is quite possible that other subscribers can be called not only concurrently but also at different times. Often it is subscribers themselves that control pace of event flow (create back-pressure) by handling events slower than the pace at which they arrive. In this situation typical Rx operators queue against individual subscribers rather than holding up the whole subscriber pool. In contrast, classic .NET event sources will more typically broadcast to subscribers in lock-step, waiting for an event to be fully processed by all subscribers before proceeding. This is the long-standing assumed behaviour for classic events, but it is not actually anywhere decreed.
The C# 5.0 Language Specification (this is a word document, see section 1.6.7.4) and the .NET Framework Design Guidelines : Event Design have surprisingly little to say on the event behaviour. The spec observes that:
The notion of raising an event is precisely equivalent to invoking the
delegate represented by the event—thus, there are no special language
constructs for raising events.
The C# Programming Guide : Events section says that:
When an event has multiple subscribers, the event handlers are invoked
synchronously when an event is raised. To invoke events
asynchronously, see Calling Synchronous Methods Asynchronously.
So classic events are traditionally issued serially by invoking a delegate chain on a single thread, but there is no such restriction in the guidelines - and occasionally we see parallel invocation of delegates - but even here two instances of an event will usually be raised serially even if each one is broadcast in parallel.
There is nothing anywhere I can find in the official specifications that explicitly states that event instances themselves must be raised or received serially. To put it another way, there is nothing that says multiple instances of an event can't be raised concurrently.
This is in contrast to observables where it is explicitly stated in the Rx Design Guidelines that we should:
4.2. Assume observer instances are called in a serialized fashion
Note how this statement only addresses the viewpoint of an individual subscriber instance and says nothing about events being sent concurrently across instances (which in fact is very common in Rx).
So two takeways:
Whilst OnNext captures the idea of an event it is possible that the classic .NET event may violate the Rx Grammar by invoking events concurrently.
It is common for pure Rx Observables to have different semantics around the delivery of events under load because back-pressure is typically handled per subscriber rather than per-event.
As long as you don't raise events concurrently in your API, and you don't care about the back-pressure semantics, then translation to an observable interface via a mechanism like Rx's Observable.FromEvent is going to be just fine.
Reverse Transformation
On the reverse transformation, note that OnError and OnCompleted have no analogue in classic .NET events, so it is not possible to make the reverse mapping without some additional machinery and agreed usage.
For example, one could translate OnError and OnCompleted to additional events - but this is definitely stepping outside of classic event territory. Also, some very awkward synchronization mechanism would be required across the different handlers; in Rx, it is quite possible for one subscriber to receive an OnCompleted whilst another is still receiving OnNext events - it's much harder to pull this off in a classic .NET events transformation.
Errors
Considering behaviour in error cases: It's important to distinguish an error in the event source from one in the handlers/subscribers. OnError is there to deal with the former, in the latter case both classic events and Rx simply (and correctly) blow up. This aspect of errors does translate well in either direction.
Conclusion
.NET classic events and Observables are not isomorphic. You can translate from events to observables reasonably easily as long as you stick to normal usage patterns. It might be the case that your API requires the additional semantics of observables not so easily modelled with .NET events and therefore it makes more sense to go Observable only - but this is a specific consideration rather than a general one, and more of a design issue than a technical one.
As general guidance, I suggest a preference for classic events if possible as these are broadly understood and well supported and can be transformed - but don't hesitate to use observables if you need the extra semantics of source error or completion represented in the elegant form of OnError and OnCompleted events.
I've been reading a lot about Reactive extensions before finally dipping my toe, and after some rough starts I found them really interesting and useful.
Observables extension have this lovely optional parameter where you can pass your own time manager, effectively letting you manipulate time. In my case it helped a lot since I was doing some time related work (check this webservice every ten minutes, send one email per minute, etc) and it made testing a breeze. I would plug the TestScheduler in the component under test and simulate one day of events in a snap.
So if you have some workflows in your library where time plays a role in orchestration, I would really recommend using Observables as your output.
However if you are just raising events in direct responses to user inputs, I don't think that it's worth the added complexity for your users. As you noted they can wrap the event into their own Observable if needed.
You could have your cake and eat it too, although it would mean more work; offer a facade that turns your event library into a Observable-fueled one, by creating said Observable from your events. Or do it the other way: have an optional facade that suscribes to your observable and raise a classic event when triggered.
In my opinion there is a non-trivial technical step to take when dealing with reactive extensions and in this case it may come down to what your API consumers would be the most comfortable using
The IObservable is the IEnumerable of events, so the only question here is do you think IObservable will become the standard as the IEnumerable is now so yes its preferable, if you think its just a passing by thing that will fall in future use event instead.
The IObservable is better than event in most cases but I personally think I'll forget to use it as its not very common to be used and when the time arrives I'll have forgotten about it.
I know my answer is not of great help but only time will tell if RX will become the standard, I think it has good chances.
[EDIT] To make it more Concrete.
To the end user the only difference is that one is an interface an the other is not, making the interface more testable and expandable, because different sources can implement the same interface.
As Adam Houldsworth said one can be changed to the other easily to make no other difference.
To address your headline question:
No they should not be preferred on the basis that they exist in .NET 4 and are available to use. Preference depends on intended use, so a blanket preference is unwarranted.
That said, I would tend towards them as an alternative model to traditional C# events.
As I have commented on throughout this question, there are many ancillary benefits to approaching the API with IObservable, not least of which is external support and the range of choice available to the end consumer.
To address your inner question:
I believe there would be little difficulty between exposing events or IObserable in your API as there is a route to one from the other in both cases. This would put a layer over your API, but in actuality this is a layer you could also release.
It is my opinion that choosing one over the other isn't going to be part of the deciding reason why someone choose to use or not use your API.
To address your re-stated question:
The reason might be found in why there is an Observable.FromEvent in the first place :-) IObservable is gaining support in many places in .NET for reactive programming and forms part of many popular libraries (Rx, Ix, ReactiveUI), and also interoperates well with LINQ and IEnumerable and further into the likes of TPL and TPL DataFlow.
A non-Rx example of the observable pattern, so not specifically IObservable would be ObservableCollection for XAML apps.
Based on lack of search results no matter how I word this, I'm pretty sure I'm thinking about this wrong.
I have a program that will be creating a large number of objects and there will be a number of events that should be wired up to listen to all the other instances, especially as soon as the instance is created. Managing this through pure events doesn't make sense to me. So that's my thought for using the pub/sub pattern to make things easier to handle. Also the plan is for the pub/sub to be purely in-process, so the events would not cross any boundaries. Also the events would not be persisted anywhere outside of memory, so there's no playback of events.
The problem comes with events that typically are CancelEventArgs. Is there a way to publish an event that subscribers can mark as being Cancelled?
Here's my current thoughts at a possible solution:
Publish a ShouldCancelEventX event and wait for some amount of time for an EventXCancelled event to be published back. If none are published in the time span, publish EventX event. The biggest issue I see with this is the arbitrary time span to wait for the events.
Have the pub/sub implementation have a little more logic so that it can notify the publisher after all subscribers have received the event. This would allow the publisher of ShouldCancelEventX to know when all the subscribers have received the message. This just feels wrong as every implementation of pub/sub I've seen provides void Publish methods. So that, again, leads me to believe I'm thinking about this the wrong way.