.NET Core DI и подклассы

Nov 21 2020

Новинка .NET Core здесь. Я искал другую документацию, ветку или руководство, которое отвечает на мои вопросы, но не могу найти его. Если вы думаете, что да, укажите на это.

Я пытаюсь создать простое консольное приложение .NET 5 с DI и буквально застреваю на структурировании классов с ведением журнала.

  1. Это правильный способ передать регистратор (или любую другую службу) в подкласс с помощью DI в .NET Core? Согласно приведенному ниже коду, в моем конструкторе родительского класса я беру дополнительный ILogger для каждого подкласса, например. ILogger<SubClass>?

    public TestClass(ILogger<TestClass> log, ILogger<SubClass> subClassLog, IConfiguration config)
    
  2. Как мне инициализировать регистратор в моем статическом процессе StaticProc?

    public static async Task<bool> StaticProc()
    

Program.cs:

    с использованием Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    с использованием Microsoft.Extensions.Hosting;
    с помощью Microsoft.Extensions.Logging;
    используя Систему;
    используя System.IO;
    using System.Threading.Tasks;
    
    пространство имен ConsoleApp1
    {
        программа класса
        {
            статическая асинхронная задача Main (строка [] аргументы)
            {
                var builder = новый ConfigurationBuilder ();
                BuildConfig (строитель);
    
                var host = Host.CreateDefaultBuilder ()
                    .ConfigureServices ((контекст, услуги) =>
                    {
                        services.AddTransient <ITestClass, TestClass> ();
                        services.AddTransient <ISubClass, SubClass> ();
                    })
                    .ConfigureLogging (logBuilder =>
                    {
                        logBuilder.SetMinimumLevel (LogLevel.Trace);
                        logBuilder.AddLog4Net ("log4net.config");
                    })
                    .Build ();
    
                var log = host.Services.GetService <ILoggerFactory> () .CreateLogger <Program> ();
    
                log.LogInformation ($"Application Started");
    
                var svc = ActivatorUtilities.CreateInstance<TestClass>(host.Services);
                await svc.Run();
    
                log.LogInformation($«Заявка завершена»);
            }
    
            static void BuildConfig (построитель IConfigurationBuilder)
            {
                builder.SetBasePath (Directory.GetCurrentDirectory ())
                    .AddJsonFile ("appsettings.json", необязательно: false, reloadOnChange: true)
                    .AddJsonFile ($ "appsettings. {Environment.GetEnvironmentVariable (" ASPNETCORE_ENVIRONMENT ") ??" Разработка "}. Json", необязательно: true)
                    .AddEnvironmentVariables ();
            }
        }
    }

TestClass.cs:

    с использованием Microsoft.Extensions.Configuration;
    с помощью Microsoft.Extensions.Logging;
    using System.Threading.Tasks;
    
    пространство имен ConsoleApp1
    {
        открытый класс TestClass: ITestClass
        {
            закрытый только для чтения ILogger <TestClass> _log;
            закрытый только для чтения ILogger <SubClass> _subClassLog;
            закрытый только для чтения IConfiguration _config;
    
            общедоступный TestClass (журнал ILogger <TestClass>, ILogger <SubClass> subClassLog, конфигурация IConfiguration)
            {
                _log = журнал;
                _subClassLog = subClassLog;
                _config = config;
            }
    
            общедоступная асинхронная задача Run ()
            {
                for (int i = 0; i <_config.GetValue <int> ("Цикл"); i ++)
                    _log.LogDebug ("Отладка цикла {loopNumber}", i);
    
                for (int i = 0; i <_config.GetValue <int> ("Цикл"); i ++)
                    _log.LogInformation ("Информация о цикле {loopNumber}", i);
    
                for (int i = 0; i <_config.GetValue <int> ("Цикл"); i ++)
                    _log.LogWarning ("Предупреждение цикла {номер цикла}", i);
    
                for (int i = 0; i <_config.GetValue <int> ("Цикл"); i ++)
                    _log.LogError ("Ошибка цикла {loopNumber}", i);
    
                for (int i = 0; i <_config.GetValue <int> ("Цикл"); i ++)
                    _log.LogCritical ("Критический цикл {loopNumber}", i);
    
                var subClass = новый подкласс (_subClassLog, _config);
                ждать subClass.AnotherProc ();
    
                ждать SubClass.StaticProc ();
            }
        }
    }

SubClass.cs:

    с использованием Microsoft.Extensions.Configuration;
    с помощью Microsoft.Extensions.Logging;
    используя Систему;
    using System.Threading.Tasks;
    
    пространство имен ConsoleApp1
    {
        открытый класс SubClass: ISubClass
        {
            закрытый только для чтения ILogger <SubClass> _log;
            закрытый только для чтения IConfiguration _config;
    
            общедоступный подкласс (журнал ILogger <SubClass>, конфигурация IConfiguration)
            {
                _log = журнал;
                _config = config;
            }
    
            общедоступная асинхронная задача AnotherProc ()
            {
                for (int i = 0; i <_config.GetValue <int> ("Цикл"); i ++)
                    _log.LogDebug ("Отладка цикла {loopNumber}", i);
    
                for (int i = 0; i <_config.GetValue <int> ("Цикл"); i ++)
                    _log.LogInformation ("Информация о цикле {loopNumber}", i);
    
                for (int i = 0; i <_config.GetValue <int> ("Цикл"); i ++)
                    _log.LogWarning ("Предупреждение цикла {номер цикла}", i);
    
                for (int i = 0; i <_config.GetValue <int> ("Цикл"); i ++)
                    _log.LogError ("Ошибка цикла {loopNumber}", i);
    
                for (int i = 0; i <_config.GetValue <int> ("Цикл"); i ++)
                    _log.LogCritical ("Критический цикл {loopNumber}", i);
            }
    
            общедоступная статическая асинхронная задача <bool> StaticProc ()
            {
                var returnBool = true;
    
                пытаться
                {
                    выбросить новое исключение ("");
                }
                улов (исключение ex)
                {
                    returnBool = false;
    
                    // Нет экземпляра, поэтому нет исключения _log.
                    // Как создать автономный ILogger?
                }
    
                return returnBool;
            }
        }
    }

appsettings.json:

    {
      «Петля»: 15
    }

log4net.config:

    <? xml version = "1.0" encoding = "utf-8"?>
    <log4net>
        <appender name = "Info" type = "log4net.Appender.RollingFileAppender">
            <пороговое значение = "DEBUG" />
            <param name = "File" value = "App_Data \\ Log \\ Info.log" />
            <param name = "AppendToFile" value = "true" />
            <maximumFileSize value = "5120 КБ" />
            <lockModel type = "log4net.Appender.FileAppender + MinimalLock" />
            <maxSizeRollBackups value = "1000" />
            <layout type = "log4net.Layout.PatternLayout">
                <conversionPattern value = "% d {yyyy-MM-dd HH: mm: ss} - [% t]% -5p% c% x -% m% n" />
            </layout>
        </appender>
        <appender name = "Error" type = "log4net.Appender.RollingFileAppender">
            <threshold value = "Ошибка" />
            <param name = "File" value = "App_Data \\ Log \\ Error.log" />
            <param name = "AppendToFile" value = "true" />
            <maximumFileSize value = "5120 КБ" />
            <lockModel type = "log4net.Appender.FileAppender + MinimalLock" />
            <maxSizeRollBackups value = "1000" />
            <layout type = "log4net.Layout.PatternLayout">
                <conversionPattern value = "% d {yyyy-MM-dd HH: mm: ss} - [% t]% -5p% c% x -% m% n" />
            </layout>
        </appender>
        <корень>
            <appender-ref ref = "Info" />
            <appender-ref ref = "Ошибка" />
        </root>
    </log4net>

Ответы

Martin Nov 21 2020 at 00:13

Резюме

Вы также можете ввести ILoggerFactoryвместо 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;
}

Но имейте в виду, что это создает новый экземпляр ILogger. Вход в asp net core В вашем случае, если вам действительно нужен статический метод с регистратором, создайте его, только если он уже существует:

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

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

Но я предпочту или лучше посоветую вам сделать это без статики и просто зарегистрировать службу как синглтон.

Пример 1

Я добавил здесь полный пример: dotnet fiddle Example 1 Также с рабочим DI для консольных приложений, как указано в комментариях.

Пример 2

Имо, вы должны использовать его не со статическими методами. Просто взгляните на мой второй пример здесь dotnet fiddle Пример 2