代码改变世界

在 .NET Core 3 上将 HostBuilder、ServiceProvider 和依赖注入与 Windows Forms一起使用

  音乐让我说  阅读(308)  评论(0编辑  收藏  举报

在上一篇文章中,我们讨论了如何将 .NET Core 3.0 依赖注入和服务提供程序与 WPF 一起使用但 .NET Core 3.x 也支持 Windows 窗体,因此是时候展示如何在此应用程序模型中使用HostBuilder、服务提供者和依赖注入的相同概念了。

首先,在创建 .NET Core Windows Forms 应用程序后,我们需要将 NuGet 包Microsoft.Extensions.Hosting添加到项目中。它将允许我们使用 HostBuilder,此外,它会自动导入一堆其他必需的包。现在让我们打开Program.cs文件并添加以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private static void Main()
{
    // ...
    var host = Host.CreateDefaultBuilder()
             .ConfigureAppConfiguration((context, builder) =>
             {
                 // Add other configuration files...
                 builder.AddJsonFile("appsettings.local.json", optional: true);
             })
             .ConfigureServices((context, services) =>
             {
                 ConfigureServices(context.Configuration, services);
             })
             .ConfigureLogging(logging =>
             {
                 // Add other loggers...
             })
             .Build();
 
    var services = host.Services;
    var mainForm = services.GetRequiredService<MainForm>();
    Application.Run(mainForm);
}
 
private static void ConfigureServices(IConfiguration configuration,
    IServiceCollection services)
{
    // ...
    services.AddSingleton<MainForm>();
}

第 4-18 行的 HostBuilder 配置遵循我们在上一篇文章中已经介绍过的相同结构,因此请参阅它以获取更多信息。之后,在第 21 行,我们检索在服务集合中添加的MainForm(第 29 行),最后我们使用Application.Run方法启动应用程序(第 22 行)。

我们现在可以运行应用程序:一切都会按预期工作。现在我们可以利用 .NET Core 3 提供的所有功能。让我们还将一个名为appsettings.json的文件添加到项目的根文件夹中。将其Build Action属性设置为ContentCopy to Output DirectoryCopy if newer

1
2
3
4
5
6
7
{
  "AppSettings": {
    "StringSetting": "Value",
    "IntegerSetting": 42,
    "BooleanSetting": true
  }
}

我们之前看到的CreateDefaultBuilder方法会自动加载该文件并使其对应用程序可用。然后,我们创建一个AppSettings.cs文件来保存配置设置。该文件将映射我们在appsettings.json中写入的设置:

1
2
3
4
5
6
7
8
public class AppSettings
{
    public string StringSetting { get; set; }
  
    public int IntegerSetting { get; set; }
  
    public bool BooleanSetting { get; set; }
}

此外,还创建一个带有其接口的示例服务:

1
2
3
4
5
6
7
8
9
public interface ISampleService
{
    string GetCurrentDate();
}
  
public class SampleService : ISampleService
{
    public string GetCurrentDate() => DateTime.Now.ToLongDateString();
}
举报此广告

现在我们必须像往常一样在 IoC 容器中注册这些服务:

1
2
3
4
5
6
7
8
9
10
private void ConfigureServices(IConfiguration configuration,
    IServiceCollection services)
{
    services.Configure<AppSettings>
            (configuration.GetSection(nameof(AppSettings)));
 
    services.AddScoped<ISampleService, SampleService>();
 
    //...
}

请记住,MainForm 本身位于 IoC 容器中。因此,当我们从 Service Provider 获取它时,它会自动注入所有需要的服务。我们只需要修改它的构造函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private readonly IServiceProvider serviceProvider;
private readonly ISampleService sampleService;
private readonly AppSettings settings;
 
public MainForm(IServiceProvider serviceProvider,
                ISampleService sampleService,
                IOptions<AppSettings> settings)
{
    InitializeComponent();
 
    this.serviceProvider = serviceProvider;
    this.sampleService = sampleService;
    this.settings = settings.Value;
}

运行此代码,我们将获得如下结果:

 


注入依赖项的 .NET Core 3.0 Windows 窗体应用程序

最后,让我们尝试向应用程序添加第二个表单,并使用主表单中的按钮打开它。但是,在此之前,请记住,在撰写本文时,适用于 .NET Core 的 Windows 窗体设计器仅在 Visual Studio 16.5 预览版中可用。如果您还没有,可以参考文章末尾的完整示例。

因此,在服务集合中注册新表单(在 Program.cs 文件中):

1
2
3
4
5
6
private static void ConfigureServices(IConfiguration configuration,
    IServiceCollection services)
{
    // ...
    services.AddTransient<SecondForm>();
}

在第 5 行,我们将 Form 注册为瞬态依赖项,这意味着,每次我们尝试获取对它的引用时,我们都会获得一个新实例。当然,我们也可以使用AddScopedAddSingleton请记住,在桌面应用程序的上下文中,Scoped 和 Singleton 总是获得相同的实例,因为在这种情况下,只要我们的应用程序运行,我们就有一个范围。

然后,在MainForm.cs添加代码以在单击按钮时打开新表单:

1
2
3
4
5
private void OpenSecondFormButton_Click(object sender, EventArgs e)
{
    var form = serviceProvider.GetRequiredService<SecondForm>();
    form.ShowDialog(this);
}

我们使用传递给 MainForm 构造函数的 ServiceProvider 来获取对SecondForm的引用,并调用它的ShowDialog方法(第 3-4 行)。但是 SecondForm 本身是在 IoC Container 中的,所以反过来它可以在构造函数中接收它需要的依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public partial class SecondForm : Form
{
    private readonly ISampleService sampleService;
    private readonly AppSettings settings;
 
    public SecondForm(ISampleService sampleService,
                      IOptions<AppSettings> settings)
    {
        InitializeComponent();
 
        this.sampleService = sampleService;
        this.settings = settings.Value;
    }
}
 

 


向服务提供商打开第二个表单

您可以使用以下链接下载示例应用程序:

https://files.cnblogs.com/files/Music/WindowsFormsNetCore.rar

 

谢谢浏览!

 

点击右上角即可分享
微信分享提示