다음을 통해 공유


ASP.NET Core Blazor 서버 쪽 상태 관리

비고

이 기사는 최신 버전이 아닙니다. 현재 릴리스는 이 문서의 .NET 10 버전을 참조하세요.

경고

이 버전의 ASP.NET Core는 더 이상 지원되지 않습니다. 자세한 내용은 .NET 및 .NET Core 지원 정책을 참조하세요. 현재 릴리스는 이 문서의 .NET 10 버전을 참조하세요.

이 문서에서는 서버 쪽 Blazor 시나리오에서 사용자의 데이터(상태)를 유지 관리하는 일반적인 방법을 설명합니다.

사용자 상태 유지 관리

서버 쪽 Blazor 은 상태 저장 앱 프레임워크입니다. 대체로 앱은 서버와의 연결을 유지합니다. 사용자 상태는 서버 메모리의 ‘회로’에 저장됩니다.

회로에 저장되는 사용자 상태의 예는 다음과 같습니다.

  • 구성 요소 인스턴스의 계층 구조 및 렌더링된 UI의 가장 최근 렌더링 출력.
  • 구성 요소 인스턴스의 필드 및 속성 값.
  • 회로로 범위가 지정된 DI(종속성 주입) 서비스 인스턴스에 저장된 데이터

사용자 상태는 JavaScript interop 호출을 통해 브라우저의 메모리 집합에 있는 JavaScript 변수에서 찾을 수도 있습니다.

사용자에게 임시 네트워크 연결 손실이 발생하는 경우, Blazor는 사용자의 원래 상태로 사용자를 원래 회로에 다시 연결하려 시도합니다. 그러나 사용자를 서버 메모리의 원래 회로에 다시 연결할 수 없는 경우도 있습니다.

  • 서버는 연결이 끊어진 회로를 계속 유지할 수 없습니다. 시간 제한 이후 또는 서버에 메모리 압력이 발생할 경우 서버는 연결이 끊어진 회로를 해제해야 합니다.
  • 부하가 분산된 다중 서버 배포 환경에서 개별 서버는 오류가 발생하거나 전체 요청 볼륨을 더 이상 처리할 필요가 없으면 자동으로 제거될 수 있습니다. 사용자가 다시 연결하려고 할 때 사용자에 대한 원래 서버 처리 요청을 사용할 수 없게 될 수 있습니다.
  • 사용자는 브라우저를 닫고 다시 열거나 페이지를 다시 로드하여 브라우저의 메모리에 저장된 상태를 제거할 수 있습니다. 예를 들어 JavaScript interop 호출을 통해 설정된 JavaScript 변수 값이 손실됩니다.

사용자가 원래 회로에 다시 연결할 수 없는 경우 사용자는 새로 초기화된 상태로 새 회로를 받습니다. 이는 데스크톱 앱을 닫고 다시 여는 것과 같습니다.

사용자 상태를 유지해야 하는 경우

상태 지속성은 자동이 아닙니다. 상태 저장 데이터 지속성을 구현하려면 앱을 개발할 때 일정 단계를 수행해야 합니다.

일반적으로 사용자가 이미 존재하는 데이터를 단순히 읽는 것이 아니라 데이터를 적극적으로 생성하는 환경에서 상태를 유지합니다.

데이터 지속성은 일반적으로 사용자가 특별히 노력해서 만든 높은 가치의 상태에만 필요합니다. 상태를 유지하면 시간이 절약되거나 상업적 활동에 도움이 됩니다.

  • 다단계 웹 양식: 상태가 손실된 경우 사용자가 다단계 웹 양식의 완료된 여러 단계에 대한 데이터를 다시 입력하는 데 시간이 많이 걸립니다. 이 시나리오에서는 사용자가 양식을 벗어났다가 나중에 돌아올 경우 상태가 손실됩니다.
  • 쇼핑 카트: 잠재적인 수익을 나타내는 앱의 상업적으로 중요한 구성 요소는 유지 관리할 수 있습니다. 상태를 상실한 사용자와 쇼핑 카트는 나중에 웹 사이트로 돌아갈 때 더 적은 제품이나 서비스를 구매할 수 있습니다.

앱은 ‘앱 상태’만 유지할 수 있습니다. 구성 요소 인스턴스 및 렌더링 트리와 같은 UI는 유지할 수 없습니다. 구성 요소 및 렌더링 트리는 일반적으로 직렬화할 수 없습니다. 트리 뷰 컨트롤의 펼친 노드와 같은 UI 상태를 유지하려면 앱이 사용자 지정 코드를 사용하여 UI 상태의 동작을 직렬화 가능한 앱 상태로 모델링해야 합니다.

회로 상태 지속성

서버 쪽 렌더링 Blazor Web App중에 전체 페이지 새로 고침이 트리거되지 않는 한 서버에 대한 연결이 장기간 손실되거나 사전에 일시 중지될 때 사용자의 세션(회로) 상태를 유지할 수 있습니다. 이렇게 하면 사용자는 다음 시나리오에서 저장되지 않은 작업을 잃지 않고 세션을 다시 시작할 수 있습니다.

  • 브라우저 탭 속도 제어
  • 앱을 전환하는 모바일 디바이스 사용자
  • 네트워크 중단
  • 적극적인 리소스 관리(비활성 회로 일시 중지)
  • 향상된 탐색

회로 상태를 유지할 수 있는 경우 서버 리소스를 해제한 다음 나중에 다시 시작합니다.

  • 연결이 끊긴 경우에도 회로는 작업을 계속 수행하고 CPU, 메모리 및 기타 리소스를 사용할 수 있습니다. 지속형 상태는 개발자가 제어하는 고정된 양의 메모리만 사용합니다.
  • 지속형 상태는 앱에서 사용하는 메모리의 하위 집합을 나타내므로 서버는 앱의 구성 요소 및 기타 서버 쪽 개체를 추적할 필요가 없습니다.

상태는 다음 두 가지 시나리오에 대해 유지됩니다.

  • 구성 요소 상태: 구성 요소가 대화형 서버 렌더링에 사용하는 상태(예: 데이터베이스에서 검색된 항목 목록 또는 사용자가 작성하는 양식).
  • 범위가 지정된 서비스: 서버 쪽 서비스 내에 있는 상태(예: 현재 사용자).

Conditions:

  • 이 기능은 대화형 서버 렌더링에만 적용됩니다.
  • 사용자가 페이지(앱)를 새로 고치면 지속형 상태가 손실됩니다.
  • 상태는 JSON 직렬화 가능해야 합니다. 순환 참조 또는 ORM 엔터티가 올바르게 직렬화되지 않을 수 있습니다.
  • @key 키 충돌을 방지하기 위해 루프에서 구성 요소를 렌더링할 때 고유성을 사용합니다.
  • 필요한 상태만 유지합니다. 과도한 데이터를 저장하면 성능에 영향을 미칠 수 있습니다.
  • 자동 최대 절전 모드가 실행되지 않습니다. 상태 지속성을 명시적으로 옵트인하고 구성해야 합니다.
  • 복구를 보장하지 않습니다. 상태 지속성이 실패하면 앱은 연결이 끊긴 기본 환경으로 돌아갑니다.

상태 지속성은 AddInteractiveServerComponents 파일에서 AddRazorComponents에 대해 Program가 호출될 때 기본적으로 활성화됩니다. MemoryCache 는 단일 앱 인스턴스에 대한 기본 스토리지 구현이며 구성 가능한 2시간 동안 최대 1,000개의 지속형 회로를 저장합니다.

다음 옵션을 사용하여 메모리 내 공급자의 기본값을 변경합니다.

  • PersistedCircuitInMemoryMaxRetained ({CIRCUIT COUNT} 자리 표시자): 유지할 최대 회로 수입니다. 기본값은 1,000개의 회로입니다. 예를 들어 최대 2,000개의 회로에 대한 상태를 유지하는 데 사용합니다 2000 .
  • PersistedCircuitInMemoryRetentionPeriod ({RETENTION PERIOD} 자리 표시자): 최대 보존 기간은 TimeSpan입니다. 기본값은 2시간입니다. 예를 들어 3시간 보존 기간에 사용합니다 TimeSpan.FromHours(3) .
services.Configure<CircuitOptions>(options =>
{
    options.PersistedCircuitInMemoryMaxRetained = {CIRCUIT COUNT};
    options.PersistedCircuitInMemoryRetentionPeriod = {RETENTION PERIOD};
});

회로에서 구성 요소 상태를 유지하는 것은 기존 PersistentComponentState API를 기반으로 빌드되며, 대화형 렌더링 모드를 채택하는 미리 렌더링된 구성 요소의 상태를 계속 유지합니다. 자세한 내용은 ASP.NET Core Blazor 미리 렌더링된 상태 지속성을 참조하세요.

[참고] 미리 렌더링을 위한 구성 요소 상태를 유지하면 모든 대화형 렌더링 모드에서 작동하지만 회로 상태 지속성은 대화형 서버 렌더링 모드에서만 작동합니다.

회로 상태 지속성을 가능하게 하려면 [PersistentState] 속성을 사용하여 구성 요소 속성을 주석 처리합니다. 다음 예제에서는 각 구성 요소 인스턴스에 @key 대한 고유 식별자를 제공하기 위해 지시문 특성을 사용하여 항목의 키를 지정합니다.

@foreach (var item in Items)
{
    <ItemDisplay @key="@($"unique-prefix-{item.Id}")" Item="item" />
}

@code {
    [PersistentState]
    public List<Item> Items { get; set; }

    protected override async Task OnInitializedAsync()
    {
        Items ??= await LoadItemsAsync();
    }
}

범위가 지정된 서비스에 대한 상태를 유지하려면 [PersistentState] 특성을 서비스 속성에 적용하고, 서비스 컬렉션에 서비스를 추가한 다음, 서비스와 함께 RegisterPersistentService 확장 메서드를 호출합니다.

public class CustomUserService
{
    [PersistentState]
    public string UserData { get; set; }
}

services.AddScoped<CustomUserService>();

services.AddRazorComponents()
  .AddInteractiveServerComponents()
  .RegisterPersistentService<CustomUserService>(RenderMode.InteractiveAuto);

[참고] 위의 예제에서는 서비스가 대화형 서버 및 Interactive WebAssembly 렌더링 모두에 대한 구성 요소 미리 렌더링에 사용되는 경우 상태를 유지 UserData 합니다 RenderMode.InteractiveAutoRegisterPersistentService. 그러나 회로 상태 지속성은 대화형 서버 렌더링 모드에서만 사용할 수 있습니다.

분산 상태 지속성을 처리하고 구성할 때 기본 상태 지속성 메커니즘으로 작동시키려면, 앱에 HybridCache을(를) 할당하여 자체 지속성 기간을 구성해야 합니다(API: HybridCache, 기본적으로 8시간). HybridCache 는 각 스토리지 공급자에 대해 별도의 패키지가 필요하지 않은 분산 스토리지에 대한 통합된 접근 방식을 제공하기 때문에 사용됩니다.

다음 예제 HybridCache 에서는 Redis 스토리지 공급자를 사용하여 구현됩니다.

services.AddHybridCache()
    .AddRedis("{CONNECTION STRING}");

services.AddRazorComponents()
    .AddInteractiveServerComponents();

앞의 예제에서 자리 표시자는 개발 환경의 {CONNECTION STRING}비밀 관리자 도구 또는 모든 환경에서 Azure 배포 앱에 대한 Azure 관리 ID가 있는 Azure Key Vault와 같은 보안 접근 방식을 사용하여 제공해야 하는 Redis 캐시 연결 문자열을 나타냅니다.

회로 일시 중지 및 다시 시작

회로를 일시 중지하고 다시 시작하여 앱의 확장성을 향상시키는 사용자 지정 정책을 구현합니다.

회로를 일시 중지하면 클라이언트 쪽 브라우저 스토리지에 회로에 대한 세부 정보가 저장되고 회로가 제거되어 서버 리소스가 해제됩니다. 회로를 다시 열면 새 회로가 설정되고 지속형 상태를 사용하여 초기화됩니다.

JavaScript 이벤트 처리기에서:

  • 회로를 일시 중지하기 위한 호출 Blazor.pause 입니다.
  • 회로를 다시 시작하려면 호출 Blazor.resume 합니다.

다음 예제에서는 표시되지 않는 앱에 회로가 필요하지 않다고 가정합니다.

window.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden') {
    Blazor.pause();
  } else if (document.visibilityState === 'visible') {
    Blazor.resume();
  }
});

회로 간 상태 유지

일반적으로 사용자가 이미 존재하는 데이터를 단순히 읽는 것이 아니라 데이터를 적극적으로 생성하는 환경에서 상태를 유지합니다.

회로 간에 상태를 유지하려면 앱이 브라우저 메모리 외의 스토리지 위치에 데이터를 유지해야 합니다. 상태 지속성은 자동이 아닙니다. 상태 저장 데이터 지속성을 구현하려면 앱을 개발할 때 일정 단계를 수행해야 합니다.

데이터 지속성은 일반적으로 사용자가 특별히 노력해서 만든 높은 가치의 상태에만 필요합니다. 다음 예제에서는 상태를 유지하면 시간을 절약하거나 상업 활동에 도움이 됩니다.

  • 다단계 웹 양식: 상태가 손실된 경우 사용자가 다단계 웹 양식의 완료된 여러 단계에 대한 데이터를 다시 입력하는 데 시간이 많이 걸립니다. 이 시나리오에서는 사용자가 양식을 벗어났다가 나중에 돌아올 경우 상태가 손실됩니다.
  • 쇼핑 카트: 잠재적인 수익을 나타내는 앱의 상업적으로 중요한 구성 요소는 유지 관리할 수 있습니다. 상태와 쇼핑 카트가 손실된 사용자는 나중에 사이트로 돌아올 때 제품 또는 서비스를 더 적게 구매할 수도 있습니다.

앱은 ‘앱 상태’만 유지할 수 있습니다. 구성 요소 인스턴스 및 렌더링 트리와 같은 UI는 유지할 수 없습니다. 구성 요소 및 렌더링 트리는 일반적으로 직렬화할 수 없습니다. 트리 뷰 컨트롤의 펼친 노드와 같은 UI 상태를 유지하려면 앱이 사용자 지정 코드를 사용하여 UI 상태의 동작을 직렬화 가능한 앱 상태로 모델링해야 합니다.

서버 쪽 스토리지

여러 사용자 및 디바이스에 걸친 영구적 데이터 지속성을 위해 앱이 서버 쪽 스토리지를 사용할 수 있습니다. 옵션은 다음과 같습니다.

  • 블롭 스토리지
  • 키값 저장소
  • 관계형 데이터베이스
  • 테이블 저장소

데이터가 저장된 후 사용자의 상태가 유지되고 모든 새 회로에서 사용할 수 있습니다.

Azure 데이터 스토리지 옵션에 대한 자세한 내용은 다음을 참조하세요.

브라우저 스토리지

자세한 내용은 보호된 브라우저 스토리지를 사용하여 ASP.NET Core Blazor 상태 관리를 참조하세요.

추가 리소스