【问题标题】:EF 7 (Core). Create DBContext like AddTransientEF 7(核心)。创建 DBContext 像 AddTransient
【发布时间】:2016-01-22 16:59:11
【问题描述】:

根据我配置 DbContext 时的文档,如下 DI 将其注册在范围内(每个 http 请求)

services.AddEntityFramework()
   .AddSqlServer()
   .AddDbContext<DBData>(options => {
        options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]);                    
    }
);

当我试图在另一个线程中访问它时出现问题。

public class HomeController : Controller
{
    private readonly DBData _context;

    public HomeController(DBData context)
    {
        _context = context;
    }

    public IActionResult StartInBackground()
    {
        Task.Run(() =>
            {
                Thread.Sleep(3000);
                //System.ObjectDisposedException here
                var res = _context.Users.FirstOrDefault(x => x.Id == 1);
            });

        return View();
    }
}

我想为每次调用 (AddTransition) 配置 DbContext 创建。这将使我有可能编写下一个代码

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddEntityFramework()
            .AddSqlServer()
            .AddDbContext<DBData>(options => {
                //somehow configure it to use AddTransient
                options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]);                    
                }
            );

        services.AddTransient<IUnitOfWorkFactoryPerCall, UnitOfWorkFactory>();
        services.AddScoped<IUnitOfWorkFactoryPerRequest, UnitOfWorkFactory>();

        services.AddMvc();
    }

    public interface IUnitOfWorkFactoryPerCall : IUnitOfWorkFactory { }
    public interface IUnitOfWorkFactoryPerRequest : IUnitOfWorkFactory { }

    public interface IUnitOfWorkFactory : IDisposable
    {
       DBData Context { get; }
    }

    public class UnitOfWorkFactory : IUnitOfWorkFactoryPerCall, IUnitOfWorkFactoryPerRequest
    {
        public UnitOfWorkFactory(DBData context)
        {
            Context = context;
        }

        public DBData Context
        {
            get; private set;
        }

        public void Dispose()
        {
            Context.Dispose();
        }
    }

所以现在如果我想为每个请求创建 DBContext,我将使用 IUnitOfWorkFactoryPerRequest,而当我想在某个后台线程中使用 DBContext 时,我可以使用 IUnitOfWorkFactoryPerCall

【问题讨论】:

  • 你有什么消息吗?有类似的任务在另一个线程中使用 DbContext。

标签: c# asp.net-core asp.net-core-mvc entity-framework-core


【解决方案1】:

我的临时解决方案。 我创建了可以“以瞬时方式”创建上下文的单例

public class AppDependencyResolver
{
    private static AppDependencyResolver _resolver;

    public static AppDependencyResolver Current
    {
        get
        {
            if (_resolver == null)
                throw new Exception("AppDependencyResolver not initialized. You should initialize it in Startup class");
            return _resolver;
        }
    }

    public static void Init(IServiceProvider services)
    {
        _resolver = new AppDependencyResolver(services);
    }

    private readonly IServiceProvider _serviceProvider;

    public AppDependencyResolver(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public IUnitOfWorkFactory CreateUoWinCurrentThread()
    {
        var scopeResolver = _serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope();
        return new UnitOfWorkFactory(scopeResolver.ServiceProvider.GetRequiredService<DBData>(), scopeResolver);
    }
}

然后我在Startup Configure方法中调用init方法

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    AppDependencyResolver.Init(app.ApplicationServices);
    //other configure code
}

毕竟我可以在某个后台线程中调用AppDependencyResolver.Current.CreateUoWinCurrentThread()

如果有人能提供更优雅的解决方案,我将不胜感激。

【讨论】:

    【解决方案2】:

    在你的控制器中,你为什么要注入private readonly DBData _context;?如果您已经通过 DI 注册了您的 IUnitOfWorkFactoryPerCall,您应该将其注入您的控制器中,我相信?然后,您可以通过界面访问您的上下文。

    为了扩展,我建议你这样做:

    public class HomeController : Controller
    {
        private readonly IUnitOfWorkFactoryPerCall _contextFactory;
    
        public HomeController(IUnitOfWorkFactoryPerCall contextFactory)
        {
            _contextFactory = contextFactory;
        }
    
        public IActionResult StartInBackground()
        {
            Task.Run(() =>
                {
                    Thread.Sleep(3000);
                    //System.ObjectDisposedException here
                    var res = _contextFactory.Context.Users.FirstOrDefault(x => x.Id == 1);
                });
    
            return View();
        }
    }
    

    【讨论】:

    • 它不起作用,因为 DBData 仍在范围内解析。所以我所有关于如何为每次调用配置 DBContext 创建的问题。
    猜你喜欢
    • 2019-06-10
    • 1970-01-01
    • 2020-01-16
    • 1970-01-01
    • 1970-01-01
    • 2021-08-17
    • 1970-01-01
    • 2018-10-30
    • 2020-11-14
    相关资源
    最近更新 更多