分享一个 .NET Core Console 项目使用依赖注入的详细例子

简介: 分享一个 .NET Core Console 项目使用依赖注入的详细例子

前言

依赖注入(Dependency Injection,简称DI)是一种软件设计模式,主要用于管理和组织一个软件系统中不同模块之间的依赖关系。

在依赖注入中,依赖项(也称为组件或服务)不是在代码内部创建或查找的,而是由外部系统提供给组件。

具体来说,当某个角色(如一个 C# 实例,调用者)需要另一个角色(如另一个 C# 实例,被调用者)的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。

但在依赖注入中,创建被调用者的工作不再由调用者来完成,而是由外部容器来完成,并注入给调用者。

依赖注入可以提高代码的可维护性、可测试性、可替换性和可扩展性,降低组件之间的耦合度,使得代码更加清晰和灵活,以前我们写过在 Asp.NET Core Web API 项目中如何通过内置的依赖注入容器使用依赖注入的文章《一个简单的 ASP.NET Core 依赖注入例子,提高代码的可维护性和可扩展性》,今天继续分享一个在 .NET Core Console 项目使用依赖注入的详细例子,大家可以比较两者之间的不同。

Step By Step 步骤

  1. 创建一个 .NET Core Console 项目
  2. 从 Nuget 安装以下包

Microsoft.Extensions.DependencyInjection

System.Data.SqlClient

3.创建 User 实体类:

record User(long Id, string UserName, string Password);

4.创建接口 IUserBiz 和 IUserDAO 及其实现类(留意注释

interface IUserBiz
{
    /// <summary>
    /// 检查用户名、密码是否匹配
    /// </summary>
    /// <param name="userName"></param>
    /// <param name="password"></param>
    /// <returns></returns>
    public bool CheckLogin(string userName, string password);
}
interface IUserDAO
{
    /// <summary>
    /// 查询用户名为userName的用户信息
    /// </summary>
    /// <param name="userName"></param>
    /// <returns></returns>
    public User? GetByUserName(string userName);
}
class UserBiz : IUserBiz
{
    private readonly IUserDAO userDAO;
  // 通过构造方法要求注入 IUserDAO 服务
    public UserBiz(IUserDAO userDAO)
    {
        this.userDAO = userDAO;
    }
    public bool CheckLogin(string userName, string password)
    {
        var user = userDAO.GetByUserName(userName);
        if (user == null)
        {
            return false;
        }
        else
        {
            return user.Password == password;
        }
    }
}
class UserDAO : IUserDAO
{
    private readonly IDbConnection conn;
  // 通过构造方法要求依赖注入容器为其注入一个 IDbConnection 对象
    public UserDAO(IDbConnection conn)
    {
        this.conn = conn;
    }
    public User? GetByUserName(string userName)
    {
        using var dt = SqlHelper.ExecuteQuery(conn, $"select * from T_Users where UserName={userName}");
        if (dt.Rows.Count <= 0)
        {
            return null;
        }
        DataRow row = dt.Rows[0];
        int id = (int)row["Id"];
        string uname = (string)row["UserName"];
        string password = (string)row["Password"];
        return new User(id, uname, password);
    }
}

5.创建数据库操作帮助类 SqlHelper

using System.Data;
static class SqlHelper
{
  // 执行查询语句并返回 DataTable
    public static DataTable ExecuteQuery(this IDbConnection conn, FormattableString formattable)
    {
        using IDbCommand cmd = CreateCommand(conn, formattable);
        DataTable dt = new DataTable();
        using var reader = cmd.ExecuteReader();
        dt.Load(reader);
        return dt;
    }
  // 执行查询语句并返回一个值
    public static object? ExecuteScalar(this IDbConnection conn, FormattableString formattable)
    {
        using IDbCommand cmd = CreateCommand(conn, formattable);
        return cmd.ExecuteScalar();
    }
  // 执行 DML 语句
    public static int ExecuteNonQuery(this IDbConnection conn, FormattableString formattable)
    {
        using IDbCommand cmd = CreateCommand(conn, formattable);
        int result = cmd.ExecuteNonQuery();
        return result;
    }
  // 创建 Command
    private static IDbCommand CreateCommand(IDbConnection conn, FormattableString formattable)
    {
        var cmd = conn.CreateCommand();
        string sql = formattable.Format;
        for (int i = 0; i < formattable.ArgumentCount; i++)
        {
            sql = sql.Replace("{" + i + "}", "@p" + i);
            var parameter = cmd.CreateParameter();
            parameter.ParameterName = "@p" + i;
            parameter.Value = formattable.GetArgument(i);
            cmd.Parameters.Add(parameter);
        }
        cmd.CommandText = sql;
        return cmd;
    }
}

6.打开 Program.cs,引入依赖注入命名空间

using Microsoft.Extensions.DependencyInjection;

7.创建依赖注入容器

// 2. 创建用于注册服务的容器
ServiceCollection services = new ServiceCollection();
``

8.注入服务(留意注释

// 3.1 注入 IDbConnection 服务(范围)
services.AddScoped<IDbConnection>(sp => {
  string connStr = "Server=(localdb)\\mssqllocaldb;Database=TestDB;Trusted_Connection=True;MultipleActiveResultSets=true";
  var conn = new SqlConnection(connStr);
  conn.Open();
  return conn;
});
// 3.2 注入 IUserDAO 和 IUserBiz 服务(范围)
// ----把UserDAO注册为IUserDAO服务的实现类
// ----实现类的参数也会一起注入
services.AddScoped<IUserDAO, UserDAO>();
services.AddScoped<IUserBiz, UserBiz>();

9.使用(留意注释

// 调用 IServiceCollection 的 BuildServiceProvider 方法创建一个 ServiceProvider 对象
using (ServiceProvider sp = services.BuildServiceProvider())
{
  // 调用 GetRequiredService 方法获取服务
  var userBiz = sp.GetRequiredService<IUserBiz>();
  bool b = userBiz.CheckLogin("jacky", "123456");
  Console.WriteLine(b);
}

结语

依赖注入的实现方式有多种,如构造注入、属性注入和接口注入等。

通过依赖注入,可以更容易地管理和维护系统的各个组件,轻松地将模拟依赖注入到单元测试中,更灵活地添加新功能或替换现有组件。

虽然依赖注入在软件开发中有很多优点,但在使用时也需要谨慎,以确保正确地管理和配置依赖关系,避免潜在的问题,比如违背单一职责原则等设计原则,导致代码结构混乱,维护成本增加等。

附录:完整的 Program.cs 代码(留意注释

using DI魅力渐显_依赖注入;
// 1. 引用依赖注入命名空间
using Microsoft.Extensions.DependencyInjection;
using System.Data;
using System.Data.SqlClient;
// 2. 创建用于注册服务的容器
ServiceCollection services = new ServiceCollection();
// 3.1 注入 IDbConnection 服务(范围)
services.AddScoped<IDbConnection>(sp => {
    string connStr = "Server=(localdb)\\mssqllocaldb;Database=TestDB;Trusted_Connection=True;MultipleActiveResultSets=true";
    var conn = new SqlConnection(connStr);
    conn.Open();
    return conn;
});
// 3.2 注入 IUserDAO 和 IUserBiz 服务(范围)
// ----把UserDAO注册为 IUserDAO 服务的实现类
// ----实现类的参数也会一起注入
services.AddScoped<IUserDAO, UserDAO>();
services.AddScoped<IUserBiz, UserBiz>();
// 4. 使用
// 调用 IServiceCollection 的 BuildServiceProvider 方法创建一个 ServiceProvider 对象
using (ServiceProvider sp = services.BuildServiceProvider())
{
    // 调用 GetRequiredService 方法获取服务
    var userBiz = sp.GetRequiredService<IUserBiz>();
    bool b = userBiz.CheckLogin("jacky", "123456");
    Console.WriteLine(b);
}

我是老杨,一个奋斗在一线的资深研发老鸟,让我们一起聊聊技术,聊聊人生。

都看到这了,求个点赞、关注、在看三连呗,感谢支持。


相关文章
|
8天前
|
开发框架 .NET 开发者
简化 ASP.NET Core 依赖注入(DI)注册-Scrutor
Scrutor 是一个简化 ASP.NET Core 应用程序中依赖注入(DI)注册过程的开源库,支持自动扫描和注册服务。通过简单的配置,开发者可以轻松地从指定程序集中筛选、注册服务,并设置其生命周期,同时支持服务装饰等高级功能。适用于大型项目,提高代码的可维护性和简洁性。仓库地址:&lt;https://github.com/khellang/Scrutor&gt;
30 5
|
21天前
|
开发框架 .NET 程序员
驾驭Autofac,ASP.NET WebApi实现依赖注入详细步骤总结
Autofac 是一个轻量级的依赖注入框架,专门为 .NET 应用程序量身定做,它就像是你代码中的 "魔法师",用它来管理对象的生命周期,让你的代码更加模块化、易于测试和维护
驾驭Autofac,ASP.NET WebApi实现依赖注入详细步骤总结
|
1月前
|
开发框架 网络协议 .NET
C#/.NET/.NET Core优秀项目和框架2024年10月简报
C#/.NET/.NET Core优秀项目和框架2024年10月简报
|
2月前
|
开发框架 前端开发 API
C#/.NET/.NET Core优秀项目和框架2024年9月简报
C#/.NET/.NET Core优秀项目和框架2024年9月简报
winform .net6 和 framework 的图表控件,为啥项目中不存在chart控件,该如何解决?
本文讨论了在基于.NET 6和.NET Framework的WinForms项目中添加图表控件的不同方法。由于.NET 6的WinForms项目默认不包含Chart控件,可以通过NuGet包管理器安装如ScottPlot等图表插件。而对于基于.NET Framework的WinForms项目,Chart控件是默认存在的,也可以通过NuGet安装额外的图表插件,例如LiveCharts。文中提供了通过NuGet添加图表控件的步骤和截图说明。
winform .net6 和 framework 的图表控件,为啥项目中不存在chart控件,该如何解决?
|
2月前
|
存储 消息中间件 前端开发
.NET常见的几种项目架构模式,你知道几种?
.NET常见的几种项目架构模式,你知道几种?
101 0
|
2月前
|
边缘计算 开发框架 人工智能
C#/.NET/.NET Core优秀项目和框架2024年8月简报
C#/.NET/.NET Core优秀项目和框架2024年8月简报
|
2月前
|
Cloud Native API C#
.NET云原生应用实践(一):从搭建项目框架结构开始
.NET云原生应用实践(一):从搭建项目框架结构开始
|
3月前
|
开发框架 前端开发 JavaScript
ASP.NET MVC 教程
ASP.NET 是一个使用 HTML、CSS、JavaScript 和服务器脚本创建网页和网站的开发框架。
48 7
|
3月前
|
存储 开发框架 前端开发
ASP.NET MVC 迅速集成 SignalR
ASP.NET MVC 迅速集成 SignalR
75 0