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/
Related
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.
I'm writing a class library and I'm wondering how I can pass messages to the consumer application for logging purposes. For Exceptions I plan to create custom Exceptions and throw them. But what's about information logging? Like: "Connecting successful".
I had the idea to implement some sort of event aggregator in my library and allow the consumer app to subscribe to certain events. Then the consumer app can decide if the want to log information or not.
Is this good practice? I just think Logging shouldn't be part of the library's responsibility.
Or are there any other ways to pass logging information to the user?
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 have a simple application that consists of a console application and a class library. The class library does all of the heavy lifting throughout its few-dozen classes. Some of those classes are internal to the class library, and even if public, I'd rather not have the console application completely aware of them.
So I could have something like:
My Program.cs class that is running.
My DoSomething.cs class that is being called by Program.cs.
My DoSomethingInParticular.cs class that is being called by DoSomething.cs
And so on, and so on.
Is there a generally understood way of letting Program.cs be aware of lower changes?
Functionally I'd like to have my console application write out lower level events to the console window, which is where I'm trying to go with this.
A module only knows as much as it knows.
I see 2.1 main paths for you.
1) Make public events in DoSomething that Program can listen to.
Make public events in DoSomethingInParticular that DoSomething can listen to.
When DoSomething receives an event it decides if it is proper for bubbling and transforms it to one event of its own and raises it for Program to receive.
1.1) Put the data carrying structures/classes in the events in another, common, lib. Then when an event is received DoSomething doesn't have to transform it but only decide whether to bubble it or not.
2) Make an event handling lib of its own to handle who receives what.
Without knowing more I would go with 1.1.
HTH
Im struggling with a problem and need some options for possible solutions.
I have three layers - ClientApp, ServiceLayer and Domain Layer
The service layer and the domain layer implements a Publisher and Subscriber events pattern so that different areas of the domain can be notified when things happen.
The clientApp calls the domian to create a new order. On creation of the order the publisher raises an event to notify another are of the domain to do something. I am hooking into this event in the Service layer via a subscriber and the correct event is recieved.
I want the event to be bubbled up to the clientApp, but am struggling to get this to work. I think its because the events is trigger Asynchronously and are therefore not in the same thread. I have implemented a publish and subscriber between the clientApp and service layer, but again this failed.
ClientApp(create a new order)>ServiceLayer(recieves)>Domain(created order raises event)
ServiceLayer(recieves event)> ?????
Any help or guidance appreciated.