ReuseScope by Request and Container

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:

Kernel.Bind<IDbConnection>()
    .ToMethod(x => DbFactory.Open())
    .InScope(ctx => TestContext.CurrentContext.Test.MethodName ?? TestContext.CurrentContext.Test.ClassName)

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?

Thanks

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();
//...

Although for multitenancy-aware dependencies like IDbConnection its best to retrieve it from:

using var db = HostContext.AppHost.GetDbConnection(Request);
//...

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.

A Request Scope in Funq is registered as:

container.Register(c => new MyType()).ReusedWithin(ReuseScope.Request); 

Transient Scope examples:

container.Register(c => new MyType()).ReusedWithin(ReuseScope.None); 
container.AddTransient(c => new MyType());

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.

Anyway we solved like this:

public override void OnEndRequest(IRequest request = null)
{
    // Dispose InRequest scoped objects
    _kernel.Components
        .Get<ICache>()
        .Clear(RequestContext.Instance.Items);

    base.OnEndRequest(request);
}

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.

No it’s most definitely not. I’ve already described why it leads to lower resource usage.

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.

Yes that’s what’s used for per-request storage in ServiceStack.