Pet*_*ron 8 structuremap asp.net-mvc lifetime idbconnection signalr
HttpContext在我的ASP.NET MVC应用程序中存在持久HTTP连接(如SignalR集线器)时,我在管理使用StructureMap的开放式数据库连接的生命周期时遇到了问题.
我的DI容器StructureMap IDbConnection为几个服务注入了一个open .为了确保关闭并妥善处理这些数据库连接,我调用ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects()了该EndRequest事件.
这对于MVC控制器非常有用,直到需要数据库连接的服务注入到SignalR集线器中,这会为每个客户端保持持久的HTTP连接,并最终使连接池饱和.
如果我IDbConnection使用单一范围,每个应用程序只打开一个连接,并且池不会饱和,但如果连接被锁定或超时,这是一个坏主意.
那么也许有一种方法可以自定义SignalR集线器的数据库连接范围?我尝试在每个Hub方法中解析服务实例,但这仍然在HttpContext范围内实例化数据库连接,并在调用客户端的集线器连接期间保持打开状态.
当存在持久的HTTP连接时,如何在HTTP范围的上下文中管理使用StructureMap的数据库连接的生命周期?
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();
}
}
Run Code Online (Sandbox Code Playgroud)
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();
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
For<IDbConnection>()
.HybridHttpOrThreadLocalScoped()
.Use(() => BaseController.GetOpenConnection(MyConnectionString));
Run Code Online (Sandbox Code Playgroud)
public class GlobalApplication : System.Web.HttpApplication
{
public GlobalApplication()
{
EndRequest += delegate
{
ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
};
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
首先,在 StructureMap 中配置一个命名的临时数据库连接实例:
For<IDbConnection>()
.Transient() // scope
.Add(x => BaseController.GetOpenConnection(connectionString, IsDebugging()))
.Named("Transient");
Run Code Online (Sandbox Code Playgroud)
确保在默认实例之前配置此项,否则它将覆盖默认实例。
其次,将 an 注入IContainer到您的 SignalR hub 中,以便您可以构建一个嵌套的 StructureMap 容器:
public class JobHub : Hub
{
private readonly IContainer _container;
public JobHub(IContainer container)
{
_container = container;
}
public Task DoStuff(string input)
{
// ...
Run Code Online (Sandbox Code Playgroud)
在 SignalR 方法中实例化一个嵌套容器并解析您的命名瞬态数据库连接:
using (var httpRequestScope = _container.GetNestedContainer())
{
var transientConnection =
httpRequestScope.GetInstance<IDbConnection>("Transient");
Run Code Online (Sandbox Code Playgroud)
用于.With<IDbConnection>(transientConnection)确保嵌套容器实例化的服务和存储库使用此连接:
var myService = httpRequestScope
.With<IDbConnection>(transientConnection)
.GetInstance<MyService>();
var result = myService.DoStuff(input);
return Clients.addResult(result);
}
}
}
Run Code Online (Sandbox Code Playgroud)
最后,作用域using (...)语句将确保嵌套容器在自身之后进行清理,包括数据库连接。
这里的缺点是,您要为每个 SignalR 方法调用打开和关闭数据库连接,但由于连接是池化的,因此提前释放可能并没有那么糟糕。您的里程数应取决于您的 SignalR 请求量。
您也许可以放弃嵌套容器,只请求DependencyResolver.Current命名的连接实例,但是您可能必须记住显式关闭每个连接以防止泄漏。
| 归档时间: |
|
| 查看次数: |
1325 次 |
| 最近记录: |