다음을 통해 공유


ASP.NET Core의 레이아웃

작성자: Steve SmithDave Brock

페이지와 보기는 시각적 요소와 프로그래밍 방식 요소를 자주 공유합니다. 이 문서에서는 다음을 수행하는 방법을 보여줍니다.

  • 일반적인 레이아웃을 사용합니다.
  • 지시문을 공유합니다.
  • 페이지 또는 뷰를 렌더링하기 전에 공통 코드를 실행합니다.

이 문서에서는 ASP.NET Core MVC의 두 가지 방법, 즉 Razor 보기를 사용하는 페이지와 컨트롤러에 대한 레이아웃을 논의합니다. 이 항목의 경우 차이점은 최소화됩니다.

  • Razor Pages 폴더에 페이지 가 있습니다.
  • 보기가 있는 컨트롤러는 보기에 대해 Views 폴더를 사용합니다.

레이아웃이란?

대부분의 웹앱에는 사용자가 페이지에서 페이지로 이동할 때 일관된 환경을 제공하는 일반적인 레이아웃이 있습니다. 레이아웃에는 일반적으로 앱 헤더, 탐색 또는 메뉴 요소, 바닥글과 같은 일반적인 사용자 인터페이스 요소가 포함됩니다.

페이지 레이아웃 예제

스크립트 및 스타일시트와 같은 일반적인 HTML 구조는 앱 내의 많은 페이지에서도 자주 사용됩니다. 이러한 공유 요소는 모두 레이아웃 파일에 정의될 수 있으며, 앱 내에서 사용되는 모든 보기에서 참조할 수 있습니다. 레이아웃은 보기에서 중복 코드를 줄입니다.

규칙에 따라 ASP.NET Core 앱의 기본 레이아웃 이름은 _Layout.cshtml지정됩니다. 템플릿을 사용하여 만든 새 ASP.NET Core 프로젝트의 레이아웃 파일은 다음과 같습니다.

  • Razor 페이지: Pages/Shared/_Layout.cshtml

    솔루션 탐색기의 Pages 폴더

  • 뷰가 있는 컨트롤러: Views/Shared/_Layout.cshtml

    솔루션 탐색기의 뷰 폴더

레이아웃은 앱의 보기에 대한 최상위 템플릿을 정의합니다. 앱에는 레이아웃이 필요하지 않습니다. 앱은 서로 다른 레이아웃을 지정하는 다른 보기를 사용하여 둘 이상의 레이아웃을 정의할 수 있습니다.

다음 코드는 컨트롤러 및 뷰를 사용하여 만든 템플릿 프로젝트에 대한 레이아웃 파일을 보여 냅니다.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - WebApplication1</title>

    <environment include="Development">
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
        <link rel="stylesheet" href="~/css/site.css" />
    </environment>
    <environment exclude="Development">
        <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
              asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
        <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
    </environment>
</head>
<body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a asp-page="/Index" class="navbar-brand">WebApplication1</a>
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li><a asp-page="/Index">Home</a></li>
                    <li><a asp-page="/About">About</a></li>
                    <li><a asp-page="/Contact">Contact</a></li>
                </ul>
            </div>
        </div>
    </nav>

    <partial name="_CookieConsentPartial" />

    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; 2018 - WebApplication1</p>
        </footer>
    </div>

    <environment include="Development">
        <script src="~/lib/jquery/dist/jquery.js"></script>
        <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
        <script src="~/js/site.js" asp-append-version="true"></script>
    </environment>
    <environment exclude="Development">
        <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.3.1.min.js"
                asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
                asp-fallback-test="window.jQuery"
                crossorigin="anonymous"
                integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT">
        </script>
        <script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js"
                asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
                asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
                crossorigin="anonymous"
                integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa">
        </script>
        <script src="~/js/site.min.js" asp-append-version="true"></script>
    </environment>

    @RenderSection("Scripts", required: false)
</body>
</html>

레이아웃 지정

Razor view에는 Layout 속성이 있습니다. 개별 보기는 이 속성을 설정하여 레이아웃을 지정합니다.

@{
    Layout = "_Layout";
}

지정된 레이아웃은 전체 경로(예: /Pages/Shared/_Layout.cshtml 또는) 또는 /Views/Shared/_Layout.cshtml부분 이름(예: _Layout)을 사용할 수 있습니다. 부분 이름이 제공되면 Razor 뷰 엔진은 표준 검색 프로세스를 사용하여 레이아웃 파일을 검색합니다. 처리기 메서드(또는 컨트롤러)가 있는 폴더를 먼저 검색한 다음 공유 폴더를 검색합니다. 이 검색 프로세스는 부분 보기를 검색하는 데 사용되는 프로세스와 동일합니다.

기본적으로 모든 레이아웃은 RenderBody을 호출해야 합니다. RenderBody를 호출할 때마다 뷰의 콘텐츠가 렌더링될 것입니다.

Sections

레이아웃은 필요에 따라 하나 이상의 섹션을 호출 RenderSection하여 참조할 수 있습니다. 섹션은 특정 페이지 요소를 배치할 위치를 구성하는 방법을 제공합니다. 각 호출은 RenderSection 해당 섹션이 필요한지 선택 사항인지를 지정할 수 있습니다.

<script type="text/javascript" src="~/scripts/global.js"></script>

@RenderSection("Scripts", required: false)

필요한 섹션을 찾을 수 없으면 예외가 throw됩니다. 개별 뷰는 구문을 사용하여 @sectionRazor 섹션 내에서 렌더링할 콘텐츠를 지정합니다. 페이지 또는 뷰가 섹션을 정의하는 경우 렌더링해야 합니다(또는 오류가 발생).

Razor 페이지 보기에서의 @section 정의 예:

@section Scripts {
     <script type="text/javascript" src="~/scripts/main.js"></script>
}

코드의 앞 부분에서 scripts/main.js가 페이지 또는 보기의 scripts 섹션에 추가됩니다. 동일한 앱의 다른 페이지 또는 보기에는 이 스크립트가 필요하지 않을 수 있으며 스크립트 섹션을 정의하지 않을 수 있습니다.

다음 마크업은 Partial Tag Helper를 사용하여 _ValidationScriptsPartial.cshtml를 렌더링합니다.

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

이전 태그는 스캐폴딩을 통해 Identity생성되었습니다.

페이지 또는 보기에 정의된 섹션은 바로 레이아웃 페이지에서만 사용할 수 있습니다. 이들을 부분, 뷰 구성 요소 또는 뷰 시스템의 다른 부분에서 참조할 수 없습니다.

섹션을 무시하기

기본적으로 콘텐츠 페이지의 본문과 모든 섹션은 모두 레이아웃 페이지에서 렌더링되어야 합니다. 뷰 엔진은 Razor 본문과 각 섹션이 렌더링되었는지 여부를 추적하여 이를 적용합니다.

뷰 엔진에 본문 또는 섹션을 무시하도록 지시하려면 IgnoreBody 메서드와 IgnoreSection 메서드를 호출합니다.

본문과 페이지의 모든 섹션 Razor 은 렌더링되거나 무시되어야 합니다.

공유 지시문 가져오기

뷰와 페이지는 지시문을 사용하여 Razor 네임스페이스를 가져오고 종속성 주입을 사용할 수 있습니다. 많은 뷰에서 공유되는 지시문은 공통 _ViewImports.cshtml 파일에 지정할 수 있습니다. 파일은 _ViewImports 다음 지시문을 지원합니다.

  • @addTagHelper
  • @removeTagHelper
  • @tagHelperPrefix
  • @using
  • @model
  • @inherits
  • @inject
  • @namespace

파일은 함수 및 섹션 정의와 같은 다른 Razor 기능을 지원하지 않습니다.

샘플 _ViewImports.cshtml 파일:

@using WebApplication1
@using WebApplication1.Models
@using WebApplication1.Models.AccountViewModels
@using WebApplication1.Models.ManageViewModels
@using Microsoft.AspNetCore.Identity
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

_ViewImports.cshtml ASP.NET Core MVC 앱의 파일은 일반적으로 Pages(또는 Views) 폴더에 배치됩니다. 파일은 _ViewImports.cshtml 모든 폴더 내에 배치할 수 있으며, 이 경우 해당 폴더 및 하위 폴더 내의 페이지 또는 뷰에만 적용됩니다. _ViewImports 파일은 루트 수준에서 시작한 다음 페이지 또는 보기 자체의 위치로 이어지는 각 폴더에 대해 처리됩니다. _ViewImports 루트 수준에서 지정된 설정은 폴더 수준에서 재정의될 수 있습니다.

예를 들어 다음을 가정해 보겠습니다.

  • 루트 수준 _ViewImports.cshtml 파일에는 @model MyModel1@addTagHelper *, MyTagHelper1가 포함되어 있습니다.
  • 하위 폴더 _ViewImports.cshtml 파일에는 @model MyModel2@addTagHelper *, MyTagHelper2가 포함되어 있습니다.

하위 폴더의 페이지와 뷰는 태그 도우미와 모델 MyModel2 모두에 액세스할 수 있습니다.

파일 계층 구조에 여러 _ViewImports.cshtml 파일이 있는 경우 지시문의 결합된 동작은 다음과 같습니다.

  • @addTagHelper, @removeTagHelper: 모든 실행 순서대로
  • @tagHelperPrefix: 뷰에 가장 가까운 항목이 다른 항목보다 우선합니다.
  • @model: 뷰에 가장 가까운 항목이 다른 항목보다 우선합니다.
  • @inherits: 뷰에 가장 가까운 항목이 다른 항목보다 우선합니다.
  • @using: 모두 포함됩니다. 중복 항목은 무시됩니다.
  • @inject: 각 속성에 대해 보기에 가장 가까운 속성이 동일한 속성 이름을 가진 다른 모든 속성을 재정의합니다.

각 보기 전에 코드 실행

각 뷰 또는 페이지 전에 실행해야 하는 코드는 _ViewStart.cshtml 파일에 배치해야 합니다. 파일은 통상적으로 Pages (또는 Views) 폴더에 위치합니다. 나열된 _ViewStart.cshtml 문은 레이아웃과 부분 보기를 제외한 모든 전체 보기 전에 실행됩니다. ViewImports.cshtml_ViewStart.cshtml과 마찬가지로 계층적입니다. _ViewStart.cshtml 보기 또는 페이지 폴더에 정의된 파일은 Pages(또는 Views) 폴더(있는 경우)의 루트에 정의된 파일 이후에 실행됩니다.

샘플 _ViewStart.cshtml 파일:

@{
    Layout = "_Layout";
}

위의 파일은 모든 보기에서 레이아웃을 _Layout.cshtml 사용하도록 지정합니다.

_ViewStart.cshtml_ViewImports.cshtml일반적으로/Pages/Shared(또는 /Views/Shared) 폴더에 배치되지 않습니다. 이러한 파일의 앱 수준 버전은 /Pages (또는 /Views) 폴더에 직접 배치해야 합니다.