I'm facing the following problem. I have a SignalR hub like this:
public class NewsLetterHub : Hub
{
private readonly IServicesContainer _servicesContainer;
private readonly ILifetimeScope _hubLifetimeScope;
public NewsLetterHub(ILifetimeScope lifetimeScope, IServicesContainer servicesContainer)
{
_servicesContainer = servicesContainer;
_hubLifetimeScope = lifetimeScope.BeginLifetimeScope();
_servicesContainer.NewsLetterService.ImportProgress += _sentNewsLetter_Progress;
}
I register this hub in Autofac this way:
builder.RegisterHubs(Assembly.GetExecutingAssembly());
Debugging the code I see that hub constructor is called once per request but the ImportProgress event contains the previous registered handler. This brings _sentNewsLetter_Progress method to be executed multiple times.
I tryied to register the hub this way:
builder.RegisterHubs(Assembly.GetExecutingAssembly()).InstancePerLifetimeScope();
Doing this it seems to work but I don't know if this is the right solution (it becomes singleton).
I also tryied to unregister the event:
_servicesContainer.NewsLetterService.ImportProgress -= _sentNewsLetter_Progress;
_servicesContainer.NewsLetterService.ImportProgress += _sentNewsLetter_Progress;
But it seems to do nothing.
How to prevent this behavior?
You need to change where you're de-registering the event handler to do it in a destructor or Dispose() method. If you try to do in the constructor it will try to de-register the _sentNewsLetter_Progress handler from the instance being constructed. Since that instance isn't registered yet it will do nothing. However, if you de-register in the destructor/Dispose then it will work.
Related
I have created application in .net core 3.1, In which there are one singleton interface and its implementation class, which is receiving the TCP/IP socket message. There is one event handler in the class, which will be invoked once messages received on the socket.
public Class IncomingMessageHandler : IIncomingMessageHandler
{
public event EventHandler<string> OnMessageReceived;
private void InvokeMessageRecived(object sender, string message)
{
this.OnMessageReceived?.Invoke(this, message);
}
}
There is one another service TransactionService class which is having dependency injected for the interface IIncomingMessageHandler and subscribe to OnMessageReceived.
public TransactionService(IIncomingMessageHandler incomingMessageHandler)
{
this.incomingMessageHandler = incomingMessageHandler;
this.incomingMessageHandler.OnMessageReceived += this.IncomingMessageHandler_OnMessageReceived;
}
From this class, I am initiating the transaction and once a transaction started I will receive the messages into IncomingMessageHandler and OnMessageReceived invokes, Messages I am storing into the List for further processing.
Now TransactionService is the Scoped service class and for each API request new object will be created, Now If there are multiple requests are made, for each TransactionService would subscribe to OnMessageReceived and it invokes multiple time because there are multiple objects initiated and override the List of messages.
I can't register TransactionService as singleton due to some other limitations.
Is there any other way through which OnMessageReceived gets invoked only for the specific service object?
I have tried to un-subscribe the OnMessageReceived, but still, this issue will occur for multiple API requests at the same time.
Since you are binding to an event and not unbinding when finished, it causes a bit of a memory leak - the instances of TransactionService live on in other references and can't be GC'd. You should have TransactionService implement IDisposable and unbind it in the Dispose method. That removes the reference from the event in IncomingMessageHandler and you won't have duplicate calls.
Aside: I tried something very similar and I actually found using Reactive Extensions made for a much better pattern overall.
As a part of creating my SimpleInjector container, I've followed recommended practices and called container.Verify() to check that my type registrations make sense.
This works well and has caught a number of errors that I've made - but it also creates debris that lingers around afterwards that I'd like to clean up.
One of my classes is a singleton event hub that's used to route messages between other transient components; these other components accept the event hub in their constructor, create a subscription to receive the messages they're interested in receiving, then Dispose() the subscription when they're finished.
The call to container.Verify() creates one of each kind of object, resulting in a number of these otherwise transient instances lingering around because the event hub still knows about their subscriptions.
At the moment I've worked around the problem by manually terminating all subscriptions immediately after the Verify() call, before the application starts up. However, this feels like a problem that must be already solved, though I haven't been able to find an answer in the docs, here on Stack Overflow, or by searching.
Perhaps using a scoped lifestyle is the solution? They didn't seem relevant because I'm building a WPF application, but if I knew the answer I wouldn't be asking here!
Update, 12 Jan - As requested by #steven, here's some code to demonstrate my issue.
I tried (and failed) to demonstrate the issue with something that was both compilable and short enough to share inline; instead I'm showing some code excerpts from the actual project. If you want to see the whole thing, the WordTutor project is on GitHub.
At the core of my application I have a singleton IReduxStore<T> which both encapsulates application state and acts as a kind of event hub. Other classes subscribe to the store in order to be proactively notified when the application state changes.
Here is IReduxStore<T>, pared down to the essentials:
// IReduxStore.cs
public interface IReduxStore<T>
{
T State { get; }
void Dispatch(IReduxMessage message);
IDisposable SubscribeToReference<V>(
Func<T, V?> referenceReader,
Action<V?> whenChanged)
where V : class, IEquatable<V>?;
}
Subscriptions implement IDisposable as a convenient and idiomatic way for deterministic cleanup when the subscription is no longer required.
The store is registered as a singleton, bound to a specific type of state:
// Program.cs
container.RegisterSingleton<
IReduxStore<WordTutorApplication>,
ReduxStore<WordTutorApplication>>();
The implementation of IReduxStore<T> stores all the subscriptions:
private readonly HashSet<ReduxSubscription<T>> _subscriptions
= new HashSet<ReduxSubscription<T>>();
They're removed from the HashSet when disposed.
Many of my ViewModels accept IReduxStore<WordTutorApplication> to their constructors so they can subscribe to updates:
// VocabularyBrowserViewModel.cs
public sealed class VocabularyBrowserViewModel : ViewModelBase
{
private readonly IReduxStore<WordTutorApplication> _store;
private readonly IDisposable _screenSubscription;
private readonly IDisposable _vocabularySubscription;
public VocabularyBrowserViewModel(IReduxStore<WordTutorApplication> store)
{
_store = store ?? throw new ArgumentNullException(nameof(store));
// ... elided ...
_screenSubscription = _store.SubscribeToReference(
app => app.CurrentScreen as VocabularyBrowserScreen,
RefreshFromScreen);
_vocabularySubscription = _store.SubscribeToReference(
app => app.VocabularySet,
RefreshFromVocabularySet);
// ... elided ...
}
// ... elided ...
}
ViewModels are registered as transient because each window needs a unique instance:
// Program.cs
var desktopAssembly = typeof(WordTutorWindow).Assembly;
container.Collection.Register<ViewModelBase>(desktopAssembly);
The ViewModels release their subscriptions proactively when they are no longer needed:
// VocabularyBrowserViewModel.cs
private void RefreshFromScreen(VocabularyBrowserScreen? screen)
{
if (screen == null)
{
_screenSubscription.Dispose();
_vocabularySubscription.Dispose();
return;
}
Selection = screen.Selection;
Modified = screen.Modified;
}
When Verify() is called on the SimpleInjector container, an exemplar of every object is created, including the singleton IReduxStore<T>. The transient viewmodels (such as VocabularyBrowserViewModel shown above) are also created, but those instances remain live because their subscriptions are still held by the store.
I tried implementing IDisposable on the ViewModels, but because their lifestyle is transient, the only effect was to generate an additional warning when Verify() was called.
Update II, 12 Jan:
The workaround I have at the moment is to manually clear all the subscriptions as a part of application startup, after the container has been successfully initialized:
var store = (ReduxStore<WordTutorApplication>)
container.GetInstance<IReduxStore<WordTutorApplication>>();
store.ClearSubscriptions();
This feels like a nasty hack. First it needs to explicitly cast to the implementation type, then it calls a method that otherwise wouldn't need to exist at all.
Try setting EnableAutoVerification to false in Simple Injector 5.0 (https://simpleinjector.org/ReferenceLibrary/html/P_SimpleInjector_ContainerOptions_EnableAutoVerification.htm)
I looked for an answer to this for quite sometime now but didn't find any.
I will refer to Application start as a stage.
Most of the documentations out there talk about the Global.asax file and the Application_Start method which is invoked only once when the first request reaches the Application, even if this behaviour is similar to subscribing to an event it's technicaly not an event.
While lifecycle events such as BeginRequest, AuthenticateRequest and so on are accessible through the application instance as events, the Application.Start is not.
I can subscribe to BeginRequest event in an HttpModule.Init() method or Global.asax Init() method but not to the Application.Start stage like so:
Module
public class MyModule : IHttpModule
{
public void Init(HttpApplication httpApplication)
{
httpApplication.BeginRequest += new EventHandler(ApplicationBeginRequest);
}
}
Global
public class Global : HttpApplication
{
public override void Init()
{
BeginRequest += new EventHandler(ApplicationBeginRequest);
}
}
My question:
Since there is no HttpApplication.Start event accessible from the Application instance, is Global.asax and the "Application_Start" method the only hope to subscribe to the Application start stage ?
After jumping to the .NET source code i found that the HttpApplicationFactory class looks for a method named Application_OnStart or Application_Start in the Global.asax file and then invokes it using reflection => ReflectOnMethodInfoIfItLooksLikeEventHandler().
I don't have the answer why HttpApplication.Start is not event but it's clearly intended to be handled in an event like fashion using Application_OnStart or Application_Start methods.
I have this code
List<DaSubscription> lstSubscription=new List<DaSubscription>();
for(int i=0;i<20;i++)//20 is just to simulate the behavior
{
DaSubscription Generic=new DaSubscription();
Generic.DataChanged += new DataChangedEventHandler(Generic_DataChanged);
lstSubscription.add(Generic);
}
//EVENT Handler which is raised from a 3rd party library [COM]
void Generic_DataChanged(DaSubscription aDaSubscription, DaItem[] items, ValueQT[] values, int[] results)
{
UpdateDataChangedDTO(items, values);
}
As the same event handler [m_daSubscription_Generic_DataChanged] is assigned to the multiple instance of same class [m_daSubscription]. Question i have is if at the same time multiple instances invokes this handler how will be handled here. will there will be any instance it shall overwrite the data. or the event handler will be separate for each instance.
The event handlers execute seperately. It sounds like your worried about the parameters being overwritten by another call to the handler. That won't happen (I don't think it is even possible). Since it doesn't look like you are accessing any shared objects in the event handler, you should be perfectly safe.
My app uses a logging class which is invoked by each module as it is constructed.
The logging class fires an event every time a new entry is added, so that the GUI can be updated.
Is there any way I can listen to events fired during the construction of an instance?
For instance, I currently have this in my calling class:
input = new Inputs.Webcam();
input.log.LogUpdate += new LogUpdateHandler(...);
But I also write to the log during the construction of the modules. (Currently this throws an error because there isn't a listener.) Is there any way to listen to these events?
This is completely impossible.
Instead, you can use a static event.
Could not you just pass the log handler method to the ctor?
var input = new Inputs.Webcam(new LogUpdateHandler(...));