Solution using transient database connection and nested StructureMap container
First, configure a named, transient database connection instance in StructureMap:
For<IDbConnection>()
.Transient() // scope
.Add(x => BaseController.GetOpenConnection(connectionString, IsDebugging()))
.Named("Transient");
Make sure you configure this before your default instance, or it will override the default instance.
Secondly, inject an IContainer
into your SignalR hub so you can build a nested StructureMap container:
public class JobHub : Hub
{
private readonly IContainer _container;
public JobHub(IContainer container)
{
_container = container;
}
public Task DoStuff(string input)
{
// ...
Instantiate a nested container in your SignalR method and resolve your named transient database connection:
using (var httpRequestScope = _container.GetNestedContainer())
{
var transientConnection =
httpRequestScope.GetInstance<IDbConnection>("Transient");
Use .With<IDbConnection>(transientConnection)
to ensure services and repositories instantiated 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 scoped using (...)
statement will ensure that your nested container cleans up after itself, including the database connection.
The downside here is that you are opening and closing a database connection for every SignalR method call, but since connections are pooled, releasing early may not be so bad. Your mileage should depend on your SignalR request volume.
You may be able to ditch the nested container and just ask DependencyResolver.Current
for the named connection instance, but then you may have to remember to explicitly close each connection to prevent a leak.