[英]IDbConnection lifecycle management with persistent HTTP connections
當我的ASP.NET MVC應用程序(例如SignalR集線器)中存在持久的HTTP連接時,我無法管理范圍為HttpContext
StructureMap的開放數據庫連接的生命周期。
我的DI容器StructureMap將一個開放的IDbConnection
注入幾個服務中。 為了確保這些數據庫連接已關閉並正確處理,我在EndRequest
事件上調用ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects()
。
這對於MVC控制器非常有用,直到需要將數據庫連接的服務注入到SignalR集線器中為止,SignalR集線器將為每個客戶端保持持久的HTTP連接打開,並最終使連接池飽和。
如果我將IDbConnection
作用域IDbConnection
為一個單例,則每個應用程序只能打開一個連接,並且該池不會飽和,但這是一個壞主意 ,以防連接被鎖定或超時。
因此,也許有一種方法可以自定義SignalR集線器的數據庫連接范圍? 我嘗試在每個Hub方法中解析服務實例,但這仍然在HttpContext范圍內實例化數據庫連接,並在調用客戶端的Hub連接期間將其保持打開狀態。
當周圍存在持久的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();
}
}
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();
// ...
}
}
For<IDbConnection>()
.HybridHttpOrThreadLocalScoped()
.Use(() => BaseController.GetOpenConnection(MyConnectionString));
public class GlobalApplication : System.Web.HttpApplication
{
public GlobalApplication()
{
EndRequest += delegate
{
ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
};
}
// ...
}
在SignalR 1.0.0 Alpha中, Hub
的實現IDisposable
。 SignalR Hub
實例是短暫的,與HttpContext
不同,因此,如果在Hub
的Dispose
方法中關閉IDbConnection
,則不必不必要地使連接池飽和。
首先,在StructureMap中配置一個命名的臨時數據庫連接實例:
For<IDbConnection>()
.Transient() // scope
.Add(x => BaseController.GetOpenConnection(connectionString, IsDebugging()))
.Named("Transient");
確保在默認實例之前配置此配置,否則它將覆蓋默認實例。
其次,將IContainer
注入SignalR集線器中,以便您可以構建嵌套的StructureMap容器:
public class JobHub : Hub
{
private readonly IContainer _container;
public JobHub(IContainer container)
{
_container = container;
}
public Task DoStuff(string input)
{
// ...
在SignalR方法中實例化一個嵌套容器,並解析您的命名瞬態數據庫連接:
using (var httpRequestScope = _container.GetNestedContainer())
{
var transientConnection =
httpRequestScope.GetInstance<IDbConnection>("Transient");
使用.With<IDbConnection>(transientConnection)
以確保由嵌套容器實例化的服務和存儲庫使用此連接:
var myService = httpRequestScope
.With<IDbConnection>(transientConnection)
.GetInstance<MyService>();
var result = myService.DoStuff(input);
return Clients.addResult(result);
}
}
}
最后,范圍限定的using (...)
語句將確保嵌套容器在其自身(包括數據庫連接)之后清除。
不利的一面是您要為每個SignalR方法調用打開和關閉數據庫連接,但是由於連接是池化的,提早釋放可能不是很糟糕。 您的里程數應取決於SignalR的請求量。
您也許可以拋棄嵌套的容器,而只問DependencyResolver.Current
作為命名的連接實例,但是您可能必須記住顯式關閉每個連接以防止泄漏。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.