依赖注入以包含 post-构造操作?
Dependency injection to include post-construction actions?
在我们的解决方案中,我们使用依赖注入来实例化许多其他服务所依赖的 DbContext
class 的实例:
var container = new UnityContainer();
container.RegisterType<OurAppDbContext>(new PerThreadLifetimeManager());
// ... A bunch of services that take a new OurAppDbContext as an argument
这成功地用它们自己的 OurAppDbContext
个实例实例化了十几个服务。
问题
OurAppDbContext
构造函数(由 EntityFramework 自动生成,因此不可编辑)不足以满足我们的目的。如果我们按照自己的方式进行,每个实例都将这样构造:
OurAppDbContext newDbContext = new OurAppDbContext();
newDbContext.Database.Log += log => Debug.WriteLine(log);
return newDbContext;
现在,我们可以挂接此事件的方法是在获取这些实例之一的每个服务的每个构造函数中。例如:
public class AdminDataRepository : IAdminDataRepository
{
private readonly OurAppDbContext _dbContext;
public AdminDataRepository(OurAppDbContext dbContext)
{
_dbContext = dbContext;
_dbContext.Database.Log += log => Debug.WriteLine(log);
...
但我们不希望将此代码复制粘贴到 10 多个不同的服务构造函数中,因为这会成为维护的难题,我们可能会在一些地方遗漏它,或者它们可能会不同步等。
有没有办法指示依赖注入器对它构造的每个 OurAppDbContext
执行此操作 - 在将它传递给它正在构造的任何依赖于它的服务之前?
我想到了一个可能的解决方案,事实证明它有效!
我们可以创建我们自己的 DBContext
class 从 EF 自动生成的派生:
public class LoggingOurAppDbContext : OurAppDbContext
{
public LoggingOurAppDbContext() : base()
{
this.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
}
}
并指示 Unity(依赖注入)创建这些实例而不是 EF 生成的实例。
它应该“正常工作”——甚至不需要编辑依赖于 PortfolioAccumulationDbContext 实例的所有服务的构造函数参数——因为继承使这两种类型可以互换。
我熟悉提供具体类型以在需要时作为依赖项实现接口的语法:
container.RegisterType<ISomeInterface, SomeConcreteType>();
但我不确定它是否适用于我的情况,因为 entity framework 自动生成的基础 OurAppDbContext
没有实现任何类型的接口,所有需要接口的服务都需要一个具体类型的实例 OurAppDbContext
。事实证明,相同的语法可用于提供更派生的类型以满足已经具体的类型参数:
container.RegisterType<OurAppDbContext, LoggingOurAppDbContext>(...);
问题已解决。
您可以使用工厂委托进行注册:
container.RegisterFactory<OurAppDbContext>(c =>
{
OurAppDbContext newDbContext = new OurAppDbContext();
newDbContext.Database.Log += log => Debug.WriteLine(log);
return newDbContext;
},
new PerThreadLifetimeManager());
在我们的解决方案中,我们使用依赖注入来实例化许多其他服务所依赖的 DbContext
class 的实例:
var container = new UnityContainer();
container.RegisterType<OurAppDbContext>(new PerThreadLifetimeManager());
// ... A bunch of services that take a new OurAppDbContext as an argument
这成功地用它们自己的 OurAppDbContext
个实例实例化了十几个服务。
问题
OurAppDbContext
构造函数(由 EntityFramework 自动生成,因此不可编辑)不足以满足我们的目的。如果我们按照自己的方式进行,每个实例都将这样构造:
OurAppDbContext newDbContext = new OurAppDbContext();
newDbContext.Database.Log += log => Debug.WriteLine(log);
return newDbContext;
现在,我们可以挂接此事件的方法是在获取这些实例之一的每个服务的每个构造函数中。例如:
public class AdminDataRepository : IAdminDataRepository
{
private readonly OurAppDbContext _dbContext;
public AdminDataRepository(OurAppDbContext dbContext)
{
_dbContext = dbContext;
_dbContext.Database.Log += log => Debug.WriteLine(log);
...
但我们不希望将此代码复制粘贴到 10 多个不同的服务构造函数中,因为这会成为维护的难题,我们可能会在一些地方遗漏它,或者它们可能会不同步等。
有没有办法指示依赖注入器对它构造的每个 OurAppDbContext
执行此操作 - 在将它传递给它正在构造的任何依赖于它的服务之前?
我想到了一个可能的解决方案,事实证明它有效!
我们可以创建我们自己的 DBContext
class 从 EF 自动生成的派生:
public class LoggingOurAppDbContext : OurAppDbContext
{
public LoggingOurAppDbContext() : base()
{
this.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
}
}
并指示 Unity(依赖注入)创建这些实例而不是 EF 生成的实例。
它应该“正常工作”——甚至不需要编辑依赖于 PortfolioAccumulationDbContext 实例的所有服务的构造函数参数——因为继承使这两种类型可以互换。
我熟悉提供具体类型以在需要时作为依赖项实现接口的语法:
container.RegisterType<ISomeInterface, SomeConcreteType>();
但我不确定它是否适用于我的情况,因为 entity framework 自动生成的基础 OurAppDbContext
没有实现任何类型的接口,所有需要接口的服务都需要一个具体类型的实例 OurAppDbContext
。事实证明,相同的语法可用于提供更派生的类型以满足已经具体的类型参数:
container.RegisterType<OurAppDbContext, LoggingOurAppDbContext>(...);
问题已解决。
您可以使用工厂委托进行注册:
container.RegisterFactory<OurAppDbContext>(c =>
{
OurAppDbContext newDbContext = new OurAppDbContext();
newDbContext.Database.Log += log => Debug.WriteLine(log);
return newDbContext;
},
new PerThreadLifetimeManager());