You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
only when called by OnReceived method from the SimpleInjectorHubDispatcher. For all other calls in the hub dispatcher (OnConnected, OnDisconnected, and OnReconnected) no exception is thrown.
Debugging findings leading to belief scopes are confused
I cloned down the Simple Injector 4.1.x branch and added it to my project so I could debug. Here's is what I've found:
Line 446 of Scope.cs is where the exception is thrown. Here's the call stack at that point:
Letting the previous exception bubble up, I see it reach line 37 of SimpleInjectorHubDispatcher just prior to exiting the using statement.
Here's what that looks like:
protectedoverrideTaskOnReceived(IRequestrequest,stringconnectionId,stringdata){using(Scopescope=AsyncScopedLifestyle.BeginScope(container)){scope.WhenScopeEnds(()=>{// Scope is disposed. Inspect the call stack to find out who // is invoking dispose.//Debugger.Break();Console.WriteLine("wth");});//line 37--exception has bubbled up to this pointreturnbase.OnReceived(request,connectionId,data);}//return Invoke(() => base.OnReceived(request, connectionId, data));}
I press continue, and then my breakpoint is hit at Scope.cs line 270. I inspect the Scope object, and it's status is Alive just prior to being set to Disposing on line 270. Here's what the surrounding code looks like from Scope.cs:
protectedvirtualvoidDispose(booldisposing){if(disposing){// We completely block the Dispose method from running in parallel, because there's// all kinds of state that needs to be read/written, such as this.state,// this.disposables, and this.scopeEndActions. Making this thread-safe with smaller// granular locks will be much harder and simply not necessarily, since Dispose// should normally only be called from one thread.lock(this.syncRoot){if(this.state!=DisposeState.Alive){// Either this instance is already disposed, or a different thread is // currently disposing it. We can break out immediately.return;}//line 270--right here this.state = Alive just prior to executingthis.state=DisposeState.Disposing;try{this.DisposeRecursively();}finally{this.state=DisposeState.Disposed;// Remove all references, so we won't hold on to created instances even if // the scope accidentally keeps referenced. This prevents leaking memory.this.cachedInstances=null;this.scopeEndActions=null;this.disposables=null;this.manager?.RemoveScope(this);}}}}
Right now I have default scoped lifestyle set as follows:
container.Options.DefaultScopedLifestyle=Lifestyle.CreateHybrid(defaultLifestyle:newWebRequestLifestyle(),//mvc & webapifallbackLifestyle:newAsyncScopedLifestyle()// for signalR?);
All of my signalR hubs are registered using Lifestyle.Scoped.
I set my MVC resolver to SimpleInjectorDependencyResolver, and Web API resolver to SimpleInjectorWebApiDependencyResolver.
Here's my simpleinjector signalr related classes:
usingSystem;usingSystem.Threading.Tasks;usingMicrosoft.AspNet.SignalR;usingMicrosoft.AspNet.SignalR.Hubs;usingSimpleInjector;usingSimpleInjector.Lifestyles;namespaceScs.Core.DependencyInjection.SimpleInjector{//see https://github.com/simpleinjector/SimpleInjector/issues/232#issuecomment-221837128publicclassSimpleInjectorHubDispatcher:HubDispatcher{privatereadonlyContainercontainer;publicSimpleInjectorHubDispatcher(Containercontainer,HubConfigurationconfiguration):base(configuration){this.container=container;}protectedoverrideTaskOnConnected(IRequestrequest,stringconnectionId){returnInvoke(()=>base.OnConnected(request,connectionId));}protectedoverrideTaskOnReceived(IRequestrequest,stringconnectionId,stringdata){using(Scopescope=AsyncScopedLifestyle.BeginScope(container)){scope.WhenScopeEnds(()=>{// Scope is disposed. Inspect the call stack to// find out who is invoking dispose.//Debugger.Break();Console.WriteLine("wth");});returnbase.OnReceived(request,connectionId,data);}//return Invoke(() => base.OnReceived(request, connectionId, data));}protectedoverrideTaskOnDisconnected(IRequestrequest,stringconnectionId,boolstopCalled){returnInvoke(()=>base.OnDisconnected(request,connectionId,stopCalled));}protectedoverrideTaskOnReconnected(IRequestrequest,stringconnectionId){returnInvoke(()=>base.OnReconnected(request,connectionId));}privateasyncTaskInvoke(Func<Task>method){using(varscope=AsyncScopedLifestyle.BeginScope(container)){scope.WhenScopeEnds(()=>{// Scope is disposed. Inspect the call stack to// find out who is invoking dispose.//Debugger.Break();Console.WriteLine("wth");});awaitmethod();}}}}
Now with all this being said, if I flip the default/fallback scoped dependencies so it looks like the following, I no longer get the object disposed exception from within Scope.cs and SimpleInjector does create my signalr hub (CaseHub). However my signalr hub (CaseHub) then throws 'System.ObjectDisposedException' in System.Net.Http.dll when trying to make an api call using HttpClient.GetAsync.
Any help here would be appreciated. We're looking to migrate from Autofac for performance reasons. Outside of this issue, I've really enjoyed the opinionated approach Simple Injector takes (so thanks!).
I hijacked another github issue previously pertaining to this: #232. Sorry for that--I wasn't expecting it to be a significant undertaking to resolve.
The text was updated successfully, but these errors were encountered:
I got everything working using AsyncScopedLifestyle as default, and fallback as WebRequestLifestyle. I'm still wrapping my head around why I got the ObjectDisposedException on the HttpClient--but I don't think that's Simple Injector related.
When using WebRequestLifestyle as the default and AsyncScopedLifestyle as the fallback, is it possible that OnReceived is trying to use a WebRequestLifestyle that's already been disposed even though the AsyncScopedLifestyle does exist?
Issue
I'm getting an ObjectDisposedException:
in my
SimpleInjectorHubActivator
when attempting:only when called by
OnReceived
method from theSimpleInjectorHubDispatcher
. For all other calls in the hub dispatcher (OnConnected
,OnDisconnected
, andOnReconnected
) no exception is thrown.Debugging findings leading to belief scopes are confused
I cloned down the Simple Injector 4.1.x branch and added it to my project so I could debug. Here's is what I've found:
Here's what that looks like:
And the callstack at this point in time is:
Setup and supporting classes
Right now I have default scoped lifestyle set as follows:
All of my signalR hubs are registered using Lifestyle.Scoped.
Here's my hubConfig setup:
I set my MVC resolver to
SimpleInjectorDependencyResolver
, and Web API resolver toSimpleInjectorWebApiDependencyResolver
.Here's my simpleinjector signalr related classes:
Other bits I've found
Now with all this being said, if I flip the default/fallback scoped dependencies so it looks like the following, I no longer get the object disposed exception from within Scope.cs and SimpleInjector does create my signalr hub (CaseHub). However my signalr hub (CaseHub) then throws
'System.ObjectDisposedException' in System.Net.Http.dll
when trying to make an api call using HttpClient.GetAsync.Any help here would be appreciated. We're looking to migrate from Autofac for performance reasons. Outside of this issue, I've really enjoyed the opinionated approach Simple Injector takes (so thanks!).
I hijacked another github issue previously pertaining to this: #232. Sorry for that--I wasn't expecting it to be a significant undertaking to resolve.
The text was updated successfully, but these errors were encountered: