问题描述
根据文档,当我像下面的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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!