Hi, we are encountering a problem when handling injected dependencies in some edge cases.
Basically, the ReuseScope (when different by None) works either by a Container-base (Hierarchy or Container) or by Request-base (Request).
We have a special case when we need to inject some dependencies that are marked as ReuseScope.Request but have those injected by Container. Look at the following code.
// This method will not be awaited.
// Is called as a fire&forget method, so the Request ends before the method does.
// The behaviour is explicitly wanted like this.
public static async Task FireAndForgetMethod()
{
using (var container = HostContext.Container.CreateChildContainer())
{
var myService = container.Resolve<ServiceReusedByRequest>();
myService.DoSomething(); // Error! Injected IDbConnection is already been closed, because the request has already ended
}
}
My problem is that IDbConnection is injected by Request (basically it seems the only way to correctly use the connection pool without leaking connections), but in this specific case I wanted to have injected by Container, specifically the child container.
In Ninject I could use InScope method to define a custom scope, like we do in our Unit Test Project:
So in Ninject I could define a InScope function that returns something like ContainerInstance + RequestId so I could have 1 IDbConnection for each Request\Container and have them disposed at the Dispose of the child container.
Could Funq implement something like that? Is it a better idea to switch to Ninject through IContainerAdapter?
If switching to Ninject is the best thing, what can I use to differenciate one request to the other? Will I be able to manage the lifetime of my dependencies?
You shouldn’t be using Request Scope for pooled resources like IDbConnection as it holds the open connection when it’s not needed, just inject the IDbConnectionFactory and use it in a scope:
public IDbConnectionFactory DbFactory { get; set; }
//...
using var db = DbFactory.Open();
//...
I don’t understand what you are saying. We always dispose IDbConnection exactly because it’s part of a connection pool. This is the standard behaviour in basically all implementations of a connection to a Db, even with other ORMs like EF6 or NHibernate.
But the question what not about IDbConnection. We have other Request-based dependencies that we want to handle like that, so we wanted to know how we can handle request based dependencies.
Is IRelease.Release implementation enough?
EDIT: Ok, IRelease implementation does not work at all with our implementations. We see a lot of leaked connections all around the place.
If its a pooled resource you should be using Transient scope, there’s no reason why pooled resources should use request scope. But when there is already a factory like IDbConnectionFactory you should be injecting and using that instead.
We cannot use Transient scope, simply because we would open like 20 connections for each request. We have multiple injected repositories in many business logic classes, it’s simply not feasible. Also, transactions would not work at all using Transient lifetime, when the connection could be injected in more than one object.
We then defined a custom InScope for Ninject, by looking at the implementation of InRequestScope for ASP.NET:
public static class RequestScopeExtensionMethod
{
/// <summary>
/// Sets the scope to request scope.
/// </summary>
/// <typeparam name="T">The type of the service.</typeparam>
/// <param name="syntax">The syntax.</param>
/// <returns>The syntax to define more information.</returns>
public static IBindingNamedWithOrOnSyntax<T> InRequestScope<T>(this IBindingInSyntax<T> syntax)
{
return syntax.InScope(GetScope);
}
/// <summary>
/// Gets the scope.
/// </summary>
/// <param name="ctx">The context.</param>
/// <returns>The scope.</returns>
private static object GetScope(IContext ctx)
{
var scope = RequestContext.Instance.Items;
return scope;
}
}
It seems to work just fine, no leaked connections and just one connection for each request.
My only doubt is if RequestContext.Instance.Items can be used as the “request scope object”. I saw your sources use exactly that reference to identify the request scope.
You wouldn’t be opening 20 connections, you’re returning an open connection to the pool after you’re no longer using it instead of holding the connection open for the entire request (and forcing other requests to use a different open connection from the pool) which is why it’s better to inject the factory and use the db connection in a using scope as I’ve shown above so open connections are returned to the pool as soon as they’re no longer needed.
We are using the dependency injection in a way different of what you intend.
Take the following scenario:
I have a Service named MyService, which has a constructor that needs a IDbConnection, MyFirstRepository and MySecondRepository.
MyFirstRepository and MySecondRepository both needs IDbConnection.
The resolution of MyService leads to 3 IDbConnections created. That’s just it. We don’t want to pass the factory around when it’s not needed. That’s an antipattern.
We just want a reliable and safe way to have 1 Connection for each web request. If you are using the Transient lifetime, 1 Connection would be opened on every activation.
That’s something we actually tested on both Funq and Ninject, not something I’m making up.
Yes but you are asking me to inject a DbFactory and every time I need to query the DB i just go like
using (var db = factory.Open())
{
}
That is insane, when I can just register 1 connection for each web request and obtain the same (if not better) result, with hundreds of less lines.
The question is not “am i doing IoC right”. You never actually answered the original question.
I just want to be sure that I can use RequestContext.Instance.Items as a object scope when I want my injected dependencies to have a per-request lifetime.