개요
Microsoft.Extensions.Hosting 네임스페이스는 .NET 애플리케이션의 호스팅 모델(Hosting Model)을 제공하는 핵심 구성 요소입니다.
Host 클래스는 이 모델의 시작점 역할을 하며, 애플리케이션의 생명 주기(lifecycle), 구성(configuration), 의존성 주입(dependency injection, DI), 로깅(logging) 등 다양한 인프라 서비스를 중앙 집중식으로 관리합니다.
이 호스팅 모델은 ASP.NET Core 애플리케이션에서 시작되었지만, 현재는 콘솔 애플리케이션, 백그라운드 서비스, Windows 서비스, WPF 애플리케이션 등 다양한 종류의 .NET 애플리케이션에서 표준적인 방식으로 사용되고 있습니다.
1. Host 클래스의 목적과 역할
Host 클래스는 특정 애플리케이션 유형에 구애받지 않고, 공통적인 인프라 기능을 쉽게 통합하고 관리할 수 있도록 설계되었습니다.
- 생명 주기 관리: 애플리케이션의 시작(
StartAsync) 및 종료(StopAsync)를 관리하고, 이 과정에서 필요한 서비스들이 올바른 순서로 초기화되고 정리될 수 있도록 합니다. - 의존성 주입 (DI): 애플리케이션 전반에 걸쳐 강력한 DI 컨테이너를 제공하여, 서비스 간의 느슨한 결합을 촉진하고 테스트 용이성을 향상시킵니다.
- 구성 (Configuration):
appsettings.json, 환경 변수, 명령줄 인수 등 다양한 소스에서 설정을 로드하고 관리하는 일관된 방법을 제공합니다. - 로깅 (Logging): 다양한 로깅 프로바이더(콘솔, 파일, 데이터베이스 등)를 쉽게 통합하고, 로깅 레벨을 유연하게 제어할 수 있도록 합니다.
- 백그라운드 서비스 (IHostedService): 장시간 실행되는 백그라운드 작업을 호스트의 생명 주기에 통합하여 관리할 수 있도록 합니다. 이는 API를 제공하지 않고 단순히 작업을 수행하는 서비스에 특히 유용합니다.
2. Host 클래스 핵심 인터페이스 및 메서드
Host 클래스 자체보다는, 이와 관련된 IHost 및 IHostBuilder 인터페이스를 이해하는 것이 중요합니다.
(1) IHostBuilder 인터페이스
IHostBuilder는 호스트를 구성(Configure)하는 데 사용되는 인터페이스입니다.
Host.CreateDefaultBuilder() 메서드가 반환하는 객체가 바로 IHostBuilder 타입입니다.
이 빌더를 통해 다음을 정의할 수 있습니다:
ConfigureAppConfiguration:
설정 소스(파일, 환경 변수 등)를 추가하거나 커스터마이징합니다.
.ConfigureAppConfiguration((context, config) =>
{
config.AddJsonFile("custom.json", optional: true)
.AddEnvironmentVariables()
.AddCommandLine(args);
})
ConfigureLogging:
로깅 프로바이더(콘솔, 디버그, 파일 등)를 추가하고 로깅 필터링 규칙을 정의합니다.
.ConfigureLogging((context, logging) =>
{
logging.AddConsole()
.AddDebug()
.SetMinimumLevel(LogLevel.Information);
})
ConfigureServices:
의존성 주입 컨테이너에 애플리케이션의 서비스들을 등록합니다.AddSingleton,AddScoped,AddTransient등의 메서드를 사용하여 서비스의 생명 주기를 지정할 수 있습니다.
.ConfigureServices((context, services) =>
{
services.AddSingleton<ISingletonService, SingletonService>();
services.AddScoped<IScopedService, ScopedService>();
services.AddTransient<ITransientService, TransientService>();
services.AddHostedService<MyBackgroundService>();
})
UseConsoleLifetime:
콘솔 애플리케이션의 경우,Ctrl+C와 같은 콘솔 시그널을 감지하여 호스트를 정상적으로 종료하도록 설정합니다.
(이는Host.CreateDefaultBuilder()에 의해 기본적으로 포함됩니다.)Build():IHostBuilder에 정의된 모든 구성을 기반으로 최종IHost인스턴스를 생성합니다.
(2) IHost 인터페이스
IHost는 빌드된 호스트 인스턴스를 나타내며, 실제로 애플리케이션을 실행하고 관리하는 데 사용됩니다.
주요 메서드는 다음과 같습니다
Services:
등록된 모든 서비스 인스턴스에 접근할 수 있는IServiceProvider를 제공합니다.
이를 통해 런타임에 필요한 서비스를 resolve(가져오기)할 수 있습니다.StartAsync(CancellationToken cancellationToken):
호스트를 비동기적으로 시작합니다. 이 메서드가 호출되면 등록된 모든IHostedService인스턴스의StartAsync메서드가 호출됩니다.StopAsync(CancellationToken cancellationToken):
호스트를 비동기적으로 종료합니다. 등록된 모든IHostedService인스턴스의StopAsync메서드가 호출되어 리소스를 정리할 기회를 줍니다.RunAsync(CancellationToken cancellationToken = default):StartAsync를 호출하고, 호스트가 종료될 때까지 대기한 후StopAsync를 호출합니다.
대부분의 콘솔 애플리케이션에서 메인 실행 루프로 사용됩니다.
(3) IHostedService 인터페이스
IHostedService는 호스트의 생명 주기에 통합되어 백그라운드 작업을 수행하는 서비스들을 정의하는 인터페이스입니다.
StartAsync와 StopAsync 두 가지 메서드를 구현해야 합니다.
StartAsync(CancellationToken cancellationToken):
호스트가 시작될 때 호출됩니다. 장시간 실행되는 작업을 시작하는 데 사용됩니다.StopAsync(CancellationToken cancellationToken):
호스트가 종료될 때 호출됩니다.StartAsync에서 시작된 작업을 정상적으로 중지하고 리소스를 정리하는 데 사용됩니다.
3. Host.CreateDefaultBuilder() 메서드의 이점
이 메서드는 많은 “관습(conventions)”을 제공하여 애플리케이션 초기 설정을 간소화하는 장점이 있습니다.
- 일관성:
모든 .NET 애플리케이션 유형(웹, 콘솔, 백그라운드 서비스)에서 동일한 방식으로 인프라를 설정할 수 있게 하여 코드의 일관성을 유지합니다. - 생산성:
설정, 로깅, DI 등 반복적인 초기화 코드를 작성할 필요 없이 바로 비즈니스 로직에 집중할 수 있도록 합니다. - 확장성:
기본 설정을 사용하면서도ConfigureAppConfiguration,ConfigureServices등의 메서드를 통해 언제든지 필요에 따라 커스터마이징하고 확장할 수 있습니다. - 테스트 용이성:
DI 컨테이너를 중심으로 설계되어, 단위 테스트 및 통합 테스트에서 의존성을 쉽게 Mocking하거나 대체할 수 있습니다.
참고: Mocking – 테스트 코드 작성 시 가짜 객체(Mock)를 만들어 실제 객체 대신 사용하는 기법
예시 코드: 콘솔 애플리케이션에서 Host 사용하기
콘솔 애플리케이션에서 Host 클래스를 사용하여 백그라운드 서비스(카운터)를 실행하고, 설정 및 로깅을 사용하는 예제
Microsoft.Extensions.HostingNuGet 패키지를 설치
dotnet add package Microsoft.Extensions.Hosting
appsettings.json파일을 추가하고 내용을 작성합니다.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AppConfig": {
"IntervalSeconds": 2
}
}
Services/MyBackgroundService.cs(커스텀IHostedService구현):
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Configuration; // IConfiguration 주입을 위해 추가
using System;
using System.Threading;
using System.Threading.Tasks;
namespace MyConsoleApp.Services
{
// IHostedService를 구현하여 호스트의 생명 주기에 통합될 백그라운드 서비스를 정의합니다.
public class MyBackgroundService : IHostedService, IDisposable
{
private readonly ILogger<MyBackgroundService> _logger;
private readonly IConfiguration _configuration;
private Timer? _timer;
private int _executionCount = 0;
private int _intervalSeconds;
public MyBackgroundService(ILogger<MyBackgroundService> logger, IConfiguration configuration)
{
_logger = logger;
_configuration = configuration;
// appsettings.json에서 설정 값 읽기
_intervalSeconds = _configuration.GetValue<int>("AppConfig:IntervalSeconds", 5); // 기본값 5초
}
// 호스트가 시작될 때 호출됩니다.
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("MyBackgroundService가 시작되었습니다.");
// 타이머를 설정하여 지정된 간격마다 DoWork 메서드를 호출합니다.
_timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(_intervalSeconds));
return Task.CompletedTask; // 비동기 작업 시작을 알리고 즉시 반환
}
// 타이머에 의해 주기적으로 호출되는 실제 작업 메서드
private void DoWork(object? state)
{
var count = Interlocked.Increment(ref _executionCount);
_logger.LogInformation(
"MyBackgroundService가 {count}번째 작업을 수행 중입니다. 현재 시간: {time}",
count, DateTimeOffset.Now);
}
// 호스트가 종료될 때 호출됩니다.
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("MyBackgroundService가 중지되고 있습니다.");
// 타이머를 중지하고 리소스를 해제합니다.
// Change(Timeout.Infinite, 0)은 타이머를 비활성화하는 표준 방법입니다.
_timer?.Change(Timeout.Infinite, 0);
_logger.LogInformation("MyBackgroundService가 중지되었습니다.");
return Task.CompletedTask; // 작업 완료를 알립니다.
}
// 리소스 해제를 위한 Dispose 메서드 (IHostedService는 IDisposable을 구현하는 경우가 많음)
public void Dispose()
{
_timer?.Dispose();
}
}
}
Program.cs구현:
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using MyConsoleApp.Services; // MyBackgroundService를 사용하기 위해 추가
using System;
using System.Threading.Tasks;
namespace MyConsoleApp
{
public class Program
{
public static async Task Main(string[] args)
{
Console.WriteLine("콘솔 애플리케이션 호스트가 시작됩니다. 종료하려면 Ctrl+C를 누르세요.");
// 1. IHostBuilder 인스턴스 생성: Host.CreateDefaultBuilder()는 기본적인 구성(config, logging, DI)을 설정합니다.
var builder = Host.CreateDefaultBuilder(args)
// 2. 서비스 컨테이너 구성: 의존성 주입을 위한 서비스들을 등록합니다.
.ConfigureServices((hostContext, services) =>
{
// MyBackgroundService를 IHostedService로 등록합니다.
// 호스트가 시작될 때 StartAsync가 호출되고, 종료될 때 StopAsync가 호출됩니다.
services.AddHostedService<MyBackgroundService>();
// 여기에 다른 서비스들도 등록할 수 있습니다. 예:
// services.AddSingleton<IMyService, MyService>();
// services.AddScoped<IOtherService, OtherService>();
})
// 3. 로깅 구성 (선택 사항: CreateDefaultBuilder가 기본 설정 제공하지만, 커스터마이징 가능)
.ConfigureLogging(logging =>
{
logging.ClearProviders(); // 기본 로깅 프로바이더를 지우고 새로 추가하거나
logging.AddConsole(); // 콘솔 로거를 추가합니다.
// logging.AddDebug(); // 디버그 로거 추가
});
// 4. 기타 구성 (선택 사항: 파일 경로, 환경 등)
// .UseContentRoot(Directory.GetCurrentDirectory())
// .UseEnvironment("Development")
// .ConfigureAppConfiguration((hostingContext, config) => {
// config.AddJsonFile("custom.json", optional: true);
// });
// 5. IHost 인스턴스 빌드: 구성된 빌더를 바탕으로 실제 호스트를 생성합니다.
var host = builder.Build();
// 6. 호스트 실행: 등록된 모든 IHostedService를 시작하고 애플리케이션 종료를 대기합니다.
// Ctrl+C 시그널을 감지하여 정상적으로 종료됩니다.
await host.RunAsync();
Console.WriteLine("콘솔 애플리케이션 호스트가 종료되었습니다.");
}
}
}



