IServiceScopeFactory 란?
IServiceScopeFactory
는 ASP.NET Core의 의존성 주입(DI) 컨테이너에서 새로운 서비스 범위(Scope) 를 만들기 위한 팩토리 인터페이스입니다.
기본적으로 DI 컨테이너는 Singleton / Scoped / Transient 세 가지 생명주기를 제공합니다.
일반적으로 Scoped 서비스는 HTTP 요청(Request)마다 생성되고, 요청이 끝나면 해제됩니다.
하지만 BackgroundService
, Singleton
클래스 안에서는 Scoped 서비스를 직접 DI 받을 수 없습니다.
이를 해결하기 위하여 IServiceScopeFactory
를 이용해 임시 Scope를 만들어서 Scoped 서비스를 안전하게 사용합니다.
구분 | Singleton | Scoped | Transient |
---|---|---|---|
인스턴스 생성 시점 | 애플리케이션 시작 시 한 번 | HTTP 요청 시작 시 한 번 | 의존성 주입 요청 시마다 |
인스턴스 수명 | 애플리케이션 전체 수명 | HTTP 요청 수명 | 가장 짧은 수명 |
공유 범위 | 전체 애플리케이션에서 단일 인스턴스 공유 | 동일 HTTP 요청 내에서 동일 인스턴스 공유 | 매번 새로운 인스턴스 생성 |
사용 사례 | – 캐시 서비스 – 설정 관리자 – 로깅 서비스 | – DB Context – 사용자 세션 – 트랜잭션 관리 | – 경량 서비스 – 상태 없는 헬퍼 – 일회성 작업 |
주의사항 | 상태 저장 시 thread-safe 고려 필요 | 요청 간 상태 공유 불가 | 빈번한 생성으로 성능 영향 가능성 |
사용법
1. 기본적인 사용법
using (var scope = scopeFactory.CreateScope()) { var myService = scope.ServiceProvider.GetRequiredService<MyScopedService>(); myService.DoSomething(); } // scope.Dispose()가 호출되면서 MyScopedService도 정리됨
2. BackgroundService에서 DbContext 사용하기
public class MyWorker : BackgroundService { private readonly IServiceScopeFactory _scopeFactory; public MyWorker(IServiceScopeFactory scopeFactory) { _scopeFactory = scopeFactory; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { using var scope = _scopeFactory.CreateScope(); var db = scope.ServiceProvider.GetRequiredService<MyDbContext>(); var users = await db.Users.ToListAsync(stoppingToken); Console.WriteLine($"현재 사용자 수: {users.Count}"); await Task.Delay(5000, stoppingToken); } } } // MyDbContext 가 Scoped 로 등록되어 있어도 Worker에서 안전하게 사용 가능.
3. Scoped 서비스 임시 실행
public class ReportGenerator { private readonly IServiceScopeFactory _scopeFactory; public ReportGenerator(IServiceScopeFactory scopeFactory) { _scopeFactory = scopeFactory; } public void Generate() { using var scope = _scopeFactory.CreateScope(); var service = scope.ServiceProvider.GetRequiredService<ReportService>(); service.CreateDailyReport(); } } // ReportService 가 Scoped 로 등록되어 있어도 IServiceScopeFactory 를 사용해 특정 시점에만 실행 가능.
4. 여러 Scoped 서비스 조합
public class CleanupJob { private readonly IServiceScopeFactory _scopeFactory; public CleanupJob(IServiceScopeFactory scopeFactory) { _scopeFactory = scopeFactory; } public async Task RunAsync() { using var scope = _scopeFactory.CreateScope(); var db = scope.ServiceProvider.GetRequiredService<MyDbContext>(); var emailService = scope.ServiceProvider.GetRequiredService<EmailService>(); var expiredUsers = db.Users.Where(u => u.IsExpired).ToList(); db.Users.RemoveRange(expiredUsers); await db.SaveChangesAsync(); await emailService.SendCleanupReport(expiredUsers.Count); } }
정리
IServiceScopeFactory
는 Scoped 서비스의 생명주기를 직접 제어할 수 있게 해줍니다.- 주로 Singleton 객체나 BackgroundService 에서 Scoped 서비스를 안전하게 사용하기 위해 필요합니다.
CreateScope()
로 범위를 열고, 작업이 끝나면 자동으로 Dispose 되어 메모리 누수 없이 관리됩니다.
Scoped 서비스와 `IServiceScopeFactory`의 쓸모는 정말 대단하네요! Singleton처럼 영원히 살아있는 것들한테 Scoped 서비스를 주는 건 꿀잠이라도 자는 거겠죠? BackgroundService에서 안심하고 쓸 수 있게 해주는 부분은 진짜 고양이 밥 같아요. 물론, 임시 Scope를 열 때마다 새로운 인스턴스를 만드는 거라 좀 번거로울 수도 있겠지만, 그래야 메모리가 터질까도 모르니까 안전장치라는 거겠죠! 이건 개발자들에게는 정말 최고의 선물이겠어요!grow a garden calculator