ASP.NET Core의 레이아웃Layout in ASP.NET Core

작성자: Steve SmithBy Steve Smith

뷰는 시각적 개체 및 프로그래밍 요소를 자주 공유합니다.Views frequently share visual and programmatic elements. 이 문서에서는 ASP.NET Core 앱에서 뷰를 렌더링하기 전에 일반적인 레이아웃을 사용하고, 지시문을 공유하며, 공용 코드를 실행하는 방법에 대해 알아봅니다.In this article, you'll learn how to use common layouts, share directives, and run common code before rendering views in your ASP.NET Core app.

레이아웃이란What is a Layout

대부분의 웹앱에는 사용자가 페이지를 탐색하는 동안 일관된 환경을 제공하는 일반적인 레이아웃이 있습니다.Most web apps have a common layout that provides the user with a consistent experience as they navigate from page to page. 일반적으로 레이아웃에는 앱 헤더, 탐색 또는 메뉴 요소, 바닥글과 같은 공통 사용자 인터페이스 요소가 포함됩니다.The layout typically includes common user interface elements such as the app header, navigation or menu elements, and footer.

페이지 레이아웃 예제

스크립트 및 스타일시트와 같은 공통 HTML 구조는 앱 내에서 여러 페이지에서도 자주 사용됩니다.Common HTML structures such as scripts and stylesheets are also frequently used by many pages within an app. 이러한 모든 공유 요소를 레이아웃 파일에 정의한 후 앱 내에 사용된 모든 뷰에서 참조할 수 있습니다.All of these shared elements may be defined in a layout file, which can then be referenced by any view used within the app. 레이아웃은 뷰에서 중복 코드를 줄여 DRY(반복 금지) 원칙을 따르도록 도와줍니다.Layouts reduce duplicate code in views, helping them follow the Don't Repeat Yourself (DRY) principle.

규칙에 따라, ASP.NET Core 앱의 기본 레이아웃 이름을 _Layout.cshtml로 지정합니다.By convention, the default layout for an ASP.NET Core app is named _Layout.cshtml. Visual Studio ASP.NET Core MVC 프로젝트 템플릿은 Views/Shared 폴더에 이 레이아웃 파일을 포함합니다.The Visual Studio ASP.NET Core MVC project template includes this layout file in the Views/Shared folder:

솔루션 탐색기의 뷰 폴더

이 레이아웃은 앱의 뷰에 대한 최상위 수준 템플릿을 정의합니다.This layout defines a top level template for views in the app. 앱에는 레이아웃이 필요하지 않으며, 앱은 다른 레이아웃을 지정하는 서로 다른 뷰를 포함하는 둘 이상의 레이아웃을 정의할 수 있습니다.Apps don't require a layout, and apps can define more than one layout, with different views specifying different layouts.

_Layout.cshtml 예:An example _Layout.cshtml:

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

    <environment names="Development">
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
        <link rel="stylesheet" href="~/css/site.css" />
    <environment names="Staging,Production">
        <link rel="stylesheet" href=""
              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" />
    <div 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>
                <a asp-area="" asp-controller="Home" asp-action="Index" class="navbar-brand">WebApplication1</a>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
                    <li><a asp-area="" asp-controller="Home" asp-action="About">About</a></li>
                    <li><a asp-area="" asp-controller="Home" asp-action="Contact">Contact</a></li>
                @await Html.PartialAsync("_LoginPartial")
    <div class="container body-content">
        <hr />
            <p>&copy; 2016 - WebApplication1</p>

    <environment names="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 names="Staging,Production">
        <script src=""
        <script src=""
                asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal">
        <script src="~/js/site.min.js" asp-append-version="true"></script>

    @RenderSection("scripts", required: false)

레이아웃 지정Specifying a Layout

Razor 뷰는 Layout 속성을 포함합니다.Razor views have a Layout property. 이 속성을 설정하여 레이아웃을 지정하는 개별 뷰:Individual views specify a layout by setting this property:

    Layout = "_Layout";

지정한 레이아웃은 전체 경로(예: /Views/Shared/_Layout.cshtml) 또는 부분 이름(예: _Layout)을 사용할 수 있습니다.The layout specified can use a full path (example: /Views/Shared/_Layout.cshtml) or a partial name (example: _Layout). 부분 이름이 제공되면 Razor 뷰 엔진이 표준 검색 프로세스를 사용하여 레이아웃 파일을 검색합니다.When a partial name is provided, the Razor view engine will search for the layout file using its standard discovery process. 컨트롤러 관련 폴더를 먼저 검색한 후 Shared 폴더를 검색합니다.The controller-associated folder is searched first, followed by the Shared folder. 이 검색 프로세스는 부분 뷰를 검색하는 데 사용된 것과 동일합니다.This discovery process is identical to the one used to discover partial views.

기본적으로 모든 레이아웃에서 RenderBody를 호출해야 합니다.By default, every layout must call RenderBody. RenderBody 호출이 배치될 때마다 뷰의 내용이 렌더링됩니다.Wherever the call to RenderBody is placed, the contents of the view will be rendered.


레이아웃은 RenderSection을 호출하여 필요에 따라 하나 이상의 섹션을 참조합니다.A layout can optionally reference one or more sections, by calling RenderSection. 섹션에서는 특정 페이지 요소를 배치할 위치를 구성하는 방법을 제공합니다.Sections provide a way to organize where certain page elements should be placed. RenderSection 호출 때마다 섹션이 필수 또는 옵션인지 여부를 지정할 수 있습니다.Each call to RenderSection can specify whether that section is required or optional. 필수 섹션이 없는 경우 예외가 throw됩니다.If a required section isn't found, an exception will be thrown. 개별 뷰는 @section Razor 구문을 사용하여 섹션 내에 렌더링될 콘텐츠를 지정합니다.Individual views specify the content to be rendered within a section using the @section Razor syntax. 뷰에서 섹션을 정의하는 경우 렌더링되어야 합니다(그렇지 않은 경우 오류 발생).If a view defines a section, it must be rendered (or an error will occur).

뷰에서 @section 정의 예:An example @section definition in a view:

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

위의 코드에서는 유효성 검사 스크립트가 양식을 포함하는 뷰의 scripts 섹션에 추가됩니다.In the code above, validation scripts are added to the scripts section on a view that includes a form. 동일한 응용 프로그램의 다른 뷰에는 추가 스크립트가 필요하지 않을 수 있으므로 스크립트 섹션을 정의할 필요가 없습니다.Other views in the same application might not require any additional scripts, and so wouldn't need to define a scripts section.

뷰에 정의된 섹션은 즉시 레이아웃 페이지에서만 사용할 수 있습니다.Sections defined in a view are available only in its immediate layout page. 이들은 부분 뷰, 뷰 구성 요소 또는 뷰 시스템의 다른 부분에서 참조할 수 없습니다.They cannot be referenced from partials, view components, or other parts of the view system.

섹션 무시Ignoring sections

기본적으로 콘텐츠 페이지 본문 및 모든 섹션은 레이아웃 페이지에서 모두 렌더링되어야 합니다.By default, the body and all sections in a content page must all be rendered by the layout page. Razor 뷰 엔진은 본문과 각 섹션이 렌더링되었는지 여부를 추적하여 이를 적용합니다.The Razor view engine enforces this by tracking whether the body and each section have been rendered.

뷰 엔진이 본문 또는 섹션을 무시하도록 지시하려면 IgnoreBodyIgnoreSection 메서드를 호출합니다.To instruct the view engine to ignore the body or sections, call the IgnoreBody and IgnoreSection methods.

Razor 페이지의 본문 및 모든 섹션은 렌더링되거나 무시되어야 합니다.The body and every section in a Razor page must be either rendered or ignored.

공유 지시문 가져오기Importing Shared Directives

뷰는 Razor 지시문을 사용하여 네임스페이스 가져오기 또는 종속성 주입 수행과 같은 많은 작업을 수행할 수 있습니다.Views can use Razor directives to do many things, such as importing namespaces or performing dependency injection. 많은 뷰에서 공유된 지시문은 공용 _ViewImports.cshtml 파일에 지정할 수 있습니다.Directives shared by many views may be specified in a common _ViewImports.cshtml file. _ViewImports 파일은 다음 지시문을 지원합니다.The _ViewImports file supports the following directives:

  • @addTagHelper

  • @removeTagHelper

  • @tagHelperPrefix

  • @using

  • @model

  • @inherits

  • @inject

이 파일은 다른 Razor 기능(예: 함수 및 섹션 정의)을 지원하지 않습니다.The file doesn't support other Razor features, such as functions and section definitions.

샘플 _ViewImports.cshtml 파일:A sample _ViewImports.cshtml file:

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

ASP.NET Core MVC 앱에 대한 _ViewImports.cshtml 파일은 일반적으로 Views 폴더에 배치됩니다.The _ViewImports.cshtml file for an ASP.NET Core MVC app is typically placed in the Views folder. _ViewImports.cshtml 파일은 모든 폴더 내에 배치할 수 있으며, 이 경우 해당 폴더 및 해당 하위 폴더 내의 뷰에만 적용됩니다.A _ViewImports.cshtml file can be placed within any folder, in which case it will only be applied to views within that folder and its subfolders. _ViewImports 파일은 루트 수준에서부터 처리된 다음, 각 폴더에 대해 뷰 자체의 위치까지 처리되므로 루트 수준에서 지정된 설정이 폴더 수준에서 재정의될 수 있습니다._ViewImports files are processed starting at the root level, and then for each folder leading up to the location of the view itself, so settings specified at the root level may be overridden at the folder level.

예를 들어 루트 수준 _ViewImports.cshtml 파일이 @model@addTagHelper를 지정하고, 뷰의 컨트롤러 관련 폴더에서 다른 _ViewImports.cshtml 파일이 다른 @model을 지정하며 다른 @addTagHelper를 추가하면, 뷰는 두 태그 도우미에 액세스할 수 있고 후자 @model을 사용합니다.For example, if a root level _ViewImports.cshtml file specifies @model and @addTagHelper, and another _ViewImports.cshtml file in the controller-associated folder of the view specifies a different @model and adds another @addTagHelper, the view will have access to both tag helpers and will use the latter @model.

뷰에 대해 여러 _ViewImports.cshtml 파일이 실행되는 경우 ViewImports.cshtml 파일에 포함된 지시문의 결합된 동작은 다음과 같습니다.If multiple _ViewImports.cshtml files are run for a view, combined behavior of the directives included in the ViewImports.cshtml files will be as follows:

  • @addTagHelper, @removeTagHelper: 순서대로 모두 실행@addTagHelper, @removeTagHelper: all run, in order

  • @tagHelperPrefix: 뷰에 가장 가까운 것이 다른 것보다 우선함@tagHelperPrefix: the closest one to the view overrides any others

  • @model: 뷰에 가장 가까운 것이 다른 것보다 우선함@model: the closest one to the view overrides any others

  • @inherits: 뷰에 가장 가까운 것이 다른 것보다 우선함@inherits: the closest one to the view overrides any others

  • @using: 모두 포함됨. 중복 항목은 무시됨@using: all are included; duplicates are ignored

  • @inject: 각 속성에 대해 뷰에 가장 가까운 것이 같은 속성 이름의 다른 것보다 우선함@inject: for each property, the closest one to the view overrides any others with the same property name

각 뷰 이전에 코드 실행Running Code Before Each View

모든 뷰 이전에 실행해야 하는 코드가 있는 경우 _ViewStart.cshtml 파일에 배치해야 합니다.If you have code you need to run before every view, this should be placed in the _ViewStart.cshtml file. 규칙에 따라 _ViewStart.cshtml 파일은 Views 폴더에 있습니다.By convention, the _ViewStart.cshtml file is located in the Views folder. _ViewStart.cshtml에 나열된 문은 모든 전체 뷰(레이아웃 및 부분 뷰가 아님) 이전에 실행됩니다.The statements listed in _ViewStart.cshtml are run before every full view (not layouts, and not partial views). ViewImports.cshtml처럼 _ViewStart.cshtml은 계층적입니다.Like ViewImports.cshtml, _ViewStart.cshtml is hierarchical. _ViewStart.cshtml 파일이 컨트롤러 관련 뷰 폴더에 정의된 경우 Views 폴더의 루트에 정의된 항목 뒤에 실행됩니다(있는 경우).If a _ViewStart.cshtml file is defined in the controller-associated view folder, it will be run after the one defined in the root of the Views folder (if any).

샘플 _ViewStart.cshtml 파일:A sample _ViewStart.cshtml file:

    Layout = "_Layout";

위의 파일은 모든 뷰가 _Layout.cshtml 레이아웃을 사용하도록 지정합니다.The file above specifies that all views will use the _Layout.cshtml layout.


일반적으로 _ViewStart.cshtml 또는 _ViewImports.cshtml/Views/Shared 폴더에 배치되지 않습니다.Neither _ViewStart.cshtml nor _ViewImports.cshtml are typically placed in the /Views/Shared folder. 이러한 파일의 앱 수준 버전은 /Views 폴더에 직접 배치해야 합니다.The app-level versions of these files should be placed directly in the /Views folder.