.net 8 InteractiveAuto 모드 질문드립니다

안녕하세요! C#을 열심히 공부하고 있는 초보입니다…ㅎㅎ
이번 .NET 8에서 사용할 수 있게된 InteractiveAuto 모드에 대해 공부하며 테스트해보고 있는데요,
질문드리고싶은 부분이 생겨 작성하게 되었습니다!

Auto 모드는 페이지 첫 로드(방문)시에 InteractiveServer 모드로 동작하고 이후 재방문 시에는 InteractiveWebAssembly 모드로 동작하는 방식이라고 알고있는데

  1. Server 모드로 동작을 하는지, WebAssembly 모드로 동작하는지 확인할 방법이 있나요?
    지금은 Console.WirteLine 코드를 추가해서 콘솔 메시지가 서버 콘솔 창에 출력되는지, 브라우저의 콘솔 창에 출력되는지로 확인하고 있는데 이렇게 확인하는 방법이 맞는 방법인지, 다른 방법이 있다면 어떻게 확인할 수 있는지 궁금합니다!

  2. 1번의 콘솔 메시지 방법으로 출력 위치로 확인했을 때 Auto 모드의 페이지가 Server 동작 → WebAssembly로 클라이언트에서 동작하도록 스위치되는 조건이 단순히 재방문할 때가 아니라 WebSocket 연결이 되어있는지의 여부인 것 같더라구요…!
    (WebSocket 연결 여부는 브라우저 콘솔 창의 connect 메시지로 확인했습니다)
    (아래 서버에서 실행/클라이언트에서 실행이라는 말은 콘솔 메시지가 어디에서 출력되는지를 보고 작성했습니다 이 방법이 실행되는 위치를 판단하는 데에 잘못된 방법이라면 알려주시면 감사하겠습니다!)

예를 들어 첫 페이지가 Static Server 모드로 실행됐으면 연결된 WebSocket이 없음 → Interactive Auto모드 페이지로 진입하면 바로 클라이언트에서 실행
첫 페이지가 Interactive Server 모드면 연결된 WebSocket이 있음 → Auto 페이지에 진입하면 서버에서 실행
이후 Server 모드 페이지와 Auto모드 페이지를 왔다갔다 이동하면 재방문 시에도 계속 서버에서 동작하다가 WebAssembly 모드의 페이지나 Static Server 모드의 페이지 방문으로 WebSocket 연결이 끊어지면 Auto 모드의 페이지 방문시 클라이언트에서 동작, 다시 Server 모드 페이지 방문으로 WebSocket 연결이 생기면 Auto 모드 페이지 재방문시 클라이언트가 아닌 서버에서 동작

설명이 너무 간결하지 못하네요 죄송합니다…ㅠ-ㅠ Auto 모드의 설명만 봤을때는 첫 방문: 서버 동작, 이후 재방문: 쭉 클라이언트 동작으로 예상했는데 제가 테스트해본 방식이 잘못됐을까요?

4 Likes

테스트 잘 했습니다. Console.WriteLine()으로 찍었을 때 어디로 출력되는지 잘 확인하셨어요. Server의 경우 콘솔에 (서버가 콘솔로 떠 있으므로) 웹어셈블리의 경우 웹브라우저 디버그 콘솔로 출력이 됩니다.

현재 .NET 8의 Interactive Auto 모두가 정말 Interactive하게 동작하는지는 저는 아직 잘 모르겠습니다. 테스트 결과 Interactive Auto의 경우

최초 방문 시 서버 모드로 동작 후 재방문 시 웹어셈블리로 동작하는 것이 아니라 Prerendering Webassembly Mode 처럼 동작 합니다.

코드로 현재 모드가 Server 또는 Webassembly인지 확인하는 방법은 아직 모르겠습니다. 찾으면 댓글로 공유할께요.

3 Likes

답변 주셔서 정말 감사드립니다! 콘솔 출력 위치가 달라지는걸 확실히 알고 넘어갈 수 있게 되었어요 알려주셔서 감사드려요 :smiley: !!
Auto 모드가 공식 문서를 보면서 이해했던 개념+기대했던 동작이랑 테스트하며 확인하는 동작이랑 달라서 조금 어렵네요ㅠ.ㅠ Prerendering Webassembly Mode처럼 동작한다는 말씀이 맞는 것 같아요
혹시 Console.WriteLine(RuntimeInformation.OSDescription);로 출력했을 때 Browser/Window 버전으로 각각 나누어 출력이 되는데 이렇게 확인할 수도 있다고도 볼 수 있을까요?

3 Likes

네 그렇게 확인하는 것이 맞는 것 같습니다.

System.Environment.OSVersion.Platform == PlatformID.Other 일 경우 웹브라우저 아닐 경우 서버 라고 체크할 수 도 있어요.

4 Likes

prerending webassembly와 조금 다른 점은 이 점 같습니다.

웹어셈블리 관련 파일이 브라우저 캐싱 되었을 경우 서버 모드를 건너뛰고 바로 웹어셈블리로 띄운다고 합니다. 만약 캐싱이 안되었을 경우 서버 모드로 떴다가 이후 페이지에 다시 진입 시(캐싱 완료 후) 웹어셈블리로 뜬다고 합니다.

4 Likes

프레임워크 별로 실행 환경을 알려주는 클래스가 있기는 한데, 범용으로 쓰기에는 무리가 있습니다.
예를 들면, IJSInProcessRuntime 은 블레이저 와즘에만 존재하는 서비스입니다.

이 서비스의 주입을 요청받을 때 에러가 나지 않으면 Wasm 이라고 볼 수 있는 것이죠.

블레이저는 호스팅 모델에 기반하고 있어, 호스트가 제공하는 서비스 컨테이너를 이용하면 좀 더 범용적인 방식을 도입할 수 있습니다.

interface IBlazorHost
{
    string Name {get; }
}

class ServerHost : IBlazorHost
{
   public string Name { get; } = "Server"; 
}

class WasmHost : IBlazorHost
{
   public string Name { get; } = "Wasm"; 
}

class MauiHost : IBlazorHost
{
   public string Name { get; } = "Maui"; 
}

각 구현체를 알맞은 프로젝트의 서비스 컨테이너에 개별적으로 등록하면 됩니다.

블레이저 웹앱 서버 프로젝트

// Program.cs
builder.Services.AddSingleton<IBlazorHost, ServerHost>();

블레이저 웹앱 클라이언트 프로젝트

// Program.cs
builder.Services.AddSingleton<IBlazorHost, WasmHost>();
  • 사용
    .razor
@inject IBlazorHost BlazorHost

<h1> Mode : @BlazorHost.Name </h1>

만약 위 코드를 Counter 페이지 요소에 삽입하면, 처음에는 Mode: Server 라고 떴다가, 와즘 다운로드가 완료되어, 실행 컨텍스트가 와즘으로 변경되면, Mode: Wasm 으로 변경될 것입니다.
참고로, 이 시점에 Counter 도 0으로 초기화됩니다.

5 Likes

좋은 방법입니다! ^^

4 Likes

감사합니다!! 테스트해보니까 말씀하신 대로 동작해서 궁금했던 부분(서버/클라이언트) 체크를 더 확실히 할 수 있을 것 같습니다!! 메모해놓고 잘 이용하겠습니다 :blush::blush:

3 Likes

브라우저 캐싱 여부가 중요한 부분이군요 감사합니다 더 많이 테스트해보고 찾아봐야겠습니다ㅠ.ㅠ

3 Likes

웹소캣 오픈 여부로 확인하셔도 됩니다

5 Likes

자세한 답변 정말정말 감사드립니다!! 저에게 너무 필요했던 답변입니다
그런데 혹시 제가 어떤 부분을 실수한건지 클라이언트 프로젝트의 Program.cs 파일에 올려주신 코드로 서비스 등록을 하였는데도 등록된 서비스를 찾을 수 없다는 오류가 발생합니다:sweat_drops: 서버 프로젝트의 Program.cs에 등록한 서비스는 잘 인식하는데 무엇을 놓친걸까요?
서버 프로젝트와 클라이언트 프로젝트에 모두 IBlazorHost 인터페이스 클래스를 만들고 양쪽 Program.cs에 모두 서비스를 등록했는데 클라이언트 쪽 서비스만 찾을 수 없다는 에러가 출력됩니다ㅠ.ㅠ

3 Likes

헉 정말 제가 알고싶었던 내용인데 심지어 한글로 들을 수 있다니 너무너무 감사드립니다!! 다 들어보겠습니다 너무 도움되었습니다 감사합니다ㅠ.ㅠ

3 Likes

IBlazorHost 가 복수가 되면 서로 다른 객체가 됩니다.

이 객체는 모든 프로젝트에서 참조하기 때문에 별도의 클래스 라이브러리 프로젝트에 정의하는게 좋습니다.

예를 들면, CommonServices 라는 이름으로 클래스 라이브러리 프로젝트를 추가하고 거기에, IBlazorhost 를 정의합니다.

// CommonServices.IBlazorHost.cs

namespace CommonServices;

public interface IBlazorHost
{
    string Name {get; }
}

public class ServerHost : IBlazorHost
{
   public string Name { get; } = "Server"; 
}

public class WasmHost : IBlazorHost
{
   public string Name { get; } = "Wasm"; 
}

public class MauiHost : IBlazorHost
{
   public string Name { get; } = "Maui"; 
}

각각의 구현 클래스를 각 프로젝트에 분산시킬 수도 있는데, 위의 코드는 클래스 라이브러리에 기본 구현체들을 넣어 둔 것입니다.

서버 프로젝트와 클라이언트 프로젝트는 이 프로젝트를 참조하여, IBlazorHost를 공통적으로 사용하면 됩니다.

참고로, 클래스 이름은 꼭 따라할 필요는 없습니다.

4 Likes

시간 내주셔서 세세하게 알려주셔서 정말 감사드립니다 ㅠㅠ 많이 배워갑니다, 알려주신 대로 한 번 테스트 해보겠습니다!!

3 Likes

저도 궁금했던 부분인데
대신 시원하게 질문해주셔서 너무 고맙습니다. ㅎㅎㅎ
테스트 해주신 부분도 너무 좋으셨어요.

3 Likes

그렇게 말씀해주셔서 감사드립니다!! ㅠㅠ 이것저것 배워가며 테스트해보니 더 흥미가 느껴지는 것 같아요 댓글로 도움주신 분들께 모두 정말 감사드려요 :smiley:

3 Likes