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

时间:2021-06-20 00:39:16

1、简介

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

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

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

2、实例

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

  依赖关系如图

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

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

  接着往下走...

3、代码结构

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

  框架说明:

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

    2)UserSite:Net5 控制台程序

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

 

  编码内容:

  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文件
    {
        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<ILog, ConsoleLog>();
            services.AddScoped<IConfig, EnvironmentConfig>(); //1、我希望从环境变量读取配置
            services.AddScoped(typeof(IConfig), x => new IniFileConfig("db.ini")); //2、我希望从ini读取配置
            services.AddScoped<IDBHelper, SqlServerHelper>();
            using (var sp = services.BuildServiceProvider())
            {
                var service = sp.GetRequiredService<IDBHelper>();
                service.CheckUser("kxy", "123");
            };
            Console.ReadLine();
        }
    }
}

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