.Net6開發(fā)winform程序使用依賴注入
.net? Blazor webassembly 和 webAPI 內(nèi)建支持依賴注入, Winform 和 Console 應(yīng)用雖然不帶有依賴注入功能, 但增加依賴注入也很簡單.?
本文將示例如何為 WinForm 程序增加依賴注入特性, 實(shí)現(xiàn)通過DI容器獲取Cofiguration 實(shí)例, 并讀取appsettings.json文件.
安裝依賴庫, 有點(diǎn)多
- Microsoft.Extensions.DependencyInjection 庫, 依賴注入的類庫
- Microsoft.Extensions.Configuration 庫, 包含IConfiguration接口 和 Configuration類
- Microsoft.Extensions.Configuration.Json 庫, 為 IConfiguration 增加了讀取 Json 文件功能,
- Microsoft.Extensions.Hosting 庫,? 提供 Host 靜態(tài)類,? 有能力從 appsettings.{env.EnvironmentName}.json 加載相應(yīng) env? 的設(shè)定值,? 并將設(shè)定值用于IConfiguration/ILoggerFactory中, 同時(shí)增加 Console/EventSourceLogger 等 logger.
僅適用于 Asp.Net core 和 Console 類應(yīng)用
- Microsoft.Extensions.Logging 庫,? 包含 ILogger 和 ILoggerFactory 接口
- Serilog.Extensions.Logging 庫, 為DI 容器提供 AddSerilog() 方法.
- Serilog.Sinks.File 庫, 提供 Serilog rolling logger
- Serilog.Sinks.Console 庫, 增加 serilog console logger
- Serilog.Settings.Configuration 庫, 允許在 appsetting.json? 配置 Serilog, 頂層節(jié)點(diǎn)要求是 Serilog.?
- Serilog.Enrichers.Thread 和 Serilog.Enrichers.Environment 庫,? 為輸出日志文本增加 Thread和 env 信息
補(bǔ)充庫:
- Microsoft.Extensions.Options.ConfigurationExtensions 庫,? 為DI容器增加了從配置文件中實(shí)例化對象的能力, 即? serviceCollection.Configure<TOptions>(IConfiguration)
- Microsoft.Extensions.Options 庫,? 提供以強(qiáng)類型的方式讀取configuration文件, 這是.Net中首選的讀取configuration文件方式.
appsettings.json 配置文件
配置一個 ConnectionString, 另外配 serilog
{ "ConnectionStrings": { "oeeDb": "Server=localhost\\SQLEXPRESS01;Database=Oee;Trusted_Connection=True;" }, "Serilog": { "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ], "MinimumLevel": "Debug", "WriteTo": [ { "Name": "Console" }, { "Name": "File", "Args": { "path": "Logs/serilog.txt" } } ], "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ] } }
Program.cs , 增加DI容器
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Serilog; namespace Collector { internal static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { ApplicationConfiguration.Initialize(); //未使用依賴注入的寫法 //Application.Run(new FormMain()); //生成 DI 容器 ServiceCollection services = new ServiceCollection(); ConfigureServices(services); //注冊各種服務(wù)類 //先用DI容器生成 serviceProvider, 然后通過 serviceProvider 獲取Main Form的注冊實(shí)例 var serviceProvider =services.BuildServiceProvider(); var formMain = serviceProvider.GetRequiredService<FormMain>(); //主動從容器中獲取FormMain實(shí)例, 這是簡潔寫法 // var formMain = (FormMain)serviceProvider.GetService(typeof(FormMain)); //更繁瑣的寫法 Application.Run(formMain); } /// <summary> /// 在DI容器中注冊所有的服務(wù)類型 /// </summary> /// <param name="services"></param> private static void ConfigureServices(ServiceCollection services) { //注冊 FormMain 類 services.AddScoped<FormMain>(); //register configuration IConfigurationBuilder cfgBuilder = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json") .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT")}.json", optional: true, reloadOnChange: false) ; IConfiguration configuration=cfgBuilder.Build(); services.AddSingleton<IConfiguration>(configuration); //Create logger instance var serilogLogger = new LoggerConfiguration() .ReadFrom.Configuration(configuration) .Enrich.FromLogContext() .CreateLogger(); //register logger services.AddLogging(builder => { object p = builder.AddSerilog(logger: serilogLogger, dispose: true); }); } } }
FormMain.cs , 驗(yàn)證依賴注入的效果
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; namespace Collector { public partial class FormMain : Form { private readonly IConfiguration _configuration; private readonly ILogger _logger; /// <summary> /// 為 FormMain 構(gòu)造子增加兩個形參, 構(gòu)造子參數(shù)將由于DI容器自動注入 /// </summary> /// <param name="configuration"></param> /// <param name="logger">形參必須是 ILogger泛型類型, 不能是 ILogger 類型</param> public FormMain(IConfiguration configuration, ILogger<FormMain> logger) { _configuration = configuration; _logger = logger; InitializeComponent(); var connectionString = _configuration.GetConnectionString("oeeDb"); //從配置文件中讀取oeeDb connectionString _logger.LogInformation(connectionString); //將connection String 寫入到日志文件中 } } }
DI容器管理配置文件Section
上面示例, 我們通過 _configuration.GetConnectionString("oeeDb")? 可以拿到connectionString, 非常方便, 這主要是得益于.Net 已經(jīng)類庫已經(jīng)考慮到在配置文件中存儲 connectionString 是一個普遍的做法, 所以類庫內(nèi)置支持了.
如果在 appsettings.json 中存一些自定義的信息, 如何方便讀取呢? 微軟推薦的 Options 模式, 下面詳細(xì)介紹.
首先安裝庫:
- Microsoft.Extensions.Options.ConfigurationExtensions 庫,? 為DI容器增加了從配置文件中實(shí)例化對象的能力, 即? serviceCollection.Configure<TOptions>(IConfiguration)
- Microsoft.Extensions.Options 庫,? 提供以強(qiáng)類型的方式讀取configuration文件, 這是.Net中首選的讀取configuration文件方式.
假設(shè) appsettings.json 中要存放appKey和appSecret信息, 具體配置如下:
"AppServiceOptions": { "appKey": "appkey1", "appSecret": "appSecret1" }
定義對應(yīng)的 Poco Class,? 推薦后綴為 Options,
public class AppServiceOptions { public string AppKey { get; set; } = ""; public string AppSecret { get; set; } = ""; }
注冊函數(shù) ConfigureServices()中,? 注冊 AppServiceOptions 類, 告知DI容器, 要基于配置文件AppServiceOptions section來實(shí)例化
private static void ConfigureServices(ServiceCollection services) { //注冊 FormMain 類 services.AddScoped<FormMain>(); //register configuration IConfigurationBuilder cfgBuilder = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json") .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT")}.json", optional: true, reloadOnChange: false) ; IConfiguration configuration=cfgBuilder.Build(); services.AddSingleton<IConfiguration>(configuration); //Create logger instance var serilogLogger = new LoggerConfiguration() .ReadFrom.Configuration(configuration) .Enrich.FromLogContext() .CreateLogger(); //register logger services.AddLogging(builder => { object p = builder.AddSerilog(logger: serilogLogger, dispose: true); }); //注冊 AppServiceOptions 類, 告知DI容器, 要基于配置文件AppServiceOptions section來實(shí)例化 services.AddOptions(); services.Configure<AppServiceOptions>(configuration.GetSection("AppServiceOptions")); }
主動從DI容器中獲取 AppServiceOptions 配置信息代碼如下, 注意GetRequiredService函數(shù)的的泛型參數(shù)要使用 IOptions<> 包一下.
var appServiceOptionsWrapper=serviceProvider.GetRequiredService<IOptions<AppServiceOptions>>(); AppServiceOptions appServiceOptions= appServiceOptionsWrapper.Value;
將 AppServiceOptions 注入到 FormMain 的代碼, 和主動從DI容器中獲取 AppServiceOptions 實(shí)例一樣, 都需要使用 IOptions<> 接口包一下構(gòu)造子形參.
public partial class FormMain : Form { private readonly IConfiguration _configuration; private readonly ILogger _logger; private AppServiceOptions _appServiceOptions; /// <summary> /// 為 FormMain 構(gòu)造子增加三個形參, 構(gòu)造子參數(shù)將由于DI容器自動注入 /// </summary> /// <param name="configuration">形參必須是接口 IConfigurations</param> /// <param name="logger">形參必須是 ILogger泛型類型, 不能是 ILogger 類型</param> /// <param name="appServiceOptionsWrapper">形參必須是 IOptions 泛型接口 </param> public FormMain(IConfiguration configuration, ILogger<FormMain> logger, IOptions<AppServiceOptions> appServiceOptionsWrapper) { _configuration = configuration; _logger = logger; _appServiceOptions = appServiceOptionsWrapper.Value; InitializeComponent(); var connectionString = _configuration.GetConnectionString("oeeDb"); //從配置文件中讀取oeeDb connectionString _logger.LogInformation(connectionString); //將connection String 寫入到日志文件中 } private void button1_Click(object sender, EventArgs e) { this.Text = _appServiceOptions.AppKey; } }
.net core 復(fù)雜 configuration Section 的讀取
appsettings文件定義一個復(fù)雜的設(shè)置項(xiàng), 頂層是一個json 數(shù)組, 里面又嵌套了另一個數(shù)組
"PlcDevices": [ { "PlcDeviceId": "Plc1", "IpAddress": "127.0.0.1", "Port": 1234, "SlaveId": 1, "DataPoints": [ { "ModbusAddress": 0, "EqpId": "eqp1" }, { "ModbusAddress": 0, "EqpId": "eqp2" } ] }, { "PlcDeviceId": "Plc2", "IpAddress": "127.0.0.2", "Port": 1234, "SlaveId": "2", "DataPoints": [ { "ModbusAddress": 0, "EqpId": "eqp3" }, { "ModbusAddress": 0, "EqpId": "eqp4" } ] } ]
對應(yīng)poco對象為:
public class PlcDevice { public string IpAddress { get; set; } = ""; public int Port { get; set; } = 0; public string PlcDeviceId { get; set; } = ""; public int SlaveId { get; set; } public List<DataPoint> DataPoints { get; set; } } public class DataPoint { public int ModbusAddress { get; set; } public string EqpId { get; set; } = ""; }
讀取 json 的C# 代碼:
services.AddOptions(); //實(shí)例化一個對應(yīng) PlcDevices json 數(shù)組對象, 使用了 IConfiguration.Get<T>() var PlcDeviceSettings= configuration.GetSection("PlcDevices").Get<List<PlcDevice>>(); //或直接通過 service.Configure<T>() 將appsettings 指定 section 放入DI 容器, 這里的T 為 List<PlcDevice> services.Configure<List<PlcDevice>>(configuration.GetSection("PlcDevices"));
到此這篇關(guān)于.Net6開發(fā)winform程序使用依賴注入的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
c#利用Session對象實(shí)現(xiàn)購物車的方法示例
這篇文章主要介紹了c#利用Session對象實(shí)現(xiàn)購物車的方法示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02帶著問題讀CLR via C#(筆記一)CLR的執(zhí)行模型
CLR (Common Language Runtime) 是一個可以由多種編程語言使用的“運(yùn)行時(shí)”。2013-04-04VS2019配置OpenCV4.1.0詳細(xì)教程與測試代碼(推薦)
這篇文章主要介紹了VS2019配置OpenCV4.1.0詳細(xì)教程與測試代碼,本文通過截圖實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03c#創(chuàng)建windows服務(wù)入門教程實(shí)例
windows服務(wù)是windows系統(tǒng)中一類特殊的應(yīng)用程序,一般情況下它們只會在后臺運(yùn)行,不會影響前臺操作,非常適合做一些不需要用戶參與的而又需要長時(shí)間執(zhí)行的任務(wù)2014-04-04關(guān)于Flyweight模式應(yīng)用實(shí)踐的相關(guān)介紹
本篇文章,小編將為大家介紹Flyweight模式應(yīng)用實(shí)踐,有需要的朋友可以參考一下2013-04-04