如何使用 Unity 容器从 Winforms 应用程序中的 BLL class 实例化 DAL class
How do I use Unity Container to Instantiate a DAL class From a BLL class in a Winforms App
我正在尝试在使用 Visual Studio 2015 和 .net 4.5.2 的 Winforms C# 解决方案中使用 Microsoft Unity 容器。和 Entity Framework 6.
我有一个包含以下项目的分层 WinForms 解决方案:
- AppStartup(仅设置 Unity 容器和注册。否 UI
这里)
- UI(用户界面)
- BLL(业务逻辑层)
- DAL(数据访问层)
我最初将 AppStartup 项目创建为 WinForms 应用程序,然后删除了所有 Winform 文件。 AppStartup 项目充当应用程序启动,其唯一目的是注册我的所有 Unity 容器类型,如下所示:
public class UnityFramework
{
public UnityContainer MyAppUnityContainer = null;
public UnityFramework()
{
ClassRegistrations();
}
private void ClassRegistrations()
{
MyAppUnityContainer = new UnityContainer();
MyAppUnityContainer.RegisterType<MyApp.BLL.IDepartmentDataServices,
MyApp.BLL.DepartmentDataServices>();
MyAppUnityContainer.RegisterType<MyApp.DAL.IDepartmentUnitOfWork,
MyApp.DAL.DepartmentUnitOfWork>();
}
}
为了让这个注册生效,我必须添加对 BLL 和 DAL 项目的引用。
UnityFrameworkclass从AppStartup项目program.cs文件调用如下:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Register interfaces and concrete classes
UnityFramework aUnityFramework = new UnityFramework();
Application.Run(new MyApp.UI.FormMain());
}
}
最后一行从 MyApp.UI 项目调用 UI,因此我还必须添加对 MyApp.UI 项目的引用。基本上,AppStartup 项目引用了我解决方案中的所有其他项目。
我希望 BLL 有一个名为 GetProductList() 的服务。接口及实现如下:
// Interface defined in BLL
public interface IDepartmentDataServices
{
List<Product> GetProductList();
}
// Interface implemented in BLL
public class DepartmentDataServices : IDepartmentDataServices
{
Public List<Product> GetProductList()
{
//Note: IDepartmentUnitOfWork is defined and implemented in the DAL
IDepartmentUnitOfWork aIDepartmentUnitOfWork =
MyAppUnityContainer.Resolve<IDepartmentUnitOfWork >();
return aIDepartmentUnitOfWork.GetProductList();
}
}
这是我做错的地方。我这里的问题是,定义为 MyAppUnityContainer 的 Unity 容器位于 AppStartup 项目中。我试图将 AppStartup 项目添加为对我的 BLL 项目的引用,但我不能,因为它警告循环依赖。也许我不应该使用 MyAppUnityContainer 在 BLL 中创建 aIDepartmentUnitOfWork 实例?
我考虑过将它作为参数传递到 UI 的 BLL 中的 DepartmentDataServices 具体 class 的构造函数中,但这意味着要尝试在 UI 中实例化它这也会导致循环依赖。
这些循环依赖错误是由于在 AppStartup 项目中引用的所有项目为 MyAppUnityContainer 注册类型。我可以在 AppStartup 项目中创建 DepartmentDataServices 实例,并将其作为参数传递给 UI 项目中的启动 WinForm,但这样做将使 UI 无需通过 BLL 即可获取部门数据.
我不喜欢这种尝试的另一件事是我没有在 BLL 和 DAL 中使用相同的 class DepartmentDataServices 名称来获取部门列表。我希望该服务在 BLL 和 DAL 中都被称为 DepartmentDataServices 但在这样做时我不知道 Unity 容器如何知道当我从 BLL 请求它时要使用哪个实现它来自 DAL。这就是为什么我让 BLL 使用 DepartmentDataServices 的名称,然后它使用名称 DepartmentUnitOfWork 再次从 DAL 请求服务。
我该如何实现它才能完成以下操作:
我的 UI 是有一个带有按钮的屏幕,按下该按钮将要求 BLL 使用 BLL 中的 DepartmentDataServices 具体 class 获取产品列表,这反过来又会导致 BLL 询问 DAL对于使用 DepartmentUnitOfWork 的 DAL 实现的产品列表。 DAL 是将 return 结果传给 BLL,后者又 return 将其传给 UI。
提前致谢。
解决方案是使用构造函数注入(这与您认为应该做的类似)。
这是一个例子:
public class DepartmentDataServices : IDepartmentDataServices
{
private readonly IDepartmentUnitOfWork m_DepartmentUnitOfWork;
public DepartmentDataServices(IDepartmentUnitOfWork uow)
{
m_DepartmentUnitOfWork = uow;
}
Public List<Product> GetProductList()
{
return m_DepartmentUnitOfWork.GetProductList();
}
}
现在,关于循环依赖问题:在 Composition Root 中组合你的对象。这意味着您不会在业务层中构造 DAL 对象,并且您不会在 UI 层中构造业务层对象。相反,您在 Composition Root 中构建整个对象图(所有层的所有对象),在您的例子中是 AppStartup 项目。
因此,UI 表单的构造函数应该接受对业务层类型(例如 IDepartmentDataServices
)的依赖,并且业务层对象的构造函数(例如 DepartmentDataServices
)应该接受对 DAL 类型的依赖(例如 IDepartmentUnitOfWork
)。
下面是如何在 AppStartup 项目中手动构造对象图的示例:
var uow = new DepartmentUnitOfWork(connection_string);
var service = new DepartmentDataServices(uow);
var form = MyApp.UI.FormMain(service);
Application.Run(form);
这是一个示例,说明如何在没有容器(称为 Pure DI)的情况下组合对象。我使用它只是为了让您了解构造函数注入的工作原理。但是您仍然可以使用 DI 容器。只需在 Composition Root 中注册这里的类型,然后让 DI 容器解析主要的 UI 对象,然后 DI 容器就会知道如何自动创建所有依赖项(一直到数据访问层对象) .这叫做自动接线。
请注意,Composition Root 是唯一应该使用 DI 容器的地方。使用其他项目中的容器(如您的示例)称为服务位置和 is considered an anti-pattern.
顺便说一句,两个类使用相同的名称是没有问题的,只要它们在不同的命名空间。就系统而言,这些 类 具有完全不同的名称。
我正在尝试在使用 Visual Studio 2015 和 .net 4.5.2 的 Winforms C# 解决方案中使用 Microsoft Unity 容器。和 Entity Framework 6.
我有一个包含以下项目的分层 WinForms 解决方案:
- AppStartup(仅设置 Unity 容器和注册。否 UI 这里)
- UI(用户界面)
- BLL(业务逻辑层)
- DAL(数据访问层)
我最初将 AppStartup 项目创建为 WinForms 应用程序,然后删除了所有 Winform 文件。 AppStartup 项目充当应用程序启动,其唯一目的是注册我的所有 Unity 容器类型,如下所示:
public class UnityFramework
{
public UnityContainer MyAppUnityContainer = null;
public UnityFramework()
{
ClassRegistrations();
}
private void ClassRegistrations()
{
MyAppUnityContainer = new UnityContainer();
MyAppUnityContainer.RegisterType<MyApp.BLL.IDepartmentDataServices,
MyApp.BLL.DepartmentDataServices>();
MyAppUnityContainer.RegisterType<MyApp.DAL.IDepartmentUnitOfWork,
MyApp.DAL.DepartmentUnitOfWork>();
}
}
为了让这个注册生效,我必须添加对 BLL 和 DAL 项目的引用。
UnityFrameworkclass从AppStartup项目program.cs文件调用如下:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Register interfaces and concrete classes
UnityFramework aUnityFramework = new UnityFramework();
Application.Run(new MyApp.UI.FormMain());
}
}
最后一行从 MyApp.UI 项目调用 UI,因此我还必须添加对 MyApp.UI 项目的引用。基本上,AppStartup 项目引用了我解决方案中的所有其他项目。
我希望 BLL 有一个名为 GetProductList() 的服务。接口及实现如下:
// Interface defined in BLL
public interface IDepartmentDataServices
{
List<Product> GetProductList();
}
// Interface implemented in BLL
public class DepartmentDataServices : IDepartmentDataServices
{
Public List<Product> GetProductList()
{
//Note: IDepartmentUnitOfWork is defined and implemented in the DAL
IDepartmentUnitOfWork aIDepartmentUnitOfWork =
MyAppUnityContainer.Resolve<IDepartmentUnitOfWork >();
return aIDepartmentUnitOfWork.GetProductList();
}
}
这是我做错的地方。我这里的问题是,定义为 MyAppUnityContainer 的 Unity 容器位于 AppStartup 项目中。我试图将 AppStartup 项目添加为对我的 BLL 项目的引用,但我不能,因为它警告循环依赖。也许我不应该使用 MyAppUnityContainer 在 BLL 中创建 aIDepartmentUnitOfWork 实例?
我考虑过将它作为参数传递到 UI 的 BLL 中的 DepartmentDataServices 具体 class 的构造函数中,但这意味着要尝试在 UI 中实例化它这也会导致循环依赖。
这些循环依赖错误是由于在 AppStartup 项目中引用的所有项目为 MyAppUnityContainer 注册类型。我可以在 AppStartup 项目中创建 DepartmentDataServices 实例,并将其作为参数传递给 UI 项目中的启动 WinForm,但这样做将使 UI 无需通过 BLL 即可获取部门数据.
我不喜欢这种尝试的另一件事是我没有在 BLL 和 DAL 中使用相同的 class DepartmentDataServices 名称来获取部门列表。我希望该服务在 BLL 和 DAL 中都被称为 DepartmentDataServices 但在这样做时我不知道 Unity 容器如何知道当我从 BLL 请求它时要使用哪个实现它来自 DAL。这就是为什么我让 BLL 使用 DepartmentDataServices 的名称,然后它使用名称 DepartmentUnitOfWork 再次从 DAL 请求服务。
我该如何实现它才能完成以下操作: 我的 UI 是有一个带有按钮的屏幕,按下该按钮将要求 BLL 使用 BLL 中的 DepartmentDataServices 具体 class 获取产品列表,这反过来又会导致 BLL 询问 DAL对于使用 DepartmentUnitOfWork 的 DAL 实现的产品列表。 DAL 是将 return 结果传给 BLL,后者又 return 将其传给 UI。
提前致谢。
解决方案是使用构造函数注入(这与您认为应该做的类似)。
这是一个例子:
public class DepartmentDataServices : IDepartmentDataServices
{
private readonly IDepartmentUnitOfWork m_DepartmentUnitOfWork;
public DepartmentDataServices(IDepartmentUnitOfWork uow)
{
m_DepartmentUnitOfWork = uow;
}
Public List<Product> GetProductList()
{
return m_DepartmentUnitOfWork.GetProductList();
}
}
现在,关于循环依赖问题:在 Composition Root 中组合你的对象。这意味着您不会在业务层中构造 DAL 对象,并且您不会在 UI 层中构造业务层对象。相反,您在 Composition Root 中构建整个对象图(所有层的所有对象),在您的例子中是 AppStartup 项目。
因此,UI 表单的构造函数应该接受对业务层类型(例如 IDepartmentDataServices
)的依赖,并且业务层对象的构造函数(例如 DepartmentDataServices
)应该接受对 DAL 类型的依赖(例如 IDepartmentUnitOfWork
)。
下面是如何在 AppStartup 项目中手动构造对象图的示例:
var uow = new DepartmentUnitOfWork(connection_string);
var service = new DepartmentDataServices(uow);
var form = MyApp.UI.FormMain(service);
Application.Run(form);
这是一个示例,说明如何在没有容器(称为 Pure DI)的情况下组合对象。我使用它只是为了让您了解构造函数注入的工作原理。但是您仍然可以使用 DI 容器。只需在 Composition Root 中注册这里的类型,然后让 DI 容器解析主要的 UI 对象,然后 DI 容器就会知道如何自动创建所有依赖项(一直到数据访问层对象) .这叫做自动接线。
请注意,Composition Root 是唯一应该使用 DI 容器的地方。使用其他项目中的容器(如您的示例)称为服务位置和 is considered an anti-pattern.
顺便说一句,两个类使用相同的名称是没有问题的,只要它们在不同的命名空间。就系统而言,这些 类 具有完全不同的名称。