你知道如何使用 .NET Core 中的接口注入服务。您可能已经无数次编写了这样的代码:
public class ItemsController : ControllerBase
{
private readonly IItemService _itemService;
public ItemsController(IItemService itemService)
{
_itemService = itemService;
}
// Actions here...
}
当然,您已在 中注册了您的服务 :Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IItemRepository, ItemRepository>();
services.AddScoped<IItemService, ItemService>();
}
效果很好,对吧?您的代码是干净的,服务被整齐地注入到控制器中或您需要的任何位置。但是,你有没有想过,当你像这样设置依赖关系注入 (DI) 时,幕后实际上发生了什么?框架如何知道要注入什么以及何时注入?
使用 DotNet-FullStack-Dev 踏上持续学习和探索的旅程。通过访问我们的 https://dotnet-fullstack-dev.blogspot.com 了解更多信息**。**
让我们深入研究一下 DI 在运行时会发生什么,以及它与 、 和 的关系。我们将抽离各个层次,以对话式、代码驱动的方式了解 .NET Core 如何为你处理所有这些魔力。Item APIItemServiceItemRepository
第 1 步:DI 容器准备就绪(启动阶段)
启动 .NET Core 应用时,首先要做的一件事是创建依赖项注入容器。把它想象成一个大盒子,你所有的服务注册(如 和 )都存储在其中。ItemServiceItemRepository
在 中,该方法注册具有特定**生命周期(**如 、 或 )的服务。框架现在知道需要哪些类以及它们应该存在多长时间:Startup.csConfigureServicesScopedTransientSingleton
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IItemRepository, ItemRepository>();
services.AddScoped<IItemService, ItemService>();
}
以下是此注册在人类术语中的含义:
AddScoped: “亲爱的 DI 容器,每次有 HTTP 请求时,请创建一个 and 实例,并在该请求中共享它。但不要留着下次请求。ItemServiceItemRepository
第 2 步:控制器请求依赖项
现在,假设您的应用程序收到了对 .框架看到你的控制器类在其构造函数中需要一个 of 实例:ItemsControllerIItemService
public class ItemsController : ControllerBase
{
private readonly IItemService _itemService;
public ItemsController(IItemService itemService)
{
_itemService = itemService;
}
// Actions here...
}
这就是 DI 容器发挥作用的地方。容器看着你说,“好的,我需要给这个控制器一个 .我在哪里可以买到它?ItemsControllerIItemService
由于我们在 中注册,容器知道它应该提供 whenever 的实例。IItemServiceStartup.csItemServiceIItemService
第 3 步:解决依赖关系(连锁反应)
DI 容器不仅仅以 .真正的魔力发生在自身具有依赖项时,例如:IItemServiceItemServiceIItemRepository
public class ItemService : IItemService
{
private readonly IItemRepository _itemRepository;
public ItemService(IItemRepository itemRepository)
{
_itemRepository = itemRepository;
}
// Service logic here...
}
由于 needs ,容器也会寻找如何解决该依赖关系。它看到 in 的注册,并提供 的实例 to 。ItemServiceIItemRepositoryIItemRepositoryStartup.csItemRepositoryItemService
这种连锁反应一直持续到所有依赖项都得到解决。在这种情况下:
ItemsController 需要 ,因此容器提供了 .IItemServiceItemService
ItemService 需要 ,因此容器提供了 .IItemRepositoryItemRepository
所有这些都是自动发生的 — 无需手动实例化,也不需要关键字。new
第 4 步:对象创建(幕后)
当容器解析所有依赖项时,它会根据需要实例化对象。让我们看看这个例子中容器在幕后做了什么:
ItemRepository 首先创建,因为依赖于它。ItemService
var itemRepository = new ItemRepository();
接下来创建 ItemService,并将其传递到其构造函数中。itemRepository
var itemService = new ItemService(itemRepository);
最后,创建 ItemsController 并注入其中。itemService
var itemsController = new ItemsController(itemService);
每个服务仅在需要时创建,并且每个 HTTP 请求仅创建一次(感谢)。AddScoped
第 5 步:请求后进行清理
HTTP 请求完成后,DI 容器将释放范围服务。此清理过程可确保正确释放任何资源(如数据库连接),从而防止内存泄漏。
对于 ,这意味着 和 的实例在请求结束后被释放,并为下一个请求创建新实例。AddScopedItemServiceItemRepository
你有没有像我一样至少问过自己一次,dependency-injection-is-a-curse-to-developers,然后看看我的想法。
为什么这一切对您作为开发人员来说都很重要
现在,你已了解了 .NET Core 中 DI 的幕后情况,你可以看到框架为你做了多少繁重的工作。这就是为什么这很重要:
无需手动创建对象:您不必担心实例化或 .DI 容器会处理这个问题。ItemServiceItemRepository
松散耦合:通过接口 (, ) 注入依赖项,您的代码更灵活,更易于测试。您可以在不更改其余代码的情况下交换实现。IItemServiceIItemRepository
自动生命周期管理:服务在正确的时间创建和销毁,这意味着您不必担心手动管理其生命周期。
可测试性:您可以在单元测试中模拟依赖项。例如,在 testing 时,您可以模拟以仅测试控制器的行为。ItemsControllerIItemService
快速了解依赖关系注入的实际应用
总而言之,我们来看一个典型的流程,当用户发出请求以从您的 .ItemsController
Request comes in:用户点击终端节点。/api/items
DI 容器启动:容器发现需要一个 .ItemsControllerIItemService
链式反应:容器通过创建 .它还会解析为 。IItemServiceItemServiceIItemRepositoryItemService
响应发出:控制器使用该服务从存储库中获取数据,并将响应发送回用户。
所有这些都无需手动实例化对象即可完成。您专注于编写干净的模块化代码,其余的由框架处理。
.NET Core 中的依赖项注入不仅仅是一种模式,它还是一种内置机制,可简化应用程序的结构并促进良好的软件设计。通过了解幕后发生的事情,您可以了解 DI 容器在运行时为您做了多少工作。
下次您注册服务或注入依赖项时,请考虑一下后台发生的无形连锁反应。DI 容器正在解决依赖关系、管理生命周期并确保一切顺利进行 — 同时您可以编写更简洁、更易于维护的代码。
如果你喜欢我的文章,请给我一个赞!谢谢