我有一个使用Entity Framework、SignalR和Hangfire任务的ASP.NET MVC项目。
我的主(根)容器定义如下:
builder.RegisterType<DbContext>().InstancePerLifetimeScope(); // EF Db Context
builder.RegisterType<ChatService>().As<IChatService>().SingleInstance(); // classic "service", has dependency on DbContext
builder.RegisterType<ChatHub>().ExternallyOwned(); // SignalR hub
builder.RegisterType<UpdateStatusesJob>().InstancePerDependency(); // Hangfire job
builder.RegisterType<HomeController>().InstancePerRequest(); // ASP.NET MVC controller
IContainer container = builder.Build();
我正在使用Autofac.MVC5 nuget软件包来实现MVC。依赖解析器:
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
我正在使用Autofac.SignalR nuget包来处理SignalR。依赖解析器:
GlobalHost.DependencyResolver = new Autofac.Integration.SignalR.AutofacDependencyResolver(container);
我的 SignalR hub 是这样实例化的(http://autofac.readthedocs.org/en/latest/integration/signalr.html#managing-dependency-lifetimes):
private ILifetimeScope _hubScope;
protected IChatService ChatService;
public ChatHub(ILifetimeScope scope) {
_hubScope = scope.BeginLifetimeScope(); // scope
ChatService = _hubScope.Resolve<IChatService>(); // this service is used in hub methods
}
protected override void Dispose(bool disposing)
{
// Dipose the hub lifetime scope when the hub is disposed.
if (disposing && _hubScope != null)
{
_hubScope.Dispose();
}
base.Dispose(disposing);
}
我正在使用Hangfire.Autofac包来使用Hangfire:
config.UseActivator(new AutofacJobActivator(container));
创建Job的方式如下:
private readonly ILifetimeScope _jobScope;
protected IChatService ChatService;
protected BaseJob(ILifetimeScope scope)
{
_jobScope = scope.BeginLifetimeScope();
ChatService = _jobScope.Resolve<IChatService>();
}
public void Dispose()
{
_jobScope.Dispose();
}
问题/难题: 我总是在聊天室和工作中得到相同的DbContext实例。 我希望所有hub实例都能获取相同的ChatService,但是DbContext(它是ChatService的依赖项)将始终是新实例。 同样,Hangfire作业也应该表现出相同的特性。
这可以做到吗? 还是我有什么遗漏?
更新1:
经过思考(并且睡过觉),我认为我有两个选择。 我仍然希望保持“每个请求一个会话”(“每个hub一个会话”,“每个工作一个会话”)。
选项1:
更改所有服务将具有InstancePerLifetimeScope。 实例化服务并不昂贵。 对于维护某种状态的服务,我将创建另一个“存储”(类),它将是SingleInstance,并且不会依赖于会话(DbContext)。 我认为这也适用于聊天室和工作。
选项2:
创建一种工厂,如@Ric .Net建议的那样。 类似于下面这样:
public class DbFactory: IDbFactory
{
public MyDbContext GetDb()
{
if (HttpContext.Current != null)
{
var db = HttpContext.Current.Items["db"] as MyDbContext;
if (db == null)
{
db = new MyDbContext();
HttpContext.Current.Items["db"] = db;
}
return db;
}
// What to do for jobs and hubs?
return new MyDbContext();
}
}
protected void Application_EndRequest(object sender, EventArgs e)
{
var db = HttpContext.Current.Items["db"] as MyDbContext;
if (db != null)
{
db.Dispose();
}
}
我认为这对于MVC来说是可行的,但我不知道如何使其适用于hubs(每个hub调用都是该hub的新实例)和jobs(每次运行作业都是该作业类的新实例)。
我倾向于选项1。你觉得呢?
非常感谢!