builder.Services

By | 2026년 10월 28일

builder.Services 등록 메서드 상세 설명

builder.Services는 DI(의존성 주입) 컨테이너입니다. 여기에 “이런 기능/클래스를 쓰겠다”고 등록해 두면, 앱이 실행될 때 필요한 곳에 ASP.NET Core가 알아서 만들어 넣어 줍니다. 아래 메서드들은 모두 이 컨테이너에 무언가를 등록하는 역할입니다.

1. AddCors

csharp

builder.Services.AddCors(options => options.AddPolicy("FrontPage", policy =>
    policy.WithOrigins(frontPageOrigins)
          .WithMethods("GET", "POST")
          .WithHeaders("Content-Type", "X-Admin-Key")));

역할: CORS 정책을 정의합니다. 정의만 할 뿐, 실제 적용은 아래 미들웨어가 합니다.

csharp

app.UseCors("FrontPage");   // 정의한 정책을 요청 파이프라인에 적용
메서드의미
AddPolicy("FrontPage", ...)이름이 있는 정책을 등록
WithOrigins(...)허용할 오리진 목록
WithMethods("GET","POST")허용할 HTTP 메서드 (PUT, DELETE는 차단됨)
WithHeaders(...)허용할 요청 헤더

참고로 AllowAnyOrigin(), AllowAnyMethod(), AllowAnyHeader()도 있지만 모두 허용이라 보안상 권장되지 않고, 이 코드는 필요한 것만 여는 방식을 썼습니다. 또한 AllowCredentials()를 쓰지 않았기 때문에 쿠키 같은 자격 증명 포함 요청은 허용되지 않습니다 (헤더 키 방식이라 필요 없음).

2. AddControllers

csharp

builder.Services.AddControllers();

역할: [ApiController] 클래스(컨트롤러)를 사용하는 데 필요한 기능을 등록합니다.

포함되는 것들:

  • 컨트롤러 탐색 (어셈블리에서 ControllerBase를 상속한 클래스 찾기)
  • 모델 바인딩 (요청 JSON, 쿼리스트링을 C# 객체로 변환)
  • JSON 직렬화/역직렬화 (System.Text.Json)
  • 모델 검증 ([Required] 등 어트리뷰트 검사)

AddControllers() 후 app.MapControllers()를 호출해야 컨트롤러가 실제 엔드포인트로 연결됩니다. 등록(Add)과 사용(Map/Use)이 짝을 이루는 구조입니다.

참고: AddControllersWithViews()는 Razor 뷰까지 포함한 MVC용이고, AddControllers()는 View 없이 API 전용입니다.

3. AddHttpClient

csharp

builder.Services.AddHttpClient<AiService>(c => c.Timeout = TimeSpan.FromSeconds(40));

역할: 외부 HTTP API를 호출하기 위한 HttpClient를 팩토리(IHttpClientFactory) 방식으로 등록합니다. 이 코드는 타입 지정 클라이언트(typed client) 패턴입니다.

AiService는 이렇게 HttpClient를 생성자로 받습니다.

csharp

public class AiService
{
    private readonly HttpClient _http;
    public AiService(HttpClient http) => _http = http;   // 40초 타임아웃이 설정된 HttpClient가 주입됨
}

왜 new HttpClient()를 직접 쓰지 않나?

직접 생성AddHttpClient 사용
요청마다 만들면 소켓 고갈(socket exhaustion) 위험내부 연결 풀을 팩토리가 관리
싱글톤으로 오래 쓰면 DNS 변경을 반영 못 함핸들러를 주기적으로 교체해 DNS 갱신 반영
설정이 코드 곳곳에 흩어짐등록 시점에 한 번 설정 (타임아웃, 기본 주소, 헤더)

Timeout을 40초로 둔 것은 AI API 응답이 오래 걸릴 수 있어서로 보입니다 (기본값은 100초). 필요하면 c.BaseAddress, c.DefaultRequestHeaders 등도 여기서 설정할 수 있고, Polly 같은 재시도 정책도 이어서 붙일 수 있습니다.

4. AddSingleton / AddScoped (그리고 AddTransient)

csharp

builder.Services.AddSingleton<IsoCatalog>();
builder.Services.AddScoped<CountryRepository>();
builder.Services.AddScoped<ApprovalService>();

역할: 클래스를 DI 컨테이너에 등록하되, 인스턴스의 수명(lifetime) 을 지정합니다.

수명인스턴스 생성적합한 용도
Singleton앱 전체에서 딱 1개 공유불변 데이터, 캐시, 설정 (예: IsoCatalog)
ScopedHTTP 요청 1건당 1개 (요청 안에서는 공유)DB 컨텍스트, 리포지토리, 서비스 (예: CountryRepository)
Transient주입받을 때마다 새로 생성가볍고 상태 없는 유틸리티

이 프로젝트의 선택이 합리적인 이유:

  • IsoCatalog: ISO 국가 코드 같은 변하지 않는 목록이라 한 번 만들어 공유하면 효율적입니다.
  • CountryRepository, ApprovalService: 요청 단위로 상태/DB 연결을 다루므로 Scoped가 일반적입니다.

주의할 점 (수명 불일치): Singleton이 Scoped를 주입받으면 안 됩니다. 예를 들어 IsoCatalog(Singleton)가 생성자에서 CountryRepository(Scoped)를 받으면, 요청이 끝나도 Scoped 객체가 살아남는 문제가 생겨 개발 환경에서는 예외가 납니다. 수명이 긴 쪽이 짧은 쪽에 의존하지 않도록 하세요.

참고로 AddHttpClient<AiService>로 등록된 AiService는 기본적으로 Transient입니다.

5. AddEndpointsApiExplorer

csharp

builder.Services.AddEndpointsApiExplorer();

역할: 앱에 어떤 엔드포인트(경로, 메서드, 파라미터, 응답 타입)가 있는지 메타데이터를 수집할 수 있게 해 줍니다.

이 자체는 화면에 아무것도 보여주지 않고, 뒤의 Swagger가 “문서를 만들 재료”를 가져가는 통로입니다. 특히 Minimal API(app.MapGet(...)) 엔드포인트를 Swagger에 보이게 하려면 필수이고, 컨트롤러만 쓰더라도 관례적으로 함께 등록합니다.

6. AddSwaggerGen

csharp

builder.Services.AddSwaggerGen();

역할: 위에서 수집한 엔드포인트 정보로 OpenAPI(Swagger) 명세 문서(JSON)를 생성하는 기능을 등록합니다. (Swashbuckle.AspNetCore 패키지)

등록만으로는 부족하고, 미들웨어로 노출해야 합니다. 이 프로젝트는 개발 환경에서만 켭니다.

csharp

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();     // /swagger/v1/swagger.json 문서 제공
    app.UseSwaggerUI();   // /swagger 에서 브라우저용 테스트 화면 제공
}

옵션으로 문서 제목, X-Admin-Key 헤더 입력 버튼 등을 추가할 수도 있습니다.

csharp

builder.Services.AddSwaggerGen(c =>
{
    c.AddSecurityDefinition("AdminKey", new OpenApiSecurityScheme
    {
        Type = SecuritySchemeType.ApiKey,
        In = ParameterLocation.Header,
        Name = "X-Admin-Key"
    });
});

이 프로젝트처럼 /api 전체가 API 키를 요구한다면, 위처럼 설정해야 Swagger UI에서 “Authorize” 버튼으로 키를 넣고 테스트할 수 있습니다. 설정하지 않으면 Swagger UI에서 호출 시 모두 401이 납니다.

전체 구조 한눈에 보기

ASP.NET Core는 “등록(Services) → 빌드 → 사용(Middleware)” 3단계입니다.

builder.Services.AddXxx()   ← 1. 기능/클래스를 DI에 "등록" (재료 준비)
var app = builder.Build();  ← 2. 컨테이너 확정
app.UseXxx() / MapXxx()     ← 3. 요청 파이프라인에 "적용" (실제 사용)
등록 (builder.Services)적용 (app)
AddCorsUseCors("FrontPage")
AddControllersMapControllers()
AddEndpointsApiExplorer + AddSwaggerGenUseSwagger() + UseSwaggerUI()
AddSingleton/Scoped/HttpClient컨트롤러 등의 생성자 주입으로 사용

Add...만 하고 Use.../Map...을 빠뜨리면 아무 일도 일어나지 않으니, 기능이 동작하지 않을 때는 이 짝이 맞는지부터 확인해 보세요.