使用配置文件和映射不同存储库的 ASP.NET Unity 框架






4.50/5 (2投票s)
本文涵盖了 Unity 框架的概念,以帮助实现依赖注入和控制反转 (IoC)。
引言
本文解释了 Unity 框架在依赖注入中的应用,并提供了一种不同的方法来解析类和接口之间的依赖关系。依赖注入的优点是代码简化和生成依赖对象实例。我们可能知道如何使用 C# 注册类型,但还有另一种方法。我们可以使用配置文件来声明和注册类型,然后在代码中解析它们。本文将以一种实用且清晰的方式帮助您理解这一点。本文还涵盖了根据业务需求切换不同 Unity 配置文件的一种场景。
背景
在阅读本文之前,建议您参考Microsoft Unity 和如何在 ASP.NET MVC 框架中使用 Unity 文章,以更好地理解 Unity 的工作原理及其如何解决我们的大部分问题,让生活更轻松。
业务需求
我想分享我开始使用 Unity 的原因。业务方面有一个特殊的要求,他们希望迁移现有的数据库并切换到一个没有可比模式的新数据库。因此,所有开发人员都必须根据新数据库重新编写所有存储库。但是,如果存储库方法发生更改,业务逻辑或引用很可能需要更新。因此,我的技术主管提出了使用 Unity 框架进行依赖注入的想法,并允许灵活地在旧存储库和新存储库之间切换。他们想测试新存储库,但又不想在确定一切都良好之前删除旧存储库。接下来的部分将解释我如何使用 Unity 来处理这个需求。
Using the Code
在开始编码之前,我们需要从 Nuget 包管理器获取 Unity 框架包。要获取该包,请转到工具 -> NuGet 包管理器 -> 管理解决方案的 NuGet 包。
为了演示,我创建了一个项目,其中将使用不同的快递公司存储库来获取费率。有一个接口 ICourierRepository
,它由 UspsRepository
和 FedexRepository
实现。基本上,应用程序将根据在 Web.Config
或 Unity.Config
文件中注册的“Type
”来选择存储库。项目的第一个部分是在 Web.Config 文件中创建 Unity 部分。
我们创建了一个名为“Unity
”的新节,它又提供了 Unity 的文件名。在图像中,configSource = "NewRepositoryUnity.config"
表示有一个文件也需要进行检查。代码将查看 NewRepositoryUnity.config
。
以下是使用 Web.Config 文件声明和解析类型的代码。在使用 Unity 容器之前,我们需要对其进行设置。它涉及注册类型,在前四行中,我们正在设置需要使用和注入的变量类型的别名。在 type
属性中,我们需要指定类型的 namespace
和 Assembly
以便正确映射。别名用于引用任何类型,而不是指定其 Namespace
和 Assembly
。
下一部分是声明 Unity 容器。在这里,我使用 CourierContainer
作为我的容器名称。当存在多个容器并且我想解析特定容器时,会使用容器名称。在此容器节中,我们将所有类型与 Unity 一起注册,并明确指定其 Type
、mapTo
和 name
。我们将接口与实现该接口的所有类一起注册,并为它们提供在 Aliases
中定义的名称。我们也以不同的方式注册了我们的业务类 CourierBusiness
。我们使用带参数的构造函数进行依赖注入,因此我们需要在配置文件中指定类型。在这里,我们需要确保构造函数签名中的参数名称与配置中的名称匹配(在本例中为 courierRepository
)。我们对业务类进行了两次注册,因为我们希望使用 Usps 或 Fedex 这两个存储库中的任何一个,并且不希望每次都显式地 NEW
化实例。因此,我们需要为我想使用的每个存储库设置单独的 Register 标签。
namespace UnityFrameworkExample.Business
{
public class CourierBusinessClass
{
private ICourierRepository _courierRepostitory;
public CourierBusinessClass(ICourierRepository courierRepository)
{
_courierRepostitory = courierRepository;
}
public string GetLatestPrices()
{
var message = _courierRepostitory.GetCourierPrices();
return message;
}
}
}
工作原理
//***
//*** Loading Unity Configuration
//***
IUnityContainer container = new UnityContainer();
container.LoadConfiguration("CourierContainer");
首先,我们需要创建一个 UnityContainer
实例,然后加载所需的 Unity 配置(在本例中为 CourierContainer
)。如果我们的所有程序集和命名空间都正确,此步骤将不会出现任何错误。
//***
//*** Resolving Dependency Injection on Business Class and accessing repositories
//***
var uspsInstance = container.Resolve<CourierBusinessClass>("UspsCourier");
ViewBag.uspsCourierPrice = uspsInstance.GetLatestPrices();
var fedexInstance = container.Resolve<CourierBusinessClass>("FedexCourier");
ViewBag.fedexCourierPrice = fedexInstance.GetLatestPrices();
现在,我们需要解析我们想要使用的类。在这里,我们正在解析 CourierBusinessClass
。我们不需要创建该类的 New
实例,也不需要在声明时向构造函数传递任何参数,Unity 框架会自动为我们完成。现在,根据我们的需求,我们是需要使用 Usps
还是 Fedex repository
,我们需要在解析时传递 string
。Unity 框架将尝试将 string
与配置文件中的名称进行匹配,如果找到匹配项,它将创建该类型的实例。例如,在这里,我们在第一行传递 UspsCourier
。Unity 框架将查找 CourierBusinessClass
类型在配置文件中的该名称。找到了匹配项。Unity 将意识到它使用了带有 ICourierRepository
类型的参数化构造函数。但是我们声明了依赖项名称,这将帮助 Unity 指向合适的类型。这里的依赖项名称是 UspsCourierRepository
。Unity 将查找别名 UspsCourierRepository
,如果找到匹配项,它将创建 UspsCourierRepository
类的实例。最后,当执行 GetLatestPrices()
方法时,它将指向 UspsCourierRepository
中的方法并相应地返回结果。
在多个 Unity 配置文件之间切换
正如我之前解释的业务问题,我们需要多个存储库,可以根据需要进行切换。这可以通过在Web.Config 文件中更改文件名来完成。所以我创建了一个新的 Unity 配置文件,并将所有类型映射到了旧存储库。下面是包含旧存储库的配置文件的屏幕截图。
关注点
当我理解了 Unity 的依赖注入概念以及它如何简化代码时,我真的感到惊讶。最好的部分是 Unity 的文档非常简单,它帮助我理解并提出了这个概念。我们甚至可以通过 Unity 实现控制反转 (IoC),确保业务层不必处理“新建”存储库实例的问题。