[英]EF 7 (Core). Create DBContext like AddTransient
根據文檔,我在下面配置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();
}
}
我想為每個調用配置DbContext創建(AddTransition)。 它可以讓我編寫下一個代碼
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
,當我想在某些后台線程中使用IUnitOfWorkFactoryPerCall
我可以使用IUnitOfWorkFactoryPerCall
。
我的臨時解決方案 我創建了單例,它可以“以瞬態方式”創建上下文
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()
。
如果有人能提供更優雅的解決方案,我將不勝感激。
在你的控制器中,你為什么要嘗試注入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();
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.