ASP.NET Core Razor 구성 요소 미리 렌더링 및 통합

참고 항목

이 문서의 최신 버전은 아닙니다. 이 문서의 최신 버전은 .NET 7 버전을 참조하세요.

이 문서에서는 서버에서의 Razor 구성 요소 미리 렌더링을 비롯하여 Blazor 앱의 Razor 구성 요소 통합 시나리오를 설명합니다.

Important

ASP.NET Core 릴리스의 프레임워크 변경으로 인해 이 문서의 다양한 지침 집합이 제공되었습니다. 이 문서의 지침을 사용하기 전에 이 페이지의 문서 버전 선택기가 앱에 사용하려는 ASP.NET Core 버전과 일치하는지 확인합니다.

Razor 구성 요소는 Razor Pages 및 호스트된 Blazor WebAssembly솔루션의 MVC 앱에 통합할 수 있습니다. 페이지나 뷰를 렌더링할 때 구성 요소를 동시에 미리 렌더링할 수 있습니다.

미리 렌더링은 검색 엔진이 페이지 순위를 계산하는 데 사용할 수 있는 초기 HTTP 응답에 대한 콘텐츠를 렌더링하여 SEO(검색 엔진 최적화)를 향상시킬 수 있습니다.

솔루션 구성

미리 렌더링 구성

호스트된 Blazor WebAssembly 앱의 미리 렌더링을 설정하려면 다음을 수행합니다.

  1. ASP.NET Core 앱에서 Blazor WebAssembly 앱을 호스트합니다. 독립 실행형 Blazor WebAssembly 앱을 ASP.NET Core 솔루션에 추가하거나 호스트된 옵션으로 Blazor WebAssembly 프로젝트 템플릿에서 만든 호스트된 Blazor WebAssembly 앱을 사용할 수 있습니다.

    • Visual Studio: 추가 정보 대화 상자에서 Blazor WebAssembly 앱을 만들 때 ASP.NET Core 호스팅 확인란을 선택합니다. 이 문서의 예제에서는 솔루션의 이름을 BlazorHosted로 지정합니다.
    • Visual Studio Code/.NET CLI 명령 셸: dotnet new blazorwasm -ho(-ho|--hosted 옵션 사용) -o|--output {LOCATION} 옵션을 사용하여 솔루션에 대한 폴더를 만들고 솔루션의 프로젝트 네임스페이스를 설정합니다. 이 문서의 예제에서는 솔루션 이름이 BlazorHosted(dotnet new blazorwasm -ho -o BlazorHosted)입니다.

    이 문서의 예제에서는 호스트된 솔루션의 이름(어셈블리 이름)이 BlazorHosted입니다. 클라이언트 프로젝트의 네임스페이스는 BlazorHosted.Client이고 서버 프로젝트의 네임스페이스는 BlazorHosted.Server입니다.

  2. 프로젝트에서 파일을 삭제합니다Blazor WebAssemblyClient.wwwroot/index.html

  3. Client 프로젝트에서 Program.cs의 다음 줄을 삭제합니다.

    - builder.RootComponents.Add<App>("#app");
    - builder.RootComponents.Add<HeadOutlet>("head::after");
    
  4. _Host.cshtml 파일을 Server 프로젝트의 Pages 폴더에 추가합니다. 명령 셸에서 Visual Studio나 .NET CLI를 dotnet new blazorserver -o BlazorServer 명령과 함께 사용하여 Blazor Server 템플릿에서 만든 프로젝트로부터 파일을 가져올 수 있습니다. -o BlazorServer 옵션은 프로젝트용 폴더를 만듭니다. 파일을 Server 프로젝트의 Pages 폴더에 배치한 후 파일을 다음과 같이 변경합니다.

    _Host.cshtml 파일에 다음 변경 내용을 적용합니다.

    • Server 앱 페이지의 네임스페이스와 일치하도록 파일 맨 위에 있는 Pages 네임스페이스를 업데이트합니다. 다음 예제의 {APP NAMESPACE} 자리 표시자는 _Host.cshtml 파일을 제공한 기부자 앱 페이지의 네임스페이스를 나타냅니다.

      삭제:

      - @namespace {APP NAMESPACE}.Pages
      

      추가:

      @namespace BlazorHosted.Server.Pages
      
    • 파일의 맨 위에 Client 프로젝트에 대한 @using 지시문을 추가합니다.

      @using BlazorHosted.Client
      
    • WebAssembly의 스타일시트를 가리키도록 스타일시트 링크를 업데이트합니다. 다음 예제에서 클라이언트 프로젝트의 네임스페이스는 BlazorHosted.Client입니다. {APP NAMESPACE} 자리 표시자는 _Host.cshtml 파일을 제공한 기부자 앱의 네임스페이스를 나타냅니다. HeadOutlet 구성 요소에 대한 구성 요소 태그 도우미(<component> 태그)를 업데이트하여 구성 요소를 미리 렌더링합니다.

      삭제:

      - <link href="css/site.css" rel="stylesheet" />
      - <link href="{APP NAMESPACE}.styles.css" rel="stylesheet" />
      - <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
      

      추가:

      <link href="css/app.css" rel="stylesheet" />
      <link href="BlazorHosted.Client.styles.css" rel="stylesheet" />
      <component type="typeof(HeadOutlet)" render-mode="WebAssemblyPrerendered" />
      

      참고 항목

      부트스트랩 스타일시트를 요청하는 <link> 요소(css/bootstrap/bootstrap.min.css)를 그대로 둡니다.

    • 클라이언트 쪽 Blazor WebAssembly 스크립트를 사용하도록 Blazor 스크립트 원본을 업데이트합니다.

      삭제:

      - <script src="_framework/blazor.server.js"></script>
      

      추가:

      <script src="_framework/blazor.webassembly.js"></script>
      
    • 루트 App 구성 요소를 WebAssemblyPrerendered로 미리 렌더링하도록 구성 요소 태그 도우미render-mode를 업데이트합니다.

      삭제:

      - <component type="typeof(App)" render-mode="ServerPrerendered" />
      

      추가:

      <component type="typeof(App)" render-mode="WebAssemblyPrerendered" />
      

      Important

      미리 렌더링은 인증 엔드포인트(/authentication/ 경로 세그먼트)에 대해 지원되지 않습니다. 자세한 내용은 ASP.NET Core Blazor WebAssembly 추가 보안 시나리오를 참조하세요.

  5. Server 프로젝트의 Program.cs 파일에서 대체 엔드포인트를 index.html 파일에서 _Host.cshtml 페이지로 변경합니다.

    삭제:

    - app.MapFallbackToFile("index.html");
    

    추가:

    app.MapFallbackToPage("/_Host");
    
  6. Client 프로젝트와 Server 프로젝트가 미리 렌더링하는 동안 하나 이상의 공통 서비스를 사용하는 경우 서비스 등록을 두 프로젝트 모두에서 호출할 수 있는 메서드로 팩터링합니다. 자세한 내용은 ASP.NET Core Blazor 종속성 주입을 참조하세요.

  7. Server 프로젝트를 실행합니다. 호스트된 Blazor WebAssembly 앱은 클라이언트에 대한 Server 프로젝트에 의해 미리 렌더링됩니다.

Razor 구성 요소를 페이지 및 뷰에 포함하는 구성

앱에서 ClientBlazor WebAssembly 서버 앱의 페이지 및 보기로 구성 요소를 포함하기 Razor 위한 다음 섹션과 예제에는 추가 구성이 필요합니다.

Server 프로젝트에는 다음 파일 및 폴더가 있어야 합니다.

Razor 페이지:

  • Pages/Shared/_Layout.cshtml
  • Pages/Shared/_Layout.cshtml.css
  • Pages/_ViewImports.cshtml
  • Pages/_ViewStart.cshtml

MVC:

  • Views/Shared/_Layout.cshtml
  • Views/Shared/_Layout.cshtml.css
  • Views/_ViewImports.cshtml
  • Views/_ViewStart.cshtml

위의 파일은 다음을 사용하여 ASP.NET Core 프로젝트 템플릿에서 앱을 생성하면 가져올 수 있습니다.

  • Visual Studio의 새 프로젝트 만들기 도구를 사용합니다.
  • 명령 셸을 열고 dotnet new webapp -o {PROJECT NAME}(Razor Pages) 또는 dotnet new mvc -o {PROJECT NAME}(MVC)를 실행합니다. {PROJECT NAME} 자리 표시자의 값을 포함하는 옵션 -o|--output은 앱의 이름을 제공하고 앱을 위한 폴더를 만듭니다.

가져온 _ViewImports.cshtml 파일의 네임스페이스를 파일을 받는 Server 프로젝트에서 사용하는 것과 일치 하도록 업데이트합니다.

Pages/_ViewImports.cshtml(Razor Pages):

@using BlazorHosted.Server
@namespace BlazorHosted.Server.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Views/_ViewImports.cshtml(MVC):

@using BlazorHosted.Server
@using BlazorHosted.Server.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

가져온 레이아웃 파일( Razor Pages를 위한 Pages/Shared/_Layout.cshtml 또는 MVC용 Views/Shared/_Layout.cshtml)을 업데이트합니다.

먼저 다음 예제에서 RPDonor.styles.css인 기부자 프로젝트에서 제목과 스타일시트를 삭제합니다. {PROJECT NAME} 자리 표시자는 기부자 프로젝트의 앱 이름을 나타냅니다.

- <title>@ViewData["Title"] - {PROJECT NAME}</title>
- <link rel="stylesheet" href="~/RPDonor.styles.css" asp-append-version="true" />

레이아웃 파일에 Client 프로젝트의 스타일을 포함합니다. 다음 예제에서 Client 프로젝트의 네임스페이스는 BlazorHosted.Client입니다. <title> 요소는 동시에 업데이트할 수 있습니다.

레이아웃 파일의 <head> 내용에 다음 줄을 배치합니다.

<title>@ViewData["Title"] - BlazorHosted</title>
<link href="css/app.css" rel="stylesheet" />
<link rel="stylesheet" href="BlazorHosted.Client.styles.css" asp-append-version="true" />
<component type="typeof(HeadOutlet)" render-mode="WebAssemblyPrerendered" />

가져온 레이아웃에는 두 개의 Home(Index 페이지) 및 Privacy 탐색 링크가 포함됩니다. 호스팅된 Blazor WebAssembly 앱에 대한 Home 링크 지점을 만들려면 하이퍼링크를 변경합니다.

- <a class="navbar-brand" asp-area="" asp-page="/Index">{PROJECT NAME}</a>
+ <a class="navbar-brand" href="/">BlazorHosted</a>
- <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>

MVC 레이아웃 파일에서 다음을 수행합니다.

- <a class="navbar-brand" asp-area="" asp-controller="Home" 
-     asp-action="Index">{PROJECT NAME}</a>
+ <a class="navbar-brand" href="/">BlazorHosted</a>
- <a class="nav-link text-dark" asp-area="" asp-controller="Home" 
-     asp-action="Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>

<footer> 요소의 앱 이름을 업데이트합니다. 다음 예제에서는 앱 이름 BlazorHosted를 사용합니다.

- &copy; {DATE} - {DONOR NAME} - <a asp-area="" asp-page="/Privacy">Privacy</a>
+ &copy; {DATE} - BlazorHosted - <a asp-area="" asp-page="/Privacy">Privacy</a>

앞의 예제에서 {DATE} 자리 표시자는 Razor Pages 또는 MVC 프로젝트 템플릿에서 생성된 앱의 저작권 날짜를 나타냅니다.

Privacy 링크가 개인 정보 페이지(Razor Pages)로 연결되도록 하려면 Server 프로젝트에 개인 정보 페이지를 추가합니다.

Server 프로젝트의 Pages/Privacy.cshtml:

@page
@model PrivacyModel
@{
    ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<p>Use this page to detail your site's privacy policy.</p>

MVC 기반 개인 정보 보기의 경우에는 Server 프로젝트에서 개인 정보 보기를 만듭니다.

Server 프로젝트의 View/Home/Privacy.cshtml:

@{
    ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<p>Use this page to detail your site's privacy policy.</p>

MVC 앱의 Home 컨트롤러에서 보기를 반환합니다.

다음 코드를 Controllers/HomeController.cs에 추가합니다.

public IActionResult Privacy()
{
    return View();
}

기부자 앱에서 파일을 가져오는 경우 파일의 네임스페이스를 Server 프로젝트의 네임스페이스와 일치하도록 업데이트해야 합니다(예: BlazorHosted.Server).

Server 프로젝트의 wwwroot 폴더에서 기부자 프로젝트에 대한 정적 자산 가져오기:

  • wwwroot/css 폴더 및 콘텐츠
  • wwwroot/js 폴더 및 콘텐츠
  • wwwroot/lib 폴더 및 콘텐츠

기부자 프로젝트가 ASP.NET Core 프로젝트 템플릿에서 만들어지고 파일이 수정되지 않으면 기부자 프로젝트의 전체 wwwroot 폴더를 Server 프로젝트로 복사하여 favicon 아이콘 파일을 제거할 수 있습니다.

Warning

정적 자산을 Client 폴더와 Serverwwwroot 폴더 모두에 배치하지 마세요. 두 폴더 모두에 동일한 파일이 존재하면 정적 자산이 동일한 웹 루트 경로를 공유하므로 예외가 throw됩니다. 따라서 wwwroot 폴더 중 하나에만 정적 자산을 호스트합니다.

이전 구성을 채택한 후 Razor 구성 요소를 Server 프로젝트의 페이지나 보기에 포함합니다. 이 문서의 다음 섹션에 있는 지침을 활용하세요.

  • 구성 요소 태그 도우미를 사용하여 페이지 또는 보기에서 구성 요소 렌더링
  • CSS 선택기를 사용하여 페이지 또는 보기에서 구성 요소 렌더링

구성 요소 태그 도우미를 사용하여 페이지 또는 보기에서 구성 요소를 렌더링

추가 구성을 포함하여 솔루션을 구성한 후 구성 요소 태그 도우미는 페이지 또는 보기의 Blazor WebAssembly 앱에서 구성 요소를 렌더링하기 위한 두 가지 렌더링 모드를 지원합니다.

다음 Razor Pages 예제에서는 Counter 구성 요소가 페이지에서 렌더링됩니다. 구성 요소를 대화형으로 만들기 위해 Blazor WebAssembly 스크립트가 페이지의 렌더링 섹션에 포함됩니다. 구성 요소 태그 도우미Counter 구성 요소의 전체 네임스페이스를 사용하지 않으려면({ASSEMBLY NAME}.Pages.Counter) 클라이언트 프로젝트의 Pages 네임스페이스에 대한 @using 지시문을 추가합니다. 다음 예제에서 Client 프로젝트의 네임스페이스는 BlazorHosted.Client입니다.

Server 프로젝트에서 Pages/RazorPagesCounter1.cshtml:

@page
@using BlazorHosted.Client.Pages

<component type="typeof(Counter)" render-mode="WebAssemblyPrerendered" />

@section Scripts {
    <script src="_framework/blazor.webassembly.js"></script>
}

Server 프로젝트를 실행합니다. /razorpagescounter1의 Razor 페이지로 이동합니다. 미리 렌더링된 Counter 구성 요소가 페이지에 포함되어 있습니다.

RenderMode는 구성 요소에 대해 다음을 구성합니다.

  • 페이지에 미리 렌더링할지 여부
  • 페이지에 정적 HTML로 렌더링할지 여부 또는 사용자 에이전트에서 Blazor 앱을 부트스트랩하는 데 필요한 정보를 포함할지 여부

매개 변수 전달과 RenderMode 구성을 포함하여 구성 요소 태그 도우미에 대한 자세한 내용은 ASP.NET Core의 구성 요소 태그 도우미를 참조하세요.

구성 요소에서 사용하는 정적 리소스와 앱에서 레이아웃 페이지를 구성하는 방법에 따라 추가 작업이 필요할 수 있습니다. 일반적으로 스크립트는 페이지 또는 뷰의 Scripts 렌더링 섹션에 추가되고 스타일시트는 레이아웃의 <head> 요소 콘텐츠에 추가됩니다.

렌더링 조각을 통해 자식 콘텐츠 설정

구성 요소 태그 도우미는 자식 콘텐츠(예param-ChildContent="...": )에 대한 대리자 수신을 RenderFragment 지원하지 않습니다. 전달하려는 자식 콘텐츠로 렌더링하려는 구성 요소를 참조하는 Razor 구성 요소(.razor)를 만든 다음, 페이지 또는 보기에서 Razor 구성 요소를 호출하는 것이 좋습니다.

미리 렌더링된 최상위 구성 요소가 게시할 때 잘리지 않는지 확인

구성 요소 태그 도우미가 게시할 때 잘릴 수 있는 라이브러리의 구성 요소를 직접 참조하는 경우 클라이언트 쪽 앱 코드에서는 참조가 없으므로 게시 중에 구성 요소가 잘릴 수 있습니다. 따라서 구성 요소가 미리 렌더링되지 않아 출력에 빈 지점이 남게 됩니다. 이 경우 클라이언트 쪽 앱의 모든 클래스에 DynamicDependency 특성을 추가하여 라이브러리 구성 요소를 유지하도록 트리머에 지시합니다. SomeLibraryComponentToBePreserved라는 구성 요소를 유지하려면 구성 요소에 다음을 추가합니다.

@using System.Diagnostics.CodeAnalysis
@attribute [DynamicDependency(DynamicallyAccessedMemberTypes.All, 
    typeof(SomeLibraryComponentToBePreserved))]

대부분의 경우 앱이 구성 요소를 미리 렌더링하는(트리밍되지 않음)하고 라이브러리의 구성 요소를 참조하므로(역시 트리밍을 유발하지 않음) 일반적으로는 위의 접근 방식이 필요하지 않습니다. 라이브러리가 잘릴 수 있는 경우에만 라이브러리 구성 요소를 직접 미리 렌더링하기 위해 DynamicDependency를 명시적으로 사용합니다.

CSS 선택기를 사용하여 페이지 또는 보기에서 구성 요소 렌더링

추가 구성을 포함하여 솔루션을 구성한 후 Program.cs 파일에서 호스트된 Blazor WebAssembly 솔루션의 Client 프로젝트에 루트 구성 요소를 추가합니다. 다음 예제에서 Counter 구성 요소는 counter-component와 일치하는 id가 있는 요소를 선택하는 CSS 선택기를 사용하여 루트 구성 요소로 선언됩니다. 다음 예제에서 Client 프로젝트의 네임스페이스는 BlazorHosted.Client입니다.

Client 프로젝트의 Program.cs 파일에서 프로젝트의 Razor 구성 요소에 대한 네임스페이스를 파일의 맨 위에 추가합니다.

using BlazorHosted.Client.Pages;

Program.cs에서 builder이 설정된 후에는 Counter 구성 요소를 루트 구성 요소로 추가합니다.

builder.RootComponents.Add<Counter>("#counter-component");

다음 Razor Pages 예제에서는 Counter 구성 요소가 페이지에서 렌더링됩니다. 구성 요소를 대화형으로 만들기 위해 Blazor WebAssembly 스크립트가 페이지의 렌더링 섹션에 포함됩니다.

Server 프로젝트에서 Pages/RazorPagesCounter2.cshtml:

@page

<div id="counter-component">Loading...</div>

@section Scripts {
    <script src="_framework/blazor.webassembly.js"></script>
}

Server 프로젝트를 실행합니다. /razorpagescounter2의 Razor 페이지로 이동합니다. 미리 렌더링된 Counter 구성 요소가 페이지에 포함되어 있습니다.

구성 요소에서 사용하는 정적 리소스와 앱에서 레이아웃 페이지를 구성하는 방법에 따라 추가 작업이 필요할 수 있습니다. 일반적으로 스크립트는 페이지 또는 뷰의 Scripts 렌더링 섹션에 추가되고 스타일시트는 레이아웃의 <head> 요소 콘텐츠에 추가됩니다.

참고 항목

이전 예제에서는 Blazor WebAssembly 앱이 미리 렌더링되고 Razor Pages 또는 MVC 앱에 CSS 선택기를 사용하여 동시에 통합된 경우에는 JSException을 throw합니다. 포함된 구성 요소를 이용해 Client 프로젝트의 Razor 구성 요소 중 하나로 이동하거나 Server의 페이지 또는 보기로 이동하면 하나 이상의 JSException이 throw됩니다.

이는 라우팅 가능한 Razor구성 요소와 Blazor WebAssembly 앱의 렌더링 및 통합이 CSS 선택기의 사용과 호환되지 않기 때문에 정상적인 동작입니다.

이전 섹션의 예제를 이용했고 CSS 선택기가 샘플 앱에서 작동하는지만 알고 싶다면, Client 프로젝트 Program.cs 파일의 App 루트 구성 요소의 사양을 주석으로 처리하세요.

- builder.RootComponents.Add<App>("#app");
+ //builder.RootComponents.Add<App>("#app");

CSS 선택기를 사용하는, 포함된 Razor 구성 요소(예: 이전 예제의 /razorpagescounter2)를 이용해 페이지나 보기로 이동합니다. 포함된 구성 요소와 함께 페이지나 보기가 로드되고, 포함된 구성 요소가 예상대로 작동합니다.

Razor Pages 및 MVC 앱에 Razor 구성 요소를 통합할 수 있습니다. 페이지나 뷰를 렌더링할 때 구성 요소를 동시에 미리 렌더링할 수 있습니다.

미리 렌더링은 검색 엔진이 페이지 순위를 계산하는 데 사용할 수 있는 초기 HTTP 응답에 대한 콘텐츠를 렌더링하여 SEO(검색 엔진 최적화)를 향상시킬 수 있습니다.

프로젝트를 구성한 후 프로젝트 요구 사항에 따라 다음 섹션의 지침을 따릅니다.

구성

다음 지침을 사용하여 Razor 구성 요소를 기존 Razor Pages 또는 MVC 앱의 페이지 및 보기에 통합합니다.

  1. 다음 콘텐츠를 사용하여 프로젝트 루트 폴더에 가져오기 파일을 추가합니다. {APP NAMESPACE} 자리 표시자를 프로젝트의 네임스페이스로 변경합니다.

    _Imports.razor:

    @using System.Net.Http
    @using Microsoft.AspNetCore.Authorization
    @using Microsoft.AspNetCore.Components.Authorization
    @using Microsoft.AspNetCore.Components.Forms
    @using Microsoft.AspNetCore.Components.Routing
    @using Microsoft.AspNetCore.Components.Web
    @using Microsoft.AspNetCore.Components.Web.Virtualization
    @using Microsoft.JSInterop
    @using {APP NAMESPACE}
    
  2. 프로젝트의 레이아웃 파일(Razor Pages 앱의 Pages/Shared/_Layout.cshtml 또는 MVC 앱의 Views/Shared/_Layout.cshtml)에서

    • <head> 요소에 다음 <base> 태그 및 HeadOutlet 구성 요소 태그 도우미를 추가합니다.

      <base href="~/" />
      <component type="typeof(Microsoft.AspNetCore.Components.Web.HeadOutlet)" 
          render-mode="ServerPrerendered" />
      

      위의 예제에서 href 값(‘앱 기본 경로’)은 앱이 루트 URL 경로(/)에 있는 것으로 가정합니다. 앱이 하위 애플리케이션인 경우, ASP.NET Core Blazor 호스트 및 배포 문서의 앱 기본 경로 섹션에 설명된 지침을 따르세요.

      HeadOutlet 구성 요소는 Razor 구성 요소에서 설정한 페이지 제목(PageTitle 구성 요소) 및 기타 헤드 요소(HeadContent 구성 요소)에 대한 헤드(<head>) 콘텐츠를 렌더링하는 데 사용됩니다. 자세한 내용은 ASP.NET Core Blazor 앱의 헤드 콘텐츠 제어를 참조하세요.

    • Scripts 렌더링 섹션(@await RenderSectionAsync(...)) 바로 앞에 blazor.server.js 스크립트의 <script> 태그를 추가합니다.

      <script src="_framework/blazor.server.js"></script>
      

      프레임워크는 앱에 blazor.server.js 스크립트를 추가합니다. 앱에 blazor.server.js 스크립트 파일을 수동으로 추가할 필요는 없습니다.

    참고 항목

    일반적으로 레이아웃은 _ViewStart.cshtml 파일을 통해 로드됩니다.

  3. 서비스가 등록된 Program.cs에 Blazor Server 서비스를 등록합니다.

    builder.Services.AddServerSideBlazor();
    
  4. Blazor 허브 엔드포인트를 경로가 매핑되는 Program.cs의 엔드포인트에 추가합니다. MapRazorPages(Razor Pages) 또는 MapControllerRoute(MVC)에 대한 호출 뒤에 다음 라인을 배치합니다.

    app.MapBlazorHub();
    
  5. 페이지 또는 뷰에 구성 요소를 통합합니다. 예를 들어 프로젝트의 Shared 폴더에 Counter구성 요소를 추가합니다.

    Pages/Shared/Counter.razor(Razor 페이지) 또는 Views/Shared/Counter.razor(MVC):

    <h1>Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    

    Razor 페이지:

    Razor 페이지 앱의 프로젝트 Index 페이지에서 Counter 구성 요소의 네임스페이스를 추가하고 이 구성 요소를 페이지에 포함합니다. Index 페이지가 로드되면 Counter 구성 요소가 페이지에 미리 렌더링됩니다. 다음 예제에서는 {APP NAMESPACE} 자리 표시자를 프로젝트의 네임스페이스로 바꿉니다.

    Pages/Index.cshtml:

    @page
    @using {APP NAMESPACE}.Pages.Shared
    @model IndexModel
    @{
        ViewData["Title"] = "Home page";
    }
    
    <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    

    MVC:

    MVC 앱의 프로젝트 Index뷰에서 Counter 구성 요소 네임스페이스를 추가하고 해당 구성 요소를 뷰에 포함합니다. Index 뷰가 로드되면 Counter 구성 요소가 페이지에서 미리 렌더링됩니다. 다음 예제에서는 {APP NAMESPACE} 자리 표시자를 프로젝트의 네임스페이스로 바꿉니다.

    Views/Home/Index.cshtml:

    @using {APP NAMESPACE}.Views.Shared
    @{
        ViewData["Title"] = "Home Page";
    }
    
    <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    

자세한 내용은 페이지 또는 뷰에서 구성 요소 렌더링 섹션을 참조하세요.

Razor Pages 앱에서 라우팅 가능한 구성 요소 사용

‘이 섹션에서는 사용자 요청에서 직접 라우팅할 수 있는 구성 요소를 추가하는 방법을 설명합니다.’

Razor Pages 앱에서 라우팅 가능한 Razor 구성 요소를 지원하려면 다음을 수행합니다.

  1. 구성 섹션의 지침을 따릅니다.

  2. 다음 콘텐츠를 사용하여 프로젝트 루트에 App 구성 요소를 추가합니다.

    App.razor:

    @using Microsoft.AspNetCore.Components.Routing
    
    <Router AppAssembly="typeof(App).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" />
        </Found>
        <NotFound>
            <PageTitle>Not found</PageTitle>
            <p role="alert">Sorry, there's nothing at this address.</p>
        </NotFound>
    </Router>
    
  3. 다음 콘텐츠로 _Host 페이지를 프로젝트에 추가합니다. {APP NAMESPACE} 자리 표시자를 앱의 네임스페이스로 바꿉니다.

    Pages/_Host.cshtml:

    @page
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    
    <component type="typeof(App)" render-mode="ServerPrerendered" />
    

    참고 항목

    앞의 예제에서는 HeadOutlet 구성 요소 및 Blazor 스크립트(_framework/blazor.server.js)가 앱의 레이아웃에 의해 렌더링된다고 가정합니다. 자세한 내용은 구성 섹션을 참조하세요.

    RenderModeApp 구성 요소에 대해 다음을 구성합니다.

    • 페이지에 미리 렌더링할지 여부
    • 페이지에 정적 HTML로 렌더링할지 여부 또는 사용자 에이전트에서 Blazor 앱을 부트스트랩하는 데 필요한 정보를 포함할지 여부

    매개 변수 전달과 RenderMode 구성을 포함하여 구성 요소 태그 도우미에 대한 자세한 내용은 ASP.NET Core의 구성 요소 태그 도우미를 참조하세요.

  4. Program.cs 엔드포인트에서 _Host 페이지의 우선 순위가 낮은 경로를 마지막 엔드포인트로 추가합니다.

    app.MapFallbackToPage("/_Host");
    
  5. 라우팅 가능한 구성 요소를 프로젝트에 추가합니다. 다음 예제는 Blazor 프로젝트 템플릿의 Counter 구성 요소를 기반으로 하는 RoutableCounter 구성 요소입니다.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <PageTitle>Routable Counter</PageTitle>
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  6. 프로젝트를 실행하고 /routable-counter에서 라우팅할 수 있는 RoutableCounter 구성 요소로 이동합니다.

네임스페이스에 대한 자세한 내용은 구성 요소 네임스페이스 섹션을 참조하세요.

MVC 앱에서 라우팅 가능한 구성 요소 사용

‘이 섹션에서는 사용자 요청에서 직접 라우팅할 수 있는 구성 요소를 추가하는 방법을 설명합니다.’

MVC 앱에서 라우팅 가능한 Razor 구성 요소를 지원하려면 다음을 수행합니다.

  1. 구성 섹션의 지침을 따릅니다.

  2. 다음 콘텐츠를 사용하여 프로젝트 루트에 App 구성 요소를 추가합니다.

    App.razor:

    @using Microsoft.AspNetCore.Components.Routing
    
    <Router AppAssembly="typeof(App).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" />
        </Found>
        <NotFound>
            <PageTitle>Not found</PageTitle>
            <p role="alert">Sorry, there's nothing at this address.</p>
        </NotFound>
    </Router>
    
  3. 다음 콘텐츠를 사용하여 _Host 뷰를 프로젝트에 추가합니다. {APP NAMESPACE} 자리 표시자를 앱의 네임스페이스로 바꿉니다.

    Views/Home/_Host.cshtml:

    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    
    <component type="typeof(App)" render-mode="ServerPrerendered" />
    

    참고 항목

    앞의 예제에서는 HeadOutlet 구성 요소 및 Blazor 스크립트(_framework/blazor.server.js)가 앱의 레이아웃에 의해 렌더링된다고 가정합니다. 자세한 내용은 구성 섹션을 참조하세요.

    RenderModeApp 구성 요소에 대해 다음을 구성합니다.

    • 페이지에 미리 렌더링할지 여부
    • 페이지에 정적 HTML로 렌더링할지 여부 또는 사용자 에이전트에서 Blazor 앱을 부트스트랩하는 데 필요한 정보를 포함할지 여부

    매개 변수 전달과 RenderMode 구성을 포함하여 구성 요소 태그 도우미에 대한 자세한 내용은 ASP.NET Core의 구성 요소 태그 도우미를 참조하세요.

  4. Home 컨트롤러에 작업을 추가합니다.

    Controllers/HomeController.cs:

    public IActionResult Blazor()
    {
       return View("_Host");
    }
    
  5. Program.cs 엔드포인트에 _Host 보기를 반환하는 컨트롤러 작업에 우선 순위가 낮은 경로를 추가합니다.

    app.MapFallbackToController("Blazor", "Home");
    
  6. MVC 앱에 Pages 폴더를 만들고 라우팅 가능한 구성 요소를 추가합니다. 다음 예제는 Blazor 프로젝트 템플릿의 Counter 구성 요소를 기반으로 하는 RoutableCounter 구성 요소입니다.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <PageTitle>Routable Counter</PageTitle>
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  7. 프로젝트를 실행하고 /routable-counter에서 라우팅할 수 있는 RoutableCounter 구성 요소로 이동합니다.

네임스페이스에 대한 자세한 내용은 구성 요소 네임스페이스 섹션을 참조하세요.

페이지 또는 뷰에서 구성 요소 렌더링

‘이 섹션에서는 사용자 요청에서 직접 구성 요소를 라우팅할 수 없는 페이지 또는 뷰에 구성 요소를 추가하는 방법을 설명합니다.’

페이지 또는 뷰에서 구성 요소를 렌더링하려면 구성 요소 태그 도우미를 사용합니다.

상태 저장 대화형 구성 요소 렌더링

Razor 페이지 또는 뷰에 상태 저장 대화형 구성 요소를 추가할 수 있습니다.

페이지 또는 뷰를 렌더링하는 경우와 관련해서 다음 사항을 확인합니다.

  • 구성 요소가 페이지 또는 뷰와 함께 미리 렌더링됩니다.
  • 미리 렌더링하는 데 사용된 초기 구성 요소 상태가 손실됩니다.
  • SignalR 연결이 완료되면 새 구성 요소 상태가 생성됩니다.

다음 Razor 페이지는 Counter 구성 요소를 렌더링합니다.

<h1>Razor Page</h1>

<component type="typeof(Counter)" render-mode="ServerPrerendered" 
    param-InitialValue="InitialValue" />

@functions {
    [BindProperty(SupportsGet=true)]
    public int InitialValue { get; set; }
}

자세한 내용은 ASP.NET Core 구성 요소 태그 도우미를 참조하세요.

비대화형 구성 요소 렌더링

다음 Razor 페이지에서 Counter 구성 요소는 폼을 통해 지정된 초기 값을 사용하여 정적으로 렌더링됩니다. 구성 요소가 정적으로 렌더링되므로 구성 요소는 대화형이 아닙니다.

<h1>Razor Page</h1>

<form>
    <input type="number" asp-for="InitialValue" />
    <button type="submit">Set initial value</button>
</form>

<component type="typeof(Counter)" render-mode="Static" 
    param-InitialValue="InitialValue" />

@functions {
    [BindProperty(SupportsGet=true)]
    public int InitialValue { get; set; }
}

자세한 내용은 ASP.NET Core 구성 요소 태그 도우미를 참조하세요.

구성 요소 네임스페이스

사용자 지정 폴더를 사용하여 프로젝트의 Razor 구성 요소를 저장하는 경우, 폴더를 나타내는 네임스페이스를 페이지/뷰 또는 _ViewImports.cshtml 파일에 추가합니다. 다음 예제에서

  • 구성 요소는 프로젝트의 Components 폴더에 저장됩니다.
  • {APP NAMESPACE} 자리 표시자는 프로젝트의 네임스페이스입니다. Components은 폴더의 이름을 나타냅니다.
@using {APP NAMESPACE}.Components

_ViewImports.cshtml 파일은 Razor Pages 앱의 Pages 폴더 또는 MVC 앱의 Views 폴더에 있습니다.

자세한 내용은 ASP.NET Core Razor 구성 요소를 참조하세요.

미리 렌더링된 상태 유지

미리 렌더링된 상태를 유지하지 않으면 미리 렌더링하는 동안 사용된 상태를 잃게 되며 앱이 완전히 로드되면 다시 만들어야 합니다. 상태가 비동기적으로 설정된 경우 미리 렌더링된 UI가 임시 자리 표시자로 대체된 다음, 완전히 다시 렌더링되면 UI가 깜박일 수 있습니다.

미리 렌더링된 구성 요소의 상태를 유지하려면 지속 구성 요소 상태 태그 도우미(참조 원본)를 사용합니다. 구성 요소를 미리 렌더링하는 앱에서 _Host 페이지의 닫는 </body> 태그 안에 태그 도우미의 태그인 <persist-component-state />를 추가합니다.

참고 항목

.NET 참조 원본의 설명서 링크는 일반적으로 다음 릴리스의 .NET을 위한 현재 개발을 나타내는 리포지토리의 기본 분기를 로드합니다. 특정 릴리스를 위한 태그를 선택하려면 Switch branches or tags(분기 또는 태그 전환) 드롭다운 목록을 사용합니다. 자세한 내용은 ASP.NET Core 소스 코드(dotnet/AspNetCore.Docs #26205)의 버전 태그를 선택하는 방법을 참조하세요.

Pages/_Host.cshtmlBlazor WebAssembly가 호스트 Blazor WebAssembly 된 앱 또는 ServerPrerendered 앱에서 미리 렌더링된WebAssemblyPrerendered() 앱의 Blazor Server 경우:

<body>
    ...

    <persist-component-state />
</body>

PersistentComponentState 서비스를 사용하여 유지할 상태를 결정합니다. PersistentComponentState.RegisterOnPersisting은 앱이 일시 중지되기 전에 구성 요소 상태를 유지하도록 콜백을 등록합니다. 애플리케이션이 다시 시작될 때 상태가 검색됩니다.

다음 예제에서

  • {TYPE} 자리 표시자는 유지할 데이터 형식을 나타냅니다(예: WeatherForecast[]).
  • {TOKEN} 자리 표시자는 상태 식별자 문자열입니다(예: fetchdata).
@implements IDisposable
@inject PersistentComponentState ApplicationState

...

@code {
    private {TYPE} data;
    private PersistingComponentStateSubscription persistingSubscription;

    protected override async Task OnInitializedAsync()
    {
        persistingSubscription = 
            ApplicationState.RegisterOnPersisting(PersistData);

        if (!ApplicationState.TryTakeFromJson<{TYPE}>(
            "{TOKEN}", out var restored))
        {
            data = await ...;
        }
        else
        {
            data = restored!;
        }
    }

    private Task PersistData()
    {
        ApplicationState.PersistAsJson("{TOKEN}", data);

        return Task.CompletedTask;
    }

    void IDisposable.Dispose()
    {
        persistingSubscription.Dispose();
    }
}

다음 예제는 Blazor 프로젝트 템플릿을 기준으로 하는 호스트된 Blazor WebAssembly 앱에서 FetchData 구성 요소의 업데이트된 버전입니다. WeatherForecastPreserveState 구성 요소는 미리 렌더링하는 동안 날씨 예측 상태를 유지한 다음, 상태를 검색하여 구성 요소를 초기화합니다. 구성 요소 상태 유지 태그 도우미는 모든 구성 요소 호출 후 구성 요소 상태를 유지합니다.

Pages/WeatherForecastPreserveState.razor:

@page "/weather-forecast-preserve-state"
@using BlazorSample.Shared
@implements IDisposable
@inject IWeatherForecastService WeatherForecastService
@inject PersistentComponentState ApplicationState

<PageTitle>Weather Forecast</PageTitle>

<h1>Weather forecast</h1>

<p>This component demonstrates fetching data from the server.</p>

@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var forecast in forecasts)
            {
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private WeatherForecast[] forecasts = Array.Empty<WeatherForecast>();
    private PersistingComponentStateSubscription persistingSubscription;

    protected override async Task OnInitializedAsync()
    {
        persistingSubscription = 
            ApplicationState.RegisterOnPersisting(PersistForecasts);

        if (!ApplicationState.TryTakeFromJson<WeatherForecast[]>(
            "fetchdata", out var restored))
        {
            forecasts = 
                await WeatherForecastService.GetForecastAsync(DateOnly.FromDateTime(DateTime.Now));
        }
        else
        {
            forecasts = restored!;
        }
    }

    private Task PersistForecasts()
    {
        ApplicationState.PersistAsJson("fetchdata", forecasts);

        return Task.CompletedTask;
    }

    void IDisposable.Dispose()
    {
        persistingSubscription.Dispose();
    }
}

미리 렌더링하는 동안 사용된 것과 동일한 상태로 구성 요소를 초기화하면 비용이 많이 드는 초기화 단계가 한 번만 실행됩니다. 렌더링된 UI도 미리 렌더링된 UI와 일치하므로 브라우저에서 깜박임이 발생하지 않습니다.

추가 Blazor WebAssembly 리소스

미리 렌더링된 상태 크기 및 SignalR 메시지 크기 제한

미리 렌더링된 큰 상태 크기가 SignalR 회로 메시지 크기 제한을 초과할 수 있으므로 다음이 발생합니다.

  • Circuit host not initialized. 클라이언트에서 오류가 발생하여 SignalR 회로를 초기화하지 못합니다.
  • 회로가 실패하면 클라이언트의 다시 연결 대화 상자가 나타납니다. 복구는 불가능합니다.

문제를 해결하려면 다음 방법 중 하나를 사용합니다.

  • 미리 렌더링된 상태로 전환할 데이터의 양을 줄입니다.
  • SignalR 메시지 크기 제한을 늘입니다. 경고: 제한을 늘리면 DoS(서비스 거부) 공격의 위험이 증가할 수 있습니다.

추가 Blazor Server 리소스

Razor 구성 요소는 Razor Pages 및 호스트된 Blazor WebAssembly솔루션의 MVC 앱에 통합할 수 있습니다. 페이지나 뷰를 렌더링할 때 구성 요소를 동시에 미리 렌더링할 수 있습니다.

미리 렌더링은 검색 엔진이 페이지 순위를 계산하는 데 사용할 수 있는 초기 HTTP 응답에 대한 콘텐츠를 렌더링하여 SEO(검색 엔진 최적화)를 향상시킬 수 있습니다.

솔루션 구성

미리 렌더링 구성

호스트된 Blazor WebAssembly 앱의 미리 렌더링을 설정하려면 다음을 수행합니다.

  1. ASP.NET Core 앱에서 Blazor WebAssembly 앱을 호스트합니다. 독립 실행형 Blazor WebAssembly 앱을 ASP.NET Core 솔루션에 추가하거나 호스트된 옵션으로 Blazor WebAssembly 프로젝트 템플릿에서 만든 호스트된 Blazor WebAssembly 앱을 사용할 수 있습니다.

    • Visual Studio: 추가 정보 대화 상자에서 Blazor WebAssembly 앱을 만들 때 ASP.NET Core 호스팅 확인란을 선택합니다. 이 문서의 예제에서는 솔루션의 이름을 BlazorHosted로 지정합니다.
    • Visual Studio Code/.NET CLI 명령 셸: dotnet new blazorwasm -ho(-ho|--hosted 옵션 사용) -o|--output {LOCATION} 옵션을 사용하여 솔루션에 대한 폴더를 만들고 솔루션의 프로젝트 네임스페이스를 설정합니다. 이 문서의 예제에서는 솔루션 이름이 BlazorHosted(dotnet new blazorwasm -ho -o BlazorHosted)입니다.

    이 문서의 예제에서는 클라이언트 프로젝트의 네임스페이스가 BlazorHosted.Client이고 서버 프로젝트의 네임스페이스는 BlazorHosted.Server입니다.

  2. 프로젝트에서 파일을 삭제합니다Blazor WebAssemblyClient.wwwroot/index.html

  3. Client 프로젝트에서 Program.cs의 다음 줄을 삭제합니다.

    - builder.RootComponents.Add<App>("#app");
    - builder.RootComponents.Add<HeadOutlet>("head::after");
    
  4. _Host.cshtml_Layout.cshtml 파일을 Server 프로젝트의 Pages 폴더에 추가합니다. 명령 셸에서 Visual Studio나 .NET CLI를 dotnet new blazorserver -o BlazorServer 명령과 함께 사용하여 Blazor Server 템플릿에서 만든 프로젝트로부터 파일을 가져올 수 있습니다. -o BlazorServer 옵션은 프로젝트용 폴더를 만듭니다. 파일을 Server 프로젝트의 Pages 폴더에 배치한 후 파일을 다음과 같이 변경합니다.

    Important

    페이지의 제목(PageTitle 구성 요소) 및 기타 헤드 요소(HeadContent 구성 요소)와 같은 <head> 콘텐츠를 제어하려면 HeadOutlet 구성 요소에 대해 구성 요소 태그 도우미와 함께 레이아웃 페이지(_Layout.cshtml)를 사용해야 합니다. 자세한 내용은 ASP.NET Core Blazor 앱의 헤드 콘텐츠 제어를 참조하세요.

    _Layout.cshtml 파일에 다음 변경 내용을 적용합니다.

    • Server 앱 페이지의 네임스페이스와 일치하도록 파일 맨 위에 있는 Pages 네임스페이스를 업데이트합니다. 다음 예제의 {APP NAMESPACE} 자리 표시자는 _Layout.cshtml 파일을 제공한 기부자 앱 페이지의 네임스페이스를 나타냅니다.

      삭제:

      - @namespace {APP NAMESPACE}.Pages
      

      추가:

      @namespace BlazorHosted.Server.Pages
      
    • 파일의 맨 위에 Client 프로젝트에 대한 @using 지시문을 추가합니다.

      @using BlazorHosted.Client
      
    • WebAssembly의 스타일시트를 가리키도록 스타일시트 링크를 업데이트합니다. 다음 예제에서 클라이언트 프로젝트의 네임스페이스는 BlazorHosted.Client입니다. {APP NAMESPACE} 자리 표시자는 _Layout.cshtml 파일을 제공한 기부자 앱의 네임스페이스를 나타냅니다. HeadOutlet 구성 요소에 대한 구성 요소 태그 도우미(<component> 태그)를 업데이트하여 구성 요소를 미리 렌더링합니다.

      삭제:

      - <link href="css/site.css" rel="stylesheet" />
      - <link href="{APP NAMESPACE}.styles.css" rel="stylesheet" />
      - <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
      

      추가:

      <link href="css/app.css" rel="stylesheet" />
      <link href="BlazorHosted.Client.styles.css" rel="stylesheet" />
      <component type="typeof(HeadOutlet)" render-mode="WebAssemblyPrerendered" />
      

      참고 항목

      부트스트랩 스타일시트를 요청하는 <link> 요소(css/bootstrap/bootstrap.min.css)를 그대로 둡니다.

    • 클라이언트 쪽 Blazor WebAssembly 스크립트를 사용하도록 Blazor 스크립트 원본을 업데이트합니다.

      삭제:

      - <script src="_framework/blazor.server.js"></script>
      

      추가:

      <script src="_framework/blazor.webassembly.js"></script>
      

    파일에서 다음을 수행 _Host.cshtml 합니다.

    • Pages 네임스페이스를 Client 프로젝트의 네임스페이스로 변경합니다. {APP NAMESPACE} 자리 표시자는 _Host.cshtml 파일을 제공한 기부자 앱 페이지의 네임스페이스를 나타냅니다.

      삭제:

      - @namespace {APP NAMESPACE}.Pages
      

      추가:

      @namespace BlazorHosted.Client
      
    • 루트 App 구성 요소를 WebAssemblyPrerendered로 미리 렌더링하도록 구성 요소 태그 도우미render-mode를 업데이트합니다.

      삭제:

      - <component type="typeof(App)" render-mode="ServerPrerendered" />
      

      추가:

      <component type="typeof(App)" render-mode="WebAssemblyPrerendered" />
      

      Important

      미리 렌더링은 인증 엔드포인트(/authentication/ 경로 세그먼트)에 대해 지원되지 않습니다. 자세한 내용은 ASP.NET Core Blazor WebAssembly 추가 보안 시나리오를 참조하세요.

  5. Program.cs에 있는 Server 프로젝트의 엔드포인트 매핑에서 index.html 파일의 대체(Fallback)를 _Host.cshtml 페이지로 변경합니다.

    삭제:

    - app.MapFallbackToFile("index.html");
    

    추가:

    app.MapFallbackToPage("/_Host");
    
  6. Client 프로젝트와 Server 프로젝트가 미리 렌더링하는 동안 하나 이상의 공통 서비스를 사용하는 경우 서비스 등록을 두 프로젝트 모두에서 호출할 수 있는 메서드로 팩터링합니다. 자세한 내용은 ASP.NET Core Blazor 종속성 주입을 참조하세요.

  7. Server 프로젝트를 실행합니다. 호스트된 Blazor WebAssembly 앱은 클라이언트에 대한 Server 프로젝트에 의해 미리 렌더링됩니다.

Razor 구성 요소를 페이지 및 뷰에 포함하는 구성

앱에서 ClientBlazor WebAssembly 서버 앱의 페이지 및 보기로 구성 요소를 포함하기 Razor 위한 다음 섹션과 예제에는 추가 구성이 필요합니다.

Server 프로젝트에는 다음 파일 및 폴더가 있어야 합니다.

Razor 페이지:

  • Pages/Shared/_Layout.cshtml
  • Pages/Shared/_Layout.cshtml.css
  • Pages/_ViewImports.cshtml
  • Pages/_ViewStart.cshtml

MVC:

  • Views/Shared/_Layout.cshtml
  • Views/Shared/_Layout.cshtml.css
  • Views/_ViewImports.cshtml
  • Views/_ViewStart.cshtml

Important

페이지의 제목(PageTitle 구성 요소) 및 기타 헤드 요소(HeadContent 구성 요소)와 같은 <head> 콘텐츠를 제어하려면 HeadOutlet 구성 요소에 대해 구성 요소 태그 도우미와 함께 레이아웃 페이지(_Layout.cshtml)를 사용해야 합니다. 자세한 내용은 ASP.NET Core Blazor 앱의 헤드 콘텐츠 제어를 참조하세요.

위의 파일은 다음을 사용하여 ASP.NET Core 프로젝트 템플릿에서 앱을 생성하면 가져올 수 있습니다.

  • Visual Studio의 새 프로젝트 만들기 도구를 사용합니다.
  • 명령 셸을 열고 dotnet new webapp -o {PROJECT NAME}(Razor Pages) 또는 dotnet new mvc -o {PROJECT NAME}(MVC)를 실행합니다. {PROJECT NAME} 자리 표시자의 값을 포함하는 옵션 -o|--output은 앱의 이름을 제공하고 앱을 위한 폴더를 만듭니다.

가져온 _ViewImports.cshtml 파일의 네임스페이스를 파일을 받는 Server 프로젝트에서 사용하는 것과 일치 하도록 업데이트합니다.

Pages/_ViewImports.cshtml(Razor Pages):

@using BlazorHosted.Server
@namespace BlazorHosted.Server.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Views/_ViewImports.cshtml(MVC):

@using BlazorHosted.Server
@using BlazorHosted.Server.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

가져온 레이아웃 파일( Razor Pages를 위한 Pages/Shared/_Layout.cshtml 또는 MVC용 Views/Shared/_Layout.cshtml)을 업데이트합니다.

먼저 다음 예제에서 RPDonor.styles.css인 기부자 프로젝트에서 제목과 스타일시트를 삭제합니다. {PROJECT NAME} 자리 표시자는 기부자 프로젝트의 앱 이름을 나타냅니다.

- <title>@ViewData["Title"] - {PROJECT NAME}</title>
- <link rel="stylesheet" href="~/RPDonor.styles.css" asp-append-version="true" />

레이아웃 파일에 Client 프로젝트의 스타일을 포함합니다. 다음 예제에서 Client 프로젝트의 네임스페이스는 BlazorHosted.Client입니다. <title> 요소는 동시에 업데이트할 수 있습니다.

레이아웃 파일의 <head> 내용에 다음 줄을 배치합니다.

<title>@ViewData["Title"] - BlazorHosted</title>
<link href="css/app.css" rel="stylesheet" />
<link rel="stylesheet" href="BlazorHosted.Client.styles.css" asp-append-version="true" />
<component type="typeof(HeadOutlet)" render-mode="WebAssemblyPrerendered" />

가져온 레이아웃에는 두 개의 Home(Index 페이지) 및 Privacy 탐색 링크가 포함됩니다. 호스팅된 Blazor WebAssembly 앱에 대한 Home 링크 지점을 만들려면 하이퍼링크를 변경합니다.

- <a class="navbar-brand" asp-area="" asp-page="/Index">{PROJECT NAME}</a>
+ <a class="navbar-brand" href="/">BlazorHosted</a>
- <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>

MVC 레이아웃 파일에서 다음을 수행합니다.

- <a class="navbar-brand" asp-area="" asp-controller="Home" 
-     asp-action="Index">{PROJECT NAME}</a>
+ <a class="navbar-brand" href="/">BlazorHosted</a>
- <a class="nav-link text-dark" asp-area="" asp-controller="Home" 
-     asp-action="Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>

<footer> 요소의 앱 이름을 업데이트합니다. 다음 예제에서는 앱 이름 BlazorHosted를 사용합니다.

- &copy; {DATE} - {DONOR NAME} - <a asp-area="" asp-page="/Privacy">Privacy</a>
+ &copy; {DATE} - BlazorHosted - <a asp-area="" asp-page="/Privacy">Privacy</a>

앞의 예제에서 {DATE} 자리 표시자는 Razor Pages 또는 MVC 프로젝트 템플릿에서 생성된 앱의 저작권 날짜를 나타냅니다.

Privacy 링크가 개인 정보 페이지(Razor Pages)로 연결되도록 하려면 Server 프로젝트에 개인 정보 페이지를 추가합니다.

Server 프로젝트의 Pages/Privacy.cshtml:

@page
@model PrivacyModel
@{
    ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<p>Use this page to detail your site's privacy policy.</p>

MVC 기반 개인 정보 보기의 경우에는 Server 프로젝트에서 개인 정보 보기를 만듭니다.

Server 프로젝트의 View/Home/Privacy.cshtml:

@{
    ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<p>Use this page to detail your site's privacy policy.</p>

MVC 앱의 Home 컨트롤러에서 보기를 반환합니다.

다음 코드를 Controllers/HomeController.cs에 추가합니다.

public IActionResult Privacy()
{
    return View();
}

기부자 앱에서 파일을 가져오는 경우 파일의 네임스페이스를 Server 프로젝트의 네임스페이스와 일치하도록 업데이트해야 합니다(예: BlazorHosted.Server).

Server 프로젝트의 wwwroot 폴더에서 기부자 프로젝트에 대한 정적 자산 가져오기:

  • wwwroot/css 폴더 및 콘텐츠
  • wwwroot/js 폴더 및 콘텐츠
  • wwwroot/lib 폴더 및 콘텐츠

기부자 프로젝트가 ASP.NET Core 프로젝트 템플릿에서 만들어지고 파일이 수정되지 않으면 기부자 프로젝트의 전체 wwwroot 폴더를 Server 프로젝트로 복사하여 favicon 아이콘 파일을 제거할 수 있습니다.

Warning

정적 자산을 Client 폴더와 Serverwwwroot 폴더 모두에 배치하지 마세요. 두 폴더 모두에 동일한 파일이 존재하면 예외가 throw됩니다. 각 폴더에 있는 정적 자산이 동일한 웹 루트 경로를 공유하기 때문입니다. 따라서 wwwroot 폴더 중 하나에 정적 자산을 호스트합니다.

이전 구성을 채택한 후 Razor 구성 요소를 Server 프로젝트의 페이지나 보기에 포함합니다. 이 문서의 다음 섹션에 있는 지침을 활용하세요.

  • 구성 요소 태그 도우미를 사용하여 페이지 또는 보기에서 구성 요소 렌더링
  • CSS 선택기를 사용하여 페이지 또는 보기에서 구성 요소 렌더링

구성 요소 태그 도우미를 사용하여 페이지 또는 보기에서 구성 요소를 렌더링

추가 구성을 포함하여 솔루션을 구성한 후 구성 요소 태그 도우미는 페이지 또는 보기의 Blazor WebAssembly 앱에서 구성 요소를 렌더링하기 위한 두 가지 렌더링 모드를 지원합니다.

다음 Razor Pages 예제에서는 Counter 구성 요소가 페이지에서 렌더링됩니다. 구성 요소를 대화형으로 만들기 위해 Blazor WebAssembly 스크립트가 페이지의 렌더링 섹션에 포함됩니다. 구성 요소 태그 도우미Counter 구성 요소의 전체 네임스페이스를 사용하지 않으려면({ASSEMBLY NAME}.Pages.Counter) 클라이언트 프로젝트의 Pages 네임스페이스에 대한 @using 지시문을 추가합니다. 다음 예제에서 Client 프로젝트의 네임스페이스는 BlazorHosted.Client입니다.

Server 프로젝트에서 Pages/RazorPagesCounter1.cshtml:

@page
@using BlazorHosted.Client.Pages

<component type="typeof(Counter)" render-mode="WebAssemblyPrerendered" />

@section Scripts {
    <script src="_framework/blazor.webassembly.js"></script>
}

Server 프로젝트를 실행합니다. /razorpagescounter1의 Razor 페이지로 이동합니다. 미리 렌더링된 Counter 구성 요소가 페이지에 포함되어 있습니다.

RenderMode는 구성 요소에 대해 다음을 구성합니다.

  • 페이지에 미리 렌더링할지 여부
  • 페이지에 정적 HTML로 렌더링할지 여부 또는 사용자 에이전트에서 Blazor 앱을 부트스트랩하는 데 필요한 정보를 포함할지 여부

매개 변수 전달과 RenderMode 구성을 포함하여 구성 요소 태그 도우미에 대한 자세한 내용은 ASP.NET Core의 구성 요소 태그 도우미를 참조하세요.

구성 요소에서 사용하는 정적 리소스와 앱에서 레이아웃 페이지를 구성하는 방법에 따라 추가 작업이 필요할 수 있습니다. 일반적으로 스크립트는 페이지 또는 뷰의 Scripts 렌더링 섹션에 추가되고 스타일시트는 레이아웃의 <head> 요소 콘텐츠에 추가됩니다.

렌더링 조각을 통해 자식 콘텐츠 설정

구성 요소 태그 도우미는 자식 콘텐츠(예param-ChildContent="...": )에 대한 대리자 수신을 RenderFragment 지원하지 않습니다. 전달하려는 자식 콘텐츠로 렌더링하려는 구성 요소를 참조하는 Razor 구성 요소(.razor)를 만든 다음, 페이지 또는 보기에서 Razor 구성 요소를 호출하는 것이 좋습니다.

미리 렌더링된 최상위 구성 요소가 게시할 때 잘리지 않는지 확인

구성 요소 태그 도우미가 게시할 때 잘릴 수 있는 라이브러리의 구성 요소를 직접 참조하는 경우 클라이언트 쪽 앱 코드에서는 참조가 없으므로 게시 중에 구성 요소가 잘릴 수 있습니다. 따라서 구성 요소가 미리 렌더링되지 않아 출력에 빈 지점이 남게 됩니다. 이 경우 클라이언트 쪽 앱의 모든 클래스에 DynamicDependency 특성을 추가하여 라이브러리 구성 요소를 유지하도록 트리머에 지시합니다. SomeLibraryComponentToBePreserved라는 구성 요소를 유지하려면 구성 요소에 다음을 추가합니다.

@using System.Diagnostics.CodeAnalysis
@attribute [DynamicDependency(DynamicallyAccessedMemberTypes.All, 
    typeof(SomeLibraryComponentToBePreserved))]

대부분의 경우 앱이 구성 요소를 미리 렌더링하는(트리밍되지 않음)하고 라이브러리의 구성 요소를 참조하므로(역시 트리밍을 유발하지 않음) 일반적으로는 위의 접근 방식이 필요하지 않습니다. 라이브러리가 잘릴 수 있는 경우에만 라이브러리 구성 요소를 직접 미리 렌더링하기 위해 DynamicDependency를 명시적으로 사용합니다.

CSS 선택기를 사용하여 페이지 또는 보기에서 구성 요소 렌더링

추가 구성을 포함하여 솔루션을 구성한 후 Program.cs 파일에서 호스트된 Blazor WebAssembly 솔루션의 Client 프로젝트에 루트 구성 요소를 추가합니다. 다음 예제에서 Counter 구성 요소는 counter-component와 일치하는 id가 있는 요소를 선택하는 CSS 선택기를 사용하여 루트 구성 요소로 선언됩니다. 다음 예제에서 Client 프로젝트의 네임스페이스는 BlazorHosted.Client입니다.

Client 프로젝트의 Program.cs 파일에서 프로젝트의 Razor 구성 요소에 대한 네임스페이스를 파일의 맨 위에 추가합니다.

using BlazorHosted.Client.Pages;

Program.cs에서 builder이 설정된 후에는 Counter 구성 요소를 루트 구성 요소로 추가합니다.

builder.RootComponents.Add<Counter>("#counter-component");

다음 Razor Pages 예제에서는 Counter 구성 요소가 페이지에서 렌더링됩니다. 구성 요소를 대화형으로 만들기 위해 Blazor WebAssembly 스크립트가 페이지의 렌더링 섹션에 포함됩니다.

Server 프로젝트에서 Pages/RazorPagesCounter2.cshtml:

@page

<div id="counter-component">Loading...</div>

@section Scripts {
    <script src="_framework/blazor.webassembly.js"></script>
}

Server 프로젝트를 실행합니다. /razorpagescounter2의 Razor 페이지로 이동합니다. 미리 렌더링된 Counter 구성 요소가 페이지에 포함되어 있습니다.

구성 요소에서 사용하는 정적 리소스와 앱에서 레이아웃 페이지를 구성하는 방법에 따라 추가 작업이 필요할 수 있습니다. 일반적으로 스크립트는 페이지 또는 뷰의 Scripts 렌더링 섹션에 추가되고 스타일시트는 레이아웃의 <head> 요소 콘텐츠에 추가됩니다.

참고 항목

이전 예제에서는 Blazor WebAssembly 앱이 미리 렌더링되고 Razor Pages 또는 MVC 앱에 CSS 선택기를 사용하여 동시에 통합된 경우에는 JSException을 throw합니다. 포함된 구성 요소를 이용해 Client 프로젝트의 Razor 구성 요소 중 하나로 이동하거나 Server의 페이지 또는 보기로 이동하면 하나 이상의 JSException이 throw됩니다.

이는 라우팅 가능한 Razor구성 요소와 Blazor WebAssembly 앱의 렌더링 및 통합이 CSS 선택기의 사용과 호환되지 않기 때문에 정상적인 동작입니다.

이전 섹션의 예제를 이용했고 CSS 선택기가 샘플 앱에서 작동하는지만 알고 싶다면, Client 프로젝트 Program.cs 파일의 App 루트 구성 요소의 사양을 주석으로 처리하세요.

- builder.RootComponents.Add<App>("#app");
+ //builder.RootComponents.Add<App>("#app");

CSS 선택기를 사용하는, 포함된 Razor 구성 요소(예: 이전 예제의 /razorpagescounter2)를 이용해 페이지나 보기로 이동합니다. 포함된 구성 요소와 함께 페이지나 보기가 로드되고, 포함된 구성 요소가 예상대로 작동합니다.

Razor Pages 및 MVC 앱에 Razor 구성 요소를 통합할 수 있습니다. 페이지나 뷰를 렌더링할 때 구성 요소를 동시에 미리 렌더링할 수 있습니다.

미리 렌더링은 검색 엔진이 페이지 순위를 계산하는 데 사용할 수 있는 초기 HTTP 응답에 대한 콘텐츠를 렌더링하여 SEO(검색 엔진 최적화)를 향상시킬 수 있습니다.

프로젝트를 구성한 후 프로젝트 요구 사항에 따라 다음 섹션의 지침을 따릅니다.

구성

다음 지침을 사용하여 Razor 구성 요소를 기존 Razor Pages 또는 MVC 앱의 페이지 및 보기에 통합합니다.

Important

페이지의 제목(PageTitle 구성 요소) 및 기타 헤드 요소(HeadContent 구성 요소)와 같은 <head> 콘텐츠를 제어하려면 HeadOutlet 구성 요소에 대해 구성 요소 태그 도우미와 함께 레이아웃 페이지(_Layout.cshtml)를 사용해야 합니다. 자세한 내용은 ASP.NET Core Blazor 앱의 헤드 콘텐츠 제어를 참조하세요.

  1. 프로젝트의 레이아웃 파일에서 다음을 수행합니다.

    • Pages/Shared/_Layout.cshtml(Razor Pages) 또는 Views/Shared/_Layout.cshtml(MVC)의 <head> 요소에 다음 <base> 태그 및 HeadOutlet 구성 요소 태그 도우미를 추가합니다.

      <base href="~/" />
      <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
      

      위의 예제에서 href 값(‘앱 기본 경로’)은 앱이 루트 URL 경로(/)에 있는 것으로 가정합니다. 앱이 하위 애플리케이션인 경우, ASP.NET Core Blazor 호스트 및 배포 문서의 앱 기본 경로 섹션에 설명된 지침을 따르세요.

      HeadOutlet 구성 요소는 Razor 구성 요소에서 설정한 페이지 제목(PageTitle 구성 요소) 및 기타 헤드 요소(HeadContent 구성 요소)에 대한 헤드(<head>) 콘텐츠를 렌더링하는 데 사용됩니다. 자세한 내용은 ASP.NET Core Blazor 앱의 헤드 콘텐츠 제어를 참조하세요.

    • 앱의 레이아웃에 있는 Scripts 렌더링 섹션(@await RenderSectionAsync(...)) 바로 앞에 blazor.server.js 스크립트의 <script> 태그를 추가합니다.

      Pages/Shared/_Layout.cshtml(Razor 페이지) 또는 Views/Shared/_Layout.cshtml(MVC):

      <script src="_framework/blazor.server.js"></script>
      

      프레임워크는 앱에 blazor.server.js 스크립트를 추가합니다. 앱에 blazor.server.js 스크립트 파일을 수동으로 추가할 필요는 없습니다.

  2. 다음 콘텐츠를 사용하여 프로젝트 루트 폴더에 가져오기 파일을 추가합니다. {APP NAMESPACE} 자리 표시자를 프로젝트의 네임스페이스로 변경합니다.

    _Imports.razor:

    @using System.Net.Http
    @using Microsoft.AspNetCore.Authorization
    @using Microsoft.AspNetCore.Components.Authorization
    @using Microsoft.AspNetCore.Components.Forms
    @using Microsoft.AspNetCore.Components.Routing
    @using Microsoft.AspNetCore.Components.Web
    @using Microsoft.AspNetCore.Components.Web.Virtualization
    @using Microsoft.JSInterop
    @using {APP NAMESPACE}
    
  3. 서비스가 등록된 Program.cs에 Blazor Server 서비스를 등록합니다.

    builder.Services.AddServerSideBlazor();
    
  4. Blazor 허브 엔드포인트를 경로가 매핑되는 Program.cs의 엔드포인트에 추가합니다.

    MapRazorPages(Razor Pages) 또는 MapControllerRoute(MVC)에 대한 호출 뒤에 다음 라인을 배치합니다.

    app.MapBlazorHub();
    
  5. 페이지 또는 뷰에 구성 요소를 통합합니다. 예를 들어 프로젝트의 Shared 폴더에 Counter구성 요소를 추가합니다.

    Pages/Shared/Counter.razor(Razor 페이지) 또는 Views/Shared/Counter.razor(MVC):

    <h1>Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    

    Razor 페이지:

    Razor 페이지 앱의 프로젝트 Index 페이지에서 Counter 구성 요소의 네임스페이스를 추가하고 이 구성 요소를 페이지에 포함합니다. Index 페이지가 로드되면 Counter 구성 요소가 페이지에 미리 렌더링됩니다. 다음 예제에서는 {APP NAMESPACE} 자리 표시자를 프로젝트의 네임스페이스로 바꿉니다.

    Pages/Index.cshtml:

    @page
    @using {APP NAMESPACE}.Pages.Shared
    @model IndexModel
    @{
        ViewData["Title"] = "Home page";
    }
    
    <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    

    MVC:

    MVC 앱의 프로젝트 Index뷰에서 Counter 구성 요소 네임스페이스를 추가하고 해당 구성 요소를 뷰에 포함합니다. Index 뷰가 로드되면 Counter 구성 요소가 페이지에서 미리 렌더링됩니다. 다음 예제에서는 {APP NAMESPACE} 자리 표시자를 프로젝트의 네임스페이스로 바꿉니다.

    Views/Home/Index.cshtml:

    @using {APP NAMESPACE}.Views.Shared
    @{
        ViewData["Title"] = "Home Page";
    }
    
    <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    

자세한 내용은 페이지 또는 뷰에서 구성 요소 렌더링 섹션을 참조하세요.

Razor Pages 앱에서 라우팅 가능한 구성 요소 사용

‘이 섹션에서는 사용자 요청에서 직접 라우팅할 수 있는 구성 요소를 추가하는 방법을 설명합니다.’

Razor Pages 앱에서 라우팅 가능한 Razor 구성 요소를 지원하려면 다음을 수행합니다.

  1. 구성 섹션의 지침을 따릅니다.

  2. 다음 콘텐츠를 사용하여 프로젝트 루트에 App 구성 요소를 추가합니다.

    App.razor:

    @using Microsoft.AspNetCore.Components.Routing
    
    <Router AppAssembly="typeof(App).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" />
        </Found>
        <NotFound>
            <PageTitle>Not found</PageTitle>
            <p role="alert">Sorry, there's nothing at this address.</p>
        </NotFound>
    </Router>
    
  3. 다음 콘텐츠로 _Host 페이지를 프로젝트에 추가합니다.

    Pages/_Host.cshtml:

    @page "/blazor"
    @namespace {APP NAMESPACE}.Pages.Shared
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    @{
        Layout = "_Layout";
    }
    
    <component type="typeof(App)" render-mode="ServerPrerendered" />
    

    이 시나리오에서 구성 요소는 해당 레이아웃에 공유 _Layout.cshtml 파일을 사용합니다.

    Important

    페이지의 제목(PageTitle 구성 요소) 및 기타 헤드 요소(HeadContent 구성 요소)와 같은 <head> 콘텐츠를 제어하려면 HeadOutlet 구성 요소에 대해 구성 요소 태그 도우미와 함께 레이아웃 페이지(_Layout.cshtml)를 사용해야 합니다. 자세한 내용은 ASP.NET Core Blazor 앱의 헤드 콘텐츠 제어를 참조하세요.

    RenderModeApp 구성 요소에 대해 다음을 구성합니다.

    • 페이지에 미리 렌더링할지 여부
    • 페이지에 정적 HTML로 렌더링할지 여부 또는 사용자 에이전트에서 Blazor 앱을 부트스트랩하는 데 필요한 정보를 포함할지 여부

    매개 변수 전달과 RenderMode 구성을 포함하여 구성 요소 태그 도우미에 대한 자세한 내용은 ASP.NET Core의 구성 요소 태그 도우미를 참조하세요.

  4. Program.cs 엔드포인트에서 _Host 페이지의 우선 순위가 낮은 경로를 마지막 엔드포인트로 추가합니다.

    app.MapFallbackToPage("/_Host");
    
  5. 라우팅 가능한 구성 요소를 프로젝트에 추가합니다. 다음 예제는 Blazor 프로젝트 템플릿의 Counter 구성 요소를 기반으로 하는 RoutableCounter 구성 요소입니다.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <PageTitle>Routable Counter</PageTitle>
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  6. 프로젝트를 실행하고 /routable-counter에서 라우팅할 수 있는 RoutableCounter 구성 요소로 이동합니다.

네임스페이스에 대한 자세한 내용은 구성 요소 네임스페이스 섹션을 참조하세요.

MVC 앱에서 라우팅 가능한 구성 요소 사용

‘이 섹션에서는 사용자 요청에서 직접 라우팅할 수 있는 구성 요소를 추가하는 방법을 설명합니다.’

MVC 앱에서 라우팅 가능한 Razor 구성 요소를 지원하려면 다음을 수행합니다.

  1. 구성 섹션의 지침을 따릅니다.

  2. 다음 콘텐츠를 사용하여 프로젝트 루트에 App 구성 요소를 추가합니다.

    App.razor:

    @using Microsoft.AspNetCore.Components.Routing
    
    <Router AppAssembly="typeof(App).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" />
        </Found>
        <NotFound>
            <PageTitle>Not found</PageTitle>
            <p role="alert">Sorry, there's nothing at this address.</p>
        </NotFound>
    </Router>
    
  3. 다음 콘텐츠를 사용하여 _Host 뷰를 프로젝트에 추가합니다.

    Views/Home/_Host.cshtml:

    @namespace {APP NAMESPACE}.Views.Shared
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    @{
        Layout = "_Layout";
    }
    
    <component type="typeof(App)" render-mode="ServerPrerendered" />
    

    구성 요소는 해당 레이아웃에 공유 _Layout.cshtml 파일을 사용합니다.

    Important

    페이지의 제목(PageTitle 구성 요소) 및 기타 헤드 요소(HeadContent 구성 요소)와 같은 <head> 콘텐츠를 제어하려면 HeadOutlet 구성 요소에 대해 구성 요소 태그 도우미와 함께 레이아웃 페이지(_Layout.cshtml)를 사용해야 합니다. 자세한 내용은 ASP.NET Core Blazor 앱의 헤드 콘텐츠 제어를 참조하세요.

    RenderModeApp 구성 요소에 대해 다음을 구성합니다.

    • 페이지에 미리 렌더링할지 여부
    • 페이지에 정적 HTML로 렌더링할지 여부 또는 사용자 에이전트에서 Blazor 앱을 부트스트랩하는 데 필요한 정보를 포함할지 여부

    매개 변수 전달과 RenderMode 구성을 포함하여 구성 요소 태그 도우미에 대한 자세한 내용은 ASP.NET Core의 구성 요소 태그 도우미를 참조하세요.

  4. Home 컨트롤러에 작업을 추가합니다.

    Controllers/HomeController.cs:

    public IActionResult Blazor()
    {
       return View("_Host");
    }
    
  5. Program.cs 엔드포인트에 _Host 보기를 반환하는 컨트롤러 작업에 우선 순위가 낮은 경로를 추가합니다.

    app.MapFallbackToController("Blazor", "Home");
    
  6. MVC 앱에 Pages 폴더를 만들고 라우팅 가능한 구성 요소를 추가합니다. 다음 예제는 Blazor 프로젝트 템플릿의 Counter 구성 요소를 기반으로 하는 RoutableCounter 구성 요소입니다.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <PageTitle>Routable Counter</PageTitle>
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  7. 프로젝트를 실행하고 /routable-counter에서 라우팅할 수 있는 RoutableCounter 구성 요소로 이동합니다.

네임스페이스에 대한 자세한 내용은 구성 요소 네임스페이스 섹션을 참조하세요.

페이지 또는 뷰에서 구성 요소 렌더링

‘이 섹션에서는 사용자 요청에서 직접 구성 요소를 라우팅할 수 없는 페이지 또는 뷰에 구성 요소를 추가하는 방법을 설명합니다.’

페이지 또는 뷰에서 구성 요소를 렌더링하려면 구성 요소 태그 도우미를 사용합니다.

상태 저장 대화형 구성 요소 렌더링

Razor 페이지 또는 뷰에 상태 저장 대화형 구성 요소를 추가할 수 있습니다.

페이지 또는 뷰를 렌더링하는 경우와 관련해서 다음 사항을 확인합니다.

  • 구성 요소가 페이지 또는 뷰와 함께 미리 렌더링됩니다.
  • 미리 렌더링하는 데 사용된 초기 구성 요소 상태가 손실됩니다.
  • SignalR 연결이 완료되면 새 구성 요소 상태가 생성됩니다.

다음 Razor 페이지는 Counter 구성 요소를 렌더링합니다.

<h1>Razor Page</h1>

<component type="typeof(Counter)" render-mode="ServerPrerendered" 
    param-InitialValue="InitialValue" />

@functions {
    [BindProperty(SupportsGet=true)]
    public int InitialValue { get; set; }
}

자세한 내용은 ASP.NET Core 구성 요소 태그 도우미를 참조하세요.

Important

페이지의 제목(PageTitle 구성 요소) 및 기타 헤드 요소(HeadContent 구성 요소)와 같은 <head> 콘텐츠를 제어하려면 HeadOutlet 구성 요소에 대해 구성 요소 태그 도우미와 함께 레이아웃 페이지(_Layout.cshtml)를 사용해야 합니다. 자세한 내용은 ASP.NET Core Blazor 앱의 헤드 콘텐츠 제어를 참조하세요.

비대화형 구성 요소 렌더링

다음 Razor 페이지에서 Counter 구성 요소는 폼을 통해 지정된 초기 값을 사용하여 정적으로 렌더링됩니다. 구성 요소가 정적으로 렌더링되므로 구성 요소는 대화형이 아닙니다.

<h1>Razor Page</h1>

<form>
    <input type="number" asp-for="InitialValue" />
    <button type="submit">Set initial value</button>
</form>

<component type="typeof(Counter)" render-mode="Static" 
    param-InitialValue="InitialValue" />

@functions {
    [BindProperty(SupportsGet=true)]
    public int InitialValue { get; set; }
}

자세한 내용은 ASP.NET Core 구성 요소 태그 도우미를 참조하세요.

Important

페이지의 제목(PageTitle 구성 요소) 및 기타 헤드 요소(HeadContent 구성 요소)와 같은 <head> 콘텐츠를 제어하려면 HeadOutlet 구성 요소에 대해 구성 요소 태그 도우미와 함께 레이아웃 페이지(_Layout.cshtml)를 사용해야 합니다. 자세한 내용은 ASP.NET Core Blazor 앱의 헤드 콘텐츠 제어를 참조하세요.

구성 요소 네임스페이스

사용자 지정 폴더를 사용하여 프로젝트의 Razor 구성 요소를 저장하는 경우, 폴더를 나타내는 네임스페이스를 페이지/뷰 또는 _ViewImports.cshtml 파일에 추가합니다. 다음 예제에서

  • 구성 요소는 프로젝트의 Components 폴더에 저장됩니다.
  • {APP NAMESPACE} 자리 표시자는 프로젝트의 네임스페이스입니다. Components은 폴더의 이름을 나타냅니다.
@using {APP NAMESPACE}.Components

_ViewImports.cshtml 파일은 Razor Pages 앱의 Pages 폴더 또는 MVC 앱의 Views 폴더에 있습니다.

자세한 내용은 ASP.NET Core Razor 구성 요소를 참조하세요.

미리 렌더링된 상태 유지

미리 렌더링된 상태를 유지하지 않으면 미리 렌더링하는 동안 사용된 상태를 잃게 되며 앱이 완전히 로드되면 다시 만들어야 합니다. 상태가 비동기적으로 설정된 경우 미리 렌더링된 UI가 임시 자리 표시자로 대체된 다음, 완전히 다시 렌더링되면 UI가 깜박일 수 있습니다.

이러한 문제를 해결하기 위해 Blazor는 구성 요소 상태 유지 태그 도우미를 사용하여 미리 렌더링된 페이지에서 상태 유지를 지원합니다. 닫는 </body> 태그 안에 태그 도우미 태그인 <persist-component-state />를 추가합니다.

Pages/_Layout.cshtml:

<body>
    ...

    <persist-component-state />
</body>

PersistentComponentState 서비스를 사용하여 유지할 상태를 결정합니다. PersistentComponentState.RegisterOnPersisting은 앱이 일시 중지되기 전에 구성 요소 상태를 유지하도록 콜백을 등록합니다. 애플리케이션이 다시 시작될 때 상태가 검색됩니다.

다음 예제는 Blazor 프로젝트 템플릿을 기준으로 하는 호스트된 Blazor WebAssembly 앱에서 FetchData 구성 요소의 업데이트된 버전입니다. WeatherForecastPreserveState 구성 요소는 미리 렌더링하는 동안 날씨 예측 상태를 유지한 다음, 상태를 검색하여 구성 요소를 초기화합니다. 구성 요소 상태 유지 태그 도우미는 모든 구성 요소 호출 후 구성 요소 상태를 유지합니다.

Pages/WeatherForecastPreserveState.razor:

@page "/weather-forecast-preserve-state"
@implements IDisposable
@using BlazorSample.Shared
@inject IWeatherForecastService WeatherForecastService
@inject PersistentComponentState ApplicationState

<PageTitle>Weather Forecast</PageTitle>

<h1>Weather forecast</h1>

<p>This component demonstrates fetching data from the server.</p>

@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var forecast in forecasts)
            {
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private WeatherForecast[] forecasts = Array.Empty<WeatherForecast>();
    private PersistingComponentStateSubscription persistingSubscription;

    protected override async Task OnInitializedAsync()
    {
        persistingSubscription = 
            ApplicationState.RegisterOnPersisting(PersistForecasts);

        if (!ApplicationState.TryTakeFromJson<WeatherForecast[]>(
            "fetchdata", out var restored))
        {
            forecasts = 
                await WeatherForecastService.GetForecastAsync(DateTime.Now);
        }
        else
        {
            forecasts = restored!;
        }
    }

    private Task PersistForecasts()
    {
        ApplicationState.PersistAsJson("fetchdata", forecasts);

        return Task.CompletedTask;
    }

    void IDisposable.Dispose()
    {
        persistingSubscription.Dispose();
    }
}

미리 렌더링하는 동안 사용된 것과 동일한 상태로 구성 요소를 초기화하면 비용이 많이 드는 초기화 단계가 한 번만 실행됩니다. 렌더링된 UI도 미리 렌더링된 UI와 일치하므로 브라우저에서 깜박임이 발생하지 않습니다.

추가 Blazor WebAssembly 리소스

미리 렌더링된 상태 크기 및 SignalR 메시지 크기 제한

미리 렌더링된 큰 상태 크기가 SignalR 회로 메시지 크기 제한을 초과할 수 있으므로 다음이 발생합니다.

  • Circuit host not initialized. 클라이언트에서 오류가 발생하여 SignalR 회로를 초기화하지 못합니다.
  • 회로가 실패하면 클라이언트의 다시 연결 대화 상자가 나타납니다. 복구는 불가능합니다.

문제를 해결하려면 다음 방법 중 하나를 사용합니다.

  • 미리 렌더링된 상태로 전환할 데이터의 양을 줄입니다.
  • SignalR 메시지 크기 제한을 늘입니다. 경고: 제한을 늘리면 DoS(서비스 거부) 공격의 위험이 증가할 수 있습니다.

추가 Blazor Server 리소스

Razor 구성 요소는 Razor Pages 및 호스트된 Blazor WebAssembly솔루션의 MVC 앱에 통합할 수 있습니다. 페이지나 뷰를 렌더링할 때 구성 요소를 동시에 미리 렌더링할 수 있습니다.

미리 렌더링은 검색 엔진이 페이지 순위를 계산하는 데 사용할 수 있는 초기 HTTP 응답에 대한 콘텐츠를 렌더링하여 SEO(검색 엔진 최적화)를 향상시킬 수 있습니다.

솔루션 구성

미리 렌더링 구성

호스트된 Blazor WebAssembly 앱의 미리 렌더링을 설정하려면 다음을 수행합니다.

  1. ASP.NET Core 앱에서 Blazor WebAssembly 앱을 호스트합니다. 독립 실행형 Blazor WebAssembly 앱을 ASP.NET Core 솔루션에 추가하거나 호스트된 옵션으로 Blazor WebAssembly 프로젝트 템플릿에서 만든 호스트된 Blazor WebAssembly 앱을 사용할 수 있습니다.

    • Visual Studio: 추가 정보 대화 상자에서 Blazor WebAssembly 앱을 만들 때 ASP.NET Core 호스팅 확인란을 선택합니다. 이 문서의 예제에서는 솔루션의 이름을 BlazorHosted로 지정합니다.
    • Visual Studio Code/.NET CLI 명령 셸: dotnet new blazorwasm -ho(-ho|--hosted 옵션 사용) -o|--output {LOCATION} 옵션을 사용하여 솔루션에 대한 폴더를 만들고 솔루션의 프로젝트 네임스페이스를 설정합니다. 이 문서의 예제에서는 솔루션 이름이 BlazorHosted(dotnet new blazorwasm -ho -o BlazorHosted)입니다.

    이 문서의 예제에서는 클라이언트 프로젝트의 네임스페이스가 BlazorHosted.Client이고 서버 프로젝트의 네임스페이스는 BlazorHosted.Server입니다.

  2. 프로젝트에서 파일을 삭제합니다Blazor WebAssemblyClient.wwwroot/index.html

  3. Client 프로젝트에서 Program.cs의 다음 라인을 삭제합니다.

    - builder.RootComponents.Add<App>("#app");
    
  4. Pages/_Host.cshtml 파일을 Server 프로젝트의 Pages 폴더에 추가합니다. 명령 셸에서 dotnet new blazorserver -o BlazorServer 명령을 사용하여 Blazor Server 템플릿에서 만든 프로젝트에서 _Host.cshtml 파일을 가져올 수 있습니다(-o BlazorServer 옵션은 프로젝트 폴더를 만듦). Pages/_Host.cshtml 파일을 호스트된 Blazor WebAssembly 솔루션의 Server 프로젝트에 배치한 후 파일을 다음과 같이 변경합니다.

    • Client 프로젝트의 @using 지시문을 설정합니다(예: @using BlazorHosted.Client).

    • WebAssembly의 스타일시트를 가리키도록 스타일시트 링크를 업데이트합니다. 다음 예제에서 클라이언트 프로젝트의 네임스페이스는 BlazorHosted.Client입니다.

      - <link href="css/site.css" rel="stylesheet" />
      - <link href="_content/BlazorServer/_framework/scoped.styles.css" rel="stylesheet" />
      + <link href="css/app.css" rel="stylesheet" />
      + <link href="BlazorHosted.Client.styles.css" rel="stylesheet" />
      

      참고 항목

      부트스트랩 스타일시트를 요청하는 <link> 요소(css/bootstrap/bootstrap.min.css)를 그대로 둡니다.

    • 루트 App 구성 요소를 WebAssemblyPrerendered로 미리 렌더링하도록 구성 요소 태그 도우미render-mode를 업데이트합니다.

      - <component type="typeof(App)" render-mode="ServerPrerendered" />
      + <component type="typeof(App)" render-mode="WebAssemblyPrerendered" />
      
    • 클라이언트 쪽 Blazor WebAssembly 스크립트를 사용하도록 Blazor 스크립트 원본을 업데이트합니다.

      - <script src="_framework/blazor.server.js"></script>
      + <script src="_framework/blazor.webassembly.js"></script>
      
  5. Server 프로젝트의 Startup.Configure에서, index.html 파일의 대체(Fallback)을 _Host.cshtml으로 변경합니다.

    Startup.cs:

    - endpoints.MapFallbackToFile("index.html");
    + endpoints.MapFallbackToPage("/_Host");
    
  6. Client 프로젝트와 Server 프로젝트가 미리 렌더링하는 동안 하나 이상의 공통 서비스를 사용하는 경우 서비스 등록을 두 프로젝트 모두에서 호출할 수 있는 메서드로 팩터링합니다. 자세한 내용은 ASP.NET Core Blazor 종속성 주입을 참조하세요.

  7. Server 프로젝트를 실행합니다. 호스트된 Blazor WebAssembly 앱은 클라이언트에 대한 Server 프로젝트에 의해 미리 렌더링됩니다.

Razor 구성 요소를 페이지 및 뷰에 포함하는 구성

서버 앱의 페이지 및 뷰에 클라이언트 Blazor WebAssembly 앱 Razor 구성 요소를 포함하는 이 문서의 다음 섹션과 예제는 추가 구성이 필요합니다.

Server 프로젝트에서 Razor 기본 페이지 또는 MVC 레이아웃 파일을 사용합니다. Server 프로젝트에는 다음 파일 및 폴더가 있어야 합니다.

Razor 페이지:

  • Pages/Shared/_Layout.cshtml
  • Pages/_ViewImports.cshtml
  • Pages/_ViewStart.cshtml

MVC:

  • Views/Shared/_Layout.cshtml
  • Views/_ViewImports.cshtml
  • Views/_ViewStart.cshtml

Razor 페이지 또는 MVC 프로젝트 템플릿에서 만든 앱에서 위의 파일을 가져옵니다. 자세한 내용은 자습서: ASP.NET Core에서 Razor Pages 시작 또는 ASP.NET Core MVC 시작을 참조하세요.

가져온 _ViewImports.cshtml 파일의 네임스페이스를 파일을 받는 Server 프로젝트에서 사용하는 것과 일치 하도록 업데이트합니다.

가져온 레이아웃 파일(_Layout.cshtml)을 업데이트하여 Client 프로젝트의 스타일을 포함합니다. 다음 예제에서 Client 프로젝트의 네임스페이스는 BlazorHosted.Client입니다. <title> 요소는 동시에 업데이트할 수 있습니다.

Pages/Shared/_Layout.cshtml(Razor 페이지) 또는 Views/Shared/_Layout.cshtml(MVC):

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-   <title>@ViewData["Title"] - DonorProject</title>
+   <title>@ViewData["Title"] - BlazorHosted</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" />
+   <link href="css/app.css" rel="stylesheet" />
+   <link href="BlazorHosted.Client.styles.css" rel="stylesheet" />
</head>

가져온 레이아웃에는 HomePrivacy 탐색 링크가 포함됩니다. 호스트된 Blazor WebAssembly 앱에 대한 Home 링크 지점을 만들려면 하이퍼링크를 변경합니다.

- <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>

MVC 레이아웃 파일에서 다음을 수행합니다.

- <a class="nav-link text-dark" asp-area="" asp-controller="Home" 
-     asp-action="Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>

Privacy 링크를 개인 정보 페이지로 만들려면 Server 프로젝트에 개인 정보 페이지를 추가합니다.

Server 프로젝트의 Pages/Privacy.cshtml:

@page
@model BlazorHosted.Server.Pages.PrivacyModel
@{
}

<h1>Privacy Policy</h1>

MVC 기반 개인 정보 보기를 선호하는 경우 Server 프로젝트에서 개인 정보 보기를 만듭니다.

View/Home/Privacy.cshtml:

@{
    ViewData["Title"] = "Privacy Policy";
}

<h1>@ViewData["Title"]</h1>

Home 컨트롤러에서 뷰를 반환합니다.

Controllers/HomeController.cs:

public IActionResult Privacy()
{
    return View();
}

Server 프로젝트의 wwwroot 폴더에서 기부자 프로젝트에 대한 정적 자산 가져오기:

  • wwwroot/css 폴더 및 콘텐츠
  • wwwroot/js 폴더 및 콘텐츠
  • wwwroot/lib 폴더 및 콘텐츠

기부자 프로젝트가 ASP.NET Core 프로젝트 템플릿에서 만들어지고 파일이 수정되지 않으면 기부자 프로젝트의 전체 wwwroot 폴더를 Server 프로젝트로 복사하여 favicon 아이콘 파일을 제거할 수 있습니다.

Warning

정적 자산을 Client 폴더와 Serverwwwroot 폴더 모두에 배치하지 마세요. 두 폴더 모두에 동일한 파일이 존재하면 예외가 throw됩니다. 각 폴더에 있는 정적 자산이 동일한 웹 루트 경로를 공유하기 때문입니다. 따라서 wwwroot 폴더 중 하나에 정적 자산을 호스트합니다.

구성 요소 태그 도우미를 사용하여 페이지 또는 보기에서 구성 요소를 렌더링

추가 구성을 포함하여 솔루션을 구성한 후 구성 요소 태그 도우미는 페이지 또는 보기의 Blazor WebAssembly 앱에서 구성 요소를 렌더링하기 위한 두 가지 렌더링 모드를 지원합니다.

다음 Razor Pages 예제에서는 Counter 구성 요소가 페이지에서 렌더링됩니다. 구성 요소를 대화형으로 만들기 위해 Blazor WebAssembly 스크립트가 페이지의 렌더링 섹션에 포함됩니다. 구성 요소 태그 도우미Counter 구성 요소의 전체 네임스페이스를 사용하지 않으려면({ASSEMBLY NAME}.Pages.Counter) 클라이언트 프로젝트의 Pages 네임스페이스에 대한 @using 지시문을 추가합니다. 다음 예제에서 Client 프로젝트의 네임스페이스는 BlazorHosted.Client입니다.

Server 프로젝트에서 Pages/RazorPagesCounter1.cshtml:

@page
@using BlazorHosted.Client.Pages

<component type="typeof(Counter)" render-mode="WebAssemblyPrerendered" />

@section Scripts {
    <script src="_framework/blazor.webassembly.js"></script>
}

Server 프로젝트를 실행합니다. /razorpagescounter1의 Razor 페이지로 이동합니다. 미리 렌더링된 Counter 구성 요소가 페이지에 포함되어 있습니다.

RenderMode는 구성 요소에 대해 다음을 구성합니다.

  • 페이지에 미리 렌더링할지 여부
  • 페이지에 정적 HTML로 렌더링할지 여부 또는 사용자 에이전트에서 Blazor 앱을 부트스트랩하는 데 필요한 정보를 포함할지 여부

매개 변수 전달과 RenderMode 구성을 포함하여 구성 요소 태그 도우미에 대한 자세한 내용은 ASP.NET Core의 구성 요소 태그 도우미를 참조하세요.

구성 요소에서 사용하는 정적 리소스와 앱에서 레이아웃 페이지를 구성하는 방법에 따라 추가 작업이 필요할 수 있습니다. 일반적으로 스크립트는 페이지 또는 뷰의 Scripts 렌더링 섹션에 추가되고 스타일시트는 레이아웃의 <head> 요소 콘텐츠에 추가됩니다.

CSS 선택기를 사용하여 페이지 또는 보기에서 구성 요소 렌더링

추가 구성을 포함하여 솔루션을 구성한 후 Program.cs에서 호스팅된 Blazor WebAssembly 솔루션의 Client 프로젝트에 루트 구성 요소를 추가합니다. 다음 예제에서 Counter 구성 요소는 counter-component와 일치하는 id가 있는 요소를 선택하는 CSS 선택기를 사용하여 루트 구성 요소로 선언됩니다. 다음 예제에서 Client 프로젝트의 네임스페이스는 BlazorHosted.Client입니다.

Client프로젝트의 Program.cs에서 프로젝트의 Razor 구성 요소에 대한 네임스페이스를 파일의 맨 위에 추가합니다.

using BlazorHosted.Client.Pages;

Program.cs에서 builder이 설정된 후에는 Counter 구성 요소를 루트 구성 요소로 추가합니다.

builder.RootComponents.Add<Counter>("#counter-component");

다음 Razor Pages 예제에서는 Counter 구성 요소가 페이지에서 렌더링됩니다. 구성 요소를 대화형으로 만들기 위해 Blazor WebAssembly 스크립트가 페이지의 렌더링 섹션에 포함됩니다.

Server 프로젝트에서 Pages/RazorPagesCounter2.cshtml:

@page

<div id="counter-component">Loading...</div>

@section Scripts {
    <script src="_framework/blazor.webassembly.js"></script>
}

Server 프로젝트를 실행합니다. /razorpagescounter2의 Razor 페이지로 이동합니다. 미리 렌더링된 Counter 구성 요소가 페이지에 포함되어 있습니다.

구성 요소에서 사용하는 정적 리소스와 앱에서 레이아웃 페이지를 구성하는 방법에 따라 추가 작업이 필요할 수 있습니다. 일반적으로 스크립트는 페이지 또는 뷰의 Scripts 렌더링 섹션에 추가되고 스타일시트는 레이아웃의 <head> 요소 콘텐츠에 추가됩니다.

참고 항목

이전 예제에서는 Blazor WebAssembly 앱이 미리 렌더링되고 Razor 페이지 또는 MVC 앱에 CSS 선택기를 사용하여 동시에 통합된 경우에는 JSException을 throw합니다. Client프로젝트의 Razor 구성 요소 중 하나로 이동하면 다음과 같은 예외가 throw됩니다.

Microsoft.JSInterop.JSException: 선택기 ‘#counter-component’와 일치하는 요소를 찾을 수 없습니다.

이는 라우팅 가능한 Razor구성 요소와 Blazor WebAssembly 앱의 렌더링 및 통합이 CSS 선택기의 사용과 호환되지 않기 때문에 정상적인 동작입니다.

Razor Pages 및 MVC 앱에 Razor 구성 요소를 통합할 수 있습니다. 페이지나 뷰를 렌더링할 때 구성 요소를 동시에 미리 렌더링할 수 있습니다.

미리 렌더링은 검색 엔진이 페이지 순위를 계산하는 데 사용할 수 있는 초기 HTTP 응답에 대한 콘텐츠를 렌더링하여 SEO(검색 엔진 최적화)를 향상시킬 수 있습니다.

프로젝트를 구성한 후 프로젝트 요구 사항에 따라 다음 섹션의 지침을 따릅니다.

구성

기존 Razor Pages 또는 MVC 앱은 페이지와 뷰에 Razor 구성 요소를 통합할 수 있습니다.

  1. 프로젝트의 레이아웃 파일에서 다음을 수행합니다.

    • Pages/Shared/_Layout.cshtml(Razor 페이지) 또는 Views/Shared/_Layout.cshtml(MVC)의 <head>요소에 다음 <base>태그를 추가합니다.

      <base href="~/" />
      

      위의 예제에서 href 값(‘앱 기본 경로’)은 앱이 루트 URL 경로(/)에 있는 것으로 가정합니다. 앱이 하위 애플리케이션인 경우, ASP.NET Core Blazor 호스트 및 배포 문서의 앱 기본 경로 섹션에 설명된 지침을 따르세요.

    • Scripts 렌더링 섹션 바로 앞에 blazor.server.js 스크립트의 <script> 태그를 추가합니다.

      Pages/Shared/_Layout.cshtml(Razor 페이지) 또는 Views/Shared/_Layout.cshtml(MVC):

          ...
          <script src="_framework/blazor.server.js"></script>
      
          @await RenderSectionAsync("Scripts", required: false)
      </body>
      

      프레임워크는 앱에 blazor.server.js 스크립트를 추가합니다. 앱에 blazor.server.js 스크립트 파일을 수동으로 추가할 필요는 없습니다.

  2. 다음 콘텐츠를 사용하여 프로젝트 루트 폴더에 가져오기 파일을 추가합니다. {APP NAMESPACE} 자리 표시자를 프로젝트의 네임스페이스로 변경합니다.

    _Imports.razor:

    @using System.Net.Http
    @using Microsoft.AspNetCore.Authorization
    @using Microsoft.AspNetCore.Components.Authorization
    @using Microsoft.AspNetCore.Components.Forms
    @using Microsoft.AspNetCore.Components.Routing
    @using Microsoft.AspNetCore.Components.Web
    @using Microsoft.JSInterop
    @using {APP NAMESPACE}
    
  3. Startup.ConfigureServices에 Blazor Server 서비스를 등록합니다.

    Startup.cs의 경우

    services.AddServerSideBlazor();
    
  4. Startup.Configure의 엔드포인트(app.UseEndpoints)에 Blazor 허브 엔드포인트를 추가합니다.

    Startup.cs:

    endpoints.MapBlazorHub();
    
  5. 페이지 또는 뷰에 구성 요소를 통합합니다. 예를 들어 프로젝트의 Shared 폴더에 Counter구성 요소를 추가합니다.

    Pages/Shared/Counter.razor(Razor 페이지) 또는 Views/Shared/Counter.razor(MVC):

    <h1>Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    

    Razor 페이지:

    Razor 페이지 앱의 프로젝트 Index 페이지에서 Counter 구성 요소의 네임스페이스를 추가하고 이 구성 요소를 페이지에 포함합니다. Index 페이지가 로드되면 Counter 구성 요소가 페이지에 미리 렌더링됩니다. 다음 예제에서는 {APP NAMESPACE} 자리 표시자를 프로젝트의 네임스페이스로 바꿉니다.

    Pages/Index.cshtml:

    @page
    @using {APP NAMESPACE}.Pages.Shared
    @model IndexModel
    @{
        ViewData["Title"] = "Home page";
    }
    
    <div>
        <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    </div>
    

    앞의 예제에서 {APP NAMESPACE} 자리 표시자를 앱의 네임스페이스로 바꿉니다.

    MVC:

    MVC 앱의 프로젝트 Index뷰에서 Counter 구성 요소 네임스페이스를 추가하고 해당 구성 요소를 뷰에 포함합니다. Index 뷰가 로드되면 Counter 구성 요소가 페이지에서 미리 렌더링됩니다. 다음 예제에서는 {APP NAMESPACE} 자리 표시자를 프로젝트의 네임스페이스로 바꿉니다.

    Views/Home/Index.cshtml:

    @using {APP NAMESPACE}.Views.Shared
    @{
        ViewData["Title"] = "Home Page";
    }
    
    <div>
        <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    </div>
    

자세한 내용은 페이지 또는 뷰에서 구성 요소 렌더링 섹션을 참조하세요.

Razor Pages 앱에서 라우팅 가능한 구성 요소 사용

‘이 섹션에서는 사용자 요청에서 직접 라우팅할 수 있는 구성 요소를 추가하는 방법을 설명합니다.’

Razor Pages 앱에서 라우팅 가능한 Razor 구성 요소를 지원하려면 다음을 수행합니다.

  1. 구성 섹션의 지침을 따릅니다.

  2. 다음 콘텐츠를 사용하여 프로젝트 루트에 App 구성 요소를 추가합니다.

    App.razor:

    @using Microsoft.AspNetCore.Components.Routing
    
    <Router AppAssembly="typeof(Program).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" />
        </Found>
        <NotFound>
            <h1>Page not found</h1>
            <p>Sorry, but there's nothing here!</p>
        </NotFound>
    </Router>
    

    참고 항목

    ASP.NET Core 5.0.1 릴리스 및 추가 5.x 릴리스부터 Router 구성 요소에는 @true로 설정된 PreferExactMatches 매개 변수가 포함됩니다. 자세한 내용은 ASP.NET Core 3.1에서 5.0으로 마이그레이션을 참조하세요.

  3. 다음 콘텐츠로 _Host 페이지를 프로젝트에 추가합니다.

    Pages/_Host.cshtml:

    @page "/blazor"
    @{
        Layout = "_Layout";
    }
    
    <app>
        <component type="typeof(App)" render-mode="ServerPrerendered" />
    </app>
    

    구성 요소는 해당 레이아웃에 공유 _Layout.cshtml 파일을 사용합니다.

    RenderModeApp 구성 요소에 대해 다음을 구성합니다.

    • 페이지에 미리 렌더링할지 여부
    • 페이지에 정적 HTML로 렌더링할지 여부 또는 사용자 에이전트에서 Blazor 앱을 부트스트랩하는 데 필요한 정보를 포함할지 여부

    매개 변수 전달과 RenderMode 구성을 포함하여 구성 요소 태그 도우미에 대한 자세한 내용은 ASP.NET Core의 구성 요소 태그 도우미를 참조하세요.

  4. Startup.csStartup.Configure 엔드포인트에서 _Host 페이지의 우선 순위가 낮은 경로를 마지막 엔드포인트로 추가합니다.

    endpoints.MapFallbackToPage("/_Host");
    

    다음 예제에서는 일반적인 앱의 엔드포인트 구성에 추가된 줄을 보여줍니다.

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToPage("/_Host");
    });
    
  5. 라우팅 가능한 구성 요소를 프로젝트에 추가합니다.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  6. 프로젝트를 실행하고 /routable-counter에서 라우팅할 수 있는 RoutableCounter 구성 요소로 이동합니다.

네임스페이스에 대한 자세한 내용은 구성 요소 네임스페이스 섹션을 참조하세요.

MVC 앱에서 라우팅 가능한 구성 요소 사용

‘이 섹션에서는 사용자 요청에서 직접 라우팅할 수 있는 구성 요소를 추가하는 방법을 설명합니다.’

MVC 앱에서 라우팅 가능한 Razor 구성 요소를 지원하려면 다음을 수행합니다.

  1. 구성 섹션의 지침을 따릅니다.

  2. 다음 콘텐츠를 사용하여 프로젝트 루트에 App 구성 요소를 추가합니다.

    App.razor:

    @using Microsoft.AspNetCore.Components.Routing
    
    <Router AppAssembly="typeof(Program).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" />
        </Found>
        <NotFound>
            <h1>Page not found</h1>
            <p>Sorry, but there's nothing here!</p>
        </NotFound>
    </Router>
    

    참고 항목

    ASP.NET Core 5.0.1 릴리스 및 추가 5.x 릴리스부터 Router 구성 요소에는 @true로 설정된 PreferExactMatches 매개 변수가 포함됩니다. 자세한 내용은 ASP.NET Core 3.1에서 5.0으로 마이그레이션을 참조하세요.

  3. 다음 콘텐츠를 사용하여 _Host 뷰를 프로젝트에 추가합니다.

    Views/Home/_Host.cshtml:

    @{
        Layout = "_Layout";
    }
    
    <app>
        <component type="typeof(App)" render-mode="ServerPrerendered" />
    </app>
    

    구성 요소는 해당 레이아웃에 공유 _Layout.cshtml 파일을 사용합니다.

    RenderModeApp 구성 요소에 대해 다음을 구성합니다.

    • 페이지에 미리 렌더링할지 여부
    • 페이지에 정적 HTML로 렌더링할지 여부 또는 사용자 에이전트에서 Blazor 앱을 부트스트랩하는 데 필요한 정보를 포함할지 여부

    매개 변수 전달과 RenderMode 구성을 포함하여 구성 요소 태그 도우미에 대한 자세한 내용은 ASP.NET Core의 구성 요소 태그 도우미를 참조하세요.

  4. Home 컨트롤러에 작업을 추가합니다.

    Controllers/HomeController.cs:

    public IActionResult Blazor()
    {
       return View("_Host");
    }
    
  5. Startup.csStartup.Configure 엔드포인트 구성에 _Host 뷰를 반환하는 컨트롤러 작업의 우선순위가 낮은 경로를 추가합니다.

    endpoints.MapFallbackToController("Blazor", "Home");
    

    다음 예제에서는 일반적인 앱의 엔드포인트 구성에 추가된 줄을 보여줍니다.

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToController("Blazor", "Home");
    });
    
  6. 라우팅 가능한 구성 요소를 프로젝트에 추가합니다.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  7. 프로젝트를 실행하고 /routable-counter에서 라우팅할 수 있는 RoutableCounter 구성 요소로 이동합니다.

네임스페이스에 대한 자세한 내용은 구성 요소 네임스페이스 섹션을 참조하세요.

페이지 또는 뷰에서 구성 요소 렌더링

‘이 섹션에서는 사용자 요청에서 직접 구성 요소를 라우팅할 수 없는 페이지 또는 뷰에 구성 요소를 추가하는 방법을 설명합니다.’

페이지 또는 뷰에서 구성 요소를 렌더링하려면 구성 요소 태그 도우미를 사용합니다.

상태 저장 대화형 구성 요소 렌더링

Razor 페이지 또는 뷰에 상태 저장 대화형 구성 요소를 추가할 수 있습니다.

페이지 또는 뷰를 렌더링하는 경우와 관련해서 다음 사항을 확인합니다.

  • 구성 요소가 페이지 또는 뷰와 함께 미리 렌더링됩니다.
  • 미리 렌더링하는 데 사용된 초기 구성 요소 상태가 손실됩니다.
  • SignalR 연결이 완료되면 새 구성 요소 상태가 생성됩니다.

다음 Razor 페이지는 Counter 구성 요소를 렌더링합니다.

<h1>My Razor Page</h1>

<component type="typeof(Counter)" render-mode="ServerPrerendered" 
    param-InitialValue="InitialValue" />

@functions {
    [BindProperty(SupportsGet=true)]
    public int InitialValue { get; set; }
}

자세한 내용은 ASP.NET Core 구성 요소 태그 도우미를 참조하세요.

비대화형 구성 요소 렌더링

다음 Razor 페이지에서 Counter 구성 요소는 폼을 통해 지정된 초기 값을 사용하여 정적으로 렌더링됩니다. 구성 요소가 정적으로 렌더링되므로 구성 요소는 대화형이 아닙니다.

<h1>My Razor Page</h1>

<form>
    <input type="number" asp-for="InitialValue" />
    <button type="submit">Set initial value</button>
</form>

<component type="typeof(Counter)" render-mode="Static" 
    param-InitialValue="InitialValue" />

@functions {
    [BindProperty(SupportsGet=true)]
    public int InitialValue { get; set; }
}

자세한 내용은 ASP.NET Core 구성 요소 태그 도우미를 참조하세요.

구성 요소 네임스페이스

사용자 지정 폴더를 사용하여 프로젝트의 Razor 구성 요소를 저장하는 경우, 폴더를 나타내는 네임스페이스를 페이지/뷰 또는 _ViewImports.cshtml 파일에 추가합니다. 다음 예제에서

  • 구성 요소는 프로젝트의 Components 폴더에 저장됩니다.
  • {APP NAMESPACE} 자리 표시자는 프로젝트의 네임스페이스입니다. Components은 폴더의 이름을 나타냅니다.
@using {APP NAMESPACE}.Components

_ViewImports.cshtml 파일은 Razor Pages 앱의 Pages 폴더 또는 MVC 앱의 Views 폴더에 있습니다.

자세한 내용은 ASP.NET Core Razor 구성 요소를 참조하세요.

추가 Blazor WebAssembly 리소스

미리 렌더링된 상태 크기 및 SignalR 메시지 크기 제한

미리 렌더링된 큰 상태 크기가 SignalR 회로 메시지 크기 제한을 초과할 수 있으므로 다음이 발생합니다.

  • Circuit host not initialized. 클라이언트에서 오류가 발생하여 SignalR 회로를 초기화하지 못합니다.
  • 회로가 실패하면 클라이언트의 다시 연결 대화 상자가 나타납니다. 복구는 불가능합니다.

문제를 해결하려면 다음 방법 중 하나를 사용합니다.

  • 미리 렌더링된 상태로 전환할 데이터의 양을 줄입니다.
  • SignalR 메시지 크기 제한을 늘입니다. 경고: 제한을 늘리면 DoS(서비스 거부) 공격의 위험이 증가할 수 있습니다.

추가 Blazor Server 리소스

호스트된 Blazor WebAssembly솔루션에서 Razor 구성 요소를 Razor Pages 및 MVC 앱에 통합하는 기능은 .NET 5 이상의 ASP.NET Core에서 지원됩니다. 이 문서의 .NET 5 이상 버전을 선택하세요.

Razor Pages 및 MVC 앱에 Razor 구성 요소를 통합할 수 있습니다. 페이지나 뷰를 렌더링할 때 구성 요소를 동시에 미리 렌더링할 수 있습니다.

미리 렌더링은 검색 엔진이 페이지 순위를 계산하는 데 사용할 수 있는 초기 HTTP 응답에 대한 콘텐츠를 렌더링하여 SEO(검색 엔진 최적화)를 향상시킬 수 있습니다.

프로젝트를 구성한 후 프로젝트 요구 사항에 따라 다음 섹션의 지침을 따릅니다.

구성

기존 Razor Pages 또는 MVC 앱은 페이지와 뷰에 Razor 구성 요소를 통합할 수 있습니다.

  1. 프로젝트의 레이아웃 파일에서 다음을 수행합니다.

    • Pages/Shared/_Layout.cshtml(Razor 페이지) 또는 Views/Shared/_Layout.cshtml(MVC)의 <head>요소에 다음 <base>태그를 추가합니다.

      + <base href="~/" />
      

      위의 예제에서 href 값(‘앱 기본 경로’)은 앱이 루트 URL 경로(/)에 있는 것으로 가정합니다. 앱이 하위 애플리케이션인 경우, ASP.NET Core Blazor 호스트 및 배포 문서의 앱 기본 경로 섹션에 설명된 지침을 따르세요.

    • Scripts 렌더링 섹션 바로 앞에 blazor.server.js 스크립트의 <script> 태그를 추가합니다.

      Pages/Shared/_Layout.cshtml(Razor 페이지) 또는 Views/Shared/_Layout.cshtml(MVC):

          ...
          <script src="_framework/blazor.server.js"></script>
      
          @await RenderSectionAsync("Scripts", required: false)
      </body>
      

      프레임워크는 앱에 blazor.server.js 스크립트를 추가합니다. 앱에 blazor.server.js 스크립트 파일을 수동으로 추가할 필요는 없습니다.

  2. 다음 콘텐츠를 사용하여 프로젝트 루트 폴더에 가져오기 파일을 추가합니다. {APP NAMESPACE} 자리 표시자를 프로젝트의 네임스페이스로 변경합니다.

    _Imports.razor:

    @using System.Net.Http
    @using Microsoft.AspNetCore.Authorization
    @using Microsoft.AspNetCore.Components.Authorization
    @using Microsoft.AspNetCore.Components.Forms
    @using Microsoft.AspNetCore.Components.Routing
    @using Microsoft.AspNetCore.Components.Web
    @using Microsoft.JSInterop
    @using {APP NAMESPACE}
    
  3. Startup.ConfigureServices에 Blazor Server 서비스를 등록합니다.

    Startup.cs:

    services.AddServerSideBlazor();
    
  4. Startup.Configure의 엔드포인트(app.UseEndpoints)에 Blazor 허브 엔드포인트를 추가합니다.

    Startup.cs:

    endpoints.MapBlazorHub();
    
  5. 페이지 또는 뷰에 구성 요소를 통합합니다. 예를 들어 프로젝트의 Shared 폴더에 Counter구성 요소를 추가합니다.

    Pages/Shared/Counter.razor(Razor 페이지) 또는 Views/Shared/Counter.razor(MVC):

    <h1>Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    

    Razor 페이지:

    Razor 페이지 앱의 프로젝트 Index 페이지에서 Counter 구성 요소의 네임스페이스를 추가하고 이 구성 요소를 페이지에 포함합니다. Index 페이지가 로드되면 Counter 구성 요소가 페이지에 미리 렌더링됩니다. 다음 예제에서는 {APP NAMESPACE} 자리 표시자를 프로젝트의 네임스페이스로 바꿉니다.

    Pages/Index.cshtml:

    @page
    @using {APP NAMESPACE}.Pages.Shared
    @model IndexModel
    @{
        ViewData["Title"] = "Home page";
    }
    
    <div>
        <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    </div>
    

    앞의 예제에서 {APP NAMESPACE} 자리 표시자를 앱의 네임스페이스로 바꿉니다.

    MVC:

    MVC 앱의 프로젝트 Index뷰에서 Counter 구성 요소 네임스페이스를 추가하고 해당 구성 요소를 뷰에 포함합니다. Index 뷰가 로드되면 Counter 구성 요소가 페이지에서 미리 렌더링됩니다. 다음 예제에서는 {APP NAMESPACE} 자리 표시자를 프로젝트의 네임스페이스로 바꿉니다.

    Views/Home/Index.cshtml:

    @using {APP NAMESPACE}.Views.Shared
    @{
        ViewData["Title"] = "Home Page";
    }
    
    <div>
        <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    </div>
    

자세한 내용은 페이지 또는 뷰에서 구성 요소 렌더링 섹션을 참조하세요.

Razor Pages 앱에서 라우팅 가능한 구성 요소 사용

‘이 섹션에서는 사용자 요청에서 직접 라우팅할 수 있는 구성 요소를 추가하는 방법을 설명합니다.’

Razor Pages 앱에서 라우팅 가능한 Razor 구성 요소를 지원하려면 다음을 수행합니다.

  1. 구성 섹션의 지침을 따릅니다.

  2. 다음 콘텐츠를 사용하여 프로젝트 루트에 App 구성 요소를 추가합니다.

    App.razor:

    @using Microsoft.AspNetCore.Components.Routing
    
    <Router AppAssembly="typeof(Program).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" />
        </Found>
        <NotFound>
            <h1>Page not found</h1>
            <p>Sorry, but there's nothing here!</p>
        </NotFound>
    </Router>
    
  3. 다음 콘텐츠로 _Host 페이지를 프로젝트에 추가합니다.

    Pages/_Host.cshtml:

    @page "/blazor"
    @{
        Layout = "_Layout";
    }
    
    <app>
        <component type="typeof(App)" render-mode="ServerPrerendered" />
    </app>
    

    구성 요소는 해당 레이아웃에 공유 _Layout.cshtml 파일을 사용합니다.

    RenderModeApp 구성 요소에 대해 다음을 구성합니다.

    • 페이지에 미리 렌더링할지 여부
    • 페이지에 정적 HTML로 렌더링할지 여부 또는 사용자 에이전트에서 Blazor 앱을 부트스트랩하는 데 필요한 정보를 포함할지 여부

    매개 변수 전달과 RenderMode 구성을 포함하여 구성 요소 태그 도우미에 대한 자세한 내용은 ASP.NET Core의 구성 요소 태그 도우미를 참조하세요.

  4. Startup.csStartup.Configure 엔드포인트에서 _Host 페이지의 우선 순위가 낮은 경로를 마지막 엔드포인트로 추가합니다.

    endpoints.MapFallbackToPage("/_Host");
    

    다음 예제에서는 일반적인 앱의 엔드포인트 구성에 추가된 줄을 보여줍니다.

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToPage("/_Host");
    });
    
  5. 라우팅 가능한 구성 요소를 프로젝트에 추가합니다.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  6. 프로젝트를 실행하고 /routable-counter에서 라우팅할 수 있는 RoutableCounter 구성 요소로 이동합니다.

네임스페이스에 대한 자세한 내용은 구성 요소 네임스페이스 섹션을 참조하세요.

MVC 앱에서 라우팅 가능한 구성 요소 사용

‘이 섹션에서는 사용자 요청에서 직접 라우팅할 수 있는 구성 요소를 추가하는 방법을 설명합니다.’

MVC 앱에서 라우팅 가능한 Razor 구성 요소를 지원하려면 다음을 수행합니다.

  1. 구성 섹션의 지침을 따릅니다.

  2. 다음 콘텐츠를 사용하여 프로젝트 루트에 App 구성 요소를 추가합니다.

    App.razor:

    @using Microsoft.AspNetCore.Components.Routing
    
    <Router AppAssembly="typeof(Program).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" />
        </Found>
        <NotFound>
            <h1>Page not found</h1>
            <p>Sorry, but there's nothing here!</p>
        </NotFound>
    </Router>
    
  3. 다음 콘텐츠를 사용하여 _Host 뷰를 프로젝트에 추가합니다.

    Views/Home/_Host.cshtml:

    @{
        Layout = "_Layout";
    }
    
    <app>
        <component type="typeof(App)" render-mode="ServerPrerendered" />
    </app>
    

    구성 요소는 해당 레이아웃에 공유 _Layout.cshtml 파일을 사용합니다.

    RenderModeApp 구성 요소에 대해 다음을 구성합니다.

    • 페이지에 미리 렌더링할지 여부
    • 페이지에 정적 HTML로 렌더링할지 여부 또는 사용자 에이전트에서 Blazor 앱을 부트스트랩하는 데 필요한 정보를 포함할지 여부

    매개 변수 전달과 RenderMode 구성을 포함하여 구성 요소 태그 도우미에 대한 자세한 내용은 ASP.NET Core의 구성 요소 태그 도우미를 참조하세요.

  4. Home 컨트롤러에 작업을 추가합니다.

    Controllers/HomeController.cs:

    public IActionResult Blazor()
    {
       return View("_Host");
    }
    
  5. Startup.csStartup.Configure 엔드포인트 구성에 _Host 뷰를 반환하는 컨트롤러 작업의 우선순위가 낮은 경로를 추가합니다.

    endpoints.MapFallbackToController("Blazor", "Home");
    

    다음 예제에서는 일반적인 앱의 엔드포인트 구성에 추가된 줄을 보여줍니다.

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToController("Blazor", "Home");
    });
    
  6. 라우팅 가능한 구성 요소를 프로젝트에 추가합니다.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  7. 프로젝트를 실행하고 /routable-counter에서 라우팅할 수 있는 RoutableCounter 구성 요소로 이동합니다.

네임스페이스에 대한 자세한 내용은 구성 요소 네임스페이스 섹션을 참조하세요.

페이지 또는 뷰에서 구성 요소 렌더링

‘이 섹션에서는 사용자 요청에서 직접 구성 요소를 라우팅할 수 없는 페이지 또는 뷰에 구성 요소를 추가하는 방법을 설명합니다.’

페이지 또는 뷰에서 구성 요소를 렌더링하려면 구성 요소 태그 도우미를 사용합니다.

상태 저장 대화형 구성 요소 렌더링

Razor 페이지 또는 뷰에 상태 저장 대화형 구성 요소를 추가할 수 있습니다.

페이지 또는 뷰를 렌더링하는 경우와 관련해서 다음 사항을 확인합니다.

  • 구성 요소가 페이지 또는 뷰와 함께 미리 렌더링됩니다.
  • 미리 렌더링하는 데 사용된 초기 구성 요소 상태가 손실됩니다.
  • SignalR 연결이 완료되면 새 구성 요소 상태가 생성됩니다.

다음 Razor 페이지는 Counter 구성 요소를 렌더링합니다.

<h1>My Razor Page</h1>

<component type="typeof(Counter)" render-mode="ServerPrerendered" 
    param-InitialValue="InitialValue" />

@functions {
    [BindProperty(SupportsGet=true)]
    public int InitialValue { get; set; }
}

자세한 내용은 ASP.NET Core 구성 요소 태그 도우미를 참조하세요.

비대화형 구성 요소 렌더링

다음 Razor 페이지에서 Counter 구성 요소는 폼을 통해 지정된 초기 값을 사용하여 정적으로 렌더링됩니다. 구성 요소가 정적으로 렌더링되므로 구성 요소는 대화형이 아닙니다.

<h1>My Razor Page</h1>

<form>
    <input type="number" asp-for="InitialValue" />
    <button type="submit">Set initial value</button>
</form>

<component type="typeof(Counter)" render-mode="Static" 
    param-InitialValue="InitialValue" />

@functions {
    [BindProperty(SupportsGet=true)]
    public int InitialValue { get; set; }
}

자세한 내용은 ASP.NET Core 구성 요소 태그 도우미를 참조하세요.

구성 요소 네임스페이스

사용자 지정 폴더를 사용하여 프로젝트의 Razor 구성 요소를 저장하는 경우, 폴더를 나타내는 네임스페이스를 페이지/뷰 또는 _ViewImports.cshtml 파일에 추가합니다. 다음 예제에서

  • 구성 요소는 프로젝트의 Components 폴더에 저장됩니다.
  • {APP NAMESPACE} 자리 표시자는 프로젝트의 네임스페이스입니다. Components은 폴더의 이름을 나타냅니다.
@using {APP NAMESPACE}.Components

_ViewImports.cshtml 파일은 Razor Pages 앱의 Pages 폴더 또는 MVC 앱의 Views 폴더에 있습니다.

자세한 내용은 ASP.NET Core Razor 구성 요소를 참조하세요.

미리 렌더링된 상태 크기 및 SignalR 메시지 크기 제한

미리 렌더링된 큰 상태 크기가 SignalR 회로 메시지 크기 제한을 초과할 수 있으므로 다음이 발생합니다.

  • Circuit host not initialized. 클라이언트에서 오류가 발생하여 SignalR 회로를 초기화하지 못합니다.
  • 회로가 실패하면 클라이언트의 다시 연결 대화 상자가 나타납니다. 복구는 불가능합니다.

문제를 해결하려면 다음 방법 중 하나를 사용합니다.

  • 미리 렌더링된 상태로 전환할 데이터의 양을 줄입니다.
  • SignalR 메시지 크기 제한을 늘입니다. 경고: 제한을 늘리면 DoS(서비스 거부) 공격의 위험이 증가할 수 있습니다.

추가 Blazor Server 리소스