Unity 依赖性未在任务中解决
Unity dependency not resolving in task
我不确定如何解决我目前的情况。我正在尝试创建任务:
public class whatever
{
[Dependency]
public IReportingBL ReportingBL { get; set; }
private whatever()
{
...task factory creation, etc.
}
private readonly static Lazy<whatever> _instance = new Lazy<whatever>(() => new whatever());
public static whatever Instance { get { return _instance.Value; }
public Task GetStuff()
{
return _taskFactory.StartNew(() =>
{
return ReportingBL.Method1;
});
}
}
ReportingBL 没有得到解决。如果我在线程内创建 ReportingBL 的新实例,则它下面的层不会得到解析。
在这种情况下,如何让 unity 发挥作用?
您正在应用 Singleton Design Pattern. This is a pattern that is frown upon and considered an anti-pattern by some. In Dependency Injection terminology the Singleton pattern can be considered an Ambient Context,这是一种几乎不应该在依赖注入上下文中使用的模式。
单例设计模式不能很好地与依赖注入一起工作,因为:
- 通过依赖注入,应用程序的 Composition Root 可以控制实例的创建和缓存;不是实例本身。
- 让消费者依赖 public
Instance
字段,导致消费者违反依赖倒置原则并不允许实例被替换、模拟、修饰或拦截。这阻碍了应用程序的可维护性和可测试性。
此外,在您的代码中我没有看到任何对 Unity DI 框架的调用。请记住,DI 容器不是可以让 classes 被初始化 'by them selves' 的神奇工具。在您的代码中,您直接 new whatever
; Unity 不参与其中。 Unity(或与此相关的任何 DI 库)只有在控制对象时才能自动连接对象。换句话说,您必须调用 container.Resolve<whatever>()
让 Unity 构建您的实例。
尽管您可以从 Lazy<T>
工厂委托中调用 container.Resoolve
,但这会强制 class 依赖于容器本身,这通常被称为 Service Locator anti-pattern.
相反,我建议对您的设计进行以下更改:
- 使用构造函数注入代替 属性 注入。 属性 注射导致 Temporal Coupling.
- 使组合根和容器负责连接对象图。
- 远离单例设计模式;改用容器的单例生活方式。
这导致以下代码:
public interface IWhatever
{
Task GetStuff();
}
public class Whatever : IWhatever
{
private readonly IReportingBL reportingBL;
public whatever(IReportingBL reportingBL) {
this.reportingBL = reportingBL;
}
public Task GetStuff() {
return _taskFactory.StartNew(() => {
return ReportingBL.Method1;
});
}
}
// Some consumer of whatever
public class MyController : Controller
{
private readonly IWhatever whatever;
public MyController(IWhatever whatever) {
this.whatever = whatever;
}
public ActionResult Index() {
return View(this.whatever.GetStuff());
}
}
在你的composition root中,你可以配置class如下:
var container = new UnityContainer();
container.RegisterType<IReportingBL, ReportingBL>(
new ContainerControlledLifetimeManager());
container.RegisterType<IWhatever, Whatever>(
new ContainerControlledLifetimeManager());
var controller = container.Resolve<MyController>();
controller.Index();
我不确定如何解决我目前的情况。我正在尝试创建任务:
public class whatever
{
[Dependency]
public IReportingBL ReportingBL { get; set; }
private whatever()
{
...task factory creation, etc.
}
private readonly static Lazy<whatever> _instance = new Lazy<whatever>(() => new whatever());
public static whatever Instance { get { return _instance.Value; }
public Task GetStuff()
{
return _taskFactory.StartNew(() =>
{
return ReportingBL.Method1;
});
}
}
ReportingBL 没有得到解决。如果我在线程内创建 ReportingBL 的新实例,则它下面的层不会得到解析。
在这种情况下,如何让 unity 发挥作用?
您正在应用 Singleton Design Pattern. This is a pattern that is frown upon and considered an anti-pattern by some. In Dependency Injection terminology the Singleton pattern can be considered an Ambient Context,这是一种几乎不应该在依赖注入上下文中使用的模式。
单例设计模式不能很好地与依赖注入一起工作,因为:
- 通过依赖注入,应用程序的 Composition Root 可以控制实例的创建和缓存;不是实例本身。
- 让消费者依赖 public
Instance
字段,导致消费者违反依赖倒置原则并不允许实例被替换、模拟、修饰或拦截。这阻碍了应用程序的可维护性和可测试性。
此外,在您的代码中我没有看到任何对 Unity DI 框架的调用。请记住,DI 容器不是可以让 classes 被初始化 'by them selves' 的神奇工具。在您的代码中,您直接 new whatever
; Unity 不参与其中。 Unity(或与此相关的任何 DI 库)只有在控制对象时才能自动连接对象。换句话说,您必须调用 container.Resolve<whatever>()
让 Unity 构建您的实例。
尽管您可以从 Lazy<T>
工厂委托中调用 container.Resoolve
,但这会强制 class 依赖于容器本身,这通常被称为 Service Locator anti-pattern.
相反,我建议对您的设计进行以下更改:
- 使用构造函数注入代替 属性 注入。 属性 注射导致 Temporal Coupling.
- 使组合根和容器负责连接对象图。
- 远离单例设计模式;改用容器的单例生活方式。
这导致以下代码:
public interface IWhatever
{
Task GetStuff();
}
public class Whatever : IWhatever
{
private readonly IReportingBL reportingBL;
public whatever(IReportingBL reportingBL) {
this.reportingBL = reportingBL;
}
public Task GetStuff() {
return _taskFactory.StartNew(() => {
return ReportingBL.Method1;
});
}
}
// Some consumer of whatever
public class MyController : Controller
{
private readonly IWhatever whatever;
public MyController(IWhatever whatever) {
this.whatever = whatever;
}
public ActionResult Index() {
return View(this.whatever.GetStuff());
}
}
在你的composition root中,你可以配置class如下:
var container = new UnityContainer();
container.RegisterType<IReportingBL, ReportingBL>(
new ContainerControlledLifetimeManager());
container.RegisterType<IWhatever, Whatever>(
new ContainerControlledLifetimeManager());
var controller = container.Resolve<MyController>();
controller.Index();