ASP.NET Core의 Razor 페이지 소개Introduction to Razor Pages in ASP.NET Core

작성자: Rick AndersonRyan NowakBy Rick Anderson and Ryan Nowak

Razor 페이지는 더 쉽고 더 생산적으로 코딩 페이지에 초점을 맞춘 시나리오를 만드는 ASP.NET Core MVC의 새로운 기능입니다.Razor Pages is a new aspect of ASP.NET Core MVC that makes coding page-focused scenarios easier and more productive.

모델-뷰-컨트롤러 방법을 사용하는 자습서를 검색할 경우 ASP.NET Core MVC 시작을 참조하세요.If you're looking for a tutorial that uses the Model-View-Controller approach, see Get started with ASP.NET Core MVC.

이 문서에서는 Razor 페이지를 소개합니다.This document provides an introduction to Razor Pages. 이 문서는 단계별 자습서가 아닙니다.It's not a step by step tutorial. 섹션이 너무 고급인 경우 Razor 페이지 시작을 참조하세요.If you find some of the sections too advanced, see Get started with Razor Pages. ASP.NET Core의 개요는 ASP.NET Core 소개를 참조하세요.For an overview of ASP.NET Core, see the Introduction to ASP.NET Core.

전제 조건Prerequisites

다음 중 하나를 수행합니다.Install one of the following:

Razor 페이지 프로젝트 만들기Creating a Razor Pages project

Visual Studio를 사용하여 Razor 페이지 프로젝트를 만드는 방법에 대한 자세한 내용은 Razor 페이지 시작을 참조하세요.See Get started with Razor Pages for detailed instructions on how to create a Razor Pages project using Visual Studio.

Razor 페이지Razor Pages

Razor 페이지는 Startup.cs에서 사용하도록 설정됩니다.Razor Pages is enabled in Startup.cs:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // Includes support for Razor Pages and controllers.
        services.AddMvc();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseMvc();
    }
}

기본 페이지를 고려해 봅니다. Consider a basic page:

@page

<h1>Hello, world!</h1>
<h2>The time on the server is @DateTime.Now</h2>

이전 코드는 Razor 뷰 파일과 매우 비슷합니다.The preceding code looks a lot like a Razor view file. 차이점은 @page 지시문입니다.What makes it different is the @page directive. @page는 파일을 MVC 작업으로 만듭니다. 즉, 컨트롤러를 거치지 않고 요청을 직접 처리합니다.@page makes the file into an MVC action - which means that it handles requests directly, without going through a controller. @page는 페이지의 첫 번째 Razor 지시문이어야 합니다.@page must be the first Razor directive on a page. @page는 다른 Razor 생성자의 동작에 영향을 미칩니다.@page affects the behavior of other Razor constructs.

PageModel 클래스를 사용하는 비슷한 페이지는 다음 두 파일에 표시됩니다.A similar page, using a PageModel class, is shown in the following two files. Pages/Index2.cshtml 파일:The Pages/Index2.cshtml file:

@page
@using RazorPagesIntro.Pages
@model IndexModel2

<h2>Separate page model</h2>
<p>
    @Model.Message
</p>

Pages/Index2.cshtml.cs 페이지 모델:The Pages/Index2.cshtml.cs page model:

using Microsoft.AspNetCore.Mvc.RazorPages;
using System;

namespace RazorPagesIntro.Pages
{
    public class IndexModel2 : PageModel
    {
        public string Message { get; private set; } = "PageModel in C#";

        public void OnGet()
        {
            Message += $" Server time is { DateTime.Now }";
        }
    }
}

일반적으로 PageModel 클래스 파일의 이름은 Razor 페이지 파일과 동일하고 .cs가 추가됩니다.By convention, the PageModel class file has the same name as the Razor Page file with .cs appended. 예를 들어 이전 Razor 페이지는 Pages/Index2.cshtml입니다.For example, the previous Razor Page is Pages/Index2.cshtml. PageModel 클래스가 포함된 파일의 이름은 Pages/Index2.cshtml.cs입니다.The file containing the PageModel class is named Pages/Index2.cshtml.cs.

페이지에 대한 URL 경로 연결은 파일 시스템의 페이지 위치에 따라 결정됩니다.The associations of URL paths to pages are determined by the page's location in the file system. 다음 표에서는 Razor 페이지 경로 및 일치하는 URL을 보여 줍니다.The following table shows a Razor Page path and the matching URL:

파일 이름 및 경로File name and path 일치하는 URLmatching URL
/Pages/Index.cshtml/Pages/Index.cshtml / 또는 /Index/ or /Index
/Pages/Contact.cshtml/Pages/Contact.cshtml /Contact
/Pages/Store/Contact.cshtml/Pages/Store/Contact.cshtml /Store/Contact
/Pages/Store/Index.cshtml/Pages/Store/Index.cshtml /Store 또는 /Store/Index/Store or /Store/Index

메모:Notes:

  • 런타임은 기본적으로 Pages 폴더에서 Razor 페이지 파일을 검색합니다.The runtime looks for Razor Pages files in the Pages folder by default.
  • URL에 페이지가 포함되어 있지 않을 경우 Index가 기본 페이지입니다.Index is the default page when a URL doesn't include a page.

기본 폼 작성Writing a basic form

Razor 페이지는 웹 브라우저에서 사용되는 일반 패턴을 쉽게 구현할 수 있도록 설계되었습니다.Razor Pages is designed to make common patterns used with web browsers easy to implement when building an app. 모델 바인딩, 태그 도우미 및 HTML 도우미는 모두 Razor 페이지 클래스에 정의된 속성에서 제대로 작동합니다.Model binding, Tag Helpers, and HTML helpers all just work with the properties defined in a Razor Page class. Contact 모델에 대한 기본 “연락처” 폼을 구현하는 페이지를 고려해 봅니다.Consider a page that implements a basic "contact us" form for the Contact model:

이 문서에 있는 샘플의 경우 DbContextStartup.cs 파일에서 초기화됩니다.For the samples in this document, the DbContext is initialized in the Startup.cs file.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using RazorPagesContacts.Data;

namespace RazorPagesContacts
{
    public class Startup
    {
        public IHostingEnvironment HostingEnvironment { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<AppDbContext>(options =>
                              options.UseInMemoryDatabase("name"));
            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app)
        {
            app.UseMvc();
        }
    }
}

데이터 모델:The data model:

using System.ComponentModel.DataAnnotations;

namespace RazorPagesContacts.Data
{
    public class Customer
    {
        public int Id { get; set; }

        [Required, StringLength(100)]
        public string Name { get; set; }
    }
}

db 컨텍스트:The db context:

using Microsoft.EntityFrameworkCore;

namespace RazorPagesContacts.Data
{
    public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions options)
            : base(options)
        {
        }

        public DbSet<Customer> Customers { get; set; }
    }
}

Pages/Create.cshtml 뷰 파일:The Pages/Create.cshtml view file:

@page
@model RazorPagesContacts.Pages.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" />
    </form>
</body>
</html>

Pages/Create.cshtml.cs 페이지 모델:The Pages/Create.cshtml.cs page model:

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesContacts.Data;

namespace RazorPagesContacts.Pages
{
    public class CreateModel : PageModel
    {
        private readonly AppDbContext _db;

        public CreateModel(AppDbContext db)
        {
            _db = db;
        }

        [BindProperty]
        public Customer Customer { get; set; }

        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            _db.Customers.Add(Customer);
            await _db.SaveChangesAsync();
            return RedirectToPage("/Index");
        }
    }
}

일반적으로 PageModel 클래스를 <PageName>Model이라고 하고 이 클래스는 페이지와 동일한 네임스페이스에 있습니다.By convention, the PageModel class is called <PageName>Model and is in the same namespace as the page.

PageModel 클래스를 사용하면 해당 프레젠테이션에서 페이지의 논리를 분리합니다.The PageModel class allows separation of the logic of a page from its presentation. 페이지에 전송된 요청 및 페이지를 렌더링하는 데 사용되는 데이터에 대한 페이지 처리기를 정의합니다.It defines page handlers for requests sent to the page and the data used to render the page. 이렇게 분리하면 종속성 주입을 통해 페이지 종속성을 관리할 수 있고 단위 테스트를 페이지로 관리할 수 있습니다.This separation allows you to manage page dependencies through dependency injection and to unit test the pages.

페이지에는 POST 요청에서 실행되는 OnPostAsync 처리기 메서드가 있습니다(사용자가 폼을 게시할 때).The page has an OnPostAsync handler method, which runs on POST requests (when a user posts the form). HTTP 동사에 대한 처리기 메서드를 추가할 수 있습니다.You can add handler methods for any HTTP verb. 가장 일반적인 처리기는 다음과 같습니다.The most common handlers are:

  • OnGet - 페이지에 필요한 상태를 초기화합니다.OnGet to initialize state needed for the page. OnGet 샘플.OnGet sample.
  • OnPost - 제출에서 처리합니다.OnPost to handle form submissions.

Async 명명 접미사는 선택 사항이지만 비동기 함수에 대한 규칙에서 종종 사용됩니다.The Async naming suffix is optional but is often used by convention for asynchronous functions. 이전 예제의 OnPostAsync 코드는 일반적으로 컨트롤러에서 작성되는 것과 비슷해 보입니다.The OnPostAsync code in the preceding example looks similar to what you would normally write in a controller. 이전 코드는 Razor 페이지에 일반적인 코드입니다.The preceding code is typical for Razor Pages. 모델 바인딩, 유효성 검사 및 작업 결과 같은 대부분의 MVC 기본 형식이 공유됩니다.Most of the MVC primitives like model binding, validation, and action results are shared.

이전 OnPostAsync 메서드:The previous OnPostAsync method:

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _db.Customers.Add(Customer);
    await _db.SaveChangesAsync();
    return RedirectToPage("/Index");
}

OnPostAsync의 기본 흐름:The basic flow of OnPostAsync:

유효성 검사 오류를 확인합니다.Check for validation errors.

  • 오류가 없는 경우 데이터를 저장하고 리디렉션됩니다.If there are no errors, save the data and redirect.
  • 오류가 있는 경우 유효성 검사 메시지가 포함된 페이지를 다시 표시합니다.If there are errors, show the page again with validation messages. 클라이언트 쪽 유효성 검사는 기존 ASP.NET Core MVC 응용 프로그램과 동일합니다.Client-side validation is identical to traditional ASP.NET Core MVC applications. 대부분의 경우 유효성 검사 오류는 클라이언트에서 검색되고 서버에는 제출되지 않습니다.In many cases, validation errors would be detected on the client, and never submitted to the server.

데이터를 성공적으로 입력하면 OnPostAsync 처리기 메서드는 RedirectToPage 도우미 메서드를 호출하여 RedirectToPageResult 인스턴스를 반환합니다.When the data is entered successfully, the OnPostAsync handler method calls the RedirectToPage helper method to return an instance of RedirectToPageResult. RedirectToPageRedirectToAction 또는 RedirectToRoute와 비슷하지만 페이지에 대해 사용자 지정된 새 작업 결과입니다.RedirectToPage is a new action result, similar to RedirectToAction or RedirectToRoute, but customized for pages. 이전 샘플에서 이 메서드는 루트 인덱스 페이지(/Index)로 리디렉션됩니다.In the preceding sample, it redirects to the root Index page (/Index). RedirectToPage페이지에 대한 URL 생성 섹션에서 자세히 설명합니다.RedirectToPage is detailed in the URL generation for Pages section.

서버에 전달되는 유효성 오류가 제출된 폼에 있는 경우 OnPostAsync 처리기 메서드는 Page 도우미 메서드를 호출합니다.When the submitted form has validation errors (that are passed to the server), theOnPostAsync handler method calls the Page helper method. PagePageResult 인스턴스를 반환합니다.Page returns an instance of PageResult. Page 반환은 컨트롤의 작업이 View를 반환하는 방식과 비슷합니다.Returning Page is similar to how actions in controllers return View. PageResult는 처리기 메서드의 기본 반환 형식입니다.PageResult is the default return type for a handler method. void를 반환하는 처리기 메서드는 페이지를 렌더링합니다.A handler method that returns void renders the page.

Customer 속성은 [BindProperty] 특성을 사용하여 모델 바인딩으로 옵트인(opt in)합니다.The Customer property uses [BindProperty] attribute to opt in to model binding.

public class CreateModel : PageModel
{
    private readonly AppDbContext _db;

    public CreateModel(AppDbContext db)
    {
        _db = db;
    }

    [BindProperty]
    public Customer Customer { get; set; }

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        _db.Customers.Add(Customer);
        await _db.SaveChangesAsync();
        return RedirectToPage("/Index");
    }
}

Razor 페이지는 기본적으로 GET이 아닌 동사에만 속성을 바인딩합니다.Razor Pages, by default, bind properties only with non-GET verbs. 속성에 바인딩하면 작성해야 하는 코드 양이 감소할 수 있습니다.Binding to properties can reduce the amount of code you have to write. 바인딩은 동일한 속성을 사용하여 폼 필드(<input asp-for="Customer.Name" />)를 렌더링하고 입력을 허용하는 방식으로 코드를 줄입니다.Binding reduces code by using the same property to render form fields (<input asp-for="Customer.Name" />) and accept the input.

참고

보안상의 이유로 페이지 모델 속성에 GET 요청 데이터를 바인딩하기 위해 옵트인해야 합니다.For security reasons, you must opt in to binding GET request data to page model properties. 속성에 매핑하기 전에 사용자 입력을 확인합니다.Verify user input before mapping it to properties. 쿼리 문자열이나 경로 값을 사용하는 시나리오를 해결할 때 이 동작을 옵트인하면 유용합니다.Opting in to this behavior is useful when addressing scenarios which rely on query string or route values.

GET 요청에 속성을 바인딩하려면 [BindProperty] 특성의 SupportsGet 속성을 true로 설정합니다. [BindProperty(SupportsGet = true)]To bind a property on GET requests, set the [BindProperty] attribute's SupportsGet property to true: [BindProperty(SupportsGet = true)]

홈페이지(Index.cshtml):The home page (Index.cshtml):

@page
@model RazorPagesContacts.Pages.IndexModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<h1>Contacts</h1>
<form method="post">
    <table class="table">
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var contact in Model.Customers)
            {
                <tr>
                    <td>@contact.Id</td>
                    <td>@contact.Name</td>
                    <td>
                        <a asp-page="./Edit" asp-route-id="@contact.Id">edit</a>
                        <button type="submit" asp-page-handler="delete" 
                                asp-route-id="@contact.Id">delete</button>
                    </td>
                </tr>
            }
        </tbody>
    </table>

    <a asp-page="./Create">Create</a>
</form>

연결된 PageModel 클래스(Index.cshtml.cs):The associated PageModel class (Index.cshtml.cs):

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesContacts.Data;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;

namespace RazorPagesContacts.Pages
{
    public class IndexModel : PageModel
    {
        private readonly AppDbContext _db;

        public IndexModel(AppDbContext db)
        {
            _db = db;
        }

        public IList<Customer> Customers { get; private set; }

        public async Task OnGetAsync()
        {
            Customers = await _db.Customers.AsNoTracking().ToListAsync();
        }

        public async Task<IActionResult> OnPostDeleteAsync(int id)
        {
            var contact = await _db.Customers.FindAsync(id);

            if (contact != null)
            {
                _db.Customers.Remove(contact);
                await _db.SaveChangesAsync();
            }

            return RedirectToPage();
        }
    }
}

Index.cshtml 파일에는 각 연락처의 편집 링크를 만들기 위해 다음 태그가 포함됩니다.The Index.cshtml file contains the following markup to create an edit link for each contact:

<a asp-page="./Edit" asp-route-id="@contact.Id">edit</a>

앵커 태그 도우미asp-route-{value} 특성을 사용하여 편집 페이지 링크를 생성했습니다.The Anchor Tag Helper used the asp-route-{value} attribute to generate a link to the Edit page. 링크에는 연락처 ID와 함께 경로 데이터가 포함됩니다.The link contains route data with the contact ID. 예를 들어, http://localhost:5000/Edit/1을 입력합니다.For example, http://localhost:5000/Edit/1.

Pages/Edit.cshtml 파일:The Pages/Edit.cshtml file:

@page "{id:int}"
@model RazorPagesContacts.Pages.EditModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@{
    ViewData["Title"] = "Edit Customer";
}

<h1>Edit Customer - @Model.Customer.Id</h1>
<form method="post">
    <div asp-validation-summary="All"></div>
    <input asp-for="Customer.Id" type="hidden" />
    <div>
        <label asp-for="Customer.Name"></label>
        <div>
            <input asp-for="Customer.Name" />
            <span asp-validation-for="Customer.Name" ></span>
        </div>
    </div>
 
    <div>
        <button type="submit">Save</button>
    </div>
</form>

첫 번째 줄에는 @page "{id:int}" 지시문이 포함됩니다.The first line contains the @page "{id:int}" directive. 라우팅 제약 조건 "{id:int}"int 경로 데이터가 포함된 페이지에 대한 요청을 허용하도록 페이지에 지시합니다.The routing constraint"{id:int}" tells the page to accept requests to the page that contain int route data. 페이지에 대한 요청에 int로 변환될 수 있는 경로 데이터가 없으면 런타임은 HTTP 404(찾을 수 없음) 오류를 반환합니다.If a request to the page doesn't contain route data that can be converted to an int, the runtime returns an HTTP 404 (not found) error. ID를 옵션으로 설정하려면 경로 제약 조건에 ?를 추가합니다.To make the ID optional, append ? to the route constraint:

@page "{id:int?}"

Pages/Edit.cshtml.cs 파일:The Pages/Edit.cshtml.cs file:

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesContacts.Data;

namespace RazorPagesContacts.Pages
{
    public class EditModel : PageModel
    {
        private readonly AppDbContext _db;

        public EditModel(AppDbContext db)
        {
            _db = db;
        }

        [BindProperty]
        public Customer Customer { get; set; }

        public async Task<IActionResult> OnGetAsync(int id)
        {
            Customer = await _db.Customers.FindAsync(id);

            if (Customer == null)
            {
                return RedirectToPage("/Index");
            }

            return Page();
        }

        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            _db.Attach(Customer).State = EntityState.Modified;

            try
            {
                await _db.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                throw new Exception($"Customer {Customer.Id} not found!");
            }

            return RedirectToPage("/Index");
        }
    }
}

또한 Index.cshtml 파일에는 각 고객 연락처의 삭제 단추를 만드는 표시가 포함됩니다.The Index.cshtml file also contains markup to create a delete button for each customer contact:

<button type="submit" asp-page-handler="delete" 
        asp-route-id="@contact.Id">delete</button>

삭제 단추가 HTML로 렌더링되는 경우 해당 formaction에는 다음을 위한 매개 변수가 포함됩니다.When the delete button is rendered in HTML, its formaction includes parameters for:

  • asp-route-id 특성에서 지정된 고객 연락처 IDThe customer contact ID specified by the asp-route-id attribute.
  • asp-page-handler 특성에서 지정된 handlerThe handler specified by the asp-page-handler attribute.

1이라는 고객 연락처 ID를 포함한 렌더링된 삭제 단추의 예는 다음과 같습니다.Here is an example of a rendered delete button with a customer contact ID of 1:

<button type="submit" formaction="/?id=1&amp;handler=delete">delete</button>

단추를 선택하면 양식 POST 요청이 서버에 전송됩니다.When the button is selected, a form POST request is sent to the server. 이름 규칙에 따라 OnPost[handler]Async 구성표에 해당하는 handler 매개 변수 값을 기반으로 처리기 메서드의 이름을 선택합니다.By convention, the name of the handler method is selected based the value of the handler parameter according to the scheme OnPost[handler]Async.

handler가 이 예제에서 delete이기 때문에 OnPostDeleteAsync 처리기 메서드는 POST 요청을 처리하는 데 사용됩니다.Because the handler is delete in this example, the OnPostDeleteAsync handler method is used to process the POST request. asp-page-handlerremove와 같은 다른 값으로 설정되면 OnPostRemoveAsync라는 이름의 페이지 처리기 메서드를 선택합니다.If the asp-page-handler is set to a different value, such as remove, a page handler method with the name OnPostRemoveAsync is selected.

public async Task<IActionResult> OnPostDeleteAsync(int id)
{
    var contact = await _db.Customers.FindAsync(id);

    if (contact != null)
    {
        _db.Customers.Remove(contact);
        await _db.SaveChangesAsync();
    }

    return RedirectToPage();
}

OnPostDeleteAsync 메서드는 다음과 같은 작업을 수행합니다.The OnPostDeleteAsync method:

  • 쿼리 문자열에서 id를 수용합니다.Accepts the id from the query string.
  • FindAsync를 사용하여 고객 연락처의 데이터베이스를 쿼리합니다.Queries the database for the customer contact with FindAsync.
  • 고객 연락처를 찾으면 고객 연락처의 목록에서 제거됩니다.If the customer contact is found, they're removed from the list of customer contacts. 데이터베이스가 업데이트됩니다.The database is updated.
  • RedirectToPage를 호출하여 루트 인덱스 페이지(/Index)를 리디렉션합니다.Calls RedirectToPage to redirect to the root Index page (/Index).

필요한 페이지 속성 표시Mark page properties required

PageModel의 속성은 필수 특성으로 데코레이팅될 수 있습니다.Properties on a PageModel can be decorated with the Required attribute:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.ComponentModel.DataAnnotations;

namespace RazorPagesMovie.Pages.Movies
{
    public class CreateModel : PageModel
    {
        public IActionResult OnGet()
        {
            return Page();
        }

        [BindProperty]
        [Required(ErrorMessage = "Color is required")]
        public string Color { get; set; }

        public IActionResult OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            // Process color.

            return RedirectToPage("./Index");
        }
    }
}

자세한 내용은 모델 유효성 검사를 참조하세요.See Model validation for more information.

OnGet 처리기를 사용하여 HEAD 요청 관리Manage HEAD requests with the OnGet handler

일반적으로 HEAD 처리기는 HEAD 요청에 대해 생성 및 호출됩니다.Ordinarily, a HEAD handler is created and called for HEAD requests:

public void OnHead()
{
HttpContext.Response.Headers.Add("HandledBy", "Handled by OnHead!");
}

HEAD 처리기(OnHead)가 정의되지 않으면 Razor 페이지는 ASP.NET Core 2.1 이상에서 GET 페이지 처리기(OnGet) 호출로 대체됩니다.If no HEAD handler (OnHead) is defined, Razor Pages falls back to calling the GET page handler (OnGet) in ASP.NET Core 2.1 or later. ASP.NET Core 2.1~2.x에 대한 Startup.ConfigureSetCompatibilityVersion 메서드로 이 동작을 옵트인(opt in)합니다.Opt in to this behavior with the SetCompatibilityVersion method in Startup.Configure for ASP.NET Core 2.1 to 2.x:

services.AddMvc()
.SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_1);

SetCompatibilityVersion은 효과적으로 Razor 페이지 옵션 AllowMappingHeadRequestsToGetHandlertrue로 설정합니다.SetCompatibilityVersion effectively sets the Razor Pages option AllowMappingHeadRequestsToGetHandler to true.

SetCompatibilityVersion을 사용하여 모든 2.1 동작을 옵트인하는 대신 특정 동작을 명시적으로 옵트인할 수 있습니다.Rather than opting into all 2.1 behaviors with SetCompatibilityVersion, you can explicitly opt-in to specific behaviors. 다음 코드는 HEAD 요청을 GET 처리기에 매핑을 옵트인합니다.The following code opts into the mapping HEAD requests to the GET handler.

services.AddMvc()
.AddRazorPagesOptions(options =>
{
options.AllowMappingHeadRequestsToGetHandler = true;
});

XSRF/CSRF 및 Razor 페이지XSRF/CSRF and Razor Pages

위조 방지 유효성 검사에 대한 코드를 작성할 필요가 없습니다.You don't have to write any code for antiforgery validation. 위조 방지 토큰 생성 및 유효성 검사는 Razor 페이지에 자동으로 포함됩니다.Antiforgery token generation and validation are automatically included in Razor Pages.

Razor 페이지와 함께 레이아웃, 부분, 템플릿 및 태그 도우미 사용Using Layouts, partials, templates, and Tag Helpers with Razor Pages

페이지는 Razor 보기 엔진의 모든 기능과 함께 작동합니다.Pages work with all the capabilities of the Razor view engine. 레이아웃, 부분, 템플릿, 태그 도우미, _ViewStart.cshtml, _ViewImports.cshtml은 기존 Razor 뷰와 동일한 방식으로 작동합니다.Layouts, partials, templates, Tag Helpers, _ViewStart.cshtml, _ViewImports.cshtml work in the same way they do for conventional Razor views.

이러한 기능 중 일부를 활용하여 이 페이지의 문제를 해결해 보겠습니다.Let's declutter this page by taking advantage of some of those capabilities.

레이아웃 페이지Pages/Shared/_Layout.cshtml에 추가합니다.Add a layout page to Pages/Shared/_Layout.cshtml:

레이아웃 페이지Pages/_Layout.cshtml에 추가합니다.Add a layout page to Pages/_Layout.cshtml:

<!DOCTYPE html>
<html>
<head> 
    <title>Razor Pages Sample</title>      
</head>
<body>    
   <a asp-page="/Index">Home</a>
    @RenderBody()  
    <a asp-page="/Customers/Create">Create</a> <br />
</body>
</html>

레이아웃:The Layout:

  • 각 페이지의 레이아웃을 제어합니다(페이지가 레이아웃에서 옵트아웃(opt out)되지 않는 경우).Controls the layout of each page (unless the page opts out of layout).
  • JavaScript 및 스타일시트 같은 HTML 구조를 가져옵니다.Imports HTML structures such as JavaScript and stylesheets.

자세한 내용은 레이아웃 페이지를 참조하세요.See layout page for more information.

Layout 속성은 Pages/_ViewStart.cshtml에서 설정됩니다.The Layout property is set in Pages/_ViewStart.cshtml:

@{
    Layout = "_Layout";
}

레이아웃은 Pages/Shared 폴더에 있습니다.The layout is in the Pages/Shared folder. 페이지는 현재 페이지와 동일한 폴더에서 시작하여 다른 뷰(레이아웃, 템플릿, 부분)를 계층 구조로 검색합니다.Pages look for other views (layouts, templates, partials) hierarchically, starting in the same folder as the current page. Pages/Shared 폴더의 레이아웃은 Pages 폴더 아래의 Razor 페이지에서 사용될 수 있습니다.A layout in the Pages/Shared folder can be used from any Razor page under the Pages folder.

레이아웃 파일은 Pages/Shared 폴더로 이동해야 합니다.The layout file should go in the Pages/Shared folder.

레이아웃은 Pages 폴더에 있습니다.The layout is in the Pages folder. 페이지는 현재 페이지와 동일한 폴더에서 시작하여 다른 뷰(레이아웃, 템플릿, 부분)를 계층 구조로 검색합니다.Pages look for other views (layouts, templates, partials) hierarchically, starting in the same folder as the current page. Pages 폴더의 레이아웃은 Pages 폴더 아래의 Razor 페이지에서 사용될 수 있습니다.A layout in the Pages folder can be used from any Razor page under the Pages folder.

레이아웃 파일은 Views/Shared 폴더에 두지 않는 것이 좋습니다.We recommend you not put the layout file in the Views/Shared folder. Views/Shared는 MVC 뷰 패턴입니다.Views/Shared is an MVC views pattern. Razor 페이지는 경로 규칙이 아니라 폴더 계층 구조를 사용해야 합니다.Razor Pages are meant to rely on folder hierarchy, not path conventions.

Razor 페이지의 뷰 검색에는 Pages 폴더가 포함됩니다.View search from a Razor Page includes the Pages folder. MVC 컨트롤러 및 기존 Razor 뷰에서 사용 중인 레이아웃, 템플릿 및 부분이 제대로 작동합니다.The layouts, templates, and partials you're using with MVC controllers and conventional Razor views just work.

Pages/_ViewImports.cshtml 파일을 추가합니다.Add a Pages/_ViewImports.cshtml file:

@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@namespace는 자습서의 뒷부분에서 설명합니다.@namespace is explained later in the tutorial. @addTagHelper 지시문은 기본 제공 태그 도우미Pages 폴더의 모든 페이지에 도입합니다.The @addTagHelper directive brings in the built-in Tag Helpers to all the pages in the Pages folder.

@namespace 지시문은 페이지에서 명시적으로 사용됩니다.When the @namespace directive is used explicitly on a page:

@page
@namespace RazorPagesIntro.Pages.Customers

@model NameSpaceModel

<h2>Name space</h2>
<p>
    @Model.Message
</p>

이 지시문은 페이지에 대한 네임스페이스를 설정합니다.The directive sets the namespace for the page. @model 지시문에는 네임스페이스가 포함될 필요가 없습니다.The @model directive doesn't need to include the namespace.

@namespace 지시문이 _ViewImports.cshtml에 포함되면 지정된 네임스페이스는 @namespace 지시문을 가져오는 페이지의 생성된 네임스페이스에 대한 접두사를 제공합니다.When the @namespace directive is contained in _ViewImports.cshtml, the specified namespace supplies the prefix for the generated namespace in the Page that imports the @namespace directive. 생성된 네임스페이스의 나머지 부분(접미사 부분)은 _ViewImports.cshtml이 포함된 폴더와 페이지가 포함된 폴더 사이의 점으로 구분된 상대 경로입니다.The rest of the generated namespace (the suffix portion) is the dot-separated relative path between the folder containing _ViewImports.cshtml and the folder containing the page.

예를 들어 PageModel 클래스 Pages/Customers/Edit.cshtml.cs는 네임스페이스를 명시적으로 설정합니다.For example, the PageModel class Pages/Customers/Edit.cshtml.cs explicitly sets the namespace:

namespace RazorPagesContacts.Pages
{
    public class EditModel : PageModel
    {
        private readonly AppDbContext _db;

        public EditModel(AppDbContext db)
        {
            _db = db;
        }

        // Code removed for brevity.

Pages/_ViewImports.cshtml 파일은 다음 네임스페이스를 설정합니다.The Pages/_ViewImports.cshtml file sets the following namespace:

@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Pages/Customers/Edit.cshtml Razor 페이지에 대한 생성된 네임스페이스는 PageModel 클래스와 동일합니다.The generated namespace for the Pages/Customers/Edit.cshtml Razor Page is the same as the PageModel class.

@namespace 는 기존 Razor 뷰에서도 작동합니다.@namespace also works with conventional Razor views.

원래 Pages/Create.cshtml 뷰 파일:The original Pages/Create.cshtml view file:

@page
@model RazorPagesContacts.Pages.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" />
    </form>
</body>
</html>

업데이트된 Pages/Create.cshtml 뷰 파일:The updated Pages/Create.cshtml view file:

@page
@model CreateModel

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" />
    </form>
</body>
</html>

Razor 페이지 시작 프로젝트에는 클라이언트 쪽 유효성 검사를 연결하는 Pages/_ValidationScriptsPartial.cshtml이 포함됩니다.The Razor Pages starter project contains the Pages/_ValidationScriptsPartial.cshtml, which hooks up client-side validation.

페이지에 대한 URL 생성URL generation for Pages

이전에 표시된 Create 페이지에서는 RedirectToPage를 사용합니다.The Create page, shown previously, uses RedirectToPage:

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _db.Customers.Add(Customer);
    await _db.SaveChangesAsync();
    return RedirectToPage("/Index");
}

앱에는 다음 파일/폴더 구조가 있습니다.The app has the following file/folder structure:

  • /Pages/Pages

    • Index.cshtmlIndex.cshtml

    • /Customers/Customers

      • Create.cshtmlCreate.cshtml
      • Edit.cshtmlEdit.cshtml
      • Index.cshtmlIndex.cshtml

Pages/Customers/Create.cshtmlPages/Customers/Edit.cshtml 페이지는 성공 후에 Pages/Index.cshtml로 리디렉션됩니다.The Pages/Customers/Create.cshtml and Pages/Customers/Edit.cshtml pages redirect to Pages/Index.cshtml after success. 문자열 /Index는 이전 페이지에 액세스하기 위한 URI 부분입니다.The string /Index is part of the URI to access the preceding page. 문자열 /IndexPages/Index.cshtml 페이지의 URI를 생성하는 데 사용될 수 있습니다.The string /Index can be used to generate URIs to the Pages/Index.cshtml page. 예:For example:

  • Url.Page("/Index", ...)
  • <a asp-page="/Index">My Index Page</a>
  • RedirectToPage("/Index")

페이지 이름은 루트 /Pages 폴더에서 선행 /를 포함한 페이지 경로입니다(예: /Index).The page name is the path to the page from the root /Pages folder including a leading / (for example, /Index). 이전 URL 생성 샘플은 URL 하드 코딩보다 향상된 옵션과 기능을 제공합니다.The preceding URL generation samples offer enhanced options and functional capabilities over hardcoding a URL. URL 생성은 라우팅을 사용하며 경로가 대상 경로에서 정의되는 방식에 따라 매개 변수를 생성하고 인코딩할 수 있습니다.URL generation uses routing and can generate and encode parameters according to how the route is defined in the destination path.

페이지에 대한 URL 생성은 상대적 이름을 지원합니다.URL generation for pages supports relative names. 다음 표에서는 Pages/Customers/Create.cshtml에서 다른 RedirectToPage 매개 변수를 통해 선택되는 인덱스 페이지를 보여 줍니다.The following table shows which Index page is selected with different RedirectToPage parameters from Pages/Customers/Create.cshtml:

RedirectToPage(x)RedirectToPage(x) 페이지Page
RedirectToPage("/Index")RedirectToPage("/Index") Pages/IndexPages/Index
RedirectToPage("./Index");RedirectToPage("./Index"); Pages/Customers/IndexPages/Customers/Index
RedirectToPage("../Index")RedirectToPage("../Index") Pages/IndexPages/Index
RedirectToPage("Index")RedirectToPage("Index") Pages/Customers/IndexPages/Customers/Index

RedirectToPage("Index"), RedirectToPage("./Index")RedirectToPage("../Index")상대적 이름입니다.RedirectToPage("Index"), RedirectToPage("./Index"), and RedirectToPage("../Index") are relative names. RedirectToPage 매개 변수는 현재 페이지의 경로와 결합되어 대상 페이지의 이름을 계산합니다.The RedirectToPage parameter is combined with the path of the current page to compute the name of the destination page.

상대적 이름 연결은 구조가 복잡한 사이트를 빌드할 때 유용합니다.Relative name linking is useful when building sites with a complex structure. 상대적 이름을 사용하여 한 폴더의 여러 페이지 간을 연결하는 경우 해당 폴더의 이름을 바꿀 수 있습니다.If you use relative names to link between pages in a folder, you can rename that folder. 그래도 모든 링크가 작동합니다(폴더 이름을 포함하지 않기 때문).All the links still work (because they didn't include the folder name).

ViewData 특성ViewData attribute

ViewDataAttribute를 사용하여 데이터를 페이지에 전달할 수 있습니다.Data can be passed to a page with ViewDataAttribute. [ViewData]로 데코레이팅된 컨트롤러 또는 Razor 페이지 모델의 속성은 값을 ViewDataDictionary에 저장하고 로드됩니다.Properties on controllers or Razor Page models decorated with [ViewData] have their values stored and loaded from the ViewDataDictionary.

다음 예제에서 AboutModel에는 [ViewData]으로 데코레이팅된 Title 속성이 있습니다.In the following example, the AboutModel contains a Title property decorated with [ViewData]. Title 속성은 정보 페이지의 제목에 설정되어 있습니다.The Title property is set to the title of the About page:

public class AboutModel : PageModel
{
[ViewData]
public string Title { get; } = "About";

public void OnGet()
{
}
}

정보 페이지에서 Title 속성을 모델 속성으로 액세스하세요.In the About page, access the Title property as a model property:

<h1>@Model.Title</h1>

레이아웃에서 제목은 ViewData 사전에서 읽습니다.In the layout, the title is read from the ViewData dictionary:

<!DOCTYPE html>
<html lang="en">
<head>
<title>@ViewData["Title"] - WebApplication</title>
...

TempDataTempData

ASP.NET Core는 TempData 속성을 컨트롤러에서 노출합니다.ASP.NET Core exposes the TempData property on a controller. 이 속성은 판독될 때까지 데이터를 저장합니다.This property stores data until it's read. KeepPeek 메서드를 사용하여 삭제 없이 데이터를 검사할 수 있습니다.The Keep and Peek methods can be used to examine the data without deletion. TempData는 두 개 이상의 요청에 대한 데이터가 필요할 경우 리디렉션에 유용합니다.TempData is useful for redirection, when data is needed for more than a single request.

[TempData] 특성은 ASP.NET Core 2.0의 새로운 기능이고 컨트롤러 및 페이지에서 지원됩니다.The [TempData] attribute is new in ASP.NET Core 2.0 and is supported on controllers and pages.

다음 코드는 TempData를 사용하여 Message 값을 설정합니다.The following code sets the value of Message using TempData:

public class CreateDotModel : PageModel
{
    private readonly AppDbContext _db;

    public CreateDotModel(AppDbContext db)
    {
        _db = db;
    }

    [TempData]
    public string Message { get; set; }

    [BindProperty]
    public Customer Customer { get; set; }

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        _db.Customers.Add(Customer);
        await _db.SaveChangesAsync();
        Message = $"Customer {Customer.Name} added";
        return RedirectToPage("./Index");
    }
}

Pages/Customers/Index.cshtml 파일의 다음 태그는 TempData를 사용하여 Message 값을 표시합니다.The following markup in the Pages/Customers/Index.cshtml file displays the value of Message using TempData.

<h3>Msg: @Model.Message</h3>

Pages/Customers/Index.cshtml.cs 페이지 모델은 [TempData] 특성을 Message 속성에 적용합니다.The Pages/Customers/Index.cshtml.cs page model applies the [TempData] attribute to the Message property.

[TempData]
public string Message { get; set; }

자세한 내용은 TempData를 참조하세요.See TempData for more information.

페이지당 여러 처리기Multiple handlers per page

다음 페이지는 asp-page-handler 태그 도우미를 사용하여 두 개의 페이지 처리기에 대한 태그를 생성합니다.The following page generates markup for two page handlers using the asp-page-handler Tag Helper:

@page
@model CreateFATHModel

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" asp-page-handler="JoinList" value="Join" />
        <input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
    </form>
</body>
</html>

이전 예제의 폼에는 두 개의 제출 단추가 있고, 각 단추는 FormActionTagHelper를 사용하여 다른 URL에 제출됩니다.The form in the preceding example has two submit buttons, each using the FormActionTagHelper to submit to a different URL. asp-page-handler 특성은 asp-page와 함께 사용됩니다.The asp-page-handler attribute is a companion to asp-page. asp-page-handler는 페이지에서 정의된 각 처리기 메서드에 제출되는 URL을 생성합니다.asp-page-handler generates URLs that submit to each of the handler methods defined by a page. 샘플이 현재 페이지에 연결되어 있으므로 asp-page가 지정되지 않습니다.asp-page isn't specified because the sample is linking to the current page.

페이지 모델:The page model:

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesContacts.Data;

namespace RazorPagesContacts.Pages.Customers
{
    public class CreateFATHModel : PageModel
    {
        private readonly AppDbContext _db;

        public CreateFATHModel(AppDbContext db)
        {
            _db = db;
        }

        [BindProperty]
        public Customer Customer { get; set; }

        public async Task<IActionResult> OnPostJoinListAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            _db.Customers.Add(Customer);
            await _db.SaveChangesAsync();
            return RedirectToPage("/Index");
        }

        public async Task<IActionResult> OnPostJoinListUCAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }
            Customer.Name = Customer.Name?.ToUpper();
            return await OnPostJoinListAsync();
        }
    }
}

이전 코드는 명명된 처리기 메서드를 사용합니다.The preceding code uses named handler methods. 명명된 처리기 메서드를 만들려면 On<HTTP Verb> 뒤와 Async(있는 경우) 앞에 이름의 텍스트를 사용합니다.Named handler methods are created by taking the text in the name after On<HTTP Verb> and before Async (if present). 이전 예제에서 페이지 메서드는 OnPostJoinListAsync 및 OnPostJoinListUCAsync입니다.In the preceding example, the page methods are OnPostJoinListAsync and OnPostJoinListUCAsync. OnPostAsync가 제거된 처리기 이름은 JoinListJoinListUC입니다.With OnPost and Async removed, the handler names are JoinList and JoinListUC.

<input type="submit" asp-page-handler="JoinList" value="Join" />
<input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />

이전 코드를 사용할 경우 OnPostJoinListAsync에 제출되는 URL 경로는 http://localhost:5000/Customers/CreateFATH?handler=JoinList입니다.Using the preceding code, the URL path that submits to OnPostJoinListAsync is http://localhost:5000/Customers/CreateFATH?handler=JoinList. OnPostJoinListUCAsync에 제출되는 URL 경로는 http://localhost:5000/Customers/CreateFATH?handler=JoinListUC입니다.The URL path that submits to OnPostJoinListUCAsync is http://localhost:5000/Customers/CreateFATH?handler=JoinListUC.

사용자 지정 경로Custom routes

@page 지시문을 사용하여 다음을 수행합니다.Use the @page directive to:

  • 페이지에 대한 사용자 지정 경로를 지정합니다.Specify a custom route to a page. 예를 들어 @page "/Some/Other/Path"를 사용하여 About 페이지에 대한 경로를 /Some/Other/Path로 설정할 수 있습니다.For example, the route to the About page can be set to /Some/Other/Path with @page "/Some/Other/Path".
  • 세그먼트를 페이지의 기본 경로에 추가합니다.Append segments to a page's default route. 예를 들어 "항목" 세그먼트는 @page "item"을 사용하여 페이지의 기본 경로에 추가할 수 있습니다.For example, an "item" segment can be added to a page's default route with @page "item".
  • 매개 변수를 페이지의 기본 경로에 추가합니다.Append parameters to a page's default route. 예를 들어 ID 매개 변수 id@page "{id}"가 있는 페이지에 필요할 수 있습니다.For example, an ID parameter, id, can be required for a page with @page "{id}".

경로의 시작 부분에 물결표(~)로 지정된 루트 상대 경로가 지원됩니다.A root-relative path designated by a tilde (~) at the beginning of the path is supported. 예를 들어 @page "~/Some/Other/Path"@page "/Some/Other/Path"과 같습니다.For example, @page "~/Some/Other/Path" is the same as @page "/Some/Other/Path".

경로 템플릿 @page "{handler?}"를 지정하여 URL의 쿼리 문자열 ?handler=JoinList를 경로 세그먼트 /JoinList로 변경할 수 있습니다.You can change the query string ?handler=JoinList in the URL to a route segment /JoinList by specifying the route template @page "{handler?}".

URL에서 쿼리 문자열 ?handler=JoinList를 사용하지 않으려면 경로를 변경하여 처리기 이름을 URL의 경로 부분에 넣습니다.If you don't like the query string ?handler=JoinList in the URL, you can change the route to put the handler name in the path portion of the URL. @page 지시문 뒤에 큰따옴표로 묶은 경로 템플릿을 추가하여 경로를 사용자 지정할 수 있습니다.You can customize the route by adding a route template enclosed in double quotes after the @page directive.

@page "{handler?}"
@model CreateRouteModel

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" asp-page-handler="JoinList" value="Join" />
        <input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
    </form>
</body>
</html>

이전 코드를 사용할 경우 OnPostJoinListAsync에 제출되는 URL 경로는 http://localhost:5000/Customers/CreateFATH/JoinList입니다.Using the preceding code, the URL path that submits to OnPostJoinListAsync is http://localhost:5000/Customers/CreateFATH/JoinList. OnPostJoinListUCAsync에 제출되는 URL 경로는 http://localhost:5000/Customers/CreateFATH/JoinListUC입니다.The URL path that submits to OnPostJoinListUCAsync is http://localhost:5000/Customers/CreateFATH/JoinListUC.

handler 뒤의 ?는 경로 매개 변수가 선택 사항임을 의미합니다.The ? following handler means the route parameter is optional.

구성 및 설정Configuration and settings

고급 옵션을 구성하려면 MVC 빌더에서 확장 메서드 AddRazorPagesOptions를 사용합니다.To configure advanced options, use the extension method AddRazorPagesOptions on the MVC builder:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc()
        .AddRazorPagesOptions(options =>
        {
            options.RootDirectory = "/MyPages";
            options.Conventions.AuthorizeFolder("/MyPages/Admin");
        });
}

현재 RazorPagesOptions를 사용하여 페이지의 루트 디렉터리를 설정하거나 페이지에 대한 응용 프로그램 모델 규칙을 추가할 수 있습니다.Currently you can use the RazorPagesOptions to set the root directory for pages, or add application model conventions for pages. 나중에 이 방법으로 더 큰 확장성을 지원할 예정입니다.We'll enable more extensibility this way in the future.

뷰를 미리 컴파일하려면 Razor 뷰 컴파일을 참조하세요.To precompile views, see Razor view compilation .

샘플 코드를 다운로드하거나 봅니다.Download or view sample code.

이 소개에 따라 빌드되는 Razor 페이지 시작을 참조하세요.See Get started with Razor Pages, which builds on this introduction.

Razor 페이지를 콘텐츠 루트로 지정Specify that Razor Pages are at the content root

기본적으로 Razor 페이지의 루트 경로는 /Pages 디렉터리입니다.By default, Razor Pages are rooted in the /Pages directory. AddMvcWithRazorPagesAtContentRoot를 추가하여 Razor 페이지를 앱의 콘텐츠 루트(ContentRootPath)로 지정합니다.Add WithRazorPagesAtContentRoot to AddMvc to specify that your Razor Pages are at the content root (ContentRootPath) of the app:

services.AddMvc()
    .AddRazorPagesOptions(options =>
    {
        ...
    })
    .WithRazorPagesAtContentRoot();

Razor 페이지가 사용자 지정 루트 디렉터리에 있도록 지정Specify that Razor Pages are at a custom root directory

AddMvcWithRazorPagesRoot를 추가하여 Razor 페이지가 앱의 사용자 지정 루트 디렉터리에 있도록 지정합니다(상대 경로 제공).Add WithRazorPagesRoot to AddMvc to specify that your Razor Pages are at a custom root directory in the app (provide a relative path):

services.AddMvc()
    .AddRazorPagesOptions(options =>
    {
        ...
    })
    .WithRazorPagesRoot("/path/to/razor/pages");

참고 항목See also