C# - .NET 6 - 使用通用主机与不使用通用主机的控制台应用程序

Tov*_*ich 27 c# console-application .net-core

我正在使用 .NET 6 中的新顶级语句来创建一个简单的控制台应用程序,但我不了解使用“通用主机”的优点/缺点。你可以解释吗?

我的通用主机代码:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

Console.WriteLine("Hello, World!");

using var host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((_, services) =>
    {
        services.AddTransient<ITestInterface, TestClass>();
    })
    .Build();

Test();
Console.ReadKey();

void Test()
{
    var testClass = host.Services.GetRequiredService<ITestInterface>();
    testClass.TestMethod();
}
Run Code Online (Sandbox Code Playgroud)

相对

using Microsoft.Extensions.DependencyInjection;

Console.WriteLine("Hello, World!");

var services = new ServiceCollection();
services.AddTransient<ITestInterface, TestClass>();
var servicesProvider = services.BuildServiceProvider();

Test();
Console.ReadKey();

void Test()
{
    var testClass = servicesProvider.GetRequiredService<ITestInterface>();
    testClass.TestMethod();
}
Run Code Online (Sandbox Code Playgroud)

Pet*_*ons 28

使用通用主机的好处是,默认情况下已经为您设置了很多服务,请参阅文档

CreateDefaultBuilder 方法:

  • 将内容根设置为 GetCurrentDirectory() 返回的路径。
  • 从以下位置加载主机配置:
    • 以 DOTNET_ 为前缀的环境变量。
    • 命令行参数。
  • 从以下位置加载应用程序配置:
    • 应用程序设置.json。
    • appsettings.{环境}.json。
    • 当应用程序在开发环境中运行时的 Secret Manager。
    • 环境变量。
    • 命令行参数。
  • 添加以下日志记录提供程序:
    • 安慰
    • 调试
    • 事件源
    • 事件日志(仅当在 Windows 上运行时)
  • 当环境为开发时启用范围验证和依赖项验证。

ConfigureServices 方法公开了将服务添加到 Microsoft.Extensions.DependencyInjection.IServiceCollection 实例的功能。稍后,可以通过依赖注入来提供这些服务。

您没有正确使用通用主机。例如:通常会添加托管服务,这样您就可以使用正确的 DI,而不是手动解析所需的服务。

可以在文档中找到一个示例

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices((hostContext, services) =>
            {
                services.AddHostedService<Worker>();
            });
}
Run Code Online (Sandbox Code Playgroud)

如果我们使用包含依赖项的实现来扩展此示例,Worker它将如下所示:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices((hostContext, services) =>
            {
                services.AddTransient<ITestInterface, TestClass>();
                services.AddHostedService<Worker>();
            });
}

internal class Worker : IHostedService
{
    public Worker(ITestInterface testClass)
    {
        testClass.Foo();
    }


    public Task StartAsync(CancellationToken cancellationToken)
    {
        throw new NotImplementedException();
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        throw new NotImplementedException();
    }
}

public interface ITestInterface
{
    void Foo();
}

public class TestClass : ITestInterface
{
    public void Foo()
    {

    }
}
Run Code Online (Sandbox Code Playgroud)

现在您会看到创建了一个新实例并注入了Worker一个实例。ITestInterface无需调用servicesProvider.GetRequiredService<ITestInterface>();哪个是反模式。

决策树

  • 如果您不需要所有这些附加服务,您可以选择不使用通用主机,就像问题中的第二个代码示例一样。
  • 如果您确实想使用日志记录、应用程序配置等服务,您应该使用通用主机。

  • 通用主机还配备配置和日志记录,因此即使有人不想要托管服务,它也很有用。 (3认同)