[ASP.NET Core] Dependency Injection 예제

참고


소개

  • ASP.NET Core는 처음부터 종속성 주입을 지원하도록 설계되었습니다.
  • ASP.NET Core는 기본 제공 IoC 컨테이너를 사용하여 생성자 또는 메서드를 통해 종속성 클래스의 객체를 주입합니다.

IoC(Inversion Of Control)란?

  • Inversion of Control(IoC) : Dependency Inversion Principle 을 적용하는 방법입니다.
  • Inversion of Control은 상위 수준 components 가 하위 수준 components의 구체적인 구현이 아닌 추상화(abstraction) 에 의존하도록 하는 실제 메커니즘입니다.
  • Inversion of Control은 할리우드 원리(Hollywood Principle) 라고도 합니다.
  • 이 이름은 할리우드 영화 산업에서 따온 것으로, 배우 오디션이 끝난 후 감독은 보통 "우리에게 전화하지 마세요. 우리가 전화할 것입니다." 라고 말합니다.

IoC Container란? : DI(Dependency Injection) Container 라고도 하며, Components 의 자동 Dependency Injection을 제공하는 프로그래밍 Framework 입니다.


Built-in IoC Container

  • ASP.NET Core 프레임워크에는 다른 타사 IoC 컨테이너만큼 많은 기능이 없는 즉시 사용 가능한 간단한 IoC 컨테이너가 포함되어 있습니다.
  • 자동 등록, 스캐닝, 인터셉터 또는 데코레이터와 같은 더 많은 기능을 원하면 내장 IoC 컨테이너를 타사 컨테이너로 교체할 수 있습니다.
  • 기본 제공 컨테이너는 기본적으로 생성자 주입을 지원하는 IServiceProvider 구현으로 표시됩니다.
  • 내장 IoC 컨테이너에서 관리하는 유형(클래스) 를 서비스라고 합니다.
  • ASP.NET Core 에는 기본적으로 두 가지 유형의 서비스가 있습니다.
    • Framework Services : IApplicationBuilder, IHostingEnvirnoment, ILoggerFactory 등과 같은 ASP.NET Core 프레임 워크의 일부 서비스
    • Application Services : 프로그래머가 응용 프로그램을 위해 만드는 서비스(사용자 지정 유형 또는 클래스) 를 의미합니다.
  • IoC 컨테이너가 자동으로 애플리케이션 서비스를 주입하도록 하려면 먼저 IoC 컨테이너에 서비스를 등록해야 합니다.

Dependency Injection 예제

  • ASP.NET Core Web API 프로젝트를 생성하고, Dependency Injection(DI) 로직을 작성해 보도록 하겠습니다.

1. ASP.NET Core Web API 프로젝트 생성

  • 첫 번째로, ASP.NET Core Web API 프로젝트를 생성합니다.


2. Model 클래스 생성

  • 예제로 Blog 라는 모델 클래스를 생성합니다.

  • Models 폴더를 생성하고, 해당 폴더 안에 Blog.cs 클래스를 생성합니다.
namespace BlogDIDemo.Models
{
    public class Blog
    {
        public int Id { get; set; } 
        public string Title { get; set; } = string.Empty;
        public string Content { get; set; } = string.Empty; 
    }
}

3. 데이터 관련 클래스 생성

  • 다음으로 앞서 만든 Blog 객체를 관리 및 데이터 생성하는 클래스를 생성합니다.
  • Data 폴더를 생성하고, 폴더 안에 BlogRepository.cs 클래스를 생성하여 다음과 같이 코드를 작성합니다.

using BlogDIDemo.Models;

namespace BlogDIDemo.Data
{
    public class BlogRepository
    {
        public static List<Blog> blogs = new()
        {
            new Blog(){ Id = 1, Title = "DI Deep Dive", Content = "This is a five part series"},
            new Blog(){ Id = 2, Title = "Minimal API", Content = "Learn in 30 mins"},
            new Blog(){ Id = 3, Title = "Prescription API", Content = "Still under construction"}
        };

        public List<Blog> GetAllBlogs()
        {
            return blogs;
        }
    }
}

4. 컨트롤러 추가

  • 다음으로 Controllers 폴더 안에 읽기/쓰기 전용의 API 컨트롤러 클래스를 생성합니다.
  • 이름은 BlogController.cs 라고 하였습니다.

  • 그리고 다음과 같이 BlogController.cs 에 코드를 작성합니다.
using BlogDIDemo.Data;
using BlogDIDemo.Models;
using Microsoft.AspNetCore.Mvc;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace BlogDIDemo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class BlogController : ControllerBase
    {
        BlogRepository repository = new BlogRepository();

        // GET: api/<BlogController>
        [HttpGet]
        public ActionResult<IEnumerable<Blog>> Get()
        {
            var blogs = repository.GetAllBlogs();
            return Ok(blogs);
        }
    }
}
  • 여기까지 작성 후, 프로젝트 실행하게 되면 정상적으로 실행은 됩니다.

  • 하지만, 현재 BlogController 클래스 안에는 직접 BlogRepository 클래스를 의존하고 있습니다.
  • 이와 같이 직접적인 의존은 추후에 코드 변경사항이 생기게 되면 참조되어 있는 모든 부분을 찾아서 수정해야 하는 단점이 있습니다.
  • 때문에 이런 문제를 해결하려면, Interface 를 이용하여 추상화 작업을 하면 됩니다.

5. 인터페이스 생성

  • Data 폴더 안에 IBlogRepository.cs 인터페이스를 생성합니다.
  • 그리고 BlogRepository 클래스는 IBlogRepository 인터페이스를 상속 받도록 합니다.

IBlogRepository.cs

using BlogDIDemo.Models;

namespace BlogDIDemo.Data
{
    public interface IBlogRepository
    {
        List<Blog> GetAllBlogs();
    }
}

BlogRepository.cs

using BlogDIDemo.Models;

namespace BlogDIDemo.Data
{
    public class BlogRepository : IBlogRepository
    {
        public static List<Blog> blogs = new()
        {
            new Blog() { Id = 1, Title = "DI Deep Dive", Content = "This is a five part series" },
            new Blog() { Id = 2, Title = "Minimal API", Content = "Learn in 30 mins" },
            new Blog() { Id = 3, Title = "Prescription API", Content = "Still under construction" }
        };

        public List<Blog> GetAllBlogs()
        {
            return blogs;
        }
    }
}

6. 생성자에 의존성 주입

  • 이제 앞서 생성한 IBlogRepository 인터페이스의 객체를 BlogsController 클래스 생성자에 주입합니다.
  • 이 작업은 앞서 BlogRepository 객체를 직접 참조하는 강한 결합을 해제하고 느슨한 결합으로 바꾸는 작업입니다.
  • BlogController.cs 의 바뀐 소스 코드 내용은 다음과 같습니다.
using BlogDIDemo.Data;
using BlogDIDemo.Models;
using Microsoft.AspNetCore.Mvc;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace BlogDIDemo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class BlogController : ControllerBase
    {
        private readonly IBlogRepository _repository;
        public BlogController(IBlogRepository repository)
        {
            _repository = repository;
        }

        // GET: api/<BlogController>
        [HttpGet]
        public ActionResult<IEnumerable<Blog>> Get()
        {
            var blogs = _repository.GetAllBlogs();
            return Ok(blogs);
        }
    }
}
  • 위 코드에서 보는 것과 같이 IBlogRepository 객체만 받지, 직접적으로 클래스 안에서 BlogRepository 객체를 생성하는 부분은 없어졌습니다.

7. 종속성 추가하기

  • 이제 Dependency Injection 을 나타내는 코드는 모두 작성 완료하였습니다.
  • 마지막으로 종속성을 추가해야 합니다.
  • 종속성을 추가하는 방법은 program.cs 에 다음과 같음 모드를 추가하면 됩니다.

program.cs

// My Dependency Injection Service Add
builder.Services.AddTransient<IBlogRepository, BlogRepository>();
  • 실행 결과, 정상적으로 실행 되는 것을 확인할 수 있습니다.


8. 새로운 데이터 추가

  • 만약 기존의 Blog 데이터에서 새로운 Blog Repository의 데이터가 추가되었다고 가정합니다.
  • Data 폴더에 NewBlogsRepository.cs 클래스를 추가합니다.
  • 그리고 다음과 같이 코드를 작성합니다.
using BlogDIDemo.Models;

namespace BlogDIDemo.Data
{
    public class NewBlogRepository : IBlogRepository
    {
        public static List<Blog> blogs = new()
        {
            new Blog() { Id = 1000, Title = "DI Deep Dive", Content = "This is a five part series" },
            new Blog() { Id = 2000, Title = "Minimal API", Content = "Learn in 30 mins" },
            new Blog() { Id = 3000, Title = "Prescription API", Content = "Still under construction" }
        };

        public List<Blog> GetAllBlogs()
        {
            return blogs;
        }
    }
}
  • 그리고 앞서 의존성 추가했던 소스코드에서 BlogRepository -> NewBlogRepository 로만 변경하여 프로그램을 실행 시켜 봅니다.
// My Dependency Injection Service Add
builder.Services.AddTransient<IBlogRepository, NewBlogRepository>();
  • 실행 결과, NewBlogRepository 의 데이터들이 나오는 것을 확인할 수 있습니다.
  • Dependency Injection 을 통하여 대상 Repository 만 변경할 뿐, Controller 는 변경없이 쉽게 Repository를 다룰 수 있는 것을 확인할 수 있습니다.

728x90

이 글을 공유하기

댓글

Designed by JB FACTORY