我有一个 Controller :

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

当我运行应用程序时,出现以下错误:



我试图像这样更改注册EfRepository:
_builder.RegisterType<EfRepository>()
   .As<IRepository>()
   .WithParameter("context", new PcpContext()).InstancePerLifetimeScope();

在这种情况下,第一个请求完成,但是在尝试打开其他页面时,我再次收到错误消息。问题出在哪儿?

最佳答案

使用WithParameter方法时,每个解析对象的参数实例都相同。因此,使用.WithParameter("context", new PcpContext()),您可以为IRepository的任何已解析实例有效地使用PcpContext类的相同实例。

使用当前代码,在处置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与数据库上下文依赖项一起使用。这意味着相同的EF上下文将为同一Http请求上的每个存储库实例共享,并被放置在请求的末尾。
_builder.RegisterType<EfRepository>()
   .As<IRepository>();

_builder.RegisterType<PcpContext>()
   .As<IDatabaseContext>()
   .WithParameter("connectionString", "NameOfConnStringInWebConfig")
   .InstancePerLifetimeScope();

10-07 16:19