我有一个 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();