.Net6開(kāi)發(fā)winform程序使用依賴注入
.net? Blazor webassembly 和 webAPI 內(nèi)建支持依賴注入, Winform 和 Console 應(yīng)用雖然不帶有依賴注入功能, 但增加依賴注入也很簡(jiǎn)單.?
本文將示例如何為 WinForm 程序增加依賴注入特性, 實(shí)現(xiàn)通過(guò)DI容器獲取Cofiguration 實(shí)例, 并讀取appsettings.json文件.
安裝依賴庫(kù), 有點(diǎn)多
- Microsoft.Extensions.DependencyInjection 庫(kù), 依賴注入的類庫(kù)
- Microsoft.Extensions.Configuration 庫(kù), 包含IConfiguration接口 和 Configuration類
- Microsoft.Extensions.Configuration.Json 庫(kù), 為 IConfiguration 增加了讀取 Json 文件功能,
- Microsoft.Extensions.Hosting 庫(kù),? 提供 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 庫(kù),? 包含 ILogger 和 ILoggerFactory 接口
- Serilog.Extensions.Logging 庫(kù), 為DI 容器提供 AddSerilog() 方法.
- Serilog.Sinks.File 庫(kù), 提供 Serilog rolling logger
- Serilog.Sinks.Console 庫(kù), 增加 serilog console logger
- Serilog.Settings.Configuration 庫(kù), 允許在 appsetting.json? 配置 Serilog, 頂層節(jié)點(diǎn)要求是 Serilog.?
- Serilog.Enrichers.Thread 和 Serilog.Enrichers.Environment 庫(kù),? 為輸出日志文本增加 Thread和 env 信息
補(bǔ)充庫(kù):
- Microsoft.Extensions.Options.ConfigurationExtensions 庫(kù),? 為DI容器增加了從配置文件中實(shí)例化對(duì)象的能力, 即? serviceCollection.Configure<TOptions>(IConfiguration)
- Microsoft.Extensions.Options 庫(kù),? 提供以強(qiáng)類型的方式讀取configuration文件, 這是.Net中首選的讀取configuration文件方式.
appsettings.json 配置文件
配置一個(gè) 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); //注冊(cè)各種服務(wù)類
//先用DI容器生成 serviceProvider, 然后通過(guò) serviceProvider 獲取Main Form的注冊(cè)實(shí)例
var serviceProvider =services.BuildServiceProvider();
var formMain = serviceProvider.GetRequiredService<FormMain>(); //主動(dòng)從容器中獲取FormMain實(shí)例, 這是簡(jiǎn)潔寫法
// var formMain = (FormMain)serviceProvider.GetService(typeof(FormMain)); //更繁瑣的寫法
Application.Run(formMain);
}
/// <summary>
/// 在DI容器中注冊(cè)所有的服務(wù)類型
/// </summary>
/// <param name="services"></param>
private static void ConfigureServices(ServiceCollection services)
{
//注冊(cè) 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è)形參, 構(gòu)造子參數(shù)將由于DI容器自動(dòng)注入
/// </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
上面示例, 我們通過(guò) _configuration.GetConnectionString("oeeDb")? 可以拿到connectionString, 非常方便, 這主要是得益于.Net 已經(jīng)類庫(kù)已經(jīng)考慮到在配置文件中存儲(chǔ) connectionString 是一個(gè)普遍的做法, 所以類庫(kù)內(nèi)置支持了.
如果在 appsettings.json 中存一些自定義的信息, 如何方便讀取呢? 微軟推薦的 Options 模式, 下面詳細(xì)介紹.
首先安裝庫(kù):
- Microsoft.Extensions.Options.ConfigurationExtensions 庫(kù),? 為DI容器增加了從配置文件中實(shí)例化對(duì)象的能力, 即? serviceCollection.Configure<TOptions>(IConfiguration)
- Microsoft.Extensions.Options 庫(kù),? 提供以強(qiáng)類型的方式讀取configuration文件, 這是.Net中首選的讀取configuration文件方式.
假設(shè) appsettings.json 中要存放appKey和appSecret信息, 具體配置如下:
"AppServiceOptions": {
"appKey": "appkey1",
"appSecret": "appSecret1"
}
定義對(duì)應(yīng)的 Poco Class,? 推薦后綴為 Options,
public class AppServiceOptions
{
public string AppKey { get; set; } = "";
public string AppSecret { get; set; } = "";
}
注冊(cè)函數(shù) ConfigureServices()中,? 注冊(cè) AppServiceOptions 類, 告知DI容器, 要基于配置文件AppServiceOptions section來(lái)實(shí)例化
private static void ConfigureServices(ServiceCollection services)
{
//注冊(cè) 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);
});
//注冊(cè) AppServiceOptions 類, 告知DI容器, 要基于配置文件AppServiceOptions section來(lái)實(shí)例化
services.AddOptions();
services.Configure<AppServiceOptions>(configuration.GetSection("AppServiceOptions"));
}
主動(dòng)從DI容器中獲取 AppServiceOptions 配置信息代碼如下, 注意GetRequiredService函數(shù)的的泛型參數(shù)要使用 IOptions<> 包一下.
var appServiceOptionsWrapper=serviceProvider.GetRequiredService<IOptions<AppServiceOptions>>(); AppServiceOptions appServiceOptions= appServiceOptionsWrapper.Value;
將 AppServiceOptions 注入到 FormMain 的代碼, 和主動(dòng)從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è)形參, 構(gòu)造子參數(shù)將由于DI容器自動(dòng)注入
/// </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文件定義一個(gè)復(fù)雜的設(shè)置項(xiàng), 頂層是一個(gè)json 數(shù)組, 里面又嵌套了另一個(gè)數(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"
}
]
}
]
對(duì)應(yīng)poco對(duì)象為:
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í)例化一個(gè)對(duì)應(yīng) PlcDevices json 數(shù)組對(duì)象, 使用了 IConfiguration.Get<T>()
var PlcDeviceSettings= configuration.GetSection("PlcDevices").Get<List<PlcDevice>>();
//或直接通過(guò) service.Configure<T>() 將appsettings 指定 section 放入DI 容器, 這里的T 為 List<PlcDevice>
services.Configure<List<PlcDevice>>(configuration.GetSection("PlcDevices"));
到此這篇關(guān)于.Net6開(kāi)發(fā)winform程序使用依賴注入的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Winform+.Net6實(shí)現(xiàn)圖片拖拽上傳功能
- Log4net在.Net?Winform項(xiàng)目中的使用實(shí)例詳解
- Winform項(xiàng)目中使用FastReport.Net報(bào)表控件
- VisualStudio2019中為.NET Core WinForm App啟用窗體設(shè)計(jì)器
- .NET WinForm實(shí)現(xiàn)在listview中添加progressbar的方法
- 在WinForm和WPF中使用GMap.Net地圖插件簡(jiǎn)單教程
- .Net Winform 實(shí)現(xiàn)CSS3.0 潑墨畫效果(示例代碼)
相關(guān)文章
C# Newtonsoft.Json 解析多嵌套json 進(jìn)行反序列化的實(shí)例
這篇文章主要介紹了C# Newtonsoft.Json 解析多嵌套json 進(jìn)行反序列化的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-01-01
C# IDE VS2005中的Hosting Process (vshost.exe)作用介紹
這篇文章主要介紹了C# IDE VS2005中的Hosting Process (vshost.exe)作用介紹,vshost.exe是一個(gè)宿主進(jìn)程,主要用來(lái)提高調(diào)試效率,需要的朋友可以參考下2015-01-01

