ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • C# 에서의 의존성 주입
    프로그래밍/의문 2022. 1. 22. 23:32
    반응형

    요약

    1. Microsoft.Extensions.DependencyInjection 패키지 설치.
    2. Microsoft.Extensions.DependencyInjection 네임스페이스의 ServiceCollection를 이용해 의존성 주입에 이용될 클래스들을 등록.
    3. ServiceCollection으로 ServiceProvider 빌드.
    4. ServiceProvider의 GetService<T>로 3의 ServiceCollection에 등록했던 인스턴스들을 사용.
    5. ServiceCollection에 등록한 클래스들이 사용하는 인수들은 ServiceProvider에 의해 알아서 주입이 됩니다.

    Microsoft.Extensions.DependencyInjection 패키지 설치.

    Nuget 같은 것을 이용해 Microsoft.Extensions.DependencyInjection 패키지를 설치합니다.

    Microsoft.Extensions.DependencyInjection

    의존성 주입에 사용될 클래스들을 등록

    ServiceCollection에 의존성 주입으로 사용할 클래스들 등록합니다.
    그리고 그 클래스들의 수명에 따라 AddSingleton, AddTransient, AddScope를 다르게 설정합니다.

    using Microsoft.Extensions.DependencyInjection;
    
    ...
    
    ServiceCollection collection = new ServiceCollection();
    
    ...
    
    collection.AddSingleton<ILogger, ConsoleLogger>();
    collection.AddTransient<TransientObject>();
    collection.AddScoped<ScopedObject>();
    • AddSingleton
      • 이 메소드로 등록되는 클래스는 싱글톤 인스턴스입니다.
      • ServiceProvider.GetService<T>() 를 호출하면 항상 같은 인스턴스가 반환 됩니다.
      • Logger 처럼 전역적으로 하나만 있는 인스턴스의 경우 적합합니다.
    • AddTransient
      • ServiceProvider.GetService<T>() 를 호출하면 항상 새 인스턴스가 반환 됩니다.
    • AddScope
      • ServiceProvider.GetService() 일정 범위 내에서는 항상 같은 인스턴스를 반환합니다.
      • 이 범위를 지정하는 방법은 아래 "ServiceCollection으로 ServiceProvider를 빌드하고, 사용하기"에 나온 코드에서 알 수 있습니다.

    ServiceCollection으로 ServiceProvider를 빌드하고, 사용하기.

    ServiceCollection.Build를 이용해 ServiceProvider를 만듭니다.

    ServiceCollection collection = new();
    
    collection.AddSingleton<ILogger, ConsoleLogger>();
    collection.AddTransient<TransientObject>();
    collection.AddScoped<ScopedObject>();
    
    ServiceProvider provider = collection.BuildServiceProvider();

    그 다음, provider.GetService<T> 를 호출해 인스턴스를 이용하면 됩니다.

    // loggerA와, loggerB는 서로 같은 인스턴스.
    ILogger loggerA = provider.GetService<ILogger>();
    ILogger loggerB = provider.GetService<ILogger>();
    
    // transientA, transientB 서로 다른 인스턴스.
    TransientObject transientA = provider.GetService<TransientObject>();
    TransientObject transientB = provider.GetService<TransientObject>();
    
    using(IServiceScope scope = provider.CreateScope())
    {// scopedA와, scopedB는 서로 같은 인스턴스.
        ScopedObject scopedA = scope.ServiceProvider.GetService<ScopedObject>();
        ScopedObject scopedB = scope.ServiceProvider.GetService<ScopedObject>();
    }
    
    using (IServiceScope scope = provider.CreateScope())
    {// scopedC와, scopedD는 서로 같은 인스턴스.
        ScopedObject scopedC = scope.ServiceProvider.GetService<ScopedObject>();
        ScopedObject scopedD = scope.ServiceProvider.GetService<ScopedObject>();
    }

     

    재밌는 점은 ServiceProvider.GetService<T>로 인스턴스가 만들어 질 때, 생성자에서 참조하는 인스턴스들은 ServiceProvider가 AddSingleton, AddTransient, AddScoped 등으로 등록됐던 클래스 중에서 넣어준다는 것입니다.

    using Microsoft.Extensions.DependencyInjection;
    
    public interface ILogger
    {
        void Log(string message);
    }
    
    public class ConsoleLogger : ILogger
    {
        public ConsoleLogger()
        {
            Console.WriteLine("Console Logger 생성 됨.");
        }
    
        public void Log(string message)
        {
            Console.WriteLine(message);
        }
    }
    
    public class TransientObject
    {
        ILogger _logger;
        ScopedObject _scoped;
    
        public TransientObject(ILogger logger, ScopedObject scoped)
        {
            _logger = logger;
            _scoped = scoped;
    
            _logger.Log("TransientObject 생성 됨.");
        }
    }
    
    
    public class ScopedObject
    {
        ILogger _logger;
    
        public ScopedObject(ILogger logger)
        {
            _logger = logger;
    
            _logger.Log("ScopedObject 생성 됨.");
        }
    }
    
    static class Program
    {
        public static void Main(string[] args)
        {
            ServiceCollection collection = new();
    
            collection.AddSingleton<ILogger, ConsoleLogger>();
            collection.AddTransient<TransientObject>();
            collection.AddScoped<ScopedObject>();
    
            ServiceProvider provider = collection.BuildServiceProvider();
    
            // loggerA와, loggerB는 서로 같은 인스턴스.
            Console.WriteLine("Singleton");
    
            ILogger loggerA = provider.GetService<ILogger>();
            ILogger loggerB = provider.GetService<ILogger>();
    
            // transientA, transientB 서로 다른 인스턴스.
            Console.WriteLine("Transient");
    
            TransientObject transientA = provider.GetService<TransientObject>();
            TransientObject transientB = provider.GetService<TransientObject>();
    
            using(IServiceScope scope = provider.CreateScope())
            {// scopedA와, scopedB는 서로 같은 인스턴스.
                Console.WriteLine("Scoped 0");
    
                ScopedObject scopedA = scope.ServiceProvider.GetService<ScopedObject>();
                ScopedObject scopedB = scope.ServiceProvider.GetService<ScopedObject>();
            }
    
            using (IServiceScope scope = provider.CreateScope())
            {// scopedC와, scopedD는 서로 같은 인스턴스.
                Console.WriteLine("Scoped 1");
    
                ScopedObject scopedC = scope.ServiceProvider.GetService<ScopedObject>();
                ScopedObject scopedD = scope.ServiceProvider.GetService<ScopedObject>();
            }
        }
    }

     

    위 코드의 결과.

     

    참고

    .NET에서 종속성 주입 사용 | Microsoft Docs

    반응형
Designed by Tistory.