从 Core 控制台应用程序的嵌套类中访问 IConfiguration 等 DI 元素

问题描述 投票:0回答:1

我浏览了许多教程并观看了几个有关在 .NET Core 控制台应用程序中使用 DI 的视频。然而,它们似乎都没有达到我想要的效果。在大型控制台应用程序中,我们可能会调用/引用多个类,并且每个类都可能需要访问记录器或配置设置。我遇到的所有教程和解释都只显示了一层深度,并将日志记录和配置 DI 实例传递到第一层。

如果类 1 调用类 2,然后类 2 调用类 3,会怎样。假设类 3 需要获取配置值,或者类 2 需要将一些信息或调试数据写入日志。如何使用 2 类和 3 类中的 DI 访问 ILogger 和 IConfiguration?

我根据 Tim Corey 的视频教程“.NET Core Console App with Dependency Injection, Logging, and Settings”创建了一个非常简单的示例,他在其中为控制台应用程序设置了配置和 Serilog。但同样,他只深入到最初的工人阶级。

该应用程序由 3 个主要类组成,Program.cs(用于设置配置)、Runner.cs(工作服务类)和 SubClass.cs(从 Runner.cs 调用的子类)。我的代码适用于记录和检索辅助服务类 (Runner.cs) 中的设置,但是当我尝试从子类访问记录器或配置设置时,我遇到了问题。

程序.cs

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;

namespace DiConsoleExample
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var builder = new ConfigurationBuilder();
            BuildConfig(builder);

            Log.Logger = new LoggerConfiguration()
                .ReadFrom.Configuration(builder.Build())
                .Enrich.FromLogContext()
                .WriteTo.Console()
                .CreateLogger();

            Log.Logger.Information("Application Starting");

            var host = Host.CreateDefaultBuilder()
                .ConfigureServices((context, services) =>
                {
                    services.AddTransient<IRunner, Runner>();
                })
                .UseSerilog()
                .Build();

            var svc = ActivatorUtilities.CreateInstance<Runner>(host.Services);
            svc.Run();
        }

        static void BuildConfig(IConfigurationBuilder builder)
        {
            builder.SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true)
                .AddEnvironmentVariables();
        }

    }
}

Runner.cs

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace DiConsoleExample
{
    public interface IRunner
    {
        void Run();
    }

    public class Runner : IRunner
    {
        private readonly ILogger<Runner> _log;
        private readonly IConfiguration _config;

        public Runner(ILogger<Runner> log, IConfiguration config)
        {
            _log = log;
            _config = config;
        }


        public void Run()
        {
            _log.LogInformation("Value for 'MyRunnerSetting': {settingValue}", _config.GetValue<string>("MyRunnerSetting"));

            var sub = new SubClass();
            sub.GetMySetting();
        }
    }
}

子类.cs

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace DiConsoleExample
{
    public class SubClass
    {
        private readonly ILogger<Runner> _log;
        private readonly IConfiguration _config;

        public SubClass(ILogger<Runner> log, IConfiguration config)
        {
            _log = log;
            _config = config;
        }

        public void GetMySetting()
        {
            _log.LogInformation("Value for 'MySubClassSetting': {settingValue}", _config.GetValue<string>("MySubClassSetting"));
        }
    }
}

appsettings.json

{
  "MyRunnerSetting": "Runner123",
  "MySubClassSetting":  "SubClass234"
}

我遇到的错误是,当我创建一个新的 SubClass() 时,它无法使用 DI 注入的日志和配置服务:

There is no argument given that corresponds to the required parameter 'log' of 'SubClass.SubClass(ILogger<Runner>, IConfiguration)

同样,如果 Runner.cs 中没有对 SubClass 进行调用,则效果很好,但我需要知道如何通过 DI 访问 Logger 和 Configurations。我知道我可以在每个类中放置每个类的构建/配置语句,但这似乎违背了 DI 的目的并重复了代码。

哦,我在 VS 2022 中使用 .NET 8。


编辑。我不应该在我的解释中使用“子类”,因为它不继承任何东西。我应该使用“NestedClass”(我的错)

我的问题是,由于我的 Runner.cs 可能会在大型应用程序中新建多个嵌套类,因此如何将 ILogger 和 IConfiguration 放入这些嵌套类中?

在 .net 框架中,我可以将 log4net 放入任何嵌套类中以开始日志记录,或在任何类中调用 ConfigurationManager 来获取设置。在 Core ASP.NET 中,我可以在每个控制器中使用带有 ILogger 和 IConfiguration 的构造函数,但我无法弄清楚如何在 Runner.cs 服务之外的任何嵌套类中访问或引用 ILogger 和 IConfiguration。

c# .net-core dependency-injection console-application
1个回答
0
投票

扔掉您所了解的有关 .NET Framework 的有关日志记录和配置的所有内容,因为它们与 .NET (Core) 世界无关。您无需手动

new
进行分类,DI 框架会为您提供。并且您不直接绑定到
IConfiguration
,而是使用 选项模式。所以你的课程看起来像这样:

public record SubClassOptions(
    string MySubClassSetting);

public class Runner
{
    private ILogger<Runner> _logger;
    private ISubClass _subClass;

    public Runner(ILogger<Runner> logger, ISubClass subClass)
    {
        _logger = logger;
        _subClass = subClass;
    }

    public void Run()
    {
        _subClass.GetMySetting();
    }
}

public interface ISubClass
{
    void GetMySetting();
}

public class SubClass : ISubClass
{
    private readonly ILogger<Runner> _logger;
    private readonly SubClassOptions _options;

    public SubClass(ILogger<Runner> log, SubClassOptions config)
    {
        _log = log;
        _config = config;
    }

    public void GetMySetting()
    {
        _log.LogInformation(
            "Value for 'MySubClassSetting': {SettingValue}",
            _config.MySubClassSetting);
    }
}

以及您的服务注册:

services.AddSingleton<SubClassOptions>(
    configuration.GetRequiredSection("SubClassSection").Get<SubClassOptions>());
services.AddScoped<ISubClass, SubClass>();
services.AddScoped<Runner>();
© www.soinside.com 2019 - 2024. All rights reserved.