.NET Core DI e subclasses

Nov 21 2020

Novo no .NET Core aqui. Eu procurei por outra documentação, tópico ou guia que responda às minhas perguntas, mas não consigo encontrar um, se você acha que há, por favor, indique.

Estou tentando criar um aplicativo de console .NET 5 simples com DI e, literalmente, ficando preso na estruturação de classes com registro.

  1. Esta é a maneira correta de passar um logger (ou qualquer outro serviço) para uma subclasse usando DI no .NET Core? Conforme o código abaixo, no meu construtor de classe pai, eu pego um ILogger extra para cada subclasse, por exemplo. ILogger<SubClass>?

    public TestClass(ILogger<TestClass> log, ILogger<SubClass> subClassLog, IConfiguration config)
    
  2. Como eu inicializaria um logger no meu proc estático StaticProc?

    public static async Task<bool> StaticProc()
    

Program.cs:

    usando Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    usando Microsoft.Extensions.Hosting;
    usando Microsoft.Extensions.Logging;
    using System;
    using System.IO;
    using System.Threading.Tasks;
    
    namespace ConsoleApp1
    {
        programa de aula
        {
            Tarefa assíncrona estática principal (string [] args)
            {
                var builder = new ConfigurationBuilder ();
                BuildConfig (construtor);
    
                var host = Host.CreateDefaultBuilder ()
                    .ConfigureServices ((contexto, serviços) =>
                    {
                        services.AddTransient <ITestClass, TestClass> ();
                        services.AddTransient <ISubClass, SubClass> ();
                    })
                    .ConfigureLogging (logBuilder =>
                    {
                        logBuilder.SetMinimumLevel (LogLevel.Trace);
                        logBuilder.AddLog4Net ("log4net.config");
                    })
                    .Construir();
    
                var log = host.Services.GetService <ILoggerFactory> () .CreateLogger <Programa> ();
    
                log.LogInformation ($"Application Started");
    
                var svc = ActivatorUtilities.CreateInstance<TestClass>(host.Services);
                await svc.Run();
    
                log.LogInformation($"Aplicativo encerrado");
            }
    
            static void BuildConfig (construtor IConfigurationBuilder)
            {
                builder.SetBasePath (Directory.GetCurrentDirectory ())
                    .AddJsonFile ("appsettings.json", opcional: falso, reloadOnChange: verdadeiro)
                    .AddJsonFile ($ "appsettings. {Environment.GetEnvironmentVariable (" ASPNETCORE_ENVIRONMENT ") ??" Development "}. Json", opcional: verdadeiro)
                    .AddEnvironmentVariables ();
            }
        }
    }

TestClass.cs:

    usando Microsoft.Extensions.Configuration;
    usando Microsoft.Extensions.Logging;
    using System.Threading.Tasks;
    
    namespace ConsoleApp1
    {
        public class TestClass: ITestClass
        {
            private readonly ILogger <TestClass> _log;
            private readonly ILogger <SubClass> _subClassLog;
            private readonly IConfiguration _config;
    
            public TestClass (ILogger <TestClass> log, ILogger <SubClass> subClassLog, IConfiguration config)
            {
                _log = log;
                _subClassLog = subClassLog;
                _config = config;
            }
    
            Execução de tarefa assíncrona pública ()
            {
                para (int i = 0; i <_config.GetValue <int> ("Loop"); i ++)
                    _log.LogDebug ("Loop debug {loopNumber}", i);
    
                para (int i = 0; i <_config.GetValue <int> ("Loop"); i ++)
                    _log.LogInformation ("Loop info {loopNumber}", i);
    
                para (int i = 0; i <_config.GetValue <int> ("Loop"); i ++)
                    _log.LogWarning ("Loop warn {loopNumber}", i);
    
                para (int i = 0; i <_config.GetValue <int> ("Loop"); i ++)
                    _log.LogError ("Erro de loop {loopNumber}", i);
    
                para (int i = 0; i <_config.GetValue <int> ("Loop"); i ++)
                    _log.LogCritical ("Loop crítico {loopNumber}", i);
    
                var subClass = new SubClass (_subClassLog, _config);
                esperar subClass.AnotherProc ();
    
                esperar SubClass.StaticProc ();
            }
        }
    }

SubClass.cs:

    usando Microsoft.Extensions.Configuration;
    usando Microsoft.Extensions.Logging;
    using System;
    using System.Threading.Tasks;
    
    namespace ConsoleApp1
    {
        public class SubClass: ISubClass
        {
            private readonly ILogger <SubClass> _log;
            private readonly IConfiguration _config;
    
            public SubClass (ILogger <SubClass> log, IConfiguration config)
            {
                _log = log;
                _config = config;
            }
    
            public async Task AnotherProc ()
            {
                para (int i = 0; i <_config.GetValue <int> ("Loop"); i ++)
                    _log.LogDebug ("Loop debug {loopNumber}", i);
    
                para (int i = 0; i <_config.GetValue <int> ("Loop"); i ++)
                    _log.LogInformation ("Loop info {loopNumber}", i);
    
                para (int i = 0; i <_config.GetValue <int> ("Loop"); i ++)
                    _log.LogWarning ("Loop warn {loopNumber}", i);
    
                para (int i = 0; i <_config.GetValue <int> ("Loop"); i ++)
                    _log.LogError ("Erro de loop {loopNumber}", i);
    
                para (int i = 0; i <_config.GetValue <int> ("Loop"); i ++)
                    _log.LogCritical ("Loop crítico {loopNumber}", i);
            }
    
            public static async Task <bool> StaticProc ()
            {
                var returnBool = true;
    
                experimentar
                {
                    lance uma nova exceção ("");
                }
                catch (exceção ex)
                {
                    returnBool = false;
    
                    // Nenhuma instância, portanto, nenhuma exceção _log.
                    // Como criar ILogger autônomo?
                }
    
                return returnBool;
            }
        }
    }

appsettings.json:

    {
      "Loop": 15
    }

log4net.config:

    <? xml version = "1.0" encoding = "utf-8"?>
    <log4net>
        <appender name = "Info" type = "log4net.Appender.RollingFileAppender">
            <valor limite = "DEBUG" />
            <param name = "Arquivo" value = "App_Data \\ Log \\ Info.log" />
            <param name = "AppendToFile" value = "true" />
            <maximumFileSize value = "5120KB" />
            <lockingModel type = "log4net.Appender.FileAppender + MinimalLock" />
            <maxSizeRollBackups value = "1000" />
            <layout type = "log4net.Layout.PatternLayout">
                <conversionPattern value = "% d {aaaa-MM-dd HH: mm: ss} - [% t]% -5p% c% x -% m% n" />
            </layout>
        </appender>
        <appender name = "Error" type = "log4net.Appender.RollingFileAppender">
            <valor limite = "Erro" />
            <param name = "Arquivo" value = "App_Data \\ Log \\ Error.log" />
            <param name = "AppendToFile" value = "true" />
            <maximumFileSize value = "5120KB" />
            <lockingModel type = "log4net.Appender.FileAppender + MinimalLock" />
            <maxSizeRollBackups value = "1000" />
            <layout type = "log4net.Layout.PatternLayout">
                <conversionPattern value = "% d {aaaa-MM-dd HH: mm: ss} - [% t]% -5p% c% x -% m% n" />
            </layout>
        </appender>
        <root>
            <appender-ref ref = "Info" />
            <appender-ref ref = "Erro" />
        </root>
    </log4net>

Respostas

Martin Nov 21 2020 at 00:13

Resumo

Você também pode injetar um em ILoggerFactoryvez de ILogger:

public TestClass(ILoggerFactory loggerFactory, IConfiguration config)
{
     // create a class logger
     _log = loggerFactory.CreateLogger<TestClass>();

     // and whenever you need a new instance of a special class logger use this:
     _subClassLog = loggerFactory.Create<SubTestClass>();
     _config = config;
}

Mas esteja ciente de que isso cria uma nova instância do ILogger. Logando no asp net core No seu caso, se você realmente precisa do método estático com um logger, crie-o apenas se já existir:

private static readonly ILogger<SubClass> _log;
private readonly IConfiguration _config;

public SubClass(ILoggerFactory loggerFactory, IConfiguration config)
{
     _log = _log ??= loggerFactory.CreateLogger<SubClass>();
     _config = config;
}

Mas prefiro ou melhor aconselho você a fazer isso sem ter estática e apenas registrar o serviço como singleton.

Exemplo 1

Eu adicionei um exemplo completo aqui: dotnet fiddle Exemplo 1 Também com o DI funcional para aplicativos de console, como mencionado nos comentários.

Exemplo 2

Imo, você não deve usá-lo com métodos estáticos. Basta olhar para o meu segundo exemplo aqui dotnet fiddle Exemplo 2