【发布时间】:2012-10-28 15:19:28
【问题描述】:
当我的 ASP.NET MVC 应用程序(如 SignalR 集线器)中存在持久 HTTP 连接时,我在管理具有范围为 HttpContext 的 StructureMap 的打开数据库连接的生命周期时遇到问题。
我的 DI 容器 StructureMap 将打开的 IDbConnection 注入到多个服务中。为确保这些数据库连接已关闭并正确处理,我在 EndRequest 事件上调用 ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects()。
这对 MVC 控制器非常有用,直到需要数据库连接的服务被注入到 SignalR 集线器中,该集线器为每个客户端保持持久的 HTTP 连接打开并最终使连接池饱和。
如果我将IDbConnection 限定为单例,则每个应用程序只会打开一个连接并且池不会饱和,但这是a bad idea,以防连接被锁定或超时。
那么也许有一种方法可以为我的 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();
}
}
典型的 SignalR 集线器
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));
Global.asax.cs
public class GlobalApplication : System.Web.HttpApplication
{
public GlobalApplication()
{
EndRequest += delegate
{
ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
};
}
// ...
}
【问题讨论】:
-
在每个集线器方法上创建您的服务是一个解决方案吗?没有足够的信息来回答。 SignalR 将管理多少客户?他们多久通信/调用一次服务器方法?
-
嘿@VladCiobanu,我用关于在每个集线器方法中解析服务实例的注释更新了我的问题。对于这个特定的应用程序,SignalR 管理大约 10-40 个持久客户端(目前),但是如果负载在高峰时间翻倍,这很容易使连接池最大化。我希望对我的问题有一个规范的答案。
-
我想我已经解决了这个问题,方法是使用
GetNestedContainer()来显式处理服务并打开它使用的连接,从而解决每个 SignalR 集线器方法中的服务实例。 -
不,看起来嵌套容器只显式处理瞬态实例,而
IDbConnection不能是瞬态的,因为服务层中的 LINQ 查询实现。 -
已使用瞬态 IDbConnection 的命名实例解决!很快就会发布答案。
标签: asp.net-mvc structuremap signalr lifetime idbconnection