Parte 3, pagine con scaffolding Razor in ASP.NET Core

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Importante

Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.

Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Di Rick Anderson

Questa esercitazione esamina le Razor pagine create dallo scaffolding nell'esercitazione precedente.

Pagine di creazione, eliminazione, dettagli e modifica

Esaminare il Pages/Movies/Index.cshtml.cs modello di pagina:

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 Le pagine sono derivate da PageModel. Per convenzione, la PageModel classe derivata è denominata PageNameModel. Ad esempio, la pagina Index è denominata IndexModel.

Il costruttore usa l'inserimento delle dipendenze per aggiungere alla RazorPagesMovieContext pagina:

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

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

Vedere Codice asincrono per altre informazioni sulla programmazione asincrona con Entity Framework.

Quando viene effettuata una GET richiesta per la pagina, il OnGetAsync metodo restituisce un elenco di film nella Razor pagina. In una Razor pagina OnGetAsync o OnGet viene chiamato per inizializzare lo stato della pagina. In questo caso, OnGetAsync ottiene un elenco di filmati e li visualizza.

Quando OnGet restituisce o OnGetAsync restituisce voidTask, non viene utilizzata alcuna istruzione return. Ad esempio, esaminare la Privacy pagina:

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()
        {
        }
    }
}

Quando il tipo restituito è IActionResult o Task<IActionResult>, è necessario specificare un'istruzione return. Ad esempio, il Pages/Movies/Create.cshtml.cs OnPostAsync metodo :

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

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

    return RedirectToPage("./Index");
}

Esaminare la Pages/Movies/Index.cshtmlRazor pagina:

@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 può passare da HTML a C# o in Razormarkup specifico. Quando un @ simbolo è seguito da una Razor parola chiave riservata, passa a Razormarkup specifico, altrimenti passa a C#.

La direttiva @page

La @pageRazor direttiva rende il file un'azione MVC, il che significa che può gestire le richieste. @page deve essere la prima direttiva Razor in una pagina. @page e @model sono esempi di transizione in Razormarkup specifico. Per altre informazioni, vedere Razor sintassi .

La direttiva @model

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

La @model direttiva specifica il tipo del modello passato alla Razor pagina. Nell'esempio precedente la @model riga rende la PageModel classe derivata disponibile per page Razor . Il modello viene usato negli helper HTML@Html.DisplayNameFor e @Html.DisplayFor nella pagina.

Esaminare l'espressione lambda usata nell'helper HTML seguente:

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

L'helper HTML DisplayNameFor controlla la proprietà Title a cui fa riferimento nell'espressione lambda per determinare il nome visualizzato. L'espressione lambda viene controllata anziché valutata. Ciò significa che non esiste alcuna violazione di accesso quando model, model.Movieo model.Movie[0] è null o vuoto. Quando l'espressione lambda viene valutata, ad esempio con @Html.DisplayFor(modelItem => item.Title), i valori delle proprietà del modello vengono valutati.

Pagina di layout

Selezionare i collegamenti Razordi menu PagesMovie, Homee Privacy. Ogni pagina mostra lo stesso layout di menu. Il layout del Pages/Shared/_Layout.cshtml menu viene implementato nel file.

Aprire ed esaminare il Pages/Shared/_Layout.cshtml file.

I modelli Layout consentono di:

  • Specificare il layout del contenitore HTML in un'unica posizione.
  • Applicare il layout in più pagine del sito.

Trovare la riga @RenderBody(). RenderBody è un segnaposto dove tutte le visualizzazioni specifiche della pagina vengono presentate, incapsulate nella pagina di layout. Ad esempio, selezionare il Privacy collegamento e il rendering della Pages/Privacy.cshtml vista all'interno del RenderBody metodo .

ViewData e layout

Prendere in considerazione il markup seguente dal Pages/Movies/Index.cshtml file :

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

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

Il markup evidenziato precedente è un esempio di Razor transizione in C#. Tra i caratteri { e } è racchiuso un blocco di codice C#.

La PageModel classe base contiene una ViewData proprietà del dizionario che può essere utilizzata per passare i dati a una vista. Gli oggetti vengono aggiunti al ViewData dizionario usando un modello chiave value . Nell'esempio precedente la proprietà Title viene aggiunta al dizionario ViewData.

La Title proprietà viene utilizzata nel Pages/Shared/_Layout.cshtml file . Il markup seguente mostra le prime righe del _Layout.cshtml file.

<!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" />

Aggiornare il layout

  1. Modificare l'elemento <title> nel Pages/Shared/_Layout.cshtml file in modo da visualizzare Movie anziché RazorPagesMovie.

    <!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. Trovare l'elemento di ancoraggio seguente nel Pages/Shared/_Layout.cshtml file .

    <a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
    
  3. Sostituire l'elemento precedente con il markup seguente:

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

    L'elemento di ancoraggio precedente è un helper tag. In questo caso, si tratta dell'helper tag di ancoraggio. L'attributo asp-page="/Movies/Index" helper tag e il valore creano un collegamento alla /Movies/IndexRazor pagina. Poiché il valore dell'attributo asp-area è vuoto, l'area non viene usata nel collegamento. Per altre informazioni, vedere Aree.

  4. Salvare le modifiche e testare l'app selezionando il collegamento RpMovie . In caso di problemi, vedere il file _Layout.cshtml in GitHub.

  5. Testare i Homecollegamenti , RpMovie, Create, Edit e Delete . Ogni pagina imposta il titolo, che è possibile visualizzare nella scheda del browser. Quando si segnalibra una pagina, il titolo viene usato per il segnalibro.

Nota

Potrebbe non essere possibile immettere virgole decimali nel campo Price. Per supportare la convalida di jQuery per le impostazioni locali non in lingua inglese che usano una virgola (",") per un separatore decimale e per i formati di data non inglese negli Stati Uniti, è necessario eseguire i passaggi per globalizzare l'app. Vedere questo problema 4076 su GitHub per istruzioni sull'aggiunta della virgola decimale.

La Layout proprietà è impostata nel Pages/_ViewStart.cshtml file :

@{
    Layout = "_Layout";
}

Il markup precedente imposta il file di layout su Pages/Shared/_Layout.cshtml per tutti i Razor file nella cartella Pages . Vedere Layout per altre informazioni.

Modello di pagina di creazione

Esaminare il modello di Pages/Movies/Create.cshtml.cs pagina:

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");
        }
    }
}

Il metodo OnGet inizializza lo stato necessario per la pagina. La pagina di creazione non possiede uno stato da inizializzare. Viene restituito Page. Più avanti nell'esercitazione viene visualizzato un esempio di inizializzazione dello stato con OnGet. Il Page metodo crea un PageResult oggetto che esegue il rendering della Create.cshtml pagina.

La Movie proprietà usa l'attributo [BindProperty] per acconsentire esplicitamente all'associazione di modelli. Dopo che il modulo di creazione registra i valori, il runtime di ASP.NET Core associa i valori registrati al modello Movie.

Il metodo OnPostAsync viene eseguito quando la pagina inserisce i dati del modulo:

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

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

    return RedirectToPage("./Index");
}

Se il modello contiene errori, il modulo viene nuovamente visualizzato insieme ai dati del modulo inviati. La maggior parte degli errori del modello sono riscontrabili sul lato client prima che il modulo sia inviato. La registrazione di un valore per il campo data non convertibile in una data è un esempio di errore del modello. Durante l'esercitazione saranno poi trattate nel dettaglio la convalida lato client e la convalida del modello.

Se non sono presenti errori del modello:

  • I dati vengono salvati.
  • Il browser viene reindirizzato alla pagina Indice.

Pagina Crea Razor

Esaminare il Pages/Movies/Create.cshtmlRazor file di pagina:

@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 visualizza i tag seguenti con un tipo di carattere in grassetto distintivo specifico per gli helper tag:

  • <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>

Visualizzazione di VS17 della pagina Create.cshtml

L'elemento <form method="post"> è un helper tag del modulo. L'helper tag del modulo include automaticamente un token antifalsificazione.

Il motore di scaffolding crea Razor markup per ogni campo nel modello, ad eccezione dell'ID, simile al seguente:

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

Gli helper tag di convalida (<div asp-validation-summary e <span asp-validation-for) visualizzano gli errori di convalida. Il tema della convalida viene trattato in modo più dettagliato successivamente in questa serie.

L'helper tag di etichetta (<label asp-for="Movie.Title" class="control-label"></label>) genera la didascalia dell'etichetta e l'attributo [for] per la proprietà Title.

L'helper tag di input (<input asp-for="Movie.Title" class="form-control">) usa gli attributi DataAnnotations e produce gli attributi HTML necessari per la convalida jQuery sul lato client.

Per altre informazioni sugli helper tag, ad esempio <form method="post">, vedere Helper tag in ASP.NET Core.

Passaggi successivi

Pagine di creazione, eliminazione, dettagli e modifica

Esaminare il Pages/Movies/Index.cshtml.cs modello di pagina:

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 Le pagine sono derivate da PageModel. Per convenzione, la PageModel classe derivata è denominata PageNameModel. Ad esempio, la pagina Index è denominata IndexModel.

Il costruttore usa l'inserimento delle dipendenze per aggiungere alla RazorPagesMovieContext pagina:

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

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

Vedere Codice asincrono per altre informazioni sulla programmazione asincrona con Entity Framework.

Quando viene effettuata una GET richiesta per la pagina, il OnGetAsync metodo restituisce un elenco di film nella Razor pagina. In una Razor pagina OnGetAsync o OnGet viene chiamato per inizializzare lo stato della pagina. In questo caso, OnGetAsync ottiene un elenco di filmati e li visualizza.

Quando OnGet restituisce o OnGetAsync restituisce voidTask, non viene utilizzata alcuna istruzione return. Ad esempio, esaminare la Privacy pagina:

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()
        {
        }
    }
}

Quando il tipo restituito è IActionResult o Task<IActionResult>, è necessario specificare un'istruzione return. Ad esempio, il Pages/Movies/Create.cshtml.cs OnPostAsync metodo :

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

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

    return RedirectToPage("./Index");
}

Esaminare la Pages/Movies/Index.cshtmlRazor pagina:

@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 può passare da HTML a C# o in Razormarkup specifico. Quando un @ simbolo è seguito da una Razor parola chiave riservata, passa a Razormarkup specifico, altrimenti passa a C#.

La direttiva @page

La @pageRazor direttiva rende il file un'azione MVC, il che significa che può gestire le richieste. @page deve essere la prima direttiva Razor in una pagina. @page e @model sono esempi di transizione in Razormarkup specifico. Per altre informazioni, vedere Razor sintassi .

La direttiva @model

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

La @model direttiva specifica il tipo del modello passato alla Razor pagina. Nell'esempio precedente la @model riga rende la PageModel classe derivata disponibile per page Razor . Il modello viene usato negli helper HTML@Html.DisplayNameFor e @Html.DisplayFor nella pagina.

Esaminare l'espressione lambda usata nell'helper HTML seguente:

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

L'helper HTML DisplayNameFor controlla la proprietà Title a cui fa riferimento nell'espressione lambda per determinare il nome visualizzato. L'espressione lambda viene controllata anziché valutata. Ciò significa che non esiste alcuna violazione di accesso quando model, model.Movieo model.Movie[0] è null o vuoto. Quando l'espressione lambda viene valutata, ad esempio con @Html.DisplayFor(modelItem => item.Title), i valori delle proprietà del modello vengono valutati.

Pagina di layout

Selezionare i collegamenti Razordi menu PagesMovie, Homee Privacy. Ogni pagina mostra lo stesso layout di menu. Il layout del Pages/Shared/_Layout.cshtml menu viene implementato nel file.

Aprire ed esaminare il Pages/Shared/_Layout.cshtml file.

I modelli Layout consentono di:

  • Specificare il layout del contenitore HTML in un'unica posizione.
  • Applicare il layout in più pagine del sito.

Trovare la riga @RenderBody(). RenderBody è un segnaposto dove tutte le visualizzazioni specifiche della pagina vengono presentate, incapsulate nella pagina di layout. Ad esempio, selezionare il Privacy collegamento e il rendering della Pages/Privacy.cshtml vista all'interno del RenderBody metodo .

ViewData e layout

Prendere in considerazione il markup seguente dal Pages/Movies/Index.cshtml file :

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

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

Il markup evidenziato precedente è un esempio di Razor transizione in C#. Tra i caratteri { e } è racchiuso un blocco di codice C#.

La PageModel classe base contiene una ViewData proprietà del dizionario che può essere utilizzata per passare i dati a una vista. Gli oggetti vengono aggiunti al ViewData dizionario usando un modello chiave value . Nell'esempio precedente la proprietà Title viene aggiunta al dizionario ViewData.

La Title proprietà viene utilizzata nel Pages/Shared/_Layout.cshtml file . Il markup seguente mostra le prime righe del _Layout.cshtml file.

<!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" />

La riga @*Markup removed for brevity.*@ è un Razor commento. A differenza dei commenti <!-- -->HTML, Razor i commenti non vengono inviati al client. Per altre informazioni, vedere la documentazione Web MDN: Introduzione al codice HTML .

Aggiornare il layout

  1. Modificare l'elemento <title> nel Pages/Shared/_Layout.cshtml file in modo da visualizzare Movie anziché RazorPagesMovie.

    <!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. Trovare l'elemento di ancoraggio seguente nel Pages/Shared/_Layout.cshtml file .

    <a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
    
  3. Sostituire l'elemento precedente con il markup seguente:

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

    L'elemento di ancoraggio precedente è un helper tag. In questo caso, si tratta dell'helper tag di ancoraggio. L'attributo asp-page="/Movies/Index" helper tag e il valore creano un collegamento alla /Movies/IndexRazor pagina. Poiché il valore dell'attributo asp-area è vuoto, l'area non viene usata nel collegamento. Per altre informazioni, vedere Aree.

  4. Salvare le modifiche e testare l'app selezionando il collegamento RpMovie . In caso di problemi, vedere il file _Layout.cshtml in GitHub.

  5. Testare i Homecollegamenti , RpMovie, Create, Edit e Delete . Ogni pagina imposta il titolo, che è possibile visualizzare nella scheda del browser. Quando si segnalibra una pagina, il titolo viene usato per il segnalibro.

Nota

Potrebbe non essere possibile immettere virgole decimali nel campo Price. Per supportare la convalida di jQuery per le impostazioni locali non in lingua inglese che usano una virgola (",") per un separatore decimale e per i formati di data non inglese negli Stati Uniti, è necessario eseguire i passaggi per globalizzare l'app. Vedere questo problema 4076 su GitHub per istruzioni sull'aggiunta della virgola decimale.

La Layout proprietà è impostata nel Pages/_ViewStart.cshtml file :

@{
    Layout = "_Layout";
}

Il markup precedente imposta il file di layout su Pages/Shared/_Layout.cshtml per tutti i Razor file nella cartella Pages . Vedere Layout per altre informazioni.

Modello di pagina di creazione

Esaminare il modello di Pages/Movies/Create.cshtml.cs pagina:

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");
        }
    }
}

Il metodo OnGet inizializza lo stato necessario per la pagina. La pagina di creazione non possiede uno stato da inizializzare. Viene restituito Page. Più avanti nell'esercitazione viene visualizzato un esempio di inizializzazione dello stato con OnGet. Il Page metodo crea un PageResult oggetto che esegue il rendering della Create.cshtml pagina.

La Movie proprietà usa l'attributo [BindProperty] per acconsentire esplicitamente all'associazione di modelli. Dopo che il modulo di creazione registra i valori, il runtime di ASP.NET Core associa i valori registrati al modello Movie.

Il metodo OnPostAsync viene eseguito quando la pagina inserisce i dati del modulo:

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

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

    return RedirectToPage("./Index");
}

Se il modello contiene errori, il modulo viene nuovamente visualizzato insieme ai dati del modulo inviati. La maggior parte degli errori del modello sono riscontrabili sul lato client prima che il modulo sia inviato. La registrazione di un valore per il campo data non convertibile in una data è un esempio di errore del modello. Durante l'esercitazione saranno poi trattate nel dettaglio la convalida lato client e la convalida del modello.

Se non sono presenti errori del modello:

  • I dati vengono salvati.
  • Il browser viene reindirizzato alla pagina Indice.

Pagina Crea Razor

Esaminare il Pages/Movies/Create.cshtmlRazor file di pagina:

@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 visualizza i tag seguenti con un tipo di carattere in grassetto distintivo specifico per gli helper tag:

  • <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>

Visualizzazione di VS17 della pagina Create.cshtml

L'elemento <form method="post"> è un helper tag del modulo. L'helper tag del modulo include automaticamente un token antifalsificazione.

Il motore di scaffolding crea Razor markup per ogni campo nel modello, ad eccezione dell'ID, simile al seguente:

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

Gli helper tag di convalida (<div asp-validation-summary e <span asp-validation-for) visualizzano gli errori di convalida. Il tema della convalida viene trattato in modo più dettagliato successivamente in questa serie.

L'helper tag di etichetta (<label asp-for="Movie.Title" class="control-label"></label>) genera la didascalia dell'etichetta e l'attributo [for] per la proprietà Title.

L'helper tag di input (<input asp-for="Movie.Title" class="form-control">) usa gli attributi DataAnnotations e produce gli attributi HTML necessari per la convalida jQuery sul lato client.

Per altre informazioni sugli helper tag, ad esempio <form method="post">, vedere Helper tag in ASP.NET Core.

Passaggi successivi

Pagine di creazione, eliminazione, dettagli e modifica

Esaminare il Pages/Movies/Index.cshtml.cs modello di pagina:

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 Le pagine sono derivate da PageModel. Per convenzione, la PageModel classe derivata è denominata PageNameModel. Ad esempio, la pagina Index è denominata IndexModel.

Il costruttore usa l'inserimento delle dipendenze per aggiungere alla RazorPagesMovieContext pagina:

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

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

Vedere Codice asincrono per altre informazioni sulla programmazione asincrona con Entity Framework.

Quando viene effettuata una richiesta per la pagina, il OnGetAsync metodo restituisce un elenco di film nella Razor pagina. In una Razor pagina OnGetAsync o OnGet viene chiamato per inizializzare lo stato della pagina. In questo caso, OnGetAsync ottiene un elenco di filmati e li visualizza.

Quando OnGet restituisce o OnGetAsync restituisce voidTask, non viene utilizzata alcuna istruzione return. Ad esempio, esaminare la Privacy pagina:

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()
        {
        }
    }
}

Quando il tipo restituito è IActionResult o Task<IActionResult>, è necessario specificare un'istruzione return. Ad esempio, il Pages/Movies/Create.cshtml.csOnPostAsync metodo :

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");
}

Esaminare la Pages/Movies/Index.cshtmlRazor pagina:

@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 può passare da HTML a C# o in Razormarkup specifico. Quando un @ simbolo è seguito da una Razor parola chiave riservata, passa a Razormarkup specifico, altrimenti passa a C#.

La direttiva @page

La @pageRazor direttiva rende il file un'azione MVC, il che significa che può gestire le richieste. @page deve essere la prima direttiva Razor in una pagina. @page e @model sono esempi di transizione in Razormarkup specifico. Per altre informazioni, vedere Razor sintassi .

La direttiva @model

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

La @model direttiva specifica il tipo del modello passato alla Razor pagina. Nell'esempio precedente la @model riga rende la PageModel classe derivata disponibile per page Razor . Il modello viene usato negli helper HTML@Html.DisplayNameFor e @Html.DisplayFor nella pagina.

Esaminare l'espressione lambda usata nell'helper HTML seguente:

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

L'helper HTML DisplayNameFor controlla la proprietà Title a cui fa riferimento nell'espressione lambda per determinare il nome visualizzato. L'espressione lambda viene controllata anziché valutata. Ciò significa che non esiste alcuna violazione di accesso quando model, model.Movieo model.Movie[0] è null o vuoto. Quando l'espressione lambda viene valutata, ad esempio con @Html.DisplayFor(modelItem => item.Title), i valori delle proprietà del modello vengono valutati.

Pagina di layout

Selezionare i collegamenti Razordi menu PagesMovie, Homee Privacy. Ogni pagina mostra lo stesso layout di menu. Il layout del Pages/Shared/_Layout.cshtml menu viene implementato nel file.

Aprire ed esaminare il Pages/Shared/_Layout.cshtml file.

I modelli Layout consentono di:

  • Specificare il layout del contenitore HTML in un'unica posizione.
  • Applicare il layout in più pagine del sito.

Trovare la riga @RenderBody(). RenderBody è un segnaposto dove tutte le visualizzazioni specifiche della pagina vengono presentate, incapsulate nella pagina di layout. Ad esempio, selezionare il Privacy collegamento e il rendering della Pages/Privacy.cshtml vista all'interno del RenderBody metodo .

ViewData e layout

Prendere in considerazione il markup seguente dal Pages/Movies/Index.cshtml file :

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

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

Il markup evidenziato precedente è un esempio di Razor transizione in C#. Tra i caratteri { e } è racchiuso un blocco di codice C#.

La PageModel classe base contiene una ViewData proprietà del dizionario che può essere utilizzata per passare i dati a una vista. Gli oggetti vengono aggiunti al ViewData dizionario usando un modello chiave value . Nell'esempio precedente la proprietà Title viene aggiunta al dizionario ViewData.

La Title proprietà viene utilizzata nel Pages/Shared/_Layout.cshtml file . Il markup seguente mostra le prime righe del _Layout.cshtml file.

<!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" />

La riga @*Markup removed for brevity.*@ è un Razor commento. A differenza dei commenti <!-- -->HTML, Razor i commenti non vengono inviati al client. Per altre informazioni, vedere la documentazione Web MDN: Introduzione al codice HTML .

Aggiornare il layout

  1. Modificare l'elemento <title> nel Pages/Shared/_Layout.cshtml file in modo da visualizzare Movie anziché RazorPagesMovie.

    <!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. Trovare l'elemento di ancoraggio seguente nel Pages/Shared/_Layout.cshtml file .

    <a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
    
  3. Sostituire l'elemento precedente con il markup seguente:

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

    L'elemento di ancoraggio precedente è un helper tag. In questo caso, si tratta dell'helper tag di ancoraggio. L'attributo asp-page="/Movies/Index" helper tag e il valore creano un collegamento alla /Movies/IndexRazor pagina. Poiché il valore dell'attributo asp-area è vuoto, l'area non viene usata nel collegamento. Per altre informazioni, vedere Aree.

  4. Salvare le modifiche e testare l'app selezionando il collegamento RpMovie . In caso di problemi, vedere il file _Layout.cshtml in GitHub.

  5. Testare i Homecollegamenti , RpMovie, Create, Edit e Delete . Ogni pagina imposta il titolo, che è possibile visualizzare nella scheda del browser. Quando si segnalibra una pagina, il titolo viene usato per il segnalibro.

Nota

Potrebbe non essere possibile immettere virgole decimali nel campo Price. Per supportare la convalida di jQuery per le impostazioni locali non in lingua inglese che usano una virgola (",") per un separatore decimale e per i formati di data non inglese negli Stati Uniti, è necessario eseguire i passaggi per globalizzare l'app. Vedere questo problema 4076 su GitHub per istruzioni sull'aggiunta della virgola decimale.

La Layout proprietà è impostata nel Pages/_ViewStart.cshtml file :

@{
    Layout = "_Layout";
}

Il markup precedente imposta il file di layout su Pages/Shared/_Layout.cshtml per tutti i Razor file nella cartella Pages . Vedere Layout per altre informazioni.

Modello di pagina di creazione

Esaminare il modello di Pages/Movies/Create.cshtml.cs pagina:

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");
        }
    }
}

Il metodo OnGet inizializza lo stato necessario per la pagina. La pagina di creazione non possiede uno stato da inizializzare. Viene restituito Page. Più avanti nell'esercitazione viene visualizzato un esempio di inizializzazione dello stato con OnGet. Il Page metodo crea un PageResult oggetto che esegue il rendering della Create.cshtml pagina.

La Movie proprietà usa l'attributo [BindProperty] per acconsentire esplicitamente all'associazione di modelli. Dopo che il modulo di creazione registra i valori, il runtime di ASP.NET Core associa i valori registrati al modello Movie.

Il metodo OnPostAsync viene eseguito quando la pagina inserisce i dati del modulo:

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");
}

Se il modello contiene errori, il modulo viene nuovamente visualizzato insieme ai dati del modulo inviati. La maggior parte degli errori del modello sono riscontrabili sul lato client prima che il modulo sia inviato. La registrazione di un valore per il campo data non convertibile in una data è un esempio di errore del modello. Durante l'esercitazione saranno poi trattate nel dettaglio la convalida lato client e la convalida del modello.

Se non sono presenti errori del modello:

  • I dati vengono salvati.
  • Il browser viene reindirizzato alla pagina Indice.

Pagina Crea Razor

Esaminare il Pages/Movies/Create.cshtmlRazor file di pagina:

@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 visualizza i tag seguenti con un tipo di carattere in grassetto distintivo specifico per gli helper tag:

  • <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>

Visualizzazione di VS17 della pagina Create.cshtml

L'elemento <form method="post"> è un helper tag del modulo. L'helper tag del modulo include automaticamente un token antifalsificazione.

Il motore di scaffolding crea Razor markup per ogni campo nel modello, ad eccezione dell'ID, simile al seguente:

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

Gli helper tag di convalida (<div asp-validation-summary e <span asp-validation-for) visualizzano gli errori di convalida. Il tema della convalida viene trattato in modo più dettagliato successivamente in questa serie.

L'helper tag di etichetta (<label asp-for="Movie.Title" class="control-label"></label>) genera la didascalia dell'etichetta e l'attributo [for] per la proprietà Title.

L'helper tag di input (<input asp-for="Movie.Title" class="form-control">) usa gli attributi DataAnnotations e produce gli attributi HTML necessari per la convalida jQuery sul lato client.

Per altre informazioni sugli helper tag, ad esempio <form method="post">, vedere Helper tag in ASP.NET Core.

Passaggi successivi

Pagine di creazione, eliminazione, dettagli e modifica

Esaminare il Pages/Movies/Index.cshtml.cs modello di pagina:

// 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 Le pagine sono derivate da PageModel. Per convenzione, la PageModelclasse derivata da è denominata <PageName>Model. Il costruttore usa l'inserimento delle dipendenze per aggiungere alla RazorPagesMovieContext pagina:

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

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

Vedere Codice asincrono per altre informazioni sulla programmazione asincrona con Entity Framework.

Quando viene effettuata una richiesta per la pagina, il OnGetAsync metodo restituisce un elenco di film nella Razor pagina. In una Razor pagina OnGetAsync o OnGet viene chiamato per inizializzare lo stato della pagina. In questo caso, OnGetAsync ottiene un elenco di filmati e li visualizza.

Quando OnGet restituisce o OnGetAsync restituisce voidTask, non viene utilizzata alcuna istruzione return. Ad esempio, pagina Privacy :

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

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

    public void OnGet()
    {
    }
}

Quando il tipo restituito è IActionResult o Task<IActionResult>, è necessario specificare un'istruzione return. Ad esempio, il Pages/Movies/Create.cshtml.csOnPostAsync metodo :

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

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

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

Esaminare la Pages/Movies/Index.cshtmlRazor pagina:

@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 può passare da HTML a C# o in Razormarkup specifico. Quando un @ simbolo è seguito da una Razor parola chiave riservata, passa a Razormarkup specifico, altrimenti passa a C#.

La direttiva @page

La @pageRazor direttiva rende il file un'azione MVC, il che significa che può gestire le richieste. @page deve essere la prima direttiva Razor in una pagina. @page e @model sono esempi di transizione in Razormarkup specifico. Per altre informazioni, vedere Razor sintassi .

La direttiva @model

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

La @model direttiva specifica il tipo del modello passato alla Razor pagina. Nell'esempio precedente, la @model riga rende la PageModelclasse derivata da disponibile per page Razor . Il modello viene usato negli helper HTML@Html.DisplayNameFor e @Html.DisplayFor nella pagina.

Esaminare l'espressione lambda usata nell'helper HTML seguente:

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

L'helper HTML DisplayNameFor controlla la proprietà Title a cui fa riferimento nell'espressione lambda per determinare il nome visualizzato. L'espressione lambda viene controllata anziché valutata. Ciò significa che non esiste alcuna violazione di accesso quando model, model.Movieo model.Movie[0] è null o vuoto. Quando l'espressione lambda viene valutata, ad esempio con @Html.DisplayFor(modelItem => item.Title), i valori delle proprietà del modello vengono valutati.

Pagina di layout

Selezionare i collegamenti Razordi menu PagesMovie, Homee Privacy. Ogni pagina mostra lo stesso layout di menu. Il layout del Pages/Shared/_Layout.cshtml menu viene implementato nel file.

Aprire ed esaminare il Pages/Shared/_Layout.cshtml file.

I modelli Layout consentono di:

  • Specificare il layout del contenitore HTML in un'unica posizione.
  • Applicare il layout in più pagine del sito.

Trovare la riga @RenderBody(). RenderBody è un segnaposto dove tutte le visualizzazioni specifiche della pagina vengono presentate, incapsulate nella pagina di layout. Ad esempio, selezionare il Privacy collegamento e il rendering della Pages/Privacy.cshtml vista all'interno del RenderBody metodo .

ViewData e layout

Prendere in considerazione il markup seguente dal Pages/Movies/Index.cshtml file :

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

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

Il markup evidenziato precedente è un esempio di Razor transizione in C#. Tra i caratteri { e } è racchiuso un blocco di codice C#.

La PageModel classe base contiene una ViewData proprietà del dizionario che può essere utilizzata per passare i dati a una vista. Gli oggetti vengono aggiunti al ViewData dizionario usando un modello chiave value . Nell'esempio precedente la proprietà Title viene aggiunta al dizionario ViewData.

La Title proprietà viene utilizzata nel Pages/Shared/_Layout.cshtml file . Il markup seguente mostra le prime righe del _Layout.cshtml file.

<!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.*@

La riga @*Markup removed for brevity.*@ è un Razor commento. A differenza dei commenti <!-- -->HTML, Razor i commenti non vengono inviati al client. Per altre informazioni, vedere la documentazione Web MDN: Introduzione al codice HTML .

Aggiornare il layout

  1. Modificare l'elemento <title> nel Pages/Shared/_Layout.cshtml file in modo da visualizzare Movie anziché RazorPagesMovie.

    <!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. Trovare l'elemento di ancoraggio seguente nel Pages/Shared/_Layout.cshtml file .

    <a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
    
  3. Sostituire l'elemento precedente con il markup seguente:

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

    L'elemento di ancoraggio precedente è un helper tag. In questo caso, si tratta dell'helper tag di ancoraggio. L'attributo asp-page="/Movies/Index" helper tag e il valore creano un collegamento alla /Movies/IndexRazor pagina. Poiché il valore dell'attributo asp-area è vuoto, l'area non viene usata nel collegamento. Per altre informazioni, vedere Aree.

  4. Salvare le modifiche e testare l'app selezionando il collegamento RpMovie . In caso di problemi, vedere il file _Layout.cshtml in GitHub.

  5. Testare i Homecollegamenti , RpMovie, Create, Edit e Delete . Ogni pagina imposta il titolo, che è possibile visualizzare nella scheda del browser. Quando si segnalibra una pagina, il titolo viene usato per il segnalibro.

Nota

Potrebbe non essere possibile immettere virgole decimali nel campo Price. Per supportare la convalida di jQuery per le impostazioni locali non in lingua inglese che usano una virgola (",") per un separatore decimale e per i formati di data non inglese negli Stati Uniti, è necessario eseguire i passaggi per globalizzare l'app. Vedere questo problema 4076 su GitHub per istruzioni sull'aggiunta della virgola decimale.

La Layout proprietà è impostata nel Pages/_ViewStart.cshtml file :

@{
    Layout = "_Layout";
}

Il markup precedente imposta il file di layout su Pages/Shared/_Layout.cshtml per tutti i Razor file nella cartella Pages . Vedere Layout per altre informazioni.

Modello di pagina di creazione

Esaminare il modello di Pages/Movies/Create.cshtml.cs pagina:

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");
        }
    }
}

Il metodo OnGet inizializza lo stato necessario per la pagina. La pagina di creazione non possiede uno stato da inizializzare. Viene restituito Page. Più avanti nell'esercitazione viene visualizzato un esempio di inizializzazione dello stato con OnGet. Il Page metodo crea un PageResult oggetto che esegue il rendering della Create.cshtml pagina.

La Movie proprietà usa l'attributo [BindProperty] per acconsentire esplicitamente all'associazione di modelli. Dopo che il modulo di creazione registra i valori, il runtime di ASP.NET Core associa i valori registrati al modello Movie.

Il metodo OnPostAsync viene eseguito quando la pagina inserisce i dati del modulo:

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

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

    return RedirectToPage("./Index");
}

Se il modello contiene errori, il modulo viene nuovamente visualizzato insieme ai dati del modulo inviati. La maggior parte degli errori del modello sono riscontrabili sul lato client prima che il modulo sia inviato. La registrazione di un valore per il campo data non convertibile in una data è un esempio di errore del modello. Durante l'esercitazione saranno poi trattate nel dettaglio la convalida lato client e la convalida del modello.

Se non sono presenti errori del modello:

  • I dati vengono salvati.
  • Il browser viene reindirizzato alla pagina Indice.

Pagina Crea Razor

Esaminare il Pages/Movies/Create.cshtmlRazor file di pagina:

@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 visualizza i tag seguenti con un tipo di carattere in grassetto distintivo specifico per gli helper tag:

  • <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>

Visualizzazione di VS17 della pagina Create.cshtml

L'elemento <form method="post"> è un helper tag del modulo. L'helper tag del modulo include automaticamente un token antifalsificazione.

Il motore di scaffolding crea Razor markup per ogni campo nel modello, ad eccezione dell'ID, simile al seguente:

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

Gli helper tag di convalida (<div asp-validation-summary e <span asp-validation-for) visualizzano gli errori di convalida. Il tema della convalida viene trattato in modo più dettagliato successivamente in questa serie.

L'helper tag di etichetta (<label asp-for="Movie.Title" class="control-label"></label>) genera la didascalia dell'etichetta e l'attributo [for] per la proprietà Title.

L'helper tag di input (<input asp-for="Movie.Title" class="form-control">) usa gli attributi DataAnnotations e produce gli attributi HTML necessari per la convalida jQuery sul lato client.

Per altre informazioni sugli helper tag, ad esempio <form method="post">, vedere Helper tag in ASP.NET Core.

Passaggi successivi