Hey guys - I am trying to figure out how to get the default Funq IOC to work properly when executing requests outside of a normal HTTP request.
The situation is as follows
During a standard HTTP request service call, we use Hangfire to enqueue a task to be run at a later time, even though we are using Hangfire, you can simulate this with ThreadPool.QueueUserWorkItem
This callback is executed asynchronously on a new thread that is not in the HTTP pipeline
I am following the examples on this page Executing a Service Internally to execute a request outside of the HTTP pipeline and it works fine however the main issue is that after executing the request, I can’t figure out how to get the IOC to dispose of the per requests objects that are created. I have setup a breakpoint in the IDispose method of one of our dependencies and it triggers after every single HTTP request, but I can’t for the life of me figure out how to get these “out of band” service calls to clean up. I figure it has something to do with the BasicRequest object that we are using, but can’t seem to figure it out.
You can’t have per-request scoped dependencies when executing a Service outside the context of a HTTP Request (which is where request scoped dependencies are tied to).
I’d recommend against using Request Scoped dependencies, in addition to restricting usage of dependencies within the context of a HTTP Request, it relies on environment-specific constructs to support request scope whose nuanced behavior can differ in alt environments (e.g. ASP .NET Web FX vs Unit Tests), it’s less efficient for pooled resources. There shouldn’t be any reason to use Request Scope, if you need per-request storage you can store objects in the IRequest.Items dictionary which is available throughout the entire Request Pipeline.
Basically if your dependencies only use Thread Safe dependencies register it as a singleton (the default):
container.AddSingleton<IMyDep>(c => new MyDep { Name = "bar" });
container.Register(c => new MyDep(c.Resolve<IDep>()));
container.RegisterAutoWiredType(typeof(MyDep));
container.RegisterAutoWiredType<MyDep>();
Otherwise register it as a Transient dependency, e.g:
container.AddTransient<IMyDep>(c => new MyDep { Name = "bar" });
container.Register(c => new MyDep()).ReusedWithin(ReuseScope.None);
container.RegisterAutoWiredType(typeof(MyDep)).ReusedWithin(ReuseScope.None);
container.RegisterAutoWiredType<MyDep>().ReusedWithin(ReuseScope.None);
In ASP .NET Core any disposables created are tracked in an AsyncLocal Dictionary are disposed after calling the Service in both HTTP Request and out-of-band Services where it automatically calls RequestContext.Instance.ReleaseDisposables() when called with a using, e.g:
using var service = HostContext.ResolveService<MyService>(base.Request);
//...
OK that makes sense, so if I understand correctly, an transient registration does NOT get automatically cleaned up by ServiceStack so I would need to make sure that I dispose of it myself either in the Service’s Dispose method or via some other way. Is that correct?
Right, when calling a Service outside of a HTTP Request (all IDisposabe’s get disposed for normal HTTP Requests), or if you implement the Disposable pattern it will automatically get called when the GC cleans up the unreferenced instance.
OK got it - so if I convert my registrations to Transient, can I just Dispose of them in my Service’s Dispose method instead and be safe for both HTTP requests as well as out of band requests (assuming I dispose the service as per above in the using block)?
Also I’m going to assume that ServiceStack does NOT call
RequestContext.Instance.ReleaseDisposables();
Automatically at the end of a request, but maybe you do?
Yep, it gets disposed at the end of the using scope.
It does, but after you call it, it clears any IDisposable’s registered up to that point, so will only dispose any IDisposables resolved after the Service is called (e.g. in Response Filters).
OK well you put me on the right path - thank you sir. I will figure out what works best for our architecture now that I know exactly what is going on under the hood.
OK one last question mythz sorry to bother you. So I just converted our Database registration from Request to None and basically I noticed the following
It still gets disposed after every HTTP request without me doing anything special
It automatically gets disposed now when our out of band Service disposes without me adding any special code in and BEFORE calling
RequestContext.Instance.ReleaseDisposables();
Does that sound right?
EDIT: I was trying to figure out what really separates this from Per Request instancing but it does appear that in certain situations Transient registrations get instantiated more than once in a single request e.g. if you use ResolveService etc. so that makes sense.
Yeah it always gets disposed in a HTTP Request, and actually ServiceStack is already calling RequestContext.Instance.ReleaseDisposables() in its Dispose() method so you wont have to.
So is the only real benefit to per request instancing that in certain cases you don’t instantiate the same registration multiple times (e.g. for multiple services) in a request?
EDIT: in non asp.net core environments I can see more benefits since you don’t have the ReleaseDisposables() functionality
I don’t believe there’s any benefit to using Request Scope dependencies, esp when it uses pooled resources which most resource connections do by default (e.g. RDBMS/Redis).
I personally never use Request Scoped dependencies (it’s tied to a HTTP Request and each server uses a different impl), I either use Singleton when its ThreadSafe otherwise Transient.