本文介绍了EF 7(核心).创建类似AddTransient的DBContext的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据文档,当我像下面的DI那样配置DbContext时,将其注册到范围内(按http请求)

According to documents when I configure DbContext like below DI register it in scope (per http request)

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

当我尝试在另一个线程中访问它时,会出现问题.

The problem appears when I am trying to access it in another thread.

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创建.这将使我有可能编写下一个代码

I want to configure DbContext creation per each call (AddTransition). It would give me possibility to write next code

    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.

So now if I want to create DBContext per request I will use IUnitOfWorkFactoryPerRequest, and when I want to use DBContext in some background thread I can use IUnitOfWorkFactoryPerCall.

推荐答案

我的临时解决方案.我创建了单例,该单例可以以瞬时方式"创建上下文

My temporary solution.I created singleton which can create Context "in transient way"

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

然后我在启动配置方法中调用init方法

Then I call init method in Startup Configure method

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

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

And after all I can call AppDependencyResolver.Current.CreateUoWinCurrentThread() in some background thread.

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

If someone can provide more elegant solution I will be appreciated.

这篇关于EF 7(核心).创建类似AddTransient的DBContext的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-27 10:24