加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net-mvc – Autofac(MVC EF SignalR Hangfire)生命周期范围

发布时间:2020-12-16 06:38:56 所属栏目:asp.Net 来源:网络整理
导读:我有一个ASP.NET MVC项目,它使用Entity Framwork,SignalR和Hangfire作业. 我的主(根)容器以这种方式定义: builder.RegisterTypeDbContext().InstancePerLifetimeScope(); // EF Db Contextbuilder.RegisterTypeChatService().AsIChatService().SingleInstan
我有一个ASP.NET MVC项目,它使用Entity Framwork,SignalR和Hangfire作业.

我的主(根)容器以这种方式定义:

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();

对于MVC,我使用的是Autofac.MVC5 nuget包.依赖性解析器:

DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

对于SignalR,我正在使用Autofac.SignalR nuget包.依赖性解析器:

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,我使用的是Hangfire.Autofac包:

config.UseActivator(new AutofacJobActivator(container));

作业以这种方式实例化:

private readonly ILifetimeScope _jobScope;
protected IChatService ChatService;
protected BaseJob(ILifetimeScope scope)
{
    _jobScope = scope.BeginLifetimeScope();
    ChatService = _jobScope.Resolve<IChatService>();
}
public void Dispose()
{
    _jobScope.Dispose();
}

问题/问题:
我总是在集线器和作业中获得相同的DbContext实例.我希望所有集线器实例都能获得相同的ChatService,但DbContext(它是ChatService的依赖项)将始终是一个新实例. Hangfire的工作也应该是一样的.

可以这样做,还是我错过了什么?

更新1:

思考(睡过头)后,我想我有两个选择.我仍然希望保持“每个请求的会话”(“每个集群的会话”,“每个作业的会话”).

选项1:

更改所有服务将具有InstancePerLifetimeScope.实例化服务并不昂贵.对于维护某种状态的服务,我将创建另一个“存储”(类),它将是SingleInstance并且不依赖于session(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有用,但我不知道它是否适用于集线器(每个集线器调用是集线器的新实例)和作业(每次运行的作业都是作业类的新实例) .

我倾向于选项1.你怎么看?

非常感谢!

解决方法

我对AutoFac完全缺乏经验.但引起我注意的是:

I want that all hub instances will get the same ChatService,but the DbContext (which is dependency of ChatService) will always be a new instance.

你在这里基本上说的是:

“我的汽车是由依赖车库的汽车公司进行维修的,但每次我带车时我都希望车库成为新车”.

当您在其他组件中注入(完全构建实例,包括依赖项)ChatService时,当然还会构建其他依赖项,无论它们是否具有其他类型的生活方式.当创建一个比它注入的对象更短的生命周期的对象时,你创建了一个所谓的’captive dependency‘

在ChatService中获取DbContext的新“实例”的唯一方法不是注入DbContext本身,而是注入一个DbContextFactory,只要你使用它就会为你创建DbContext.

实现看起来像:

public class DbContextFactory
{
    public DbContext Create()
    {
         return new DbContext();
    }
}

//usage:
public class ChatService
{
     private readonly DbContextFactory dbContextFactory;

     public ChatService(DbContextFactory dbContextFactory)
     {
         this.dbContextFactory = dbContextFactory;
     }

    public void SomeMethodInChatService()
    {
         using (var db = this.dbContextFactory.Create())
         {
             //do something with DbContext    
         }
     }
}

可以使用Singleton Lifestyle在AutoFac中注册DbContextFactory.

然而,这可能不是你的目标.因为在这种情况下,每次使用DbContext时都会得到一个新的.另一方面,新的DbContext可能是最安全的方法,你可以阅读here.

这个伟大的答案值得阅读,原因不止一个,因为它解释了如何使用command / handler pattern,这应该非常适合您的情况.

这将使您的聊天服务完全不知道DbContext,它改进了应用程序的’SOLID‘设计,并创建了测试ChatService的可能性,这是在直接注入DbContext或DbContextFactory时几乎可以撤销的.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读