비동기 상태 관리

NuGet 패키지는 📦 Microsoft.Extensions.AsyncState 현재 비동기 컨텍스트 내에서 개체를 저장하고 검색하는 기능을 제공합니다. 이 패키지는 특히 비동기 작업에서 여러 개체를 공유해야 하는 경우 직접 사용에 AsyncLocal<T> 비해 성능 및 유용성 향상을 제공합니다.

AsyncState를 사용하는 이유

.NET 비동기 컨텍스트에서 앰비언트 데이터를 관리하기 위한 AsyncLocal<T> 제공하지만 직접 사용하면 단점이 있을 수 있습니다.

  • 성능: 각 AsyncLocal<T> 인스턴스는 오버헤드를 추가합니다. 여러 개체가 비동기 컨텍스트를 통과해야 하는 경우 많은 AsyncLocal<T> 인스턴스를 관리하면 성능에 영향을 미칠 수 있습니다.
  • 추상화: AsyncLocal<T>을(를) 직접 사용하여 코드를 특정 구현에 묶어두면, 나중에 최적화하거나 변경하기가 더 어려워집니다.
  • 수명 관리: AsyncState 패키지는 명시적 API를 통해 앰비언트 데이터의 수명을 더 잘 제어할 수 있습니다.

패키지는 Microsoft.Extensions.AsyncState 다음을 제공하여 이러한 문제를 해결합니다.

  • 필요한 인스턴스 수를 AsyncLocal<T> 줄이는 최적화된 구현입니다.
  • 앰비언트 데이터를 저장하고 검색하기 위한 정리 추상화입니다.
  • 종속성 주입과 통합하여 더 쉽게 테스트하고 구성합니다.

시작하기

시작하려면 비동기 상태 관리를 위해 Microsoft.Extensions.AsyncState NuGet 패키지를 설치하십시오.

dotnet add package Microsoft.Extensions.AsyncState

자세한 내용은 dotnet add package 또는 .NET 애플리케이션의 패키지 종속성 관리 참조하세요.

비동기 상태 서비스 등록

확장 메서드를 사용하여 AddAsyncState 종속성 주입 컨테이너에 비동기 상태 서비스를 등록합니다.

using Microsoft.Extensions.DependencyInjection;

var services = new ServiceCollection();

services.AddAsyncState();

ServiceProvider provider = services.BuildServiceProvider();

이 등록을 통해 IAsyncContext<T>IAsyncState 인터페이스를 종속성 주입에 사용할 수 있습니다.

IAsyncContext 사용

인터페이스는 IAsyncContext<T> 현재 비동기 컨텍스트에서 값을 가져와서 설정하는 메서드를 제공합니다.

var context = provider.GetRequiredService<IAsyncContext<UserContext>>();

// Set a value in the async context
var userContext = new UserContext { UserId = "12345", UserName = "Alice" };
context.Set(userContext);

// Retrieve the value
if (context.TryGet(out var retrievedContext))
{
    Console.WriteLine($"User: {retrievedContext.UserName}");
}
public record class UserContext
{
    public required string UserId { get; set; }
    public required string UserName { get; set; }
}

컨텍스트에 설정된 값은 비동기 작업을 통해 전달되므로 동일한 비동기 컨텍스트 내에서 실행되는 모든 코드에서 사용할 수 있습니다.

IAsyncState 사용

IAsyncState 인터페이스는 IAsyncContext<T>이(가) 확장하는 기본 수명 주기 인터페이스입니다. 비동기 상태 수명 주기를 관리하기 위한 Initialize()Reset() 메서드를 제공합니다. 비동기 상태 값을 형식화된 방식으로 액세스하려면 대신 IAsyncContext<T>를 사용합니다.

실제 예제: 요청 상관 관계

비동기 상태의 일반적인 사용 사례는 HTTP 요청에서 상관 관계 정보를 유지하는 것입니다.

public class RequestProcessor(IAsyncContext<CorrelationContext> asyncContext)
{

    public async Task ProcessRequestAsync(string correlationId)
    {
        // Set correlation context at the beginning of request processing
        asyncContext.Set(new CorrelationContext { CorrelationId = correlationId });

        // The correlation ID flows through all async operations
        await Step1Async();
        await Step2Async();
    }

    private async Task Step1Async()
    {
        await Task.Yield();
        
        if (asyncContext.TryGet(out var context))
        {
            Console.WriteLine($"Step 1 - Correlation ID: {context.CorrelationId}");
        }
    }

    private async Task Step2Async()
    {
        await Task.Yield();
        
        if (asyncContext.TryGet(out var context))
        {
            Console.WriteLine($"Step 2 - Correlation ID: {context.CorrelationId}");
        }
    }
}
public class CorrelationContext
{
    public required string CorrelationId { get; set; }
}

이 예제에서 상관 관계 ID는 요청 처리 시작 시 한 번 설정되며 매개 변수로 전달하지 않고도 모든 후속 비동기 작업에서 자동으로 사용할 수 있습니다.

ASP.NET Core 통합

ASP.NET Core 애플리케이션에서는 비동기 상태를 사용하여 애플리케이션을 통해 요청 관련 정보를 흐를 수 있습니다.

public class RequestHandler(IAsyncContext<RequestMetadata> asyncContext)
{

    public async Task<object> GetDataAsync()
    {
        await Task.Yield();
        
        if (asyncContext.TryGet(out var metadata))
        {
            var duration = DateTimeOffset.UtcNow - metadata.StartTime;
            return new
            {
                RequestId = metadata.RequestId,
                RequestPath = metadata.RequestPath,
                Duration = duration.TotalMilliseconds
            };
        }

        return new { Error = "No request metadata available" };
    }
}
public record class RequestMetadata
{
    public required string RequestId { get; set; }
    public required string RequestPath { get; set; }
    public DateTimeOffset StartTime { get; set; }
}

모범 사례

비동기 상태를 사용하는 경우 다음 모범 사례를 고려합니다.

  • 상태 크기 제한: 메모리 오버헤드를 줄이고 성능을 유지하기 위해 비동기 상태 개체를 작게 유지합니다.
  • 초기화 상태: 모든 다운스트림 비동기 작업에서 사용할 수 있도록 가능한 한 빨리 비동기 상태 값을 설정합니다.
  • 정리 상태: 장기 실행 애플리케이션에서 메모리 누수 방지를 위해 더 이상 필요하지 않은 경우 비동기 상태를 다시 설정하거나 지웁니다.
  • 적절한 인터페이스 사용: 현재 비동기 컨텍스트 내에서 형식화된 값을 가져와서 설정하는 데 사용합니다 IAsyncContext<T> . 초기화를 직접 관리하고 수명 주기를 다시 설정해야 하는 경우에 사용합니다 IAsyncState .
  • 타입 안전성: 제네릭 사전을 사용하여 형식 보안을 유지하고 코드 clarity 개선하는 대신 특정 컨텍스트 형식을 만듭니다.

참고하십시오