DbContext 已被處理和 autofac
我有一個控制器:
private readonly ILogger _logger; private readonly IRepository _repository; public HomeController(ILogger logger, IRepository repository) { _logger = logger; _repository = repository; }這是儲存庫:
public class EfRepository : IRepository { // ...methods for add, delete, update entities // .... public void Dispose() { if (this._context != null) { this._context.SaveChanges(); (this._context as IDisposable).Dispose(); this._context = null; } } }最後,IoC 中的註冊類型:
_builder.RegisterType<Logger>().As<ILogger>(); _builder.RegisterType<EfRepository>().As<IRepository>().WithParameter("context", new PcpContext());當我執行應用程序時,我收到此錯誤:
操作無法完成,因為 DbContext 已被釋放。
我嘗試像這樣更改註冊 EfRepository:
_builder.RegisterType<EfRepository>() .As<IRepository>() .WithParameter("context", new PcpContext()).InstancePerLifetimeScope();在這種情況下,第一個請求完成,但在嘗試打開其他頁面時,我再次收到錯誤。哪裡有問題?
使用 WithParameter 方法時,每個已解析對象的參數實例都是相同的。因此,
.WithParameter("context", new PcpContext())您可以有效地將 PcpContext 類的相同實例用於任何已解析的 IRepository 實例。使用您目前的程式碼,當一個 IRepository 實例被釋放時,它也會釋放該 PcpContext 實例。然後,任何後續嘗試解析 IRepository 都將收到已釋放的 PcpContext 實例。您需要一種在請求結束時處理的每個 Http 請求上接收 EF DbContext 的新實例的方法。
一種選擇是為 IRepository 註冊一個程式碼塊,以便每次需要解析 IRepository 時執行程式碼塊:
_builder.Register<IRepository>(c => new EfRepository(new PcpContext()))更好的選擇是創建一個新的
IDatabaseContext抽象,更新EfRepository它依賴於新的 IDatabaseContext 抽象而不是PcpContext類(可能已經是這種情況:))。IDatabaseContext 的實現類將是您的 PcpContext 類,它必須從 EF DbContext 繼承,並且可能接收連接字元串作為參數。
public class EfRepository : IRepository { private readonly IDatabaseContext _context; public EfRepository(IDatabaseContext context) { _context = context; } ...methods for add, delete, update entities //There is no longer need for this to be disposable. //The disaposable object is the database context, and Autofac will take care of it //public void Dispose() } public interface IDatabaseContext : IDisposable { ... declare methods for add, delete, update entities } public class PcpContext: DbContext, IDatabaseContext { public EntityFrameworkContext(string connectionString) : base(connectionString) { } ...methods exposing EF for add, delete, update entities //No need to implement IDisposable as we inherit from DbContext //that already implements it and we don´t introduce new resources that should be disposed of }使用 IoC 容器並將生命週期管理的負擔留給它們的想法會變得更好。現在您的 Repository 類不需要是一次性的,也不需要管理和處理其 IDatabaseContext 依賴項。Autofac 將跟踪上下文實例並在適當的時候處理它。
出於同樣的原因,您可能希望將 InstancePerLifetimeScope 與數據庫上下文依賴項一起使用。這意味著同一 Http 請求上的每個儲存庫實例都共享相同的 EF 上下文,並在請求結束時處理。
_builder.RegisterType<EfRepository>() .As<IRepository>(); _builder.RegisterType<PcpContext>() .As<IDatabaseContext>() .WithParameter("connectionString", "NameOfConnStringInWebConfig") .InstancePerLifetimeScope();