.Net DI(Dependency Injection)依賴注入機制

wskxy發表於2023-03-02

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檔案
    {
        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的簡單原理就是這樣。。

 

  

 

相關文章