.Net6开发winform程序使用依赖注入

.net  Blazor webassembly 和 webAPI 内建支持依赖注入, Winform 和 Console 应用虽然不带有依赖注入功能, 但增加依赖注入也很简单. 

本文将示例如何为 WinForm 程序增加依赖注入特性, 实现通过DI容器获取Cofiguration 实例, 并读取appsettings.json文件.

安装依赖库, 有点多

  • Microsoft.Extensions.DependencyInjection 库, 依赖注入的类库
  • Microsoft.Extensions.Configuration 库, 包含IConfiguration接口 和 Configuration类
  • Microsoft.Extensions.Configuration.Json 库, 为 IConfiguration 增加了读取 Json 文件功能,
  • Microsoft.Extensions.Hosting 库,  提供 Host 静态类,  有能力从 appsettings.{env.EnvironmentName}.json 加载相应 env  的设定值,  并将设定值用于IConfiguration/ILoggerFactory中, 同时增加 Console/EventSourceLogger 等 logger. 仅适用于 Asp.Net core 和 Console 类应用
  • 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, 顶层节点要求是 Serilog. 
  • Serilog.Enrichers.Thread 和 Serilog.Enrichers.Environment 库,  为输出日志文本增加 Thread和 env 信息

补充库:

  • Microsoft.Extensions.Options.ConfigurationExtensions 库,  为DI容器增加了从配置文件中实例化对象的能力, 即  serviceCollection.Configure<TOptions>(IConfiguration)
  • Microsoft.Extensions.Options 库,  提供以强类型的方式读取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);  //注册各种服务类

            //先用DI容器生成 serviceProvider, 然后通过 serviceProvider 获取Main Form的注册实例
           var serviceProvider =services.BuildServiceProvider();

           var formMain = serviceProvider.GetRequiredService<FormMain>();   //主动从容器中获取FormMain实例, 这是简洁写法
           // var formMain = (FormMain)serviceProvider.GetService(typeof(FormMain));  //更繁琐的写法
           Application.Run(formMain);
        }

        /// <summary>
        /// 在DI容器中注册所有的服务类型
        /// </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 , 验证依赖注入的效果

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 构造子增加两个形参, 构造子参数将由于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 已经类库已经考虑到在配置文件中存储 connectionString 是一个普遍的做法, 所以类库内置支持了.

如果在 appsettings.json 中存一些自定义的信息, 如何方便读取呢? 微软推荐的 Options 模式, 下面详细介绍.

首先安装库:

  • Microsoft.Extensions.Options.ConfigurationExtensions 库,  为DI容器增加了从配置文件中实例化对象的能力, 即  serviceCollection.Configure<TOptions>(IConfiguration)
  • Microsoft.Extensions.Options 库,  提供以强类型的方式读取configuration文件, 这是.Net中首选的读取configuration文件方式.

假设 appsettings.json 中要存放appKey和appSecret信息, 具体配置如下:

  "AppServiceOptions": {
    "appKey": "appkey1",
    "appSecret": "appSecret1"
  }

定义对应的 Poco Class,  推荐后缀为 Options,

    public class AppServiceOptions
    {
        public string AppKey { get; set; } = "";
        public string AppSecret { get; set; } = "";

    }

注册函数 ConfigureServices()中,  注册 AppServiceOptions 类, 告知DI容器, 要基于配置文件AppServiceOptions section来实例化

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来实例化
            services.AddOptions();
            services.Configure<AppServiceOptions>(configuration.GetSection("AppServiceOptions"));
        }

主动从DI容器中获取 AppServiceOptions 配置信息代码如下, 注意GetRequiredService函数的的泛型参数要使用 IOptions<> 包一下.

   var appServiceOptionsWrapper=serviceProvider.GetRequiredService<IOptions<AppServiceOptions>>();
   AppServiceOptions appServiceOptions= appServiceOptionsWrapper.Value;

将 AppServiceOptions 注入到 FormMain 的代码, 和主动从DI容器中获取 AppServiceOptions 实例一样, 都需要使用 IOptions<> 接口包一下构造子形参.

public partial class FormMain : Form
    {
        private readonly IConfiguration _configuration;
        private readonly ILogger _logger;
        private AppServiceOptions _appServiceOptions;

        /// <summary>
        /// 为 FormMain 构造子增加三个形参, 构造子参数将由于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 复杂 configuration Section 的读取

appsettings文件定义一个复杂的设置项, 顶层是一个json 数组, 里面又嵌套了另一个数组

"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"
        }
      ]
    }
  ]

对应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();
//实例化一个对应 PlcDevices json 数组对象, 使用了 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"));

到此这篇关于.Net6开发winform程序使用依赖注入的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • ASP.NET MVC实现依赖注入的完整过程

    前言 在java的spring中有自动注入功能,使得代码变得更加简洁灵活,所以想把这个功能移植到c#中,接下来逐步分析实现过程 1.使用自动注入场景分析 在asp.net mvc中,无论是什么代码逻辑分层,最终的表现层为Controller层,所以我们注入点就是在Controller中,这里我们需要替换默认的ControllerFactory,扫描代码中标记需要注入的对象,进行实例化注入 public class FastControllerFactory : DefaultController

  • ASP.NET Core  依赖注入框架的使用

    目录 一.IoC框架 二.IoC-Autofac 三..NET Core中自带DI的使用 四.Autofac 使用 五.批量注入 前言: 还记得上篇文章中ASP.NET Core 依赖注入详细最后提及到,假如服务越来越多怎么处理呢,本篇文章将会带来解决办法.这篇是接上一篇文章的,概念方面的可以参考上一篇文章. 一.IoC框架 先说说常见的Ioc框架吧. Autofac: 目前net用的比较多,好多大佬的项目比较优先选择的框架. Ninject: 已经很少用了,还时在很早的文章中见过. Unity

  • ASP.NET Core MVC 依赖注入View与Controller

    目录 一.ASP.NET Core MVC 之依赖注入 View 1.填充查找数据 2.重写服务 二. ASP.NET Core MVC 之依赖注入 Controller 1.构造函数注入 2.使用 FromServices 操作注入 3.在控制器中访问设置 一.ASP.NET Core MVC 之依赖注入 View ASP.NET Core 支持在试图中使用依赖注入.这将有助于提供视图专用的服务,比如本地化或者仅用于填充视图元素的数据.应尽量保持控制器和视图之间的关注点分离.视图所显示的大部分

  • ASP.NET Core 依赖注入详细

    目录 一.控制反转 二.好莱坞法则 三.流程控制 四.三种依赖注入方式 1.构造器注入 2.属性注入 3.方法注入 五.生命周期 六.ASP.Net Core 中自带的注入 前言: ASP.NET Core 应用在启动过程中会依赖各种组件提供服务,而这些组件会以接口的形式标准化,这些组件这就是我们所说的服务,ASP.NET Core框架建立在一个底层的依赖注入框架之上,它使用容器提供所需的服务.要了解依赖注入容器以及它的机制,我们需要了解什么是依赖注入. 一.控制反转 说道依赖注入就不得不提控制

  • 理解ASP.NET Core 依赖注入(Dependency Injection)

    目录 依赖注入 什么是依赖注入 依赖注入有什么好处 ASP.NET Core内置的依赖注入 服务生存周期 服务释放 TryAdd{Lifetime}扩展方法 解析同一服务的多个不同实现 Replace && Remove 扩展方法 Autofac 服务解析和注入 构造函数注入 方法注入 属性注入 一些注意事项 框架默认提供的服务 依赖注入 什么是依赖注入 简单说,就是将对象的创建和销毁工作交给DI容器来进行,调用方只需要接收注入的对象实例即可. 微软官方文档-DI 依赖注入有什么好处 依赖

  • .Net6开发winform程序使用依赖注入

    .net  Blazor webassembly 和 webAPI 内建支持依赖注入, Winform 和 Console 应用虽然不带有依赖注入功能, 但增加依赖注入也很简单.  本文将示例如何为 WinForm 程序增加依赖注入特性, 实现通过DI容器获取Cofiguration 实例, 并读取appsettings.json文件. 安装依赖库, 有点多 Microsoft.Extensions.DependencyInjection 库, 依赖注入的类库 Microsoft.Extensi

  • .Net6 winform 程序使用依赖注入

    引入NuGet 注册Autofac 在Program的var app = builder.Build():前加上这段代码 builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()); builder.Host.ConfigureContainer<ContainerBuilder>(builder => { builder.RegisterType<LogRecordsService>

  • C#开发Winform程序调用存储过程

    数据表及数据准备: create table Member ( MemberId int primary key identity(1,1), MemberAccount nvarchar(20) unique, MemberPwd nvarchar(20), MemberName nvarchar(20), MemberPhone nvarchar(20) ) truncate table Member insert into Member(MemberAccount,MemberPwd,Me

  • .net6 使用Senparc开发小程序配置过程

    目录 1.添加引用 2.添加配置文件 3.在appsetting.jso里面配置参数 4.配置program 1.添加引用 2.添加配置文件 /// <summary> /// 微信 /// </summary> public class WeChat { // 小程序 public string WxOpenAppId { get; set; } public string WxOpenAppSecret { get; set; } //// 微信支付 //public stri

  • PHP进阶学习之依赖注入与Ioc容器详解

    本文实例讲述了PHP依赖注入与Ioc容器.分享给大家供大家参考,具体如下: 背景 在很多编程语言(例如java)开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,一旦有修改,牵扯的类会很多. 最早在java的spring提出了依赖注入的思想,即依赖类不由程序员实例化,而是通过spring容器帮我们new指定实例并且将实例注入到需要该对象的类中.目前许多主流PHP框架也使用了依赖注入容器,如ThinkPHP.L

  • .net程序开发IOC控制反转和DI依赖注入详解

    目录 IOC控制反转 DI依赖注入 服务生命周期 其它 IOC控制反转 大部分应用程序都是这样编写的:编译时依赖关系顺着运行时执行的方向流动,从而生成一个直接依赖项关系图. 也就是说,如果类 A 调用类 B 的方法,类 B 调用 C 类的方法,则在编译时,类 A 将取决于类 B,而 B 类又取决于类 C 应用程序中的依赖关系方向应该是抽象的方向,而不是实现详细信息的方向.而这就是控制反转的思想. 应用依赖关系反转原则后,A 可以调用 B 实现的抽象上的方法,让 A 可以在运行时调用 B,而 B

  • AngularJS应用开发思维之依赖注入3

    找不到的API? AngularJS提供了一些功能的封装,但是当你试图通过全局对象angular去 访问这些功能时,却发现与以往遇到的库大不相同. $http 比如,在jQuery中,我们知道它的API通过一个全局对象:$ 暴露出来,当你需要 进行ajax调用时,使用$.ajax()就可以了.这样的API很符合思维的预期. AngularJS也暴露了一个全局对象:angular,也对ajax调用进行封装提供了一个 $http对象,但是,但是,当你试图沿用旧经验访问angular.$http时,发

  • 在.NET Core控制台程序中如何使用依赖注入详解

    背景介绍 Dependency Injection:又称依赖注入,简称DI.在以前的开发方式中,层与层之间.类与类之间都是通过new一个对方的实例进行相互调用,这样在开发过程中有一个好处,可以清晰的知道在使用哪个具体的实现.随着软件体积越来越庞大,逻辑越来越复杂,当需要更换实现方式,或者依赖第三方系统的某些接口时,这种相互之间持有具体实现的方式不再合适.为了应对这种情况,就要采用契约式编程:相互之间依赖于规定好的契约(接口),不依赖于具体的实现.这样带来的好处是相互之间的依赖变得非常简单,又称松

  • C#控制台程序中使用官方依赖注入的实现

    asp.net core 中已经自带了一个官方的依赖注入框架,现在想把它应用到控制台程序中,控制台程序是最简洁的代码结构,摒除了其他一堆嵌入的框架代码,只包含最简洁的入口函数,是学习基础类库框架的最佳选择,为什么最佳,原因很简单,没有其他项的干扰,Demo效果清晰明了,方便写测试代码,调试也顺畅. 1. 业务接口类设计编写 先要写一个测试用的接口和类,我写了一个很简单的计算求和的接口类和方法,方便待会注入演示效果. 我设计的演示接口很简单,IBaseService 基础接口负责生成一个随机的数字

  • Asp.net core程序中使用微软的依赖注入框架

    我之前在博文中介绍过Asp.net core下系统自带的依赖注入框架,这个依赖框架在Microsoft.Extensions.DependencyInjection中实现,本身并不是.net core的一部分(是asp.net core的一部分),本文这里就简单的介绍下载.net core控制台程序中使用这个框架,顺便也了解下这个框架的全貌. 首先我们需要安装Microsoft.Extensions.DependencyInjection这个Nuget包,也可以直接使用Microsoft.Asp

随机推荐