IDbConnection Lifecycle Management with Persistent HTTP Connections

I had a problem managing the lifetime of open database connections with StructureMap with the HttpContext when my ASP.NET MVC application has persistent HTTP connections such as SignalR hubs.

My DI container, StructureMap, introduces an open IDbConnection into several services. To ensure that these database connections are closed and correctly removed, I call ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects() in the EndRequest event.

This is great for MVCs until a service that requires a database connection is injected into a SignalR hub, which maintains a constant HTTP connection for each client and ultimately saturates the connection pool.

If I use IDbConnection for singleton mode, only one connection is open for each application and the pool is not saturated, but this is a bad idea . in case the connection is blocked or disconnected.

So maybe there is a way to configure the database connection area for my SignalR hubs? I tried to resolve the service instance in each Hub method, but this still creates a database connection in the HttpContext area and keeps it open for the duration of the client hub connection.

How can I control the lifetime of database connections with StructureMap in the context of HTTP hosts when there are persistent HTTP connections?

Code example

Typical service

 public class MyService { private IDbConnection _con; public MyService(IDbConnection con) { _con = con; } public IEnumerable<string> GetStuff() { return _con.Select<string>("SELECT someString FROM SomeTable").ToList(); } } 

Typical SignalR Hub

 public class MyHub : Hub { private MyService _service; public MyHub(MyService service) { _service = service; // Oh Noes! This will open a database connection // for each Client because of HttpContext scope } public Task AddMessage() { var result = _service.GetStuff(); // ... } } 

StructureMap Configuration

 For<IDbConnection>() .HybridHttpOrThreadLocalScoped() .Use(() => BaseController.GetOpenConnection(MyConnectionString)); 

Global.asax.cs

 public class GlobalApplication : System.Web.HttpApplication { public GlobalApplication() { EndRequest += delegate { ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects(); }; } // ... } 
+8
asp.net-mvc structuremap lifetime signalr
source share
2 answers

Solution using a transitional database connection and a nested StructureMap container

First, configure a named, transitional instance of the database connection in StructureMap:

 For<IDbConnection>() .Transient() // scope .Add(x => BaseController.GetOpenConnection(connectionString, IsDebugging())) .Named("Transient"); 

Make sure you configure this before the default instance or override the default instance.

Second, enter IContainer in your SignalR hub so you can create a nested StructureMap container:

 public class JobHub : Hub { private readonly IContainer _container; public JobHub(IContainer container) { _container = container; } public Task DoStuff(string input) { // ... 

Create an instance of the nested container in your SignalR method and allow your named transient database connection:

  using (var httpRequestScope = _container.GetNestedContainer()) { var transientConnection = httpRequestScope.GetInstance<IDbConnection>("Transient"); 

Use .With<IDbConnection>(transientConnection) to ensure that the services and repositories created by your nested container use this connection:

  var myService = httpRequestScope .With<IDbConnection>(transientConnection) .GetInstance<MyService>(); var result = myService.DoStuff(input); return Clients.addResult(result); } } } 

Finally, the copied using (...) statement ensures that your nested container is cleared after itself, including connecting to the database.

The downside here is that you open and close the database connection for each call to the SignalR method, but since the connections are combined, the early early ones may not be so bad. Your mileage should depend on your SignalR request volume.

You may be able to fall into a nested container and simply ask DependencyResolver.Current for a named connection instance, but then you may need to remember to explicitly close each connection to prevent leakage.

+1
source

In SignalR 1.0.0 Alpha, Hub implement IDisposable . The SignalR Hub characters are ephemeral, unlike the HttpContext , so if you close your IDbConnection in the Hub Dispose method, you should not over-saturate the connection pool.

+1
source

All Articles