I'm using a Prism and the MVVM pattern
I've got a service running in a repository that is registered in my container like this:
_container.RegisterType<ITheService, TheService>();
_container.RegisterType<IRepository<Order>, Repository>(new ContainerControlledLifetimeManager());
The constructor of the repository will subscribe to the service, that will then received new element (like 5 to 10 every second).
The problem is that because of this subscription, when i close the window of my GUI, the module holding the service is not closed, and the service keeps on running, instead of being shut down by the dispose.
If i wasn't in MVVM i would just unsubsribe the service when i close the the window, but the shell window can't do that.
I see 2 solutions
* have an eventaggregator that will let my repository know when the shell close, and then unsubscribe the service (not sure it would work though)
* resolve the repository from the shell (as it's registered as a singleton), and unsubscribe when the service, but that would be very ugly....
So i tried my first idea, which was using an EventAggregator.
The shell publish an event in the EventAggregator when the Closed event is fired.
The repository holding the service has subscribed to that event, and will get notified when the shell close. So i just need to close the service when i get the notification...
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.
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.
Before I had refactored my project for DI with Ninject, I had a simple test class with a simple method:
public void TestImport()
{
var functionality = new ImportFunctionality();
functionality.Execute();
}
When I ran this "app" (merely a sandbox WPF client app for integration testing my library), I had the "main" window showing up and clicking a button on that window called this TestImport method, which executed and then I could test and debug my code, and when then main window was closed, the app died right there and VS would exit debug mode. Normal stuff.
Then I refactored the whole thing and implemented dependency injection with Ninject, factories and interfaces all over the code; the TestImport method now looks like this:
public void TestImport()
{
using (var kernel = new StandardKernel())
{
kernel.Load<SecurityNinjectModule>();
kernel.Load<HelpersNinjectModule>();
kernel.Load<ImportFunctionalityNinjectModule>();
var functionality = kernel.Get<IImportFunctionality>();
functionality.Execute();
}
}
Now when I run the WPF sandbox/test app, everything works and that's great, except when the "main" window gets closed, the application does not exit anymore and Visual Studio remains in debug mode. I added the call to Dispose() in the hope to fix it, but no luck; wrapping it in a using block doesn't fix it either.
If I run the sandbox without clicking the button to run the TestImport method, and then close the main window, the app shuts down properly.
This leads me to the Ninject kernel object. Could it be holding on to its resources somehow despite the Dispose() call? Then how do I properly shut down an application that's running Ninject 3.0?
EDIT
If I bring up the debug/windows/threads window, I see all instantiated threads either sleeping or "in a sleep, wait, or join", if not "not available"; a thread by the name of .NET System Events is sleeping, waiting or joining; the main thread is "managed to native transition" as well as a thread called vshost.RunParkingWindow - and this is where I got to Why won't my WPF application close properly after it displays a WinForms dialog?. The answer seems to work given it is accepted, but as #BahriGungor says "Using System.Environment.Exit is a lot like using dynamite to make a door because you didn't want to follow the exit signs". And it doesn't say why this is happening.
The interesting thing is, it doesn't happen consistently: sometimes I can break and step through code and when I "F5" to resume, and then close the main window, it does shut down properly. What's going on?
EDIT 2
The functionality brings up a FileDialog, and if that dialog doesn't return an Excel workbook's filename, the import window doesn't show up. I've narrowed it down to this:
If the import view is shown, no matter how it is closed after closing the main app window VS will properly exit debug mode.
If the import view is not shown (i.e. the FileDialog doesn't return anything editable) then VS will not exit debug mode after closing the main app window.
Your DI should have a composition root where 99% of your DI code lives. Factories should be the 1% case of dependency injection. For WPF that is the onStartup method.
Also I don't see anywhere in your code where you specify a lifetime management part of DI. If you aren't specifying a lifetime management aka Bind<Samurai>().ToSelf().InSingletonScope(); then you may be getting no lifetime management and no disposal. Here's the information on scopes for ninject.
You say you added a call to dispose somewhere along the way, but if you have event listeners set up without weak references there can be a memory leak leading to a lack of disposal.
Finally did you follow the other answer on your linked System.Environment.Exit question?
Check the Application.Current.Windows collection in the debugger to find the offending window. https://stackoverflow.com/a/7349650/57883
Have you tried using other win forms dialogs or just the one to see if it is reproducable?
I have a main application that loads up some plugins. These plugins are loaded and run in separate app domains using a class that inherits from "MarshalByRefObject"; This all works fine.
What I need now is a way to handle when the plugin wants the main app to do something and a way to dynamically handle this in the main application. If the best way is to poll the plugin for a list of commands, then I can do that, although it seems a bit of a kludge.
What are the best ways to send a request from the plugin across the app domain to the main app?
UPDATE
As an update to the question, I am looking to sent data across the app domain that makes the main app do something, like a "File->New" operation or "GetSomeData()" call. In doing this I need to make the Plugin wait for the main app to complete whatever it is doing, but also be able to decide, main app side, whether or not to execute the requested function/event.
I was doing this by passing the plugin an interface. This interface was implemented by a class in the main app that defined some events. The main app could then subscribe to these events and the plugin could make the main app functions fire. The problem is that the interface only referenced the class as it was when I passed the interface. I.e if I created the class with no events subscribed, then passed the interface like this:
CallbackClass myCallbackClass = new CallbackClass();
pluginInterface.HeresMyCallbackClass((ICallbackClass)myCallbackClass);
the plugin would receive the interface, but any changes to the original class did not propagate. So adding:
myCallbackClass.MyMainAppEvent += new MainEventHandler(MyMainAppFunction);
would not change the plugin's version of the event. The plugin could do this:
//code within plugin
ICallbackClass callToMainApp;
public HeresMyCallbackClass(ICallbackClass cbClass)
{
callToMainApp = cbClass;
}
public CallAMainAppFunction()
{
callToMainApp.CallTheSubscribedFunction(); //This is where it all goes wrong
}
...but the event that it tries to call is null. Now, this is not a problem if I make the main app subscribe to the event first, then pass the interface:
CallbackClass myCallbackClass = new CallbackClass();
myCallbackClass.MyMainAppEvent += new MainEventHandler(MyMainAppFunction); //Subscribe first
pluginInterface.HeresMyCallbackClass((ICallbackClass)myCallbackClass);
The plugin could then call CallTheSubscribedFunction() and the event would fire in the main app. I need to be able to subscribe to events like this on demand because some things/events/data in the main app are available at different times.
So, a lot of info I was trying to avoid having to write out, but I guess my question was too general in relation to my issue.
If anyone has suggestions please let me know. Again, my goal is to allow the plugin to trigger an event in the main app, wait for the main app to finish, then continue with it's execution, where the main app may or may not be subscribed to the events.
Update 2
I realize the above info is specialized to my application, but I'm looking for general suggestions as well. So, if using threads is an option, let me know how a general case might work. If another case would work better and I need to do some redesigning to implement it let me know that as well. Just looking for suggestions here. Thanks.
Mike from the looks of it, you're sort of already what what I think is required and that you should use the Observer Pattern between the class in your primary app domain and the secondary app domain.
You probably just need to iron out the some rough edges in the code you've got, in word words follow/implement the observer pattern.
The way it would work is that the class in the primary domain subscribes to "events" that the class that's been loaded in the secondary app domain raises. I'm guessing that you'll need to do this at the time the secondary app domain classes is instantiated. If you're unloading the app domain, then also make sure of "subscriptions" are "disconnected".
Does that make sense?
Make sure that your CallbackClass inherits from MarshalByRefObject. Otherwise, a copy of the callback class will be created on the other side of the appdomain boundary, making cross-appdomain communication impossible.