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

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

Razor Pages를 사용하면 컨트롤러 및 뷰를 사용하는 것보다 더 쉽고 생산적으로 코딩 페이지에 초점을 맞춘 시나리오를 만들 수 있습니다.Razor Pages can make coding page-focused scenarios easier and more productive than using controllers and views.

모델-뷰-컨트롤러 방식을 사용하는 자습서를 찾고 있다면 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 Pages에 대해 소개합니다.This document provides an introduction to Razor Pages. 단계별 자습서가 아닙니다.It's not a step by step tutorial. 섹션 일부 내용이 너무 고급이라면 Razor Pages 시작을 참조하세요.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

Razor Pages 프로젝트 만들기Create a Razor Pages project

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

Razor PagesRazor Pages

Razor Pages는 Startup.cs 에서 사용할 수 있게 설정됩니다.Razor Pages is enabled in Startup.cs:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
        });
    }
}

기본적인 페이지를 살펴보겠습니다. Consider a basic page:

@page

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

앞의 코드는 컨트롤러 및 뷰가 포함된 ASP.NET Core 앱에서 사용되는 Razor 뷰 파일과 매우 유사합니다.The preceding code looks a lot like a Razor view file used in an ASP.NET Core app with controllers and views. 차이점은 @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. Razor Pages 파일 이름에는 .cshtml 접미사가 있습니다.Razor Pages file names have a .cshtml suffix.

다음 두 파일은 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 Index2Model

<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 Microsoft.Extensions.Logging;
using System;

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

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

규칙에 따라 PageModel 클래스 파일의 이름은 .cs 가 추가된 Razor Page 파일의 이름과 동일합니다.By convention, the PageModel class file has the same name as the Razor Page file with .cs appended. 예를 들어 위의 Razor Page는 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 Page 경로 및 그와 일치하는 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 Pages 파일을 검색합니다.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.

기본적인 양식 작성하기Write a basic form

Razor Pages는 앱을 만들 때 웹 브라우저에서 사용되는 일반적인 패턴을 손쉽게 구현할 수 있도록 설계되었습니다.Razor Pages is designed to make common patterns used with web browsers easy to implement when building an app. 모델 바인딩, 태그 도우미 및 HTML 도우미는 모두 Razor Page 클래스에 정의된 속성을 통해서 ‘정확하게 작동’합니다.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.

메모리 내 데이터베이스에는 Microsoft.EntityFrameworkCore.InMemory NuGet 패키지가 필요합니다.The in memory database requires the Microsoft.EntityFrameworkCore.InMemory NuGet package.

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

데이터 모델은 다음과 같습니다.The data model:

using System.ComponentModel.DataAnnotations;

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

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

db 컨텍스트는 다음과 같습니다.The db context:

using Microsoft.EntityFrameworkCore;
using RazorPagesContacts.Models;

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

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

Pages/Create.cshtml 뷰 파일은 다음과 같습니다.The Pages/Create.cshtml view file:

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

<p>Enter a customer name:</p>

<form method="post">
    Name:
    <input asp-for="Customer.Name" />
    <input type="submit" />
</form>

Pages/Create.cshtml.cs 페이지 모델은 다음과 같습니다.The Pages/Create.cshtml.cs page model:

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

namespace RazorPagesContacts.Pages.Customers
{
    public class CreateModel : PageModel
    {
        private readonly CustomerDbContext _context;

        public CreateModel(CustomerDbContext context)
        {
            _context = context;
        }

        public IActionResult OnGet()
        {
            return Page();
        }

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

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

            _context.Customers.Add(Customer);
            await _context.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:

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

  • OnGet: 페이지에 필요한 상태를 초기화합니다.OnGet to initialize state needed for the page. 위의 코드에서 OnGet 메서드는 CreateModel.cshtml Razor Page를 표시합니다.In the preceding code, the OnGet method displays the CreateModel.cshtml Razor Page.
  • OnPost: 양식 제출을 처리합니다.OnPost to handle form submissions.

Async 명명 접미사는 선택 사항이지만 비동기 함수에 대한 규약으로 자주 사용됩니다.The Async naming suffix is optional but is often used by convention for asynchronous functions. 위의 코드는 Razor Pages의 일반적인 코드입니다.The preceding code is typical for Razor Pages.

컨트롤러 및 뷰를 사용하는 ASP.NET 앱에 대해 잘 알고 있는 경우:If you're familiar with ASP.NET apps using controllers and views:

  • 앞 예제의 OnPostAsync 코드는 일반적인 컨트롤러 코드와 비슷합니다.The OnPostAsync code in the preceding example looks similar to typical controller code.
  • 모델 바인딩, 유효성 검사 및 작업 결과와 같은 MVC의 기본적인 기능들이 대부분 컨트롤러 및 Razor Pages와 동일하게 작동합니다.Most of the MVC primitives like model binding, validation, and action results work the same with Controllers and Razor Pages.

기존 OnPostAsync 메서드는 다음과 같습니다.The previous OnPostAsync method:

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

    _context.Customers.Add(Customer);
    await _context.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. 대부분의 경우 유효성 검사 오류는 클라이언트에서 감지되어 서버에는 제출되지 않습니다.In many cases, validation errors would be detected on the client, and never submitted to the server.

Pages/Create.cshtml 뷰 파일은 다음과 같습니다.The Pages/Create.cshtml view file:

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

<p>Enter a customer name:</p>

<form method="post">
    Name:
    <input asp-for="Customer.Name" />
    <input type="submit" />
</form>

Pages/Create.cshtml 에서 렌더링된 HTML:The rendered HTML from Pages/Create.cshtml:

<p>Enter a customer name:</p>

<form method="post">
    Name:
    <input type="text" data-val="true"
           data-val-length="The field Name must be a string with a maximum length of 10."
           data-val-length-max="10" data-val-required="The Name field is required."
           id="Customer_Name" maxlength="10" name="Customer.Name" value="" />
    <input type="submit" />
    <input name="__RequestVerificationToken" type="hidden"
           value="<Antiforgery token here>" />
</form>

이전 코드에서 양식 게시:In the previous code, posting the form:

  • 유효한 데이터 사용:With valid data:

    • OnPostAsync 처리기 메서드는 RedirectToPage 도우미 메서드를 호출합니다.The OnPostAsync handler method calls the RedirectToPage helper method. RedirectToPageRedirectToPageResult의 인스턴스를 반환합니다.RedirectToPage returns an instance of RedirectToPageResult. RedirectToPage:RedirectToPage:

      • 작업 결과입니다.Is an action result.
      • RedirectToAction 또는 RedirectToRoute(컨트롤러 및 뷰에서 사용됨)와 유사합니다.Is similar to RedirectToAction or RedirectToRoute (used in controllers and views).
      • 페이지에 맞게 사용자 지정됩니다.Is 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.
  • 서버에 전달되는 유효성 검사 오류 포함:With validation errors that are passed to the server:

    • OnPostAsync 처리기 메서드는 Page 도우미 메서드를 호출합니다.The OnPostAsync 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.
    • 앞의 예제에서 값이 없는 양식을 게시하면 false를 반환하는 ModelState.IsValid를 반환합니다.In the preceding example, posting the form with no value results in ModelState.IsValid returning false. 이 샘플에서는 클라이언트에 유효성 검사 오류가 표시되지 않습니다.In this sample, no validation errors are displayed on the client. 유효성 검사 오류 처리는 이 문서의 뒷부분에 설명되어 있습니다.Validation error handing is covered later in this document.
    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }
    
        _context.Customers.Add(Customer);
        await _context.SaveChangesAsync();
    
        return RedirectToPage("./Index");
    }
    
  • 클라이언트 쪽 유효성 검사에서 검색된 유효성 검사 오류 포함:With validation errors detected by client side validation:

    • 데이터가 서버에 게시되지 않습니다.Data is not posted to the server.
    • 클라이언트 쪽 유효성 검사는 이 문서의 뒷부분에 설명되어 있습니다.Client-side validation is explained later in this document.

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

public class CreateModel : PageModel
{
    private readonly CustomerDbContext _context;

    public CreateModel(CustomerDbContext context)
    {
        _context = context;
    }

    public IActionResult OnGet()
    {
        return Page();
    }

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

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

        _context.Customers.Add(Customer);
        await _context.SaveChangesAsync();

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

클라이언트에서 변경하면 안 되는 속성을 포함하는 모델에서는 [BindProperty]를 사용하지 않아야 합니다.[BindProperty] should not be used on models containing properties that should not be changed by the client. 자세한 내용은 초과 게시를 참조하세요.For more information, see Overposting.

Razor Pages는 기본적으로 비 GET 동사에 대해서만 속성을 바인딩합니다.Razor Pages, by default, bind properties only with non-GET verbs. 속성에 바인딩하면 HTTP 데이터를 모델 형식으로 변환하는 코드를 작성할 필요가 없습니다.Binding to properties removes the need to writing code to convert HTTP data to the model type. 바인딩은 양식 필드 렌더링할 때와 (<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. 쿼리 문자열이나 경로 값을 사용하는 시나리오를 지정할 때 GET 바인딩을 옵트인하면 유용합니다.Opting into GET binding is useful when addressing scenarios that rely on query string or route values.

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

[BindProperty(SupportsGet = true)]

자세한 내용은 ASP.NET Core Community 스탠드업을 참조하세요. 토론 가져오기(YouTube)에서 바인딩합니다.For more information, see ASP.NET Core Community Standup: Bind on GET discussion (YouTube).

Pages/Create.cshtml 뷰 파일 검토:Reviewing the Pages/Create.cshtml view file:

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

<p>Enter a customer name:</p>

<form method="post">
    Name:
    <input asp-for="Customer.Name" />
    <input type="submit" />
</form>
  • 앞의 코드에서 입력 태그 도우미 <input asp-for="Customer.Name" />은 HTML <input> 요소를 Customer.Name 모델 식에 바인딩합니다.In the preceding code, the input tag helper <input asp-for="Customer.Name" /> binds the HTML <input> element to the Customer.Name model expression.
  • @addTagHelper는 태그 도우미를 사용할 수 있도록 설정합니다.@addTagHelper makes Tag Helpers available.

홈페이지The home page

Index.cshtml 은 홈페이지입니다.Index.cshtml is the home page:

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

<h1>Contacts home page</h1>
<form method="post">
    <table class="table">
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @foreach (var contact in Model.Customer)
            {
                <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 New</a>
</form>

연결된 PageModel 클래스(Index.cshtml.cs)는 다음과 같습니다.The associated PageModel class (Index.cshtml.cs):

public class IndexModel : PageModel
{
    private readonly CustomerDbContext _context;

    public IndexModel(CustomerDbContext context)
    {
        _context = context;
    }

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

    public async Task OnGetAsync()
    {
        Customer = await _context.Customers.ToListAsync();
    }

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

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

        return RedirectToPage();
    }
}

Index.cshtml 파일은 다음 변경 내용을 포함합니다.The Index.cshtml file contains the following markup:

<td>

<a /a> 앵커 태그 도우미는 편집 페이지에 대한 링크를 생성하기 위해 asp-route-{value} 특성을 사용합니다.The <a /a> 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. 예: https://localhost:5001/Edit/1.For example, https://localhost:5001/Edit/1. 태그 도우미를 사용하면 Razor 파일에서 HTML 요소를 만들고 렌더링하는 데 서버 쪽 코드를 사용할 수 있습니다.Tag Helpers enable server-side code to participate in creating and rendering HTML elements in Razor files.

Index.cshtml 파일에는 각 고객 연락처에 대한 삭제 단추를 만들기 위한 태그가 포함되어 있습니다.The Index.cshtml file contains markup to create a delete button for each customer contact:

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

렌더링된 HTML:The rendered HTML:

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

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

  • asp-route-id 특성으로 지정된 고객 연락처 ID.The customer contact ID, specified by the asp-route-id attribute.
  • asp-page-handler 특성으로 지정된 handler.The handler, specified by the asp-page-handler attribute.

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

이번 예제에서는 handlerdelete이므로 POST 요청을 처리하기 위해 OnPostDeleteAsync 처리기 메서드가 사용됩니다.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 handler method with the name OnPostRemoveAsync is selected.

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

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

    return RedirectToPage();
}

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

  • 쿼리 문자열에서 id를 가져옵니다.Gets the id from the query string.
  • FindAsync를 사용하여 데이터베이스에서 고객 연락처를 쿼리합니다.Queries the database for the customer contact with FindAsync.
  • 고객 연락처가 발견되면 제거하고 데이터베이스를 업데이트합니다.If the customer contact is found, it's removed and the database is updated.
  • RedirectToPage를 호출하여 루트 인덱스 페이지(/Index)로 리디렉션합니다.Calls RedirectToPage to redirect to the root Index page (/Index).

Edit.cshtml 파일The Edit.cshtml file

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


<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?}"

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

public class EditModel : PageModel
{
    private readonly CustomerDbContext _context;

    public EditModel(CustomerDbContext context)
    {
        _context = context;
    }

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

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

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

        return Page();
    }

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

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

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

        return RedirectToPage("./Index");
    }

}

유효성 검사Validation

유효성 검사 규칙:Validation rules:

  • 모델 클래스에서 선언적으로 지정됩니다.Are declaratively specified in the model class.
  • 앱의 모든 위치에서 적용됩니다.Are enforced everywhere in the app.

System.ComponentModel.DataAnnotations 네임스페이스는 클래스 또는 속성에 선언적으로 적용되는 유효성 검사 특성의 기본 제공 세트를 제공합니다.The System.ComponentModel.DataAnnotations namespace provides a set of built-in validation attributes that are applied declaratively to a class or property. DataAnnotations는 또한 서식 지정을 돕는 [DataType]과 같은 서식 지정 특성을 포함하며 유효성 검사를 제공하지 않습니다.DataAnnotations also contains formatting attributes like [DataType] that help with formatting and don't provide any validation.

Customer 모델 고려:Consider the Customer model:

using System.ComponentModel.DataAnnotations;

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

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

다음 Create.cshtml 뷰파일 사용:Using the following Create.cshtml view file:

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

<p>Validation: customer name:</p>

<form method="post">
    <div asp-validation-summary="ModelOnly"></div>
    <span asp-validation-for="Customer.Name"></span>
    Name:
    <input asp-for="Customer.Name" />
    <input type="submit" />
</form>

<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>

위의 코드는The preceding code:

  • jQuery 및 jQuery 유효성 검사 스크립트를 포함합니다.Includes jQuery and jQuery validation scripts.

  • <div /><span /> 태그 도우미를 사용하여 다음을 사용하도록 설정합니다.Uses the <div /> and <span /> Tag Helpers to enable:

    • 클라이언트 쪽 유효성 검사.Client-side validation.
    • 유효성 검사 오류 렌더링.Validation error rendering.
  • 다음 HTML을 생성합니다.Generates the following HTML:

    <p>Enter a customer name:</p>
    
    <form method="post">
        Name:
        <input type="text" data-val="true"
               data-val-length="The field Name must be a string with a maximum length of 10."
               data-val-length-max="10" data-val-required="The Name field is required."
               id="Customer_Name" maxlength="10" name="Customer.Name" value="" />
        <input type="submit" />
        <input name="__RequestVerificationToken" type="hidden"
               value="<Antiforgery token here>" />
    </form>
    
    <script src="/lib/jquery/dist/jquery.js"></script>
    <script src="/lib/jquery-validation/dist/jquery.validate.js"></script>
    <script src="/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
    

이름 값 없이 만들기 양식을 게시하면 “이름 필드는 필수입니다.”라는 오류 메시지가 표시됩니다.Posting the Create form without a name value displays the error message "The Name field is required." 양식에서.on the form. 클라이언트에서 JavaScript를 사용하는 경우 서버에 게시하지 않고 브라우저에 오류를 표시합니다.If JavaScript is enabled on the client, the browser displays the error without posting to the server.

[StringLength(10)] 특성은 렌더링된 HTML에서 data-val-length-max="10"을 생성합니다.The [StringLength(10)] attribute generates data-val-length-max="10" on the rendered HTML. data-val-length-max는 브라우저에서 지정된 최대 길이를 초과하여 입력하지 못하도록 합니다.data-val-length-max prevents browsers from entering more than the maximum length specified. Fiddler와 같은 도구를 사용하여 게시물을 편집하고 재생하는 경우:If a tool such as Fiddler is used to edit and replay the post:

  • 이름이 10글자보다 긴 경우.With the name longer than 10.
  • “필드 이름은 최대 길이가 10글자인 문자열이어야 합니다.”라는 오류 메시지The error message "The field Name must be a string with a maximum length of 10." 가 반환됩니다.is returned.

다음 Movie 모델을 보세요.Consider the following Movie model:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace RazorPagesMovie.Models
{
    public class Movie
    {
        public int ID { get; set; }

        [StringLength(60, MinimumLength = 3)]
        [Required]
        public string Title { get; set; }

        [Display(Name = "Release Date")]
        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }

        [Range(1, 100)]
        [DataType(DataType.Currency)]
        [Column(TypeName = "decimal(18, 2)")]
        public decimal Price { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z]*$")]
        [Required]
        [StringLength(30)]
        public string Genre { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
        [StringLength(5)]
        [Required]
        public string Rating { get; set; }
    }

이 유효성 검사 특성은 적용되는 모델 속성에 시행하려는 동작을 지정합니다.The validation attributes specify behavior to enforce on the model properties they're applied to:

  • RequiredMinimumLength 특성은 속성에 값이 있어야 하지만 사용자가 이 유효성 검사를 만족하기 위해 공백을 입력하는 것을 막을 수 없다는 것을 나타냅니다.The Required and MinimumLength attributes indicate that a property must have a value, but nothing prevents a user from entering white space to satisfy this validation.

  • RegularExpression 특성은 입력할 수 있는 문자를 제한하는 데 사용됩니다.The RegularExpression attribute is used to limit what characters can be input. 이전 코드에서 “Genre”는 다음 조건을 충족해야 합니다.In the preceding code, "Genre":

    • 문자만 사용해야 합니다.Must only use letters.
    • 첫 번째 문자는 대문자여야 합니다The first letter is required to be uppercase. 공백, 숫자 및 특수 문자는 허용되지 않습니다.White space, numbers, and special characters are not allowed.
  • RegularExpression “Rating”은 다음 조건을 충족해야 합니다.The RegularExpression "Rating":

    • 첫 번째 문자는 대문자여야 합니다.Requires that the first character be an uppercase letter.
    • 이어진 공백에서는 특수 문자와 숫자가 허용됩니다.Allows special characters and numbers in subsequent spaces. “PG-13”은 등급에서는 유효하지만 “Genre”에서는 허용되지 않습니다."PG-13" is valid for a rating, but fails for a "Genre".
  • Range 특성은 지정한 범위 내로 값을 제한합니다.The Range attribute constrains a value to within a specified range.

  • StringLength 특성은 문자열 속성의 최대 길이와, 필요에 따라 최소 길이를 설정합니다.The StringLength attribute sets the maximum length of a string property, and optionally its minimum length.

  • 값 형식(예: decimal, int, float, DateTime)은 기본적으로 필수적이며 [Required] 특성이 필요하지 않습니다.Value types (such as decimal, int, float, DateTime) are inherently required and don't need the [Required] attribute.

Movie 모델에 대한 만들기 페이지에 잘못된 값이 포함된 오류가 표시됩니다.The Create page for the Movie model shows displays errors with invalid values:

여러 jQuery 클라이언트 쪽 유효성 검사 오류가 있는 동영상 보기 양식

자세한 내용은 다음을 참조하세요.For more information, see:

OnGet 처리기 대체를 사용하여 HEAD 요청 처리Handle HEAD requests with an OnGet handler fallback

HEAD 요청을 사용하면 특정 리소스의 헤더를 검색할 수 있습니다.HEAD requests allow retrieving the headers for a specific resource. GET 요청과는 달리 HEAD 요청은 응답 본문을 반환하지 않습니다.Unlike GET requests, HEAD requests don't return a response body.

일반적으로 HEAD 요청에 대한 OnHead 처리기를 만들고 호출합니다.Ordinarily, an OnHead handler is created and called for HEAD requests:

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

정의된 OnHead 처리기가 없다면 Razor Pages가 OnGet 처리기 호출로 대체합니다.Razor Pages falls back to calling the OnGet handler if no OnHead handler is defined.

XSRF/CSRF 및 Razor PagesXSRF/CSRF and Razor Pages

위조 방지 유효성 검사를 통해 Razor Pages를 보호합니다.Razor Pages are protected by Antiforgery validation. FormTagHelper는 위조 방지 토큰을 HTML 양식 요소에 삽입합니다.The FormTagHelper injects antiforgery tokens into HTML form elements.

Razor Pages에서 레이아웃, 부분 뷰, 템플릿 및 태그 도우미 사용하기Using Layouts, partials, templates, and Tag Helpers with Razor Pages

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, and _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:

<!DOCTYPE html>
<html>
<head>
    <title>RP Sample</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
</head>
<body>
    <a asp-page="/Index">Home</a>
    <a asp-page="/Customers/Create">Create</a>
    <a asp-page="/Customers/Index">Customers</a> <br />

    @RenderBody()
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
    <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
</body>
</html>

레이아웃은 다음과 같은 역할을 수행합니다.The Layout:

  • 각 페이지의 레이아웃을 제어합니다(페이지가 명시적으로 레이아웃을 사용하지 않는 경우 제외).Controls the layout of each page (unless the page opts out of layout).
  • JavaScript 및 스타일시트 같은 HTML 구조를 가져옵니다.Imports HTML structures such as JavaScript and stylesheets.
  • Razor 페이지의 내용은 @RenderBody()가 호출되는 위치에서 렌더링됩니다.The contents of the Razor page are rendered where @RenderBody() is called.

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

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.

레이아웃 파일은 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 Pages는 경로 규칙이 아닌 폴더 계층 구조를 사용해야 합니다.Razor Pages are meant to rely on folder hierarchy, not path conventions.

Razor Page의 뷰 검색에는 Pages 폴더가 포함됩니다.View search from a Razor Page includes the Pages folder. MVC 컨트롤러 및 기존 Razor 뷰에서 사용한 레이아웃, 템플릿 및 부분 뷰는 ‘정상적으로 작동’합니다.The layouts, templates, and partials used 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 지시문:The @namespace directive set on a page:

@page
@namespace RazorPagesIntro.Pages.Customers

@model NameSpaceModel

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

@namespace 지시문은 페이지에 대한 네임스페이스를 설정합니다.The @namespace 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 Page에 대해 생성되는 네임스페이스는 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 뷰 파일은 다음과 같습니다.Consider the Pages/Create.cshtml view file:

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

<p>Validation: customer name:</p>

<form method="post">
    <div asp-validation-summary="ModelOnly"></div>
    <span asp-validation-for="Customer.Name"></span>
    Name:
    <input asp-for="Customer.Name" />
    <input type="submit" />
</form>

<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>

_ViewImports.cshtml 및 앞의 레이아웃 파일로 업데이트된 Pages/Create.cshtml 뷰 파일:The updated Pages/Create.cshtml view file with _ViewImports.cshtml and the preceding layout file:

@page
@model CreateModel

<p>Enter a customer name:</p>

<form method="post">
    Name:
    <input asp-for="Customer.Name" />
    <input type="submit" />
</form>

앞의 코드에서 _ViewImports.cshtml 은 네임스페이스 및 태그 도우미를 가져왔습니다.In the preceding code, the _ViewImports.cshtml imported the namespace and Tag Helpers. 레이아웃 파일은 JavaScript 파일을 가져왔습니다.The layout file imported the JavaScript files.

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

부분 뷰에 대한 자세한 내용은 ASP.NET Core의 부분 보기를 참고하시기 바랍니다.For more information on partial views, see ASP.NET Core의 부분 보기.

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

앞에서 살펴본 Create 페이지는 RedirectToPage를 사용합니다.The Create page, shown previously, uses RedirectToPage:

public class CreateModel : PageModel
{
    private readonly CustomerDbContext _context;

    public CreateModel(CustomerDbContext context)
    {
        _context = context;
    }

    public IActionResult OnGet()
    {
        return Page();
    }

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

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

        _context.Customers.Add(Customer);
        await _context.SaveChangesAsync();

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

예제 앱은 다음과 같은 파일/폴더 구조를 갖고 있습니다.The app has the following file/folder structure:

  • /Pages/Pages

    • Index.cshtmlIndex.cshtml

    • Privacy.cshtmlPrivacy.cshtml

    • /Customers/Customers

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

Pages/Customers/Create.cshtmlPages/Customers/Edit.cshtml 페이지는 정상적으로 작업을 마친 후 Pages/Customers/Index.cshtml 로 리디렉션됩니다.The Pages/Customers/Create.cshtml and Pages/Customers/Edit.cshtml pages redirect to Pages/Customers/Index.cshtml after success. 문자열 ./Index는 이전 페이지에 액세스하는 데 사용되는 상대 페이지 이름입니다.The string ./Index is a relative page name used to access the preceding page. 이것은 Pages/Customers/Index.cshtml 페이지에 대한 URL을 생성하는 데 사용됩니다.It is used to generate URLs to the Pages/Customers/Index.cshtml page. 예를 들어:For example:

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

절대 페이지 이름 /IndexPages/Index.cshtml 페이지에 대한 URL을 생성하는 데 사용됩니다.The absolute page name /Index is used to generate URLs to the Pages/Index.cshtml page. 예를 들어:For example:

  • Url.Page("/Index", ...)
  • <a asp-page="/Index">Home 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 hard-coding 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 using different RedirectToPage parameters in 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. 상대적 이름을 사용하여 폴더의 페이지 간을 연결하는 경우:When relative names are used to link between pages in a folder:

  • 폴더의 이름을 바꾸면 상대적 링크는 중단되지 않습니다.Renaming a folder doesn't break the relative links.
  • 링크는 폴더 이름을 포함하지 않으므로 손상되지 않습니다.Links are not broken because they don't include the folder name.

다른 영역에서 페이지로 리디렉션하려면 영역을 지정하세요.To redirect to a page in a different Area, specify the area:

RedirectToPage("/Index", new { area = "Services" });

자세한 내용은 ASP.NET Core의 영역ASP.NET Core에서 Razor Pages 경로 및 앱 규칙를 참조하세요.For more information, see ASP.NET Core의 영역 and ASP.NET Core에서 Razor Pages 경로 및 앱 규칙.

ViewData 특성ViewData attribute

ViewDataAttribute를 사용하여 데이터를 페이지에 전달할 수 있습니다.Data can be passed to a page with ViewDataAttribute. [ViewData] 특성을 가진 속성은 ViewDataDictionary에서 저장되고 로드된 값을 가집니다.Properties with the [ViewData] attribute have their values stored and loaded from the ViewDataDictionary.

다음 예제에서 AboutModel[ViewData] 특성을 Title 속성에 적용합니다.In the following example, the AboutModel applies the [ViewData] attribute to the Title property:

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. 이 속성은 해당 속성이 읽혀질 때까지만 데이터를 저장합니다.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를 사용하여 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 페이지 모델은 Message 속성에 [TempData] 특성을 적용합니다.The Pages/Customers/Index.cshtml.cs page model applies the [TempData] attribute to the Message property.

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

자세한 내용은 TempData를 참조하세요.For more information, see TempData.

한 페이지에 대한 여러 처리기Multiple handlers per page

다음 페이지는 asp-page-handler 태그 도우미를 사용하여 두 처리기에 대한 태그를 생성합니다.The following page generates markup for two 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?.ToUpperInvariant();
            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). 위의 예제에서 페이지 메서드는 OnPost JoinList Async와 OnPost JoinListUC Async입니다.In the preceding example, the page methods are OnPost JoinList Async and OnPost JoinListUC Async. 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 경로는 https://localhost:5001/Customers/CreateFATH?handler=JoinList입니다.Using the preceding code, the URL path that submits to OnPostJoinListAsync is https://localhost:5001/Customers/CreateFATH?handler=JoinList. OnPostJoinListUCAsync에 제출되는 URL 경로는 https://localhost:5001/Customers/CreateFATH?handler=JoinListUC입니다.The URL path that submits to OnPostJoinListUCAsync is https://localhost:5001/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"을 사용하여 페이지의 기본 경로에 "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. 예를 들어 @page "{id}"를 사용하여 ID 매개 변수 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".

URL에서 쿼리 문자열 ?handler=JoinList를 사용하지 않으려면 경로를 변경하여 처리기 이름을 URL의 경로 부분에 넣습니다.If you don't like the query string ?handler=JoinList in the URL, change the route to put the handler name in the path portion of the URL. @page 지시문 뒤에 큰따옴표로 묶은 경로 템플릿을 추가하여 경로를 사용자 지정할 수 있습니다.The route can be customized 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 경로는 https://localhost:5001/Customers/CreateFATH/JoinList입니다.Using the preceding code, the URL path that submits to OnPostJoinListAsync is https://localhost:5001/Customers/CreateFATH/JoinList. OnPostJoinListUCAsync에 제출되는 URL 경로는 https://localhost:5001/Customers/CreateFATH/JoinListUC입니다.The URL path that submits to OnPostJoinListUCAsync is https://localhost:5001/Customers/CreateFATH/JoinListUC.

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

고급 구성 및 설정Advanced configuration and settings

다음 섹션의 구성 및 설정은 대부분의 앱에서 필요하지 않습니다.The configuration and settings in following sections is not required by most apps.

고급 옵션을 구성하려면 RazorPagesOptions를 구성하는 AddRazorPages 오버로드를 사용합니다.To configure advanced options, use the AddRazorPages overload that configures RazorPagesOptions:

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

RazorPagesOptions를 사용하여 페이지의 루트 디렉터리를 설정하거나 페이지에 대한 애플리케이션 모델 규칙을 추가할 수 있습니다.Use the RazorPagesOptions to set the root directory for pages, or add application model conventions for pages. 규칙에 대한 자세한 내용은 Razor Pages 권한 부여 규칙을 참조하세요.For more information on conventions, see Razor Pages authorization conventions.

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

Razor Pages가 컨텐츠 루트에 있도록 지정Specify that Razor Pages are at the content root

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

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

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

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

public void ConfigureServices(IServiceCollection services)
{            
    services.AddRazorPages(options =>
        {
            options.Conventions.AuthorizeFolder("/MyPages/Admin");
        })
        .WithRazorPagesRoot("/path/to/razor/pages");
}

추가 자료Additional resources

경고

Visual Studio 2017을 사용하는 경우 Visual Studio에서 작동하지 않는 .NET Core SDK 버전에 대한 자세한 내용은 dotnet/sdk issue #3124(dotnet/sdk 문제 #3124)를 참조하세요.If you use Visual Studio 2017, see dotnet/sdk issue #3124 for information about .NET Core SDK versions that don't work with Visual Studio.

Razor Pages 프로젝트 만들기Create a Razor Pages project

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

Razor PagesRazor Pages

Razor Pages는 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>

앞의 코드는 컨트롤러 및 뷰가 포함된 ASP.NET Core 앱에서 사용되는 Razor 뷰 파일과 매우 유사합니다.The preceding code looks a lot like a Razor view file used in an ASP.NET Core app with controllers and views. 차이점은 @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 클래스 파일의 이름은 .cs 가 추가된 Razor Page 파일의 이름과 동일합니다.By convention, the PageModel class file has the same name as the Razor Page file with .cs appended. 예를 들어 위의 Razor Page는 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 Page 경로 및 그와 일치하는 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 Pages 파일을 검색합니다.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.

기본적인 양식 작성하기Write a basic form

Razor Pages는 앱을 만들 때 웹 브라우저에서 사용되는 일반적인 패턴을 손쉽게 구현할 수 있도록 설계되었습니다.Razor Pages is designed to make common patterns used with web browsers easy to implement when building an app. 모델 바인딩, 태그 도우미 및 HTML 도우미는 모두 Razor Page 클래스에 정의된 속성을 통해서 ‘정확하게 작동’합니다.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:

이 페이지에는 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. 위의 코드는 Razor Pages의 일반적인 코드입니다.The preceding code is typical for Razor Pages.

컨트롤러 및 뷰를 사용하는 ASP.NET 앱에 대해 잘 알고 있는 경우:If you're familiar with ASP.NET apps using controllers and views:

  • 앞 예제의 OnPostAsync 코드는 일반적인 컨트롤러 코드와 비슷합니다.The OnPostAsync code in the preceding example looks similar to typical controller code.
  • 모델 바인딩, 유효성 검사, 유효성 검사 및 작업 결과 같은 MVC의 기본적인 기능들이 대부분 공유됩니다.Most of the MVC primitives like model binding, validation, 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 Pages는 기본적으로 비 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. 쿼리 문자열이나 경로 값을 사용하는 시나리오를 지정할 때 GET 바인딩을 옵트인하면 유용합니다.Opting into GET binding is useful when addressing scenarios that rely on query string or route values.

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

[BindProperty(SupportsGet = true)]

자세한 내용은 ASP.NET Core Community 스탠드업을 참조하세요. 토론 가져오기(YouTube)에서 바인딩합니다.For more information, see ASP.NET Core Community Standup: Bind on GET discussion (YouTube).

홈페이지(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>

<a asp-page="./Edit" asp-route-id="@contact.Id">Edit</a> 앵커 태그 도우미는 편집 페이지에 대한 링크를 생성하기 위해 asp-route-{value} 특성을 사용합니다.The <a asp-page="./Edit" asp-route-id="@contact.Id">Edit</a> 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. 예: https://localhost:5001/Edit/1.For example, https://localhost:5001/Edit/1. 태그 도우미를 사용하면 Razor 파일에서 HTML 요소를 만들고 렌더링하는 데 서버 쪽 코드를 사용할 수 있습니다.Tag Helpers enable server-side code to participate in creating and rendering HTML elements in Razor files. 태그 도우미는 @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers를 통해 사용할 수 있습니다.Tag Helpers are enabled by @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

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 특성으로 지정된 고객 연락처의 ID.The customer contact ID specified by the asp-route-id attribute.
  • asp-page-handler 특성으로 지정된 handlerThe handler specified by the asp-page-handler attribute.

고객 연락처 ID 1에 대해 렌더링된 삭제 단추의 예는 다음과 같습니다.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. 규약에 따라 처리기 메서드의 이름은 handler 매개 변수의 값을 기반으로 OnPost[handler]Async 체계에 의해 선택됩니다.By convention, the name of the handler method is selected based on the value of the handler parameter according to the scheme OnPost[handler]Async.

이번 예제에서는 handlerdelete이므로 POST 요청을 처리하기 위해 OnPostDeleteAsync 처리기 메서드가 사용됩니다.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 handler method with the name OnPostRemoveAsync is selected. 다음은 OnPostDeleteAsync 처리기를 보여 주는 코드입니다.The following code shows the OnPostDeleteAsync handler:

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. Index.cshtml 페이지 지시문에 라우팅 제약 조건 "{id:int?}"이 포함된 경우 id는 경로 데이터에서 제공됩니다.If the Index.cshtml page directive contained routing constraint "{id:int?}", id would come from route data. id의 경로 데이터는 https://localhost:5001/Customers/2와 같은 URI에 지정됩니다.The route data for id is specified in the URI such as https://localhost:5001/Customers/2.
  • 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 as required

PageModel의 속성에는 필수 특성을 적용할 수 있습니다.Properties on a PageModel can be marked 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");
        }
    }
}

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

OnGet 처리기 대체를 사용하여 HEAD 요청 처리Handle HEAD requests with an OnGet handler fallback

HEAD 요청을 사용하면 특정 리소스의 헤더를 검색할 수 있습니다.HEAD requests allow you to retrieve the headers for a specific resource. GET 요청과는 달리 HEAD 요청은 응답 본문을 반환하지 않습니다.Unlike GET requests, HEAD requests don't return a response body.

일반적으로 HEAD 요청에 대한 OnHead 처리기를 만들고 호출합니다.Ordinarily, an OnHead handler is created and called for HEAD requests:

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

만약 정의된 OnHead 처리기가 없다면 ASP.NET Core 2.1 이상에서는 Razor Pages가 OnGet 처리기 호출로 대체합니다.In ASP.NET Core 2.1 or later, Razor Pages falls back to calling the OnGet handler if no OnHead handler is defined. 이 동작은 Startup.ConfigureServicesSetCompatibilityVersion에 대한 호출에 의해 사용 설정됩니다.This behavior is enabled by the call to SetCompatibilityVersion in Startup.ConfigureServices:

services.AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

기본 템플릿은 ASP.NET Core 2.1 및 2.2에서 SetCompatibilityVersion 호출을 생성합니다.The default templates generate the SetCompatibilityVersion call in ASP.NET Core 2.1 and 2.2. SetCompatibilityVersion은 효과적으로 Razor Pages 옵션 AllowMappingHeadRequestsToGetHandlertrue로 설정합니다.SetCompatibilityVersion effectively sets the Razor Pages option AllowMappingHeadRequestsToGetHandler to true.

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

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

XSRF/CSRF 및 Razor PagesXSRF/CSRF and Razor Pages

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

Razor Pages에서 레이아웃, 부분 뷰, 템플릿 및 태그 도우미 사용하기Using Layouts, partials, templates, and Tag Helpers with Razor Pages

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:

<!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:

  • 각 페이지의 레이아웃을 제어합니다(페이지가 명시적으로 레이아웃을 사용하지 않는 경우 제외).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.

레이아웃 파일은 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 Pages는 경로 규칙이 아닌 폴더 계층 구조를 사용해야 합니다.Razor Pages are meant to rely on folder hierarchy, not path conventions.

Razor Page의 뷰 검색에는 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 Page에 대해 생성되는 네임스페이스는 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 시작 프로젝트에는 클라이언트 측 유효성 검사를 연결하는 Pages/_ValidationScriptsPartial.cshtml 이 포함되어 있습니다.The Razor Pages starter project contains the Pages/_ValidationScriptsPartial.cshtml, which hooks up client-side validation.

부분 뷰에 대한 자세한 내용은 ASP.NET Core의 부분 보기를 참고하시기 바랍니다.For more information on partial views, see ASP.NET Core의 부분 보기.

페이지에 대한 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).

다른 영역에서 페이지로 리디렉션하려면 영역을 지정하세요.To redirect to a page in a different Area, specify the area:

RedirectToPage("/Index", new { area = "Services" });

자세한 내용은 ASP.NET Core의 영역를 참조하세요.For more information, see ASP.NET Core의 영역.

ViewData 특성ViewData attribute

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

다음 예제에서 AboutModel에는 [ViewData]가 표시된 Title 속성이 존재합니다.In the following example, the AboutModel contains a Title property marked with [ViewData]. Title 속성은 About 페이지의 제목으로 설정됩니다.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를 사용하여 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 페이지 모델은 Message 속성에 [TempData] 특성을 적용합니다.The Pages/Customers/Index.cshtml.cs page model applies the [TempData] attribute to the Message property.

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

자세한 내용은 TempData를 참고하시기 바랍니다.For more information, see TempData .

한 페이지에 대한 여러 처리기Multiple handlers per page

다음 페이지는 asp-page-handler 태그 도우미를 사용하여 두 처리기에 대한 태그를 생성합니다.The following page generates markup for two 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?.ToUpperInvariant();
            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). 위의 예제에서 페이지 메서드는 OnPost JoinList Async와 OnPost JoinListUC Async입니다.In the preceding example, the page methods are OnPost JoinList Async and OnPost JoinListUC Async. 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 경로는 https://localhost:5001/Customers/CreateFATH?handler=JoinList입니다.Using the preceding code, the URL path that submits to OnPostJoinListAsync is https://localhost:5001/Customers/CreateFATH?handler=JoinList. OnPostJoinListUCAsync에 제출되는 URL 경로는 https://localhost:5001/Customers/CreateFATH?handler=JoinListUC입니다.The URL path that submits to OnPostJoinListUCAsync is https://localhost:5001/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"을 사용하여 페이지의 기본 경로에 "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. 예를 들어 @page "{id}"를 사용하여 ID 매개 변수 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".

URL에서 쿼리 문자열 ?handler=JoinList를 사용하지 않으려면 경로를 변경하여 처리기 이름을 URL의 경로 부분에 넣습니다.If you don't like the query string ?handler=JoinList in the URL, change the route to put the handler name in the path portion of the URL. @page 지시문 뒤에 큰따옴표로 묶은 경로 템플릿을 추가하여 경로를 사용자 지정할 수 있습니다.The route can be customized 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 경로는 https://localhost:5001/Customers/CreateFATH/JoinList입니다.Using the preceding code, the URL path that submits to OnPostJoinListAsync is https://localhost:5001/Customers/CreateFATH/JoinList. OnPostJoinListUCAsync에 제출되는 URL 경로는 https://localhost:5001/Customers/CreateFATH/JoinListUC입니다.The URL path that submits to OnPostJoinListUCAsync is https://localhost:5001/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 Pages 시작하기를 참조하세요.See Get started with Razor Pages, which builds on this introduction.

Razor Pages가 컨텐츠 루트에 있도록 지정Specify that Razor Pages are at the content root

기본적으로 Razor Pages의 루트 경로는 /Pages 디렉터리입니다.By default, Razor Pages are rooted in the /Pages directory. AddMvcWithRazorPagesAtContentRoot를 추가하여 Razor Pages가 앱의 콘텐츠 루트(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 Pages가 사용자 지정 루트 디렉터리에 있도록 지정Specify that Razor Pages are at a custom root directory

AddMvcWithRazorPagesRoot를 추가하여 Razor Pages가 앱의 사용자 지정 루트 디렉터리에 있도록 지정합니다(상대 경로 제공).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");

추가 자료Additional resources