Rest API Template 만들기 - EP 03 (Dependency Injection, Scrutor)

2022. 12. 26. 00:00ASPNET/ASPNET 7

반응형

ASPNET Core 는 기본적으로 Dependency Injection 을 이용하여 의존성을 분리 하고 있다. 

https://yogingang.tistory.com/2

 

Dotnet 6 Dependency Injection

종속성 클래스와 해당 종속성 간의 Ioc (Inversion of Control)를 실현하는 기술로 DI (Dependency Injection) 라는 디자인 패턴을 지원한다. 종류 (서비스 수명) Transient : 요청할 때마다 만들어 짐, 요청이 끝날

yogingang.tistory.com

https://learn.microsoft.com/ko-kr/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-7.0 

 

ASP.NET Core에서 종속성 주입

ASP.NET Core에서 종속성 주입을 구현하는 방법 및 사용 방법에 알아봅니다.

learn.microsoft.com

기본적으로  Lifecycle 이 있다.

Transient

: 매번 새로 Create 하는 방식

 

Scope

: 클라이언트 요청(연결)마다 한 번씩 서비스가 생성됨

 

Singleton

: 한번만 Create 하는 방식

 

자 이제 이전에 만들었던 Project 를 활용해 보자.

이전 Project 에서 Login 을 구현했었다

이부분에서 Token 을 생성하는 부분을 수정해 보자

 

1. TokenGenerator 라는 Token 생성 전용 class 를 만들자

2. TokenGenerator 을 Dependency Inejection 시스템에 등록하자

3. Login.cs 에서 해당 TokenGenerator 를 resolve 해서 사용하자

 

일단 아래와 같이 폴더 구조를 생성하자

Shared/Interfaces

 

그리고 해당 폴더 밑에 ITokenGenerator.cs 를 생성하자

Shared/Interfaces/ITokenGenerator.cs

namespace ApiServer.Shared.Interfaces;

public interface ITokenGenerator
{
    string Create();
}

다음 폴더를 하나 더 생성하고 TokenGenerator.cs 를 구현하자

Shared/Utility/TokenGenerator.cs

using ApiServer.Shared.Interfaces;

namespace ApiServer.Shared.Utility;

public class TokenGenerator : ITokenGenerator
{
    public string Create() => Guid.NewGuid().ToString("N");
}

이제 위의 TokenGenerator 을 DI 시스템에 Register 하겠다.

TokenGenerator 는 ThreadSafe 하며 ReenTrant 하기 때문에 Singleton 방식으로 등록하겠다. 

Program.cs

using ApiServer.Shared.Interfaces;
using ApiServer.Shared.Utility;
...
builder.Services.AddSingleton<ITokenGenerator,TokenGenerator>();

이제 Login 에 이것을 적용해 보자

User/Login.cs

using ApiServer.Shared.Interfaces;
using MediatR;
using System.Runtime.CompilerServices;

namespace ApiServer.Features.User;

public class Login
{
    public class Command : IRequest<Response>
    {
        public string Id { get; set; } = string.Empty;
        public string Pasword { get; set; } = string.Empty;
    }
    public class Response
    {
        public bool Result { get; set; }
        public Error? Error { get; set; }
        public string? AccessToken { get; set; }
    }

    public class Error
    {
        public string Code { get; set; } = string.Empty;
        public string Message { get; set; } = string.Empty;
    }

    public class CommandHandler : IRequestHandler<Command, Response>
    {
        private readonly ITokenGenerator _tokenGenerator;

        // ITokenGenerator 를 Constructor injection 
        public CommandHandler(ITokenGenerator tokenGenerator) 
        {
            _tokenGenerator = tokenGenerator;
        }
        public Task<Response> Handle(Command request, CancellationToken cancellationToken)
        {
            var response = new Response { Result = false };
            string? accessToken = null;
            
            if (request.Pasword == "1234")
            {
                //accessToken = Guid.NewGuid().ToString("N"); // 기존 코딩 comment
                accessToken = _tokenGenerator.Create(); // DI 를 통해 가져온 TokenGenerator 를 사용
                response.Result = true;
            }
            else
            {
                response.Error = new Error()
                {
                    Code = "02",
                    Message = $"Login Failed, check your password"
                };
            }
            response.AccessToken = accessToken;
            return Task.FromResult(response);
        }
    }


}

 

 

 

Scrutor

ASPNET core 의 Dependency Injection (이후 DI 로 칭함) System 은 편리한 시스템이지만

Register 하려는 class 가 늘어날 수록 관리 하기가 점점 힘들어진다. 

또한 하나의 project 가 아닌 여러 project 로 이루어져 있고 이들 모두를 관리하려면

정말 복잡한 형태가 되어 버린다. 

 

그래서 이러한 단점을 개선한고 자동으로 class 가 DI system 에 Register 하는 방법이 있다.

3rd party libry 들이 있는데 우리는 그중에 Scrutor 을 이용하여 이를 구현할 것이다. 

개발자 명령 프롬프트로 이동

Ctrl + ` 또는 View -> Terminal click -> 개발자 명령 프롬프트로 이동

개발자 명령 프롬프트에서 프로젝트 폴더로 이동

**이미 프로젝트 폴더에 있다면 이동하지 않아도 된다. **

(현재 [솔루션명].sln 파일이 있는 폴더라면 [프로젝트명].csproj 파일이 있는 폴더로 이동)

다음 실행

 

dotnet add package Scrutor

 

의존성 주입을 위한 interface 추가

 

Shared-->Injectables 폴더 추가 -> Injectable.cs 추가 -> 코드 수정

namespace ApiServer.Shared.Injectables;

public interface IInjectableService { }
public interface ITransient : IInjectableService { }
public interface IScoped : IInjectableService { }
public interface ISingleton : IInjectableService { }

 Program.cs

using ApiServer.Shared.Injectables;
using ApiServer.Shared.Interfaces;
...
//builder.Services.AddSingleton<ITokenGenerator,TokenGenerator>(); // comment 처리
builder.Services.Scan(scan => scan
                            .FromAssemblies(AssemblyHelper.GetAllAssemblies(SearchOption.AllDirectories))
                            .AddClasses(
                                classes => classes.AssignableTo<ITransient>()
                             )
                            .AsSelfWithInterfaces()
                            .WithTransientLifetime()
                            .AddClasses(
                                classes => classes.AssignableTo<IScoped>()
                             )
                            .AsSelfWithInterfaces()
                            .WithScopedLifetime()
                            .AddClasses(
                                classes => classes.AssignableTo<ISingleton>())
                            .AsSelfWithInterfaces()
                            .WithSingletonLifetime()
                            );

Shared/Interfaces/ITokenGenerator.cs 

using ApiServer.Shared.Injectables;

namespace ApiServer.Shared.Interfaces;

public interface ITokenGenerator : ISingleton
{
    string Create();
}

 그리고 실행하면 이전 동작과 똑같이 동작한다. 

즉 이제부터는 Injectable.cs 에 정의한 ITransient, IScoped, ISingleton  을 상속하면 자동으로

해당 Lifecyle 에 맞게 DI 시스템에 register 된다. 

 

앞으론 이걸 적극 활용하자 

 

관련영상

https://youtu.be/xq-0KNuU2-M

 

반응형