Asp.net-Mvc

DbContext 已被處理和 autofac

  • November 20, 2015

我有一個控制器:

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

引用自:https://stackoverflow.com/questions/14919543