引导 Unity - Composition Root 位置
Bootstrapping Unity - Composition Root location
我有一个简单的 .NET 项目,我想知道引导 Unity 的最佳方法是什么。
我从一个带有一堆控制器的 WebApp 开始。这些控制器中的每一个都有自己的处理程序 class,控制器将实现委托给该处理程序。内容如下:
public class UsersHandler : IUsers
{
IAuthenticationClient authenticationClient;
ILogger logger;
public UsersHandler(IAuthenticationClient authClient, ILogger logger) { ... }
}
在 Global.asax 的 Application_Start 方法中,我正在创建 UnityContainer 并注册类型。
还有第二个项目(Class 库),它基本上是业务层。
我现在创建了一个新的 class 库(我们称之为 'XYZ')来处理应用程序的不同职责。这里也使用了 DI。
对于初学者,我创建了一个 Singleton class 作为该项目的入口点,我在其中实例化 UnityContainer 并注册类型。
现在我有了这个工作,我开始想知道应该由谁来处理类型注册,也就是说,我的应用程序的组合根应该是什么。 WebApp 将是首选,但这需要添加对 'XYZ' 项目的引用,这感觉不对,因为它被业务层使用。
1) Composition root 是否应该是一个新的 class 库,同时引用 WebApp 和 'XYZ' 并在我的 WebApp 的 global.asax 中初始化?
但是,这会导致循环依赖,因为这个 Bootstrapper 项目会知道 WebApp,反之亦然。
2) 如果我需要解决 'XYZ' 项目中的依赖关系怎么办?目前我有一个 UnityContainer class 的实例,所以我可以这样做:
var logger = container.Resolve<ILogger>();
无论如何,这是一个好习惯吗?
- 你应该在启动方法中执行一次
- 您可以实现 Unity 依赖解析器,而不要执行
container.Resolve<IDependency>()
之类的代码
你可以在这里阅读一篇关于它的非常好的文章https://www.asp.net/web-api/overview/advanced/dependency-injection
赞 this 说得很好
"All components in an application should be composed as late as
possible"
然后您应该将它们组合到 WebApp 项目的 global.asax 中。 全部(基本回答了两个问题)
组合根是组合应用程序中所有模块的地方。
在您的情况下,WebApp 将是该项目,因此应引用您解决方案中的所有项目。
WebApp 应该指业务层、XYZ 和您添加的所有其他项目。
"However, that would cause a circular dependency.."
不,只有组合根引用解决方案中的项目。
那么业务层和XYZ是如何协同工作的呢?
他们没有。 DIP 的核心原则是依赖于抽象,要在您的解决方案中充分使用 DIP,您需要正确设计代码。
假设我们在业务层项目中有一个 class 依赖于 XYZ 项目
using XYZ;
namespace BusinessLayer
{
public class businessData
{
public int GetData()
{
var data = new XYZData(); //from the XYZ project
return data
}
}
}
而这个 class 在 XYZ 项目中
namespace XYZ
{
public class XYZData
{
public int GetData()
{
return 1;
}
}
}
现在我们有了项目 BusinessLayer 和 XYZ 之间的依赖关系。
为了解决这个问题,我们需要让 BusinessLayer 中的 businessData 依赖于抽象而不是细节。
要做到这一点,我们需要使用接口来消除 classes 之间的依赖关系,当处理好后,我们不需要在 BusinessLayer 项目中引用 XYZ,因为它不在再用了。
但是我们在哪里存储接口?
为此,您创建了一个 ModelProject,解决方案中的所有项目都将引用它。 ModelProject 不引用任何东西,因为它的目的是仅存储 DTO 和接口等。
解决方案中的引用应该是这样的(对不起我的绘画技巧z):
其中 WebApp 作为组合根,应指代解决方案中的所有项目。其余项目应该只参考ModelProject
要解决 businessData 中的依赖关系,请将此接口添加到 Modelproject
namespace Modelproject
{
public interface IXYZData
{
int GetData();
}
}
然后在classes
中实现接口
商业项目
using Modelproject;
namespace BusinessLayer
{
public class businessData
{
private IXYZData _data;
public businessData(IXYZData data)
{
this._data = data;
}
public int GetData()
{
return _data.GetData();
}
}
}
对于 XYZ 项目
using Modelproject;
namespace XYZ
{
public class XYZData: IXYZData
{
public int GetData()
{
return 1;
}
}
}
然后在 WebApp 的 global.asax 中用 XYZData class 解析接口 IXYZData。
通过 Unity 那将是
var container = new UnityContainer();
container.RegisterType<IXYZData, XYZData>(new HierarchicalLifetimeManager());
GlobalConfiguration.Configuration.DependencyResolver = new UnityResolver(container);
希望这有帮助,干杯
更新:
如果您想在另一个 class 中使用 businessData class,您应该应用与我们在添加接口的 XYZData class 上所做的相同的结构。
namespace Modelproject
{
public interface IbusinessData
{
int GetData();
}
}
然后将接口继承添加到class
using Modelproject;
namespace BusinessLayer
{
public class businessData: IbusinessData
{
.....
最后告诉 Global.asax 中的 Unity 容器将接口解析到 class
container.RegisterType<IbusinessData, businessData>(new HierarchicalLifetimeManager());
现在,在每个需要使用 IbusinessData 的 class 中,将其添加到 class 的构造函数中,就像我们在 businessData 构造函数中所做的那样,然后 Unity 将确保注入所有在运行时创建 class 时的依赖项。
我有一个简单的 .NET 项目,我想知道引导 Unity 的最佳方法是什么。 我从一个带有一堆控制器的 WebApp 开始。这些控制器中的每一个都有自己的处理程序 class,控制器将实现委托给该处理程序。内容如下:
public class UsersHandler : IUsers
{
IAuthenticationClient authenticationClient;
ILogger logger;
public UsersHandler(IAuthenticationClient authClient, ILogger logger) { ... }
}
在 Global.asax 的 Application_Start 方法中,我正在创建 UnityContainer 并注册类型。 还有第二个项目(Class 库),它基本上是业务层。
我现在创建了一个新的 class 库(我们称之为 'XYZ')来处理应用程序的不同职责。这里也使用了 DI。
对于初学者,我创建了一个 Singleton class 作为该项目的入口点,我在其中实例化 UnityContainer 并注册类型。
现在我有了这个工作,我开始想知道应该由谁来处理类型注册,也就是说,我的应用程序的组合根应该是什么。 WebApp 将是首选,但这需要添加对 'XYZ' 项目的引用,这感觉不对,因为它被业务层使用。
1) Composition root 是否应该是一个新的 class 库,同时引用 WebApp 和 'XYZ' 并在我的 WebApp 的 global.asax 中初始化? 但是,这会导致循环依赖,因为这个 Bootstrapper 项目会知道 WebApp,反之亦然。
2) 如果我需要解决 'XYZ' 项目中的依赖关系怎么办?目前我有一个 UnityContainer class 的实例,所以我可以这样做:
var logger = container.Resolve<ILogger>();
无论如何,这是一个好习惯吗?
- 你应该在启动方法中执行一次
- 您可以实现 Unity 依赖解析器,而不要执行
container.Resolve<IDependency>()
之类的代码
你可以在这里阅读一篇关于它的非常好的文章https://www.asp.net/web-api/overview/advanced/dependency-injection
赞 this 说得很好
"All components in an application should be composed as late as possible"
然后您应该将它们组合到 WebApp 项目的 global.asax 中。 全部(基本回答了两个问题)
组合根是组合应用程序中所有模块的地方。 在您的情况下,WebApp 将是该项目,因此应引用您解决方案中的所有项目。 WebApp 应该指业务层、XYZ 和您添加的所有其他项目。
"However, that would cause a circular dependency.."
不,只有组合根引用解决方案中的项目。
那么业务层和XYZ是如何协同工作的呢?
他们没有。 DIP 的核心原则是依赖于抽象,要在您的解决方案中充分使用 DIP,您需要正确设计代码。
假设我们在业务层项目中有一个 class 依赖于 XYZ 项目
using XYZ;
namespace BusinessLayer
{
public class businessData
{
public int GetData()
{
var data = new XYZData(); //from the XYZ project
return data
}
}
}
而这个 class 在 XYZ 项目中
namespace XYZ
{
public class XYZData
{
public int GetData()
{
return 1;
}
}
}
现在我们有了项目 BusinessLayer 和 XYZ 之间的依赖关系。 为了解决这个问题,我们需要让 BusinessLayer 中的 businessData 依赖于抽象而不是细节。
要做到这一点,我们需要使用接口来消除 classes 之间的依赖关系,当处理好后,我们不需要在 BusinessLayer 项目中引用 XYZ,因为它不在再用了。
但是我们在哪里存储接口?
为此,您创建了一个 ModelProject,解决方案中的所有项目都将引用它。 ModelProject 不引用任何东西,因为它的目的是仅存储 DTO 和接口等。
解决方案中的引用应该是这样的(对不起我的绘画技巧z):
其中 WebApp 作为组合根,应指代解决方案中的所有项目。其余项目应该只参考ModelProject
要解决 businessData 中的依赖关系,请将此接口添加到 Modelproject
namespace Modelproject
{
public interface IXYZData
{
int GetData();
}
}
然后在classes
中实现接口商业项目
using Modelproject;
namespace BusinessLayer
{
public class businessData
{
private IXYZData _data;
public businessData(IXYZData data)
{
this._data = data;
}
public int GetData()
{
return _data.GetData();
}
}
}
对于 XYZ 项目
using Modelproject;
namespace XYZ
{
public class XYZData: IXYZData
{
public int GetData()
{
return 1;
}
}
}
然后在 WebApp 的 global.asax 中用 XYZData class 解析接口 IXYZData。 通过 Unity 那将是
var container = new UnityContainer();
container.RegisterType<IXYZData, XYZData>(new HierarchicalLifetimeManager());
GlobalConfiguration.Configuration.DependencyResolver = new UnityResolver(container);
希望这有帮助,干杯
更新:
如果您想在另一个 class 中使用 businessData class,您应该应用与我们在添加接口的 XYZData class 上所做的相同的结构。
namespace Modelproject
{
public interface IbusinessData
{
int GetData();
}
}
然后将接口继承添加到class
using Modelproject;
namespace BusinessLayer
{
public class businessData: IbusinessData
{
.....
最后告诉 Global.asax 中的 Unity 容器将接口解析到 class
container.RegisterType<IbusinessData, businessData>(new HierarchicalLifetimeManager());
现在,在每个需要使用 IbusinessData 的 class 中,将其添加到 class 的构造函数中,就像我们在 businessData 构造函数中所做的那样,然后 Unity 将确保注入所有在运行时创建 class 时的依赖项。