根据文档,当我像下面的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
发布评论