.NET Core DI 및 하위 클래스

Nov 21 2020

여기서 .NET Core를 처음 사용합니다. 내 질문에 대한 답변을 제공하는 다른 문서, 스레드 또는 가이드를 검색했지만 찾을 수 없습니다. 있다고 생각되면 지적 해주세요.

DI를 사용하여 간단한 .NET 5 콘솔 앱을 만들려고 노력하고 있으며 문자 그대로 로깅을 사용하여 클래스를 구조화하는 데 어려움을 겪고 있습니다.

  1. .NET Core에서 DI를 사용하여 로거 (또는 다른 서비스)를 하위 클래스로 전달하는 올바른 방법입니까? 아래 코드에 따라 부모 클래스 생성자에서 각 하위 클래스에 대해 추가 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 사용;
    Microsoft.Extensions.DependencyInjection 사용;
    Microsoft.Extensions.Hosting 사용;
    Microsoft.Extensions.Logging 사용;
    시스템 사용;
    System.IO 사용;
    System.Threading.Tasks 사용;
    
    네임 스페이스 ConsoleApp1
    {
        수업 프로그램
        {
            정적 비동기 작업 Main (string [] args)
            {
                var builder = new 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");
                    })
                    .짓다();
    
                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 ") ??"Development "}. json", 선택 사항 : true)
                    .AddEnvironmentVariables ();
            }
        }
    }

TestClass.cs :

    Microsoft.Extensions.Configuration 사용;
    Microsoft.Extensions.Logging 사용;
    System.Threading.Tasks 사용;
    
    네임 스페이스 ConsoleApp1
    {
        공용 클래스 TestClass : ITestClass
        {
            개인 읽기 전용 ILogger <TestClass> _log;
            개인 읽기 전용 ILogger <SubClass> _subClassLog;
            개인 읽기 전용 IConfiguration _config;
    
            public TestClass (ILogger <TestClass> 로그, ILogger <SubClass> subClassLog, IConfiguration 구성)
            {
                _log = 로그;
                _subClassLog = subClassLog;
                _config = 구성;
            }
    
            공용 비동기 작업 Run ()
            {
                for (int i = 0; i <_config.GetValue <int> ( "Loop"); i ++)
                    _log.LogDebug ( "루프 디버그 {loopNumber}", i);
    
                for (int i = 0; i <_config.GetValue <int> ( "Loop"); i ++)
                    _log.LogInformation ( "루프 정보 {loopNumber}", i);
    
                for (int i = 0; i <_config.GetValue <int> ( "Loop"); i ++)
                    _log.LogWarning ( "루프 경고 {loopNumber}", i);
    
                for (int i = 0; i <_config.GetValue <int> ( "Loop"); i ++)
                    _log.LogError ( "루프 오류 {loopNumber}", i);
    
                for (int i = 0; i <_config.GetValue <int> ( "Loop"); i ++)
                    _log.LogCritical ( "루프 임계 {loopNumber}", i);
    
                var subClass = new SubClass (_subClassLog, _config);
                await subClass.AnotherProc ();
    
                await SubClass.StaticProc ();
            }
        }
    }

SubClass.cs :

    Microsoft.Extensions.Configuration 사용;
    Microsoft.Extensions.Logging 사용;
    시스템 사용;
    System.Threading.Tasks 사용;
    
    네임 스페이스 ConsoleApp1
    {
        공용 클래스 SubClass : ISubClass
        {
            개인 읽기 전용 ILogger <SubClass> _log;
            개인 읽기 전용 IConfiguration _config;
    
            public SubClass (ILogger <SubClass> 로그, IConfiguration 구성)
            {
                _log = 로그;
                _config = 구성;
            }
    
            공용 비동기 작업 AnotherProc ()
            {
                for (int i = 0; i <_config.GetValue <int> ( "Loop"); i ++)
                    _log.LogDebug ( "루프 디버그 {loopNumber}", i);
    
                for (int i = 0; i <_config.GetValue <int> ( "Loop"); i ++)
                    _log.LogInformation ( "루프 정보 {loopNumber}", i);
    
                for (int i = 0; i <_config.GetValue <int> ( "Loop"); i ++)
                    _log.LogWarning ( "루프 경고 {loopNumber}", i);
    
                for (int i = 0; i <_config.GetValue <int> ( "Loop"); i ++)
                    _log.LogError ( "루프 오류 {loopNumber}", i);
    
                for (int i = 0; i <_config.GetValue <int> ( "Loop"); i ++)
                    _log.LogCritical ( "루프 임계 {loopNumber}", i);
            }
    
            공용 정적 비동기 태스크 <bool> StaticProc ()
            {
                var returnBool = true;
    
                시험
                {
                    throw new Exception ( "");
                }
                catch (예외)
                {
                    returnBool = 거짓;
    
                    // 인스턴스가 없으므로 _log 예외가 없습니다.
                    // 독립형 ILogger를 만드는 방법은 무엇입니까?
                }
    
                return returnBool;
            }
        }
    }

appsettings.json :

    {
      "루프": 15
    }

log4net.config :

    <? xml version = "1.0"encoding = "utf-8"?>
    <log4net>
        <appender name = "Info"type = "log4net.Appender.RollingFileAppender">
            <threshold value = "DEBUG"/>
            <param name = "File"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 {yyyy-MM-dd HH : mm : ss}-[% t] % -5p % c % x-% m % n"/>
            </ 레이아웃>
        </ 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 = "5120KB"/>
            <lockingModel 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"/>
            </ 레이아웃>
        </ appender>
        <루트>
            <appender-ref ref = "정보"/>
            <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 예제 1 주석에서 언급 한 것과 같은 콘솔 앱에 대해 작동하는 DI도 있습니다.

예 2

이모는 정적 메서드와 함께 사용하지 않아야합니다. 여기 내 두 번째 예제를보십시오. dotnet fiddle 예제 2