의존성 주입(Dependency Injection, DI)은 .NET 개발에서 핵심적인 디자인 패턴 중 하나입니다.
이 글에서는 DI의 개념과 목적, 그리고 실제 코드에서 어떻게 사용하는지를 쉽게 설명합니다.
초보자도 이해할 수 있도록 간단한 예시와 함께 정리했습니다.
드디어 포트폴리오 만드니?
대학교 졸업하고 일 시작한지 꽤 오래된 것 같은데 포트폴리오 하나 없다는게 좀 이상해서 시작한 프로젝트.이름하여 "드디어 포트폴리오 만드니?" 프로젝트! 귀찮음이 많은 사람이기에 아주
memoryman.tistory.com
위 프로젝트를 진행하다가 의존성 주입에 대한 궁금증이 생겼습니다.
의존성 주입이란 무엇일까?
우선 편하게 DI라고 부르겠습니다. Dependency Injection 의 줄임말 입니다.
의존성의 정의는 "내가 필요로 하는 다른 것" 이라고 할 수 있습니다.
필요하다는건 곳 의존한다는 의미이기도 합니다. 즉 내가 의존하는 것을 Injection(주입) 한다는 뜻 입니다.
(약간 억지 같기도 하네요 ㅋㅋ...)

클래스 단위에서 이해해보도록하겠습니다.
Life(삶) 라는 클래스가 있습니다. 삶 클래스는 Money(돈) 클래스가 꼭 필요합니다.
삶을 살아가는데 돈이 필요한 고증을 클래스로 표현해 봤습니다.
Money 클래스는 Life 클래스안에서 항상 초기화되어 사용되고 있는데요.
DI를 이용하면 Money 클래스를 미들웨어 단계에서 DI 컨테이너에 주입하고 해당 클래스를 사용할 수 있습니다.
아래 DI 코드는 DI 컨테이너에 주입된 인터페이스를 가져다가 사용한 코드인데 DI를 처음 접해보시는분들이 보면 이해가 안가는게 당연 하므로 구조만 보고 넘어가시면 됩니다.
// 일반적인 내부 사용
public Class Life
{
private Money money = new Money();
}
// DI
public class Life
{
private readonly IMoney _money;
public Life(IMoney money)
{
_money = money;
}
}
.NET 환경에서 DI 사용 예제에 대해서 다루기전에 DI를 왜 사용하는지에 대해 먼저 정리하고 가시죠.
결합도와 응집도를 아시나요? 좋은 코드는 결합도를 낮추고 응집도를 높이는 것 입니다.
DI의 역할은 결합도를 낮추는데 있습니다.
아래 코드에서 money를 주입 받았다고 했는데요.
외부에서 주입 받기에 어떤 money를 받던 상관이 없습니다.
원화를 받던 외화를 받던 데이터 생성에 대한 책임을 질 필요가 없어졌습니다.
이제 내부에서는 사용에 대한 역할만 수행하면 됩니다.
이는 곧 확장성 향상 및 유지보수 리소스 감소에 영향을 미칩니다.
// DI
public class Life
{
private readonly IMoney _money;
public Life(IMoney money)
{
_money = money; // 원화, 외화..... 아무 돈이나 들어와라
}
}
자 그럼 실제 .NET 환경에서 DI 동작 방식에 대해서 알아보도록 하겠습니다.
실제 제가 작성한 DI 코드를 하나씩 뜯어보도록 하겠습니다.
가장 먼저 해야하는 것은 인터페이스 생성 입니다.
클래스로 DI 할 수 있지만 확장성을 위해 인터페이스를 사용 합니다.
// 인터페이스 생성
public interface IDbContext
{
IDbConnection GetConnection();
}
인터페이스를 생성했다면 DB 관련 클래스 DbContext 클래스를 생성하고 앞전 인터페이스를 상속 받습니다.
IConfiguration 인터페이스가 보이시나요? 해당 인터페이스는 appsettings.json 에 있는 데이터를 가져올 수 있도록 연결 역할을 합니다.
저는 DbContext 클래스에 DB 연결을 담당하는 메서드 GetConnection을 생성하겠습니다.
public class DbContext : IDbContext
{
private readonly IConfiguration _config;
public DbContext(IConfiguration config)
{
_config = config;
}
public IDbConnection GetConnection()
{
return new SqlConnection(_config.GetConnectionString("MM"));
}
}
이제 미들웨어 단계에서 DI 를 추가해보도록 하겠습니다.
.NET 에서 미들웨어가 동작하는 곳은 Program.cs 입니다.
콘솔, API 환경에 따라서 기본 소스가 다르기 때문에 Program.cs 에 있는 소스 전부를 첨부합니다.
저는 API 환경에서 작업했습니다.
#region 이라고 적어놓은 곳 보이시나요?
AddScopred 를 통해서 DI 컨테이너에 인터페이스와 클래스를 저장 합니다.
using MyName.Interface;
using MyName.Service;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
#region DB DI
builder.Services.AddScoped<IDbContext, DbContext>();
#endregion
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
이제 DI 사용해 보도록 하겠습니다.
전역변수 _dbContext 선언합니다. 해당 변수에 DI 데이터를 저장할 예정 입니다.
생성자 단계에서 파라미터로 DI 데이터를 받아오고 전역변수에 데이터를 저장 합니다.
Project 액션함수에서 GetConnection() 메서드를 호출하여 DB 연결 합니다.
public class HomeController : Controller
{
private readonly IDbContext _dbContext;
public HomeController(IDbContext dbContext)
{
_dbContext = dbContext;
}
public IActionResult Project()
{
using (IDbConnection db = _dbContext.GetConnection())
{
}
return View();
}
}
의존성 주입에 대해서 알아보았는데요.
미들웨어 단계에서 DI 컨테이너에 데이터를 저장하고 필요한 클래스에서 DI 컨테이너에 접근하여 데이터를 꺼내서 사용한다는 개념 입니다.
필요한 클래스에서 데이터를 사용한다는 개념이 static 개념과 비슷한 것 같기도 합니다.
발전을 위해 메모리!

'.NET' 카테고리의 다른 글
| .NET 델리게이트(Delegate)란 무엇인가. (0) | 2025.04.15 |
|---|---|
| .NET 람다식(Lambda)란 무엇인가. (0) | 2025.04.10 |
| .NET 데퍼(Dapper)란 무엇인가. (0) | 2025.04.08 |
| .NET 린큐(LINQ) 무엇인가. (0) | 2025.04.07 |
| .NET Serilog 사용 방법 (0) | 2025.01.15 |