IServiceScopeFactory 인터페이스

IServiceScopeFactory 란?

https://learn.microsoft.com/ko-kr/dotnet/api/microsoft.extensions.dependencyinjection.iservicescopefactory?view=net-8.0

IServiceScopeFactory 는 ASP.NET Core의 의존성 주입(DI) 컨테이너에서 새로운 서비스 범위(Scope) 를 만들기 위한 팩토리 인터페이스입니다.

기본적으로 DI 컨테이너는 Singleton / Scoped / Transient 세 가지 생명주기를 제공합니다.

일반적으로 Scoped 서비스는 HTTP 요청(Request)마다 생성되고, 요청이 끝나면 해제됩니다.

하지만 BackgroundService, Singleton 클래스 안에서는 Scoped 서비스를 직접 DI 받을 수 없습니다.

이를 해결하기 위하여 IServiceScopeFactory 를 이용해 임시 Scope를 만들어서 Scoped 서비스를 안전하게 사용합니다.

구분SingletonScopedTransient
인스턴스 생성 시점애플리케이션 시작 시 한 번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);
    }
}

정리

  • IServiceScopeFactoryScoped 서비스의 생명주기를 직접 제어할 수 있게 해줍니다.
  • 주로 Singleton 객체나 BackgroundService 에서 Scoped 서비스를 안전하게 사용하기 위해 필요합니다.
  • CreateScope() 로 범위를 열고, 작업이 끝나면 자동으로 Dispose 되어 메모리 누수 없이 관리됩니다.

“IServiceScopeFactory 인터페이스”에 대한 1개의 생각

  1. Scoped 서비스와 `IServiceScopeFactory`의 쓸모는 정말 대단하네요! Singleton처럼 영원히 살아있는 것들한테 Scoped 서비스를 주는 건 꿀잠이라도 자는 거겠죠? BackgroundService에서 안심하고 쓸 수 있게 해주는 부분은 진짜 고양이 밥 같아요. 물론, 임시 Scope를 열 때마다 새로운 인스턴스를 만드는 거라 좀 번거로울 수도 있겠지만, 그래야 메모리가 터질까도 모르니까 안전장치라는 거겠죠! 이건 개발자들에게는 정말 최고의 선물이겠어요!grow a garden calculator

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤