ASP.NET Core 中的依赖注入 (DI)






2.30/5 (9投票s)
本文将引导您了解 DI 的基本概念、DI 的作用、代码示例以及如何使用 .NET Core 内置的 DI 创建 ASP.NET Core MVC Web 应用程序。
引言
照片作者:Thanh Tran, 来自 Unsplash
依赖注入 (DI) 是一种面向对象编程 (OOP) 设计模式,它允许我们在应用程序中实现松耦合。
假设我们有两个非常简单的类:Human 类和 MobilePhone 类。MobilePhone 类只有 CallFunction 和 InternetBrowse 功能。Human 类通过在 Human 类内部创建 MobilePhone 类的新对象来使用 MobilePhone 类功能。
结果,Human 类完全依赖于 MobilePhone 类。依赖注入通过提供其他类对象的依赖关系来帮助我们消除对其他类的依赖。
基本上,DI 是一种技术或过程,一个对象为另一个对象提供依赖项。
必备组件
- 精通 C# 语言
- ASP.NET Core MVC Web 应用程序
- .NET CLI
- 最好对 SOLID 原则有深入的了解
背景
现在让我们开始演示,我将创建一个 ASP.NET Core MVC Web 应用程序。本文的目标将涵盖以下内容:
- DI 详解
- DI 代码示例
- 创建 ASP.NET Core MVC Web 项目
- 代码实现
- 结论
依赖注入
紧耦合
如果一个类直接或具体地依赖于另一个类,那么它就被认为是紧耦合的。这意味着更改一个对象也需要更改另一个对象。对于小型应用程序来说这还可以,但在企业级应用程序中,进行更改非常困难。
松耦合
它确保两个对象是独立的,并且对象可以在类外部创建,而不依赖于其他类。
正如我在引言部分提到的 Human 类和 MobilePhone 类之间的依赖关系,下面是一个不使用 DI 的代码示例。Human 类完全依赖于 MobilePhone 类。这是一种依赖关系。我们可以通过使用依赖注入来解决这种依赖关系。稍后,我将通过创建一个 ASP.NET Core MVC Web 项目来展示 DI 在代码库中的用法。
public class MobilePhone
    {
        public void CallFunction()
        {
            Console.WriteLine("It Ensure Mobile Call Function");
        }
 
        public void IneternetBrowse()
        {
            Console.WriteLine("It Ensure Internet Browse Function");
        }
    }
public class Human
    {
        MobilePhone _MobilePhone = new MobilePhone();
        public void BasciNeed()
        {
            _MobilePhone.CallFunction();
            _MobilePhone.IneternetBrowse();
        }
    }
问题在于,将来 MobilePhone 类发生变化时,您也必须更改 Human 类。例如,如果 MobilePhone 类添加了一个新的基于参数的构造函数,那么 Human 类就需要通过更改现有实现来适应它。为了解决这种复杂性,我们必须使用 DI。
DI 容器通过在类外部创建对象并在我们需要它时在正确的时间提供它来帮助我们,这样我们就无需考虑对象创建。因此,我们的代码变得干净、可维护且松耦合。
DI 分类
- 构造函数注入
- Setter 注入
- 方法注入
现在我将通过详细示例来说明构造函数注入。
让我们使用构造函数注入来看上面的例子。DI 作为一种服务提供。当我们只需要 MobilePhone 类对象时,我们只需向 DI 容器发出请求,请它提供预期的对象。我们不必担心对象创建和更改现有代码。DI 容器会确保这一点。这真是一种解脱。
public interface IMobilePhone
    {       
        void CallFunction();
        void IneternetBrowse();
    }
public class MobilePhone : IMobilePhone
    {
        public void CallFunction()
        {
            Console.WriteLine("It Ensure Mobile Call Function");
        }
 
        public void IneternetBrowse()
        {
            Console.WriteLine("It Ensure Internet Browse Function");
        }
    }
public class Human
    {
        IMobilePhone _mobilePhone;
        public Human(IMobilePhone mobilePhone)
        {
            _mobilePhone = mobilePhone;
        }
        public void BasciNeed()
        {
            _mobilePhone.CallFunction();
            _mobilePhone.IneternetBrowse();
        }
    }
SOLID 的第五条原则说了什么
- 应该依赖于抽象,而不是具体实现。
- 高层模块不应依赖于低层模块。
- 两者都应依赖于抽象。
- 抽象不应依赖于细节。细节应依赖于抽象。
- 因此,高层和低层模块以及详细信息都依赖于抽象。Abstractions: High-level + Low-level modules + Details - 高层模块:描述应用程序中具有更高抽象性且包含更复杂逻辑的操作。这些模块在我们的应用程序中协调低层模块。
- 		低层模块:包含更具体的单个组件,专注于应用程序的细节和较小部分。这些模块在我们的应用程序中由高层模块使用。 
 
创建 ASP.NET Core MVC Web 项目
首先,让我们使用 .NET Core CLI 创建一个 ASP.NET Core MVC Web 应用程序。
$ dotnet new sln -n DotNetCoreDI
$ dotnet new mvc -n DotNetCoreDI
$ dotnet sln DotNetCoreDI.sln add DotNetCoreDI/DotNetCoreDI.csproj
代码实现
public interface ICommonData
    {
        DateTime GetCurrentDateTime();
        string GetMachineName();
    }
public class CommonData : ICommonData
    {
        public DateTime GetCurrentDateTime()
        {
            return DateTime.Now;
        }
        public string GetMachineName()
        {
            return Environment.MachineName.ToString();
        }
    }
控制器 (Controller)
private readonly ICommonData _commonData;
public HomeController(ICommonData commonData)
{
    _commonData = commonData;
}
public IActionResult Index()
{
    var serverTime = _commonData.GetCurrentDateTime();
    ViewData["CurrentTime"] = serverTime;
    if (serverTime.Hour < 12)
    {
        ViewData["Message"] = "It's morning here - Good Morning!";
        
    }
    else if (serverTime.Hour < 17)
    {
        ViewData["Message"] = "It's afternoon here - Good Afternoon!";
    }
    else
    {
        ViewData["Message"] = "It's evening here - Good Evening!";
    }
    ViewData["MachineName"] = _commonData.GetMachineName();
    return View();
}
构建和运行
$ dotnet build
$ dotnet run
如果在 Startup.cs 中不配置 DI 而运行项目,程序将抛出以下异常:
DI 配置
ASP.NET Core 支持依赖注入 (DI) 软件设计模式。在控制台应用程序中,您需要通过 NuGet 包管理器安装 Microsoft.Extensions.DependencyInjection。
PM> Install-Package Microsoft.Extensions.DependencyInjection -Version 3.0.0
services.AddTransient<ICommonData, CommonData>();
现在,如果我们运行该项目,我们将看到以下输出:
DI 的优势
- 使用不同的模拟实现,单元测试变得更加轻松简单
- 松耦合而非紧耦合,这对任何应用程序都非常重要
- 同样遵循了 SOLID 原则
- 可配置。
- 确保代码干净且更具可读性
- 降低模块复杂度,提高系统可维护性和模块可重用性
结论
在本文中,我只是尝试解释依赖注入的基础知识、DI 的用法以及使用 ASP.NET Core MVC Web 应用程序的代码示例。
我们可以不使用依赖注入而使用其他类对象,但它存在一些缺点和复杂性。为了克服这些缺点,我们需要使用依赖注入。SOLID 原则告诉我们应该在依赖类外部处理依赖关系。DI 的最佳之处在于确保了松耦合,从而确保了干净的代码和良好的代码库可维护性。
下次再见,学习愉快!
祝好!
历史
- 2019 年 10 月 14 日:初始版本







