• .Net DI(Dependency Injection)依赖注入机制


    1、简介

      DI:Dependency Injection,即依赖注入,他是IOC的具体实现。

      在DI中,底层服务对象不再负责依赖关系的创建,而是交由顶端调用进行管理注入

      好处:降低组件之间的耦合度,使代码更加灵活

    2、实例

      我们举个例子,有个User Login的功能,Login需要通过DB验证,DB需要读取Config和进行Log记录

      依赖关系如图

       

      DI的概念,就是把DB的依赖(Config&Log)提到User层,该怎么实现呢?

      接着往下走...

    3、代码结构

      通过代码我们来看一下原理。

      框架说明:

        1)Service类库:Standard2.1,类库推荐都使用Standard,这样可以在Framework、core、net之间通用

        2)UserSite:Net5 控制台程序

      

     

      编码内容:

      ConfigService,包含两种实现方式

    复制代码
    namespace ConfigService
    {
        public interface IConfig
        {
            public string GetValue(string key);//获取name的值
        }
    }
    
    
    using System;
    namespace ConfigService
    {
        public class EnvironmentConfig : IConfig //从环境变量里面读取配置信息,自行添加到电脑User里面
        {
            public string GetValue(string key)
            {
                return Environment.GetEnvironmentVariable(key, EnvironmentVariableTarget.User);
            }
        }
    }
    
    
    using System.IO;
    using System.Linq;
    namespace ConfigService
    {
        public class IniFileConfig : IConfig //从ini文件读取配置信息,UserSite如果注入此服务,需要创建ini文件:key=value   就行
        {
            string _filePath;
            public IniFileConfig(string filePath)
            {
                this._filePath = filePath;
            }
            public string GetValue(string key)
            {
                string str = "";
                var kv = File.ReadAllLines(_filePath)
                    .Select(x => x.Split("="))
                    .Select(x => new { key = x[0], value = x[1] })
                    .SingleOrDefault(x => x.key == key);
                return kv?.value;
            }
        }
    }
    复制代码

      LogService,简单实现

    复制代码
    namespace LogService
    {
        public interface ILog
        {
            public void LogInfo(string msg);
            public void LogError(string msg);
        }
    }
    
    
    using System;
    namespace LogService
    {
        public class ConsoleLog : ILog
        {
            public void LogInfo(string msg)
            {
                Console.WriteLine($"Info:{msg}");
            }
            public void LogError(string msg)
            {
                Console.WriteLine($"Error:{msg}");
            }
        }
    }
    复制代码

      DBService,只是做思路演示,这边只要读取到dblink就算访问数据库成功

    复制代码
    namespace DBService
    {
        public interface IDBHelper
        {
            public bool CheckUser(string acc, string pwd);
        }
    }
    
    using LogService;
    using ConfigService;
    namespace DBService
    {
        public class SqlServerHelper : IDBHelper
        {
            private IConfig _config;
            private ILog _log;
            public SqlServerHelper(IConfig config,ILog log) //Net默认从构造函数进行以来注入
            {
                this._config = config;
                this._log = log;
            }
            public bool CheckUser(string acc, string pwd)
            {
                var dblink = this._config.GetValue("dblink");
                this._log.LogInfo($"获取数据库链接={dblink}");
                if (string.IsNullOrWhiteSpace(dblink))
                {
                    this._log.LogError($"登录失败");
                    return false;
                }
                this._log.LogInfo($"登录成功-{acc}-{pwd}");
                return true;
            }
        }
    }
    复制代码

      主题来了,UserSite Program代码如下:

      我们需要注入SqlServerHelper服务,就需要将其依赖项一同注入,这样就将具体实现类提到了顶端注入,从而进行解耦

      比如:读取配置文件,我希望从哪读取,就注入哪一个(注意,都注入的话,IConfig会以后注入的为准)

    复制代码
    using System;
    using ConfigService;
    using LogService;
    using DBService;
    using Microsoft.Extensions.DependencyInjection;
    
    namespace UserSite
    {
        class Program
        {
            static void Main(string[] args)
            {
                ServiceCollection services = new ServiceCollection();
                services.AddScoped();
                services.AddScoped(); //1、我希望从环境变量读取配置
                services.AddScoped(typeof(IConfig), x => new IniFileConfig("db.ini")); //2、我希望从ini读取配置
                services.AddScoped();
                using (var sp = services.BuildServiceProvider())
                {
                    var service = sp.GetRequiredService();
                    service.CheckUser("kxy", "123");
                };
                Console.ReadLine();
            }
        }
    }
    复制代码

      DI的简单原理就是这样。。

    4、Net Core Api DI如何实现

      依赖注入一般是在StartUp实现,Net6以后取消了StartUp,将builder迁移至Program

    builder.Services.AddScoped();

      正常是在构造函数注入

    复制代码
    using DIDemo.Services;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    namespace DIDemo.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class HomeController : ControllerBase
        {
            IDBHelper _dBHelper;
            public HomeController(IDBHelper dBHelper) { 
                this._dBHelper = dBHelper;
            }
            [HttpGet]
            public bool Get(string acc,string pwd)
            {
                return _dBHelper.CheckUser(acc, pwd);
            }
        }
    }
    复制代码

      当然,如果一些服务构造起来非常耗时,在一个控制器下面又只是一两个api需要使用到,

      如果使用构造函数注入,所有api的访问都会进行依赖注入,这是十分不友好的,即使首次注入后服务器会缓存资源

      可更换为函数注入

    复制代码
    using DIDemo.Services;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    namespace DIDemo.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class HomeController : ControllerBase
        {
            [HttpGet]
            public bool Get([FromServices] IDBHelper _dBHelper, string acc,string pwd)
            {
                return _dBHelper.CheckUser(acc, pwd);
            }
        }
    }
    复制代码

     

     

      

     

  • 相关阅读:
    PeproTech重组Long R3 IGF-I
    PADS(二)更多使用和实战总结
    ffmpeg 任意文件读取漏洞/SSRF漏洞 (CVE-2016-1897/CVE-2016-1898)
    Camtasia2023简单易用的电脑录屏视频剪辑软件
    Mac中无法运行旧版本印象笔记:版本太旧 你的本地印象笔记数据是由新版印象笔记管理
    快速搭建接口自动化测试框架
    在本地运行 LLMs 的 6 种方法
    android开发电子书,android基础编程
    拿什么拯救你?这暴热的天气!只能用python分析做个可视化康康
    Nodejs+vue+Elementui课程教学网站系统
  • 原文地址:https://www.cnblogs.com/wskxy/p/17172299.html