Share via


3부. ASP.NET Core의 스캐폴드된 Razor Pages

참고 항목

이 문서의 최신 버전은 아닙니다. 현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.

Important

이 정보는 상업적으로 출시되기 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적, 또는 묵시적인 보증을 하지 않습니다.

현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.

작성자: Rick Anderson

이 자습서에서는 이전 자습서에서 스캐폴딩을 통해 만든 Razor 페이지를 살펴봅니다.

만들기, 삭제, 세부 정보 및 편집 페이지

Pages/Movies/Index.cshtml.cs 페이지 모델을 살펴봅니다.

using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Models;

namespace RazorPagesMovie.Pages.Movies;

public class IndexModel : PageModel
{
    private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

    public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
    {
        _context = context;
    }

    public IList<Movie> Movie { get;set; }  = default!;

    public async Task OnGetAsync()
    {
        if (_context.Movie != null)
        {
            Movie = await _context.Movie.ToListAsync();
        }
    }
}

Razor Pages는 PageModel에서 파생됩니다. 일반적으로 PageModel 파생 클래스의 이름은 PageNameModel로 지정됩니다. 예를 들어 인덱스 페이지의 이름은 IndexModel로 지정됩니다.

생성자는 종속성 주입을 사용하여 RazorPagesMovieContext를 페이지에 추가합니다.

public class IndexModel : PageModel
{
    private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

    public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
    {
        _context = context;
    }

Entity Framework로 비동기 프로그래밍에 대한 자세한 내용은 비동기 코드를 참조하세요.

페이지에 대한 GET 요청을 만들면 OnGetAsync 메서드가 Razor Page에 동영상 목록을 반환합니다. Razor 페이지에서 OnGetAsync 또는 OnGet을 호출하여 페이지 상태를 초기화합니다. 이 경우 OnGetAsync는 동영상 목록을 가져와 표시합니다.

OnGetvoid를 반환하거나 OnGetAsyncTask를 반환하면 return 문이 사용되지 않은 것입니다. 예를 들어 Privacy 페이지를 검토합니다.

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

namespace RazorPagesMovie.Pages
{
    public class PrivacyModel : PageModel
    {
        private readonly ILogger<PrivacyModel> _logger;

        public PrivacyModel(ILogger<PrivacyModel> logger)
        {
            _logger = logger;
        }

        public void OnGet()
        {
        }
    }
}

반환 형식이 IActionResult 또는 Task<IActionResult>이면 반환 문을 제공해야 합니다. 예를 들어 Pages/Movies/Create.cshtml.cs OnPostAsync 메서드입니다.

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

    _context.Movie.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Pages/Movies/Index.cshtmlRazor페이지를 살펴봅니다.

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model.Movie) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                <a asp-page="./Edit" asp-route-id="@item.Id">Edit</a> |
                <a asp-page="./Details" asp-route-id="@item.Id">Details</a> |
                <a asp-page="./Delete" asp-route-id="@item.Id">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Razor는 HTML에서 C# 또는 Razor 관련 태그로 전환될 수 있습니다. @ 기호 뒤에 Razor 예약 키워드가 사용되면 이 기호는 Razor 관련 태그로 전환됩니다. 이외의 경우에는 C#으로 전환됩니다.

@page 지시문

@pageRazor 지시문은 파일을 MVC 작업으로 만듭니다. 이는 요청을 처리할 수 있음을 의미합니다. @page는 페이지의 첫 번째 Razor 지시문이어야 합니다. @page@model은 Razor 관련 태그로 전환되는 예입니다. 자세한 내용은 Razor 구문을 참조하세요.

@model 지시문

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@model 지시문은 Razor Page에 전달되는 모델 형식을 지정합니다. 위의 예제에서 @model 줄은 Razor Page에서 PageModel 파생 클래스를 사용할 수 있게 만듭니다. 모델은 페이지에서 @Html.DisplayNameFor@Html.DisplayForHTML 도우미에서 사용됩니다.

다음 HTML 도우미에서 사용되는 람다 식을 살펴봅니다.

@Html.DisplayNameFor(model => model.Movie[0].Title)

DisplayNameFor HTML 도우미는 람다 식에서 참조되는 Title 속성을 검사하여 표시 이름을 확인합니다. 람다 식은 계산되는 것이 아니라 검사됩니다. 즉, model, model.Movie 또는 model.Movie[0]null이거나 비어 있을 경우 액세스 위반이 없습니다. 람다 식이 계산될 경우(예: @Html.DisplayFor(modelItem => item.Title) 사용) 모델의 속성 값이 계산됩니다.

레이아웃 페이지

메뉴 링크 RazorPagesMovie, HomePrivacy를 선택합니다. 각 페이지는 동일한 메뉴 레이아웃을 표시합니다. 메뉴 레이아웃은 파일에서 Pages/Shared/_Layout.cshtml 구현됩니다.

Pages/Shared/_Layout.cshtml 파일을 열어 검사합니다.

레이아웃 템플릿을 사용하여 HTML 컨테이너 레이아웃을 다음과 같이 지정할 수 있습니다.

  • 한 위치에 지정됩니다.
  • 사이트의 여러 페이지에 적용됩니다.

@RenderBody() 줄을 찾습니다. RenderBody는 사용자가 만드는 모든 페이지 특정 보기가 표시되는 자리 표시자이며 레이아웃 페이지에서 래핑됩니다. 예를 들어 링크를 선택하면 Privacy 보기가 Pages/Privacy.cshtml 메서드 내부에 RenderBody 렌더링됩니다.

ViewData 및 레이아웃

파일에서 다음 태그를 고려합니다.Pages/Movies/Index.cshtml

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

강조 표시된 이전 태그는 C#으로 전환되는 Razor의 예제입니다. {} 문자로 C# 코드 블록을 묶습니다.

PageModel 기본 클래스에는 데이터를 뷰에 전달하는 데 사용할 수 있는 ViewData 사전 속성이 있습니다. 키 값 패턴을 사용하여 개체가 ViewData 사전에 추가됩니다. 이전 샘플에서는 Title 속성이 ViewData 사전에 추가됩니다.

Title 속성이 Pages/Shared/_Layout.cshtml 파일에서 사용됩니다. 다음 태그는 파일의 처음 몇 줄을 보여 줍니다 _Layout.cshtml .

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - RazorPagesMovie</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
    <link rel="stylesheet" href="~/RazorPagesMovie.styles.css" asp-append-version="true" />

레이아웃 업데이트

  1. Pages/Shared/_Layout.cshtml 파일의 <title> 요소를 변경하여 RazorPagesMovie 대신 Movie를 표시합니다.

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>@ViewData["Title"] - Movie</title>
    
  2. 파일에서 다음 앵커 요소를 찾습니다 Pages/Shared/_Layout.cshtml .

    <a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
    
  3. 이전 요소를 다음 태그로 바꿉니다.

    <a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>
    

    이전 앵커 요소는 태그 도우미입니다. 이 경우에는 앵커 태그 도우미입니다. asp-page="/Movies/Index" 태그 도우미 특성 및 값으로 /Movies/IndexRazor 페이지의 링크를 만듭니다. asp-area 특성 값이 비어 있으므로 영역은 링크에서 사용되지 않습니다. 자세한 내용은 영역을 참조하세요.

  4. 변경 내용을 저장하고 RpMovie 링크를 선택하여 앱을 테스트합니다. 문제가 있는 경우 GitHub에서 _Layout.cshtml 파일을 참조하세요.

  5. Home, RpMovie, 만들기, 편집삭제 링크를 테스트합니다. 각 페이지는 브라우저 탭에서 볼 수 있는 제목을 설정합니다. 페이지에 책갈피를 지정하면 책갈피에 제목이 사용됩니다.

참고 항목

Price 필드에 소수점을 입력하지 못할 수도 있습니다. 소수점으로 쉼표(",")를 사용하는 비영어 로캘 및 비미국 영어 날짜 형식에 대해 jQuery 유효성 검사를 지원하려면 앱을 세계화하는 단계를 수행해야 합니다. 소수점 추가에 대한 지침은 이 GitHub 문제 4076을 참조하세요.

Layout 속성은 Pages/_ViewStart.cshtml 파일에서 설정됩니다.

@{
    Layout = "_Layout";
}

위의 태그는 Pages 폴더의 모든 Razor 파일에 대해 레이아웃 파일로 Pages/Shared/_Layout.cshtml로 설정합니다. 자세한 내용은 레이아웃을 참조하세요.

Create 페이지 모델

페이지 모델을 검사합니다 Pages/Movies/Create.cshtml.cs .

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesMovie.Models;

namespace RazorPagesMovie.Pages.Movies
{
    public class CreateModel : PageModel
    {
        private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

        public CreateModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
        {
            _context = context;
        }

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

        [BindProperty]
        public Movie Movie { get; set; } = default!;
        

        // To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
        public async Task<IActionResult> OnPostAsync()
        {
          if (!ModelState.IsValid || _context.Movie == null || Movie == null)
            {
                return Page();
            }

            _context.Movie.Add(Movie);
            await _context.SaveChangesAsync();

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

OnGet 메서드는 페이지에 필요한 상태를 초기화합니다. 만들기 페이지에는 초기화할 상태가 없습니다. 따라서 Page가 반환됩니다. 자습서의 뒷부분에서 상태를 초기화하는 OnGet의 예가 나와 있습니다. 메서드는 Page 페이지를 렌더링하는 개체를 Create.cshtml 만듭니다PageResult.

Movie 속성은 BindProperty 특성을 사용하여 모델 바인딩을 옵트인합니다. 만들기 폼이 폼 값을 게시하면 ASP.NET Core 런타임이 게시된 값을 Movie 모델에 바인딩합니다.

페이지에 폼 데이터가 게시되면 OnPostAsync 메서드가 실행됩니다.

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

    _context.Movie.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

모델 오류가 있는 경우 폼과 게시된 모든 폼 데이터가 다시 표시됩니다. 대부분의 모델 오류는 폼이 게시되기 전에 클라이언트 쪽에서 catch할 수 있습니다. 예를 들어 데이터로 변환될 수 없는 날짜 필드에 대한 값을 게시하는 모델 오류가 발생할 수 있습니다. 클라이언트 쪽 유효성 검사 및 모델 유효성 검사는 자습서의 뒷부분에서 설명합니다.

모델 오류가 없는 경우:

  • 데이터가 저장됩니다.
  • 브라우저가 인덱스 페이지로 리디렉션됩니다.

Create Razor Page

Pages/Movies/Create.cshtmlRazor Page 파일을 살펴봅니다.

@page
@model RazorPagesMovie.Pages.Movies.CreateModel

@{
    ViewData["Title"] = "Create";
}

<h1>Create</h1>

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Movie.Title" class="control-label"></label>
                <input asp-for="Movie.Title" class="form-control" />
                <span asp-validation-for="Movie.Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Movie.ReleaseDate" class="control-label"></label>
                <input asp-for="Movie.ReleaseDate" class="form-control" />
                <span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Movie.Genre" class="control-label"></label>
                <input asp-for="Movie.Genre" class="form-control" />
                <span asp-validation-for="Movie.Genre" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Movie.Price" class="control-label"></label>
                <input asp-for="Movie.Price" class="form-control" />
                <span asp-validation-for="Movie.Price" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-page="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Visual Studio에서는 다음 태그를 태그 도우미에 사용되는 독특한 굵은 글꼴로 표시합니다.

  • <form method="post">
  • <div asp-validation-summary="ModelOnly" class="text-danger"></div>
  • <label asp-for="Movie.Title" class="control-label"></label>
  • <input asp-for="Movie.Title" class="form-control" />
  • <span asp-validation-for="Movie.Title" class="text-danger"></span>

Create.cshtml 페이지의 VS17 보기

<form method="post"> 요소는 폼 태그 도우미입니다. 폼 태그 도우미에는 위조 방지 토큰이 자동으로 포함됩니다.

스캐폴딩 엔진은 ID를 제외하고 다음과 비슷한 모델에서 필드마다 Razor 태그를 만듭니다.

<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
    <label asp-for="Movie.Title" class="control-label"></label>
    <input asp-for="Movie.Title" class="form-control" />
    <span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>

유효성 검사 태그 도우미 (<div asp-validation-summary<span asp-validation-for) 는 유효성 검사 오류를 표시합니다. 유효성 검사는 이 시리즈의 뒷부분에서 자세히 설명합니다.

레이블 태그 도우미(<label asp-for="Movie.Title" class="control-label"></label>)는 Title 속성에 대한 레이블 캡션 및 [for] 특성을 생성합니다.

입력 태그 도우미(<input asp-for="Movie.Title" class="form-control">)는 DataAnnotations 특성을 사용하고 클라이언트 쪽의 jQuery 유효성 검사에 필요한 HTML 특성을 생성합니다.

태그 도우미(예: <form method="post">)에 대한 자세한 내용은 ASP.NET Core의 태그 도우미를 참조하세요.

다음 단계

만들기, 삭제, 세부 정보 및 편집 페이지

Pages/Movies/Index.cshtml.cs 페이지 모델을 살펴봅니다.

using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Models;

namespace RazorPagesMovie.Pages.Movies;

public class IndexModel : PageModel
{
    private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

    public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
    {
        _context = context;
    }

    public IList<Movie> Movie { get;set; }  = default!;

    public async Task OnGetAsync()
    {
        if (_context.Movie != null)
        {
            Movie = await _context.Movie.ToListAsync();
        }
    }
}

Razor Pages는 PageModel에서 파생됩니다. 일반적으로 PageModel 파생 클래스의 이름은 PageNameModel로 지정됩니다. 예를 들어 인덱스 페이지의 이름은 IndexModel로 지정됩니다.

생성자는 종속성 주입을 사용하여 RazorPagesMovieContext를 페이지에 추가합니다.

public class IndexModel : PageModel
{
    private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

    public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
    {
        _context = context;
    }

Entity Framework로 비동기 프로그래밍에 대한 자세한 내용은 비동기 코드를 참조하세요.

페이지에 대한 GET 요청을 만들면 OnGetAsync 메서드가 Razor Page에 동영상 목록을 반환합니다. Razor 페이지에서 OnGetAsync 또는 OnGet을 호출하여 페이지 상태를 초기화합니다. 이 경우 OnGetAsync는 동영상 목록을 가져와 표시합니다.

OnGetvoid를 반환하거나 OnGetAsyncTask를 반환하면 return 문이 사용되지 않은 것입니다. 예를 들어 Privacy 페이지를 검토합니다.

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

namespace RazorPagesMovie.Pages
{
    public class PrivacyModel : PageModel
    {
        private readonly ILogger<PrivacyModel> _logger;

        public PrivacyModel(ILogger<PrivacyModel> logger)
        {
            _logger = logger;
        }

        public void OnGet()
        {
        }
    }
}

반환 형식이 IActionResult 또는 Task<IActionResult>이면 반환 문을 제공해야 합니다. 예를 들어 Pages/Movies/Create.cshtml.cs OnPostAsync 메서드입니다.

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

    _context.Movie.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Pages/Movies/Index.cshtmlRazor페이지를 살펴봅니다.

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model.Movie) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                <a asp-page="./Edit" asp-route-id="@item.Id">Edit</a> |
                <a asp-page="./Details" asp-route-id="@item.Id">Details</a> |
                <a asp-page="./Delete" asp-route-id="@item.Id">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Razor는 HTML에서 C# 또는 Razor 관련 태그로 전환될 수 있습니다. @ 기호 뒤에 Razor 예약 키워드가 사용되면 이 기호는 Razor 관련 태그로 전환됩니다. 이외의 경우에는 C#으로 전환됩니다.

@page 지시문

@pageRazor 지시문은 파일을 MVC 작업으로 만듭니다. 이는 요청을 처리할 수 있음을 의미합니다. @page는 페이지의 첫 번째 Razor 지시문이어야 합니다. @page@model은 Razor 관련 태그로 전환되는 예입니다. 자세한 내용은 Razor 구문을 참조하세요.

@model 지시문

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@model 지시문은 Razor Page에 전달되는 모델 형식을 지정합니다. 위의 예제에서 @model 줄은 Razor Page에서 PageModel 파생 클래스를 사용할 수 있게 만듭니다. 모델은 페이지에서 @Html.DisplayNameFor@Html.DisplayForHTML 도우미에서 사용됩니다.

다음 HTML 도우미에서 사용되는 람다 식을 살펴봅니다.

@Html.DisplayNameFor(model => model.Movie[0].Title)

DisplayNameFor HTML 도우미는 람다 식에서 참조되는 Title 속성을 검사하여 표시 이름을 확인합니다. 람다 식은 계산되는 것이 아니라 검사됩니다. 즉, model, model.Movie 또는 model.Movie[0]null이거나 비어 있을 경우 액세스 위반이 없습니다. 람다 식이 계산될 경우(예: @Html.DisplayFor(modelItem => item.Title) 사용) 모델의 속성 값이 계산됩니다.

레이아웃 페이지

메뉴 링크 RazorPagesMovie, HomePrivacy를 선택합니다. 각 페이지는 동일한 메뉴 레이아웃을 표시합니다. 메뉴 레이아웃은 파일에서 Pages/Shared/_Layout.cshtml 구현됩니다.

Pages/Shared/_Layout.cshtml 파일을 열어 검사합니다.

레이아웃 템플릿을 사용하여 HTML 컨테이너 레이아웃을 다음과 같이 지정할 수 있습니다.

  • 한 위치에 지정됩니다.
  • 사이트의 여러 페이지에 적용됩니다.

@RenderBody() 줄을 찾습니다. RenderBody는 사용자가 만드는 모든 페이지 특정 보기가 표시되는 자리 표시자이며 레이아웃 페이지에서 래핑됩니다. 예를 들어 링크를 선택하면 Privacy 보기가 Pages/Privacy.cshtml 메서드 내부에 RenderBody 렌더링됩니다.

ViewData 및 레이아웃

파일에서 다음 태그를 고려합니다.Pages/Movies/Index.cshtml

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

강조 표시된 이전 태그는 C#으로 전환되는 Razor의 예제입니다. {} 문자로 C# 코드 블록을 묶습니다.

PageModel 기본 클래스에는 데이터를 뷰에 전달하는 데 사용할 수 있는 ViewData 사전 속성이 있습니다. 키 값 패턴을 사용하여 개체가 ViewData 사전에 추가됩니다. 이전 샘플에서는 Title 속성이 ViewData 사전에 추가됩니다.

Title 속성이 Pages/Shared/_Layout.cshtml 파일에서 사용됩니다. 다음 태그는 파일의 처음 몇 줄을 보여 줍니다 _Layout.cshtml .

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - RazorPagesMovie</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
    <link rel="stylesheet" href="~/RazorPagesMovie.styles.css" asp-append-version="true" />

@*Markup removed for brevity.*@ 줄은 Razor 주석입니다. HTML 주석 <!-- -->과 달리 Razor 주석은 클라이언트에 전송되지 않습니다. 자세한 내용은 MDN 웹 문서: HTML 시작을 참조하세요.

레이아웃 업데이트

  1. Pages/Shared/_Layout.cshtml 파일의 <title> 요소를 변경하여 RazorPagesMovie 대신 Movie를 표시합니다.

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>@ViewData["Title"] - Movie</title>
    
  2. 파일에서 다음 앵커 요소를 찾습니다 Pages/Shared/_Layout.cshtml .

    <a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
    
  3. 이전 요소를 다음 태그로 바꿉니다.

    <a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>
    

    이전 앵커 요소는 태그 도우미입니다. 이 경우에는 앵커 태그 도우미입니다. asp-page="/Movies/Index" 태그 도우미 특성 및 값으로 /Movies/IndexRazor 페이지의 링크를 만듭니다. asp-area 특성 값이 비어 있으므로 영역은 링크에서 사용되지 않습니다. 자세한 내용은 영역을 참조하세요.

  4. 변경 내용을 저장하고 RpMovie 링크를 선택하여 앱을 테스트합니다. 문제가 있는 경우 GitHub에서 _Layout.cshtml 파일을 참조하세요.

  5. Home, RpMovie, 만들기, 편집삭제 링크를 테스트합니다. 각 페이지는 브라우저 탭에서 볼 수 있는 제목을 설정합니다. 페이지에 책갈피를 지정하면 책갈피에 제목이 사용됩니다.

참고 항목

Price 필드에 소수점을 입력하지 못할 수도 있습니다. 소수점으로 쉼표(",")를 사용하는 비영어 로캘 및 비미국 영어 날짜 형식에 대해 jQuery 유효성 검사를 지원하려면 앱을 세계화하는 단계를 수행해야 합니다. 소수점 추가에 대한 지침은 이 GitHub 문제 4076을 참조하세요.

Layout 속성은 Pages/_ViewStart.cshtml 파일에서 설정됩니다.

@{
    Layout = "_Layout";
}

위의 태그는 Pages 폴더의 모든 Razor 파일에 대해 레이아웃 파일로 Pages/Shared/_Layout.cshtml로 설정합니다. 자세한 내용은 레이아웃을 참조하세요.

Create 페이지 모델

페이지 모델을 검사합니다 Pages/Movies/Create.cshtml.cs .

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesMovie.Models;

namespace RazorPagesMovie.Pages.Movies
{
    public class CreateModel : PageModel
    {
        private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

        public CreateModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
        {
            _context = context;
        }

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

        [BindProperty]
        public Movie Movie { get; set; } = default!;
        

        // To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
        public async Task<IActionResult> OnPostAsync()
        {
          if (!ModelState.IsValid || _context.Movie == null || Movie == null)
            {
                return Page();
            }

            _context.Movie.Add(Movie);
            await _context.SaveChangesAsync();

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

OnGet 메서드는 페이지에 필요한 상태를 초기화합니다. 만들기 페이지에는 초기화할 상태가 없습니다. 따라서 Page가 반환됩니다. 자습서의 뒷부분에서 상태를 초기화하는 OnGet의 예가 나와 있습니다. 메서드는 Page 페이지를 렌더링하는 개체를 Create.cshtml 만듭니다PageResult.

Movie 속성은 BindProperty 특성을 사용하여 모델 바인딩을 옵트인합니다. 만들기 폼이 폼 값을 게시하면 ASP.NET Core 런타임이 게시된 값을 Movie 모델에 바인딩합니다.

페이지에 폼 데이터가 게시되면 OnPostAsync 메서드가 실행됩니다.

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

    _context.Movie.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

모델 오류가 있는 경우 폼과 게시된 모든 폼 데이터가 다시 표시됩니다. 대부분의 모델 오류는 폼이 게시되기 전에 클라이언트 쪽에서 catch할 수 있습니다. 예를 들어 데이터로 변환될 수 없는 날짜 필드에 대한 값을 게시하는 모델 오류가 발생할 수 있습니다. 클라이언트 쪽 유효성 검사 및 모델 유효성 검사는 자습서의 뒷부분에서 설명합니다.

모델 오류가 없는 경우:

  • 데이터가 저장됩니다.
  • 브라우저가 인덱스 페이지로 리디렉션됩니다.

Create Razor Page

Pages/Movies/Create.cshtmlRazor Page 파일을 살펴봅니다.

@page
@model RazorPagesMovie.Pages.Movies.CreateModel

@{
    ViewData["Title"] = "Create";
}

<h1>Create</h1>

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Movie.Title" class="control-label"></label>
                <input asp-for="Movie.Title" class="form-control" />
                <span asp-validation-for="Movie.Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Movie.ReleaseDate" class="control-label"></label>
                <input asp-for="Movie.ReleaseDate" class="form-control" />
                <span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Movie.Genre" class="control-label"></label>
                <input asp-for="Movie.Genre" class="form-control" />
                <span asp-validation-for="Movie.Genre" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Movie.Price" class="control-label"></label>
                <input asp-for="Movie.Price" class="form-control" />
                <span asp-validation-for="Movie.Price" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-page="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Visual Studio에서는 다음 태그를 태그 도우미에 사용되는 독특한 굵은 글꼴로 표시합니다.

  • <form method="post">
  • <div asp-validation-summary="ModelOnly" class="text-danger"></div>
  • <label asp-for="Movie.Title" class="control-label"></label>
  • <input asp-for="Movie.Title" class="form-control" />
  • <span asp-validation-for="Movie.Title" class="text-danger"></span>

Create.cshtml 페이지의 VS17 보기

<form method="post"> 요소는 폼 태그 도우미입니다. 폼 태그 도우미에는 위조 방지 토큰이 자동으로 포함됩니다.

스캐폴딩 엔진은 ID를 제외하고 다음과 비슷한 모델에서 필드마다 Razor 태그를 만듭니다.

<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
    <label asp-for="Movie.Title" class="control-label"></label>
    <input asp-for="Movie.Title" class="form-control" />
    <span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>

유효성 검사 태그 도우미 (<div asp-validation-summary<span asp-validation-for) 는 유효성 검사 오류를 표시합니다. 유효성 검사는 이 시리즈의 뒷부분에서 자세히 설명합니다.

레이블 태그 도우미(<label asp-for="Movie.Title" class="control-label"></label>)는 Title 속성에 대한 레이블 캡션 및 [for] 특성을 생성합니다.

입력 태그 도우미(<input asp-for="Movie.Title" class="form-control">)는 DataAnnotations 특성을 사용하고 클라이언트 쪽의 jQuery 유효성 검사에 필요한 HTML 특성을 생성합니다.

태그 도우미(예: <form method="post">)에 대한 자세한 내용은 ASP.NET Core의 태그 도우미를 참조하세요.

다음 단계

만들기, 삭제, 세부 정보 및 편집 페이지

Pages/Movies/Index.cshtml.cs 페이지 모델을 살펴봅니다.

using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Models;

namespace RazorPagesMovie.Pages.Movies
{
    public class IndexModel : PageModel
    {
        private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

        public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
        {
            _context = context;
        }

        public IList<Movie> Movie { get;set; } = default!;

        public async Task OnGetAsync()
        {
            if (_context.Movie != null)
            {
                Movie = await _context.Movie.ToListAsync();
            }
        }
    }
}

Razor Pages는 PageModel에서 파생됩니다. 일반적으로 PageModel 파생 클래스의 이름은 PageNameModel로 지정됩니다. 예를 들어 인덱스 페이지의 이름은 IndexModel로 지정됩니다.

생성자는 종속성 주입을 사용하여 RazorPagesMovieContext를 페이지에 추가합니다.

public class IndexModel : PageModel
{
    private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

    public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
    {
        _context = context;
    }

Entity Framework로 비동기 프로그래밍에 대한 자세한 내용은 비동기 코드를 참조하세요.

페이지에 대한 요청을 만들면 OnGetAsync 메서드가 Razor Page에 동영상 목록을 반환합니다. Razor 페이지에서 OnGetAsync 또는 OnGet을 호출하여 페이지 상태를 초기화합니다. 이 경우 OnGetAsync는 동영상 목록을 가져와 표시합니다.

OnGetvoid를 반환하거나 OnGetAsyncTask를 반환하면 return 문이 사용되지 않은 것입니다. 예를 들어 Privacy 페이지를 검토합니다.

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

namespace RazorPagesMovie.Pages
{
    public class PrivacyModel : PageModel
    {
        private readonly ILogger<PrivacyModel> _logger;

        public PrivacyModel(ILogger<PrivacyModel> logger)
        {
            _logger = logger;
        }

        public void OnGet()
        {
        }
    }
}

반환 형식이 IActionResult 또는 Task<IActionResult>이면 반환 문을 제공해야 합니다. 예를 들어 Pages/Movies/Create.cshtml.csOnPostAsync 메서드입니다.

public async Task<IActionResult> OnPostAsync()
{
  if (!ModelState.IsValid || _context.Movie == null || Movie == null)
    {
        return Page();
    }

    _context.Movie.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Pages/Movies/Index.cshtmlRazor페이지를 살펴봅니다.

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model.Movie) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                <a asp-page="./Edit" asp-route-id="@item.ID">Edit</a> |
                <a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
                <a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Razor는 HTML에서 C# 또는 Razor 관련 태그로 전환될 수 있습니다. @ 기호 뒤에 Razor 예약 키워드가 사용되면 이 기호는 Razor 관련 태그로 전환됩니다. 이외의 경우에는 C#으로 전환됩니다.

@page 지시문

@pageRazor 지시문은 파일을 MVC 작업으로 만듭니다. 이는 요청을 처리할 수 있음을 의미합니다. @page는 페이지의 첫 번째 Razor 지시문이어야 합니다. @page@model은 Razor 관련 태그로 전환되는 예입니다. 자세한 내용은 Razor 구문을 참조하세요.

@model 지시문

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@model 지시문은 Razor Page에 전달되는 모델 형식을 지정합니다. 위의 예제에서 @model 줄은 Razor Page에서 PageModel 파생 클래스를 사용할 수 있게 만듭니다. 모델은 페이지에서 @Html.DisplayNameFor@Html.DisplayForHTML 도우미에서 사용됩니다.

다음 HTML 도우미에서 사용되는 람다 식을 살펴봅니다.

@Html.DisplayNameFor(model => model.Movie[0].Title)

DisplayNameFor HTML 도우미는 람다 식에서 참조되는 Title 속성을 검사하여 표시 이름을 확인합니다. 람다 식은 계산되는 것이 아니라 검사됩니다. 즉, model, model.Movie 또는 model.Movie[0]null이거나 비어 있을 경우 액세스 위반이 없습니다. 람다 식이 계산될 경우(예: @Html.DisplayFor(modelItem => item.Title) 사용) 모델의 속성 값이 계산됩니다.

레이아웃 페이지

메뉴 링크 RazorPagesMovie, HomePrivacy를 선택합니다. 각 페이지는 동일한 메뉴 레이아웃을 표시합니다. 메뉴 레이아웃은 파일에서 Pages/Shared/_Layout.cshtml 구현됩니다.

Pages/Shared/_Layout.cshtml 파일을 열어 검사합니다.

레이아웃 템플릿을 사용하여 HTML 컨테이너 레이아웃을 다음과 같이 지정할 수 있습니다.

  • 한 위치에 지정됩니다.
  • 사이트의 여러 페이지에 적용됩니다.

@RenderBody() 줄을 찾습니다. RenderBody는 사용자가 만드는 모든 페이지 특정 보기가 표시되는 자리 표시자이며 레이아웃 페이지에서 래핑됩니다. 예를 들어 링크를 선택하면 Privacy 보기가 Pages/Privacy.cshtml 메서드 내부에 RenderBody 렌더링됩니다.

ViewData 및 레이아웃

파일에서 다음 태그를 고려합니다.Pages/Movies/Index.cshtml

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

강조 표시된 이전 태그는 C#으로 전환되는 Razor의 예제입니다. {} 문자로 C# 코드 블록을 묶습니다.

PageModel 기본 클래스에는 데이터를 뷰에 전달하는 데 사용할 수 있는 ViewData 사전 속성이 있습니다. 키 값 패턴을 사용하여 개체가 ViewData 사전에 추가됩니다. 이전 샘플에서는 Title 속성이 ViewData 사전에 추가됩니다.

Title 속성이 Pages/Shared/_Layout.cshtml 파일에서 사용됩니다. 다음 태그는 파일의 처음 몇 줄을 보여 줍니다 _Layout.cshtml .

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

     @*Markup removed for brevity.*@
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />

@*Markup removed for brevity.*@ 줄은 Razor 주석입니다. HTML 주석 <!-- -->과 달리 Razor 주석은 클라이언트에 전송되지 않습니다. 자세한 내용은 MDN 웹 문서: HTML 시작을 참조하세요.

레이아웃 업데이트

  1. Pages/Shared/_Layout.cshtml 파일의 <title> 요소를 변경하여 RazorPagesMovie 대신 Movie를 표시합니다.

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>@ViewData["Title"] - Movie</title>
    
  2. 파일에서 다음 앵커 요소를 찾습니다 Pages/Shared/_Layout.cshtml .

    <a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
    
  3. 이전 요소를 다음 태그로 바꿉니다.

    <a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>
    

    이전 앵커 요소는 태그 도우미입니다. 이 경우에는 앵커 태그 도우미입니다. asp-page="/Movies/Index" 태그 도우미 특성 및 값으로 /Movies/IndexRazor 페이지의 링크를 만듭니다. asp-area 특성 값이 비어 있으므로 영역은 링크에서 사용되지 않습니다. 자세한 내용은 영역을 참조하세요.

  4. 변경 내용을 저장하고 RpMovie 링크를 선택하여 앱을 테스트합니다. 문제가 있는 경우 GitHub에서 _Layout.cshtml 파일을 참조하세요.

  5. Home, RpMovie, 만들기, 편집삭제 링크를 테스트합니다. 각 페이지는 브라우저 탭에서 볼 수 있는 제목을 설정합니다. 페이지에 책갈피를 지정하면 책갈피에 제목이 사용됩니다.

참고 항목

Price 필드에 소수점을 입력하지 못할 수도 있습니다. 소수점으로 쉼표(",")를 사용하는 비영어 로캘 및 비미국 영어 날짜 형식에 대해 jQuery 유효성 검사를 지원하려면 앱을 세계화하는 단계를 수행해야 합니다. 소수점 추가에 대한 지침은 이 GitHub 문제 4076을 참조하세요.

Layout 속성은 Pages/_ViewStart.cshtml 파일에서 설정됩니다.

@{
    Layout = "_Layout";
}

위의 태그는 Pages 폴더의 모든 Razor 파일에 대해 레이아웃 파일로 Pages/Shared/_Layout.cshtml로 설정합니다. 자세한 내용은 레이아웃을 참조하세요.

Create 페이지 모델

페이지 모델을 검사합니다 Pages/Movies/Create.cshtml.cs .

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesMovie.Models;

namespace RazorPagesMovie.Pages.Movies
{
    public class CreateModel : PageModel
    {
        private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

        public CreateModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
        {
            _context = context;
        }

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

        [BindProperty]
        public Movie Movie { get; set; } = default!;
        

        // To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
        public async Task<IActionResult> OnPostAsync()
        {
          if (!ModelState.IsValid || _context.Movie == null || Movie == null)
            {
                return Page();
            }

            _context.Movie.Add(Movie);
            await _context.SaveChangesAsync();

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

OnGet 메서드는 페이지에 필요한 상태를 초기화합니다. 만들기 페이지에는 초기화할 상태가 없습니다. 따라서 Page가 반환됩니다. 자습서의 뒷부분에서 상태를 초기화하는 OnGet의 예가 나와 있습니다. 메서드는 Page 페이지를 렌더링하는 개체를 Create.cshtml 만듭니다PageResult.

Movie 속성은 BindProperty 특성을 사용하여 모델 바인딩을 옵트인합니다. 만들기 폼이 폼 값을 게시하면 ASP.NET Core 런타임이 게시된 값을 Movie 모델에 바인딩합니다.

페이지에 폼 데이터가 게시되면 OnPostAsync 메서드가 실행됩니다.

public async Task<IActionResult> OnPostAsync()
{
  if (!ModelState.IsValid || _context.Movie == null || Movie == null)
    {
        return Page();
    }

    _context.Movie.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

모델 오류가 있는 경우 폼과 게시된 모든 폼 데이터가 다시 표시됩니다. 대부분의 모델 오류는 폼이 게시되기 전에 클라이언트 쪽에서 catch할 수 있습니다. 예를 들어 데이터로 변환될 수 없는 날짜 필드에 대한 값을 게시하는 모델 오류가 발생할 수 있습니다. 클라이언트 쪽 유효성 검사 및 모델 유효성 검사는 자습서의 뒷부분에서 설명합니다.

모델 오류가 없는 경우:

  • 데이터가 저장됩니다.
  • 브라우저가 인덱스 페이지로 리디렉션됩니다.

Create Razor Page

Pages/Movies/Create.cshtmlRazor Page 파일을 살펴봅니다.

@page
@model RazorPagesMovie.Pages.Movies.CreateModel

@{
    ViewData["Title"] = "Create";
}

<h1>Create</h1>

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Movie.Title" class="control-label"></label>
                <input asp-for="Movie.Title" class="form-control" />
                <span asp-validation-for="Movie.Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Movie.ReleaseDate" class="control-label"></label>
                <input asp-for="Movie.ReleaseDate" class="form-control" />
                <span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Movie.Genre" class="control-label"></label>
                <input asp-for="Movie.Genre" class="form-control" />
                <span asp-validation-for="Movie.Genre" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Movie.Price" class="control-label"></label>
                <input asp-for="Movie.Price" class="form-control" />
                <span asp-validation-for="Movie.Price" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-page="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Visual Studio에서는 다음 태그를 태그 도우미에 사용되는 독특한 굵은 글꼴로 표시합니다.

  • <form method="post">
  • <div asp-validation-summary="ModelOnly" class="text-danger"></div>
  • <label asp-for="Movie.Title" class="control-label"></label>
  • <input asp-for="Movie.Title" class="form-control" />
  • <span asp-validation-for="Movie.Title" class="text-danger"></span>

Create.cshtml 페이지의 VS17 보기

<form method="post"> 요소는 폼 태그 도우미입니다. 폼 태그 도우미에는 위조 방지 토큰이 자동으로 포함됩니다.

스캐폴딩 엔진은 ID를 제외하고 다음과 비슷한 모델에서 필드마다 Razor 태그를 만듭니다.

<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
    <label asp-for="Movie.Title" class="control-label"></label>
    <input asp-for="Movie.Title" class="form-control" />
    <span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>

유효성 검사 태그 도우미 (<div asp-validation-summary<span asp-validation-for) 는 유효성 검사 오류를 표시합니다. 유효성 검사는 이 시리즈의 뒷부분에서 자세히 설명합니다.

레이블 태그 도우미(<label asp-for="Movie.Title" class="control-label"></label>)는 Title 속성에 대한 레이블 캡션 및 [for] 특성을 생성합니다.

입력 태그 도우미(<input asp-for="Movie.Title" class="form-control">)는 DataAnnotations 특성을 사용하고 클라이언트 쪽의 jQuery 유효성 검사에 필요한 HTML 특성을 생성합니다.

태그 도우미(예: <form method="post">)에 대한 자세한 내용은 ASP.NET Core의 태그 도우미를 참조하세요.

다음 단계

만들기, 삭제, 세부 정보 및 편집 페이지

Pages/Movies/Index.cshtml.cs 페이지 모델을 살펴봅니다.

// Unused usings removed.
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Models;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace RazorPagesMovie.Pages.Movies
{
    public class IndexModel : PageModel
    {
        private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

        public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
        {
            _context = context;
        }
        public IList<Movie> Movie { get;set; }

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

Razor Pages는 PageModel에서 파생됩니다. 일반적으로 PageModel 파생 클래스의 이름은 <PageName>Model로 지정됩니다. 생성자는 종속성 주입을 사용하여 RazorPagesMovieContext를 페이지에 추가합니다.

public class IndexModel : PageModel
{
    private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

    public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
    {
        _context = context;
    }

Entity Framework로 비동기 프로그래밍에 대한 자세한 내용은 비동기 코드를 참조하세요.

페이지에 대한 요청을 만들면 OnGetAsync 메서드가 Razor Page에 동영상 목록을 반환합니다. Razor 페이지에서 OnGetAsync 또는 OnGet을 호출하여 페이지 상태를 초기화합니다. 이 경우 OnGetAsync는 동영상 목록을 가져와 표시합니다.

OnGetvoid를 반환하거나 OnGetAsyncTask를 반환하면 return 문이 사용되지 않은 것입니다. 예를 들어 Privacy 페이지는:

public class PrivacyModel : PageModel
{
    private readonly ILogger<PrivacyModel> _logger;

    public PrivacyModel(ILogger<PrivacyModel> logger)
    {
        _logger = logger;
    }

    public void OnGet()
    {
    }
}

반환 형식이 IActionResult 또는 Task<IActionResult>이면 반환 문을 제공해야 합니다. 예를 들어 Pages/Movies/Create.cshtml.csOnPostAsync 메서드입니다.

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

        _context.Movie.Add(Movie);
        await _context.SaveChangesAsync();

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

Pages/Movies/Index.cshtmlRazor페이지를 살펴봅니다.

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model.Movie) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                <a asp-page="./Edit" asp-route-id="@item.ID">Edit</a> |
                <a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
                <a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Razor는 HTML에서 C# 또는 Razor 관련 태그로 전환될 수 있습니다. @ 기호 뒤에 Razor 예약 키워드가 사용되면 이 기호는 Razor 관련 태그로 전환됩니다. 이외의 경우에는 C#으로 전환됩니다.

@page 지시문

@pageRazor 지시문은 파일을 MVC 작업으로 만듭니다. 이는 요청을 처리할 수 있음을 의미합니다. @page는 페이지의 첫 번째 Razor 지시문이어야 합니다. @page@model은 Razor 관련 태그로 전환되는 예입니다. 자세한 내용은 Razor 구문을 참조하세요.

@model 지시문

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@model 지시문은 Razor Page에 전달되는 모델 형식을 지정합니다. 위의 예제에서 @model 줄은 Razor Page에서 PageModel 파생 클래스를 사용할 수 있게 만듭니다. 모델은 페이지에서 @Html.DisplayNameFor@Html.DisplayForHTML 도우미에서 사용됩니다.

다음 HTML 도우미에서 사용되는 람다 식을 살펴봅니다.

@Html.DisplayNameFor(model => model.Movie[0].Title)

DisplayNameFor HTML 도우미는 람다 식에서 참조되는 Title 속성을 검사하여 표시 이름을 확인합니다. 람다 식은 계산되는 것이 아니라 검사됩니다. 즉, model, model.Movie 또는 model.Movie[0]null이거나 비어 있을 경우 액세스 위반이 없습니다. 람다 식이 계산될 경우(예: @Html.DisplayFor(modelItem => item.Title) 사용) 모델의 속성 값이 계산됩니다.

레이아웃 페이지

메뉴 링크 RazorPagesMovie, HomePrivacy를 선택합니다. 각 페이지는 동일한 메뉴 레이아웃을 표시합니다. 메뉴 레이아웃은 파일에서 Pages/Shared/_Layout.cshtml 구현됩니다.

Pages/Shared/_Layout.cshtml 파일을 열어 검사합니다.

레이아웃 템플릿을 사용하여 HTML 컨테이너 레이아웃을 다음과 같이 지정할 수 있습니다.

  • 한 위치에 지정됩니다.
  • 사이트의 여러 페이지에 적용됩니다.

@RenderBody() 줄을 찾습니다. RenderBody는 사용자가 만드는 모든 페이지 특정 보기가 표시되는 자리 표시자이며 레이아웃 페이지에서 래핑됩니다. 예를 들어 링크를 선택하면 Privacy 보기가 Pages/Privacy.cshtml 메서드 내부에 RenderBody 렌더링됩니다.

ViewData 및 레이아웃

파일에서 다음 태그를 고려합니다.Pages/Movies/Index.cshtml

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

강조 표시된 이전 태그는 C#으로 전환되는 Razor의 예제입니다. {} 문자로 C# 코드 블록을 묶습니다.

PageModel 기본 클래스에는 데이터를 뷰에 전달하는 데 사용할 수 있는 ViewData 사전 속성이 있습니다. 키 값 패턴을 사용하여 개체가 ViewData 사전에 추가됩니다. 이전 샘플에서는 Title 속성이 ViewData 사전에 추가됩니다.

Title 속성이 Pages/Shared/_Layout.cshtml 파일에서 사용됩니다. 다음 태그는 파일의 처음 몇 줄을 보여 줍니다 _Layout.cshtml .

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

    @*Markup removed for brevity.*@

@*Markup removed for brevity.*@ 줄은 Razor 주석입니다. HTML 주석 <!-- -->과 달리 Razor 주석은 클라이언트에 전송되지 않습니다. 자세한 내용은 MDN 웹 문서: HTML 시작을 참조하세요.

레이아웃 업데이트

  1. Pages/Shared/_Layout.cshtml 파일의 <title> 요소를 변경하여 RazorPagesMovie 대신 Movie를 표시합니다.

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>@ViewData["Title"] - Movie</title>
    
  2. 파일에서 다음 앵커 요소를 찾습니다 Pages/Shared/_Layout.cshtml .

    <a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
    
  3. 이전 요소를 다음 태그로 바꿉니다.

    <a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>
    

    이전 앵커 요소는 태그 도우미입니다. 이 경우에는 앵커 태그 도우미입니다. asp-page="/Movies/Index" 태그 도우미 특성 및 값으로 /Movies/IndexRazor 페이지의 링크를 만듭니다. asp-area 특성 값이 비어 있으므로 영역은 링크에서 사용되지 않습니다. 자세한 내용은 영역을 참조하세요.

  4. 변경 내용을 저장하고 RpMovie 링크를 선택하여 앱을 테스트합니다. 문제가 있는 경우 GitHub에서 _Layout.cshtml 파일을 참조하세요.

  5. Home, RpMovie, 만들기, 편집삭제 링크를 테스트합니다. 각 페이지는 브라우저 탭에서 볼 수 있는 제목을 설정합니다. 페이지에 책갈피를 지정하면 책갈피에 제목이 사용됩니다.

참고 항목

Price 필드에 소수점을 입력하지 못할 수도 있습니다. 소수점으로 쉼표(",")를 사용하는 비영어 로캘 및 비미국 영어 날짜 형식에 대해 jQuery 유효성 검사를 지원하려면 앱을 세계화하는 단계를 수행해야 합니다. 소수점 추가에 대한 지침은 이 GitHub 문제 4076을 참조하세요.

Layout 속성은 Pages/_ViewStart.cshtml 파일에서 설정됩니다.

@{
    Layout = "_Layout";
}

위의 태그는 Pages 폴더의 모든 Razor 파일에 대해 레이아웃 파일로 Pages/Shared/_Layout.cshtml로 설정합니다. 자세한 내용은 레이아웃을 참조하세요.

Create 페이지 모델

페이지 모델을 검사합니다 Pages/Movies/Create.cshtml.cs .

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesMovie.Models;
using System;
using System.Threading.Tasks;

namespace RazorPagesMovie.Pages.Movies
{
    public class CreateModel : PageModel
    {
        private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

        public CreateModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
        {
            _context = context;
        }

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

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

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

            _context.Movie.Add(Movie);
            await _context.SaveChangesAsync();

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

OnGet 메서드는 페이지에 필요한 상태를 초기화합니다. 만들기 페이지에는 초기화할 상태가 없습니다. 따라서 Page가 반환됩니다. 자습서의 뒷부분에서 상태를 초기화하는 OnGet의 예가 나와 있습니다. 메서드는 Page 페이지를 렌더링하는 개체를 Create.cshtml 만듭니다PageResult.

Movie 속성은 BindProperty 특성을 사용하여 모델 바인딩을 옵트인합니다. 만들기 폼이 폼 값을 게시하면 ASP.NET Core 런타임이 게시된 값을 Movie 모델에 바인딩합니다.

페이지에 폼 데이터가 게시되면 OnPostAsync 메서드가 실행됩니다.

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

    _context.Movie.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

모델 오류가 있는 경우 폼과 게시된 모든 폼 데이터가 다시 표시됩니다. 대부분의 모델 오류는 폼이 게시되기 전에 클라이언트 쪽에서 catch할 수 있습니다. 예를 들어 데이터로 변환될 수 없는 날짜 필드에 대한 값을 게시하는 모델 오류가 발생할 수 있습니다. 클라이언트 쪽 유효성 검사 및 모델 유효성 검사는 자습서의 뒷부분에서 설명합니다.

모델 오류가 없는 경우:

  • 데이터가 저장됩니다.
  • 브라우저가 인덱스 페이지로 리디렉션됩니다.

Create Razor Page

Pages/Movies/Create.cshtmlRazor Page 파일을 살펴봅니다.

@page
@model RazorPagesMovie.Pages.Movies.CreateModel

@{
    ViewData["Title"] = "Create";
}

<h1>Create</h1>

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Movie.Title" class="control-label"></label>
                <input asp-for="Movie.Title" class="form-control" />
                <span asp-validation-for="Movie.Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Movie.ReleaseDate" class="control-label"></label>
                <input asp-for="Movie.ReleaseDate" class="form-control" />
                <span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Movie.Genre" class="control-label"></label>
                <input asp-for="Movie.Genre" class="form-control" />
                <span asp-validation-for="Movie.Genre" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Movie.Price" class="control-label"></label>
                <input asp-for="Movie.Price" class="form-control" />
                <span asp-validation-for="Movie.Price" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-page="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Visual Studio에서는 다음 태그를 태그 도우미에 사용되는 독특한 굵은 글꼴로 표시합니다.

  • <form method="post">
  • <div asp-validation-summary="ModelOnly" class="text-danger"></div>
  • <label asp-for="Movie.Title" class="control-label"></label>
  • <input asp-for="Movie.Title" class="form-control" />
  • <span asp-validation-for="Movie.Title" class="text-danger"></span>

Create.cshtml 페이지의 VS17 보기

<form method="post"> 요소는 폼 태그 도우미입니다. 폼 태그 도우미에는 위조 방지 토큰이 자동으로 포함됩니다.

스캐폴딩 엔진은 ID를 제외하고 다음과 비슷한 모델에서 필드마다 Razor 태그를 만듭니다.

<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
    <label asp-for="Movie.Title" class="control-label"></label>
    <input asp-for="Movie.Title" class="form-control" />
    <span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>

유효성 검사 태그 도우미 (<div asp-validation-summary<span asp-validation-for) 는 유효성 검사 오류를 표시합니다. 유효성 검사는 이 시리즈의 뒷부분에서 자세히 설명합니다.

레이블 태그 도우미(<label asp-for="Movie.Title" class="control-label"></label>)는 Title 속성에 대한 레이블 캡션 및 [for] 특성을 생성합니다.

입력 태그 도우미(<input asp-for="Movie.Title" class="form-control">)는 DataAnnotations 특성을 사용하고 클라이언트 쪽의 jQuery 유효성 검사에 필요한 HTML 특성을 생성합니다.

태그 도우미(예: <form method="post">)에 대한 자세한 내용은 ASP.NET Core의 태그 도우미를 참조하세요.

다음 단계