Introduzione a Razor Pages in ASP.NET CoreIntroduction to Razor Pages in ASP.NET Core

Di Rick Anderson e Ryan NowakBy Rick Anderson and Ryan Nowak

Razor Pages possibile rendere più semplici e più produttivi gli scenari incentrati sulle pagine di codifica rispetto all'utilizzo di controller e visualizzazioni.Razor Pages can make coding page-focused scenarios easier and more productive than using controllers and views.

Se si sta cercando un'esercitazione in cui si usa l'approccio Model-View-Controller, vedere Introduzione ad ASP.NET Core MVC.If you're looking for a tutorial that uses the Model-View-Controller approach, see Get started with ASP.NET Core MVC.

Questo documento offre un'introduzione a Razor Pages.This document provides an introduction to Razor Pages. Non è un'esercitazione dettagliata.It's not a step by step tutorial. Se alcune sezioni risultano troppo avanzate, vedere Introduzione a Razor Pages.If you find some of the sections too advanced, see Get started with Razor Pages. Per una panoramica di ASP.NET Core, vedere Introduzione a ASP.NET Core.For an overview of ASP.NET Core, see the Introduction to ASP.NET Core.

PrerequisitesPrerequisites

Creare un progetto Razor PagesCreate a Razor Pages project

Per istruzioni dettagliate su come creare un progetto Razor Pages, vedere Introduzione a Razor Pages.See Get started with Razor Pages for detailed instructions on how to create a Razor Pages project.

Razor PagesRazor Pages

La funzionalità Razor Pages è abilitata in Startup.cs:Razor Pages is enabled in Startup.cs:

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

    public IConfiguration Configuration { get; }

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

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

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

        app.UseRouting();

        app.UseAuthorization();

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

Si consideri una pagina di base: Consider a basic page:

@page

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

Il codice precedente è molto simile a un file di visualizzazione Razor usato in un'app ASP.NET Core con controller e visualizzazioni.The preceding code looks a lot like a Razor view file used in an ASP.NET Core app with controllers and views. Ciò che lo rende diverso è la direttiva @page .What makes it different is the @page directive. @page trasforma il file in un'azione MVC, ovvero gestisce le richieste direttamente, senza passare attraverso un controller.@page makes the file into an MVC action - which means that it handles requests directly, without going through a controller. @page deve essere la prima direttiva Razor in una pagina.@page must be the first Razor directive on a page. @page influiscono sul comportamento di altri costrutti Razor .@page affects the behavior of other Razor constructs. I nomi dei file di Razor Pages hanno un suffisso . cshtml .Razor Pages file names have a .cshtml suffix.

Nei due file seguenti viene visualizzata una pagina simile che usa una classe PageModel.A similar page, using a PageModel class, is shown in the following two files. Il file Pages/Index2.cshtml:The Pages/Index2.cshtml file:

@page
@using RazorPagesIntro.Pages
@model Index2Model

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

Il modello di pagina Pages/Index2.cshtml.cs:The Pages/Index2.cshtml.cs page model:

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

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

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

Per convenzione, il file di classe PageModel ha lo stesso nome del file della pagina Razor con l'aggiunta di .cs.By convention, the PageModel class file has the same name as the Razor Page file with .cs appended. Ad esempio, la pagina Razor precedente è Pages/Index2.cshtml.For example, the previous Razor Page is Pages/Index2.cshtml. Il file che contiene la classe PageModel è denominato Pages/Index2.cshtml.cs.The file containing the PageModel class is named Pages/Index2.cshtml.cs.

Le associazioni dei percorsi URL alle pagine sono determinate dalla posizione della pagina nel file system.The associations of URL paths to pages are determined by the page's location in the file system. Nella tabella seguente sono riportati alcuni percorsi di pagina Razor con gli URL corrispondenti:The following table shows a Razor Page path and the matching URL:

Percorso e nome fileFile name and path URL corrispondentematching URL
/Pages/Index.cshtml/Pages/Index.cshtml / o /Index/ or /Index
/Pages/Contact.cshtml/Pages/Contact.cshtml /Contact
/Pages/Store/Contact.cshtml/Pages/Store/Contact.cshtml /Store/Contact
/Pages/Store/Index.cshtml/Pages/Store/Index.cshtml /Store o /Store/Index/Store or /Store/Index

Note:Notes:

  • Il runtime cerca i file delle pagine Razor nella cartella Pages per impostazione predefinita.The runtime looks for Razor Pages files in the Pages folder by default.
  • Index è la pagina predefinita quando un URL non include una pagina.Index is the default page when a URL doesn't include a page.

Scrivere un form di baseWrite a basic form

Razor Pages semplifica l'implementazione dei modelli normalmente usati con i Web browser durante la creazione di un'app.Razor Pages is designed to make common patterns used with web browsers easy to implement when building an app. L'associazione di modelli, gli helper tag e gli helper HTML funzionano tutti con le proprietà definite in una classe di pagina Razor.Model binding, Tag Helpers, and HTML helpers all just work with the properties defined in a Razor Page class. Si consideri una pagina che implementa un form "contact us" di base per il modello Contact:Consider a page that implements a basic "contact us" form for the Contact model:

Per gli esempi riportati in questo documento, DbContext viene inizializzato nel file Startup.cs.For the samples in this document, the DbContext is initialized in the Startup.cs file.

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

Il modello di dati:The data model:

using System.ComponentModel.DataAnnotations;

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

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

Il contesto del database:The db context:

using Microsoft.EntityFrameworkCore;
using RazorPagesContacts.Models;

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

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

Il file di visualizzazione Pages/Create.cshtml:The Pages/Create.cshtml view file:

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

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

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

Il modello di pagina Pages/Create.cshtml.cs:The Pages/Create.cshtml.cs page model:

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

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

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

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

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

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

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

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

Per convenzione, la classe PageModel è denominata <PageName>Model e si trova nello stesso spazio dei nomi della pagina.By convention, the PageModel class is called <PageName>Model and is in the same namespace as the page.

La classe PageModel consente la separazione della logica di una pagina dalla relativa presentazione.The PageModel class allows separation of the logic of a page from its presentation. Definisce i gestori di pagina per le richieste inviate alla pagina e i dati usati per il rendering della pagina.It defines page handlers for requests sent to the page and the data used to render the page. Questa separazione consente:This separation allows:

La pagina contiene un oggetto OnPostAsync, ovvero un metodo gestore che viene eseguito per le richieste POST, quando un utente invia il form.The page has an OnPostAsync handler method, which runs on POST requests (when a user posts the form). È possibile aggiungere i metodi del gestore per qualsiasi verbo HTTP.Handler methods for any HTTP verb can be added. I gestori più comuni sono:The most common handlers are:

  • OnGet per inizializzare lo stato necessario per la pagina.OnGet to initialize state needed for the page. Nel codice precedente, il metodo OnGet Visualizza la pagina Razor CreateModel. cshtml .In the preceding code, the OnGet method displays the CreateModel.cshtml Razor Page.
  • OnPost per gestire gli invii di form.OnPost to handle form submissions.

Il suffisso Async nel nome è facoltativo, ma viene spesso usato per convenzione per le funzioni asincrone.The Async naming suffix is optional but is often used by convention for asynchronous functions. Il codice precedente è tipico di Razor Pages.The preceding code is typical for Razor Pages.

Se si ha familiarità con le app ASP.NET che usano i controller e le visualizzazioni:If you're familiar with ASP.NET apps using controllers and views:

  • Il codice OnPostAsync nell'esempio precedente ha un aspetto simile al codice del controller tipico.The OnPostAsync code in the preceding example looks similar to typical controller code.
  • La maggior parte delle primitive MVC come l' associazione di modelli, la convalidae i risultati dell'azione funzionano allo stesso modo con i controller e Razor Pages.Most of the MVC primitives like model binding, validation, and action results work the same with Controllers and Razor Pages.

Il metodo OnPostAsync precedente:The previous OnPostAsync method:

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

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

    return RedirectToPage("./Index");
}

Il flusso di base di OnPostAsync:The basic flow of OnPostAsync:

Verificare se sono presenti errori di convalida.Check for validation errors.

  • Se non sono presenti errori, salvare i dati e reindirizzare.If there are no errors, save the data and redirect.
  • Se sono presenti errori, visualizzare di nuovo la pagina con i messaggi di convalida.If there are errors, show the page again with validation messages. In molti casi gli errori di convalida vengono rilevati nel client e mai inviati al server.In many cases, validation errors would be detected on the client, and never submitted to the server.

Il file di visualizzazione Pages/Create.cshtml:The Pages/Create.cshtml view file:

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

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

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

Il codice HTML sottoposto a rendering da pages/create. cshtml:The rendered HTML from Pages/Create.cshtml:

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

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

Nel codice precedente, inserendo il modulo:In the previous code, posting the form:

  • Con dati validi:With valid data:

    • Il metodo del gestore OnPostAsync chiama il metodo helper RedirectToPage.The OnPostAsync handler method calls the RedirectToPage helper method. RedirectToPage restituisce un'istanza di RedirectToPageResult.RedirectToPage returns an instance of RedirectToPageResult. RedirectToPage:RedirectToPage:

      • Risultato dell'azione.Is an action result.
      • È simile a RedirectToAction o RedirectToRoute (usato in controller e visualizzazioni).Is similar to RedirectToAction or RedirectToRoute (used in controllers and views).
      • È personalizzato per le pagine.Is customized for pages. Nell'esempio precedente viene reindirizzato alla pagina di indice radice (/Index).In the preceding sample, it redirects to the root Index page (/Index). Il metodo RedirectToPage è descritto in dettaglio nella sezione Generazione di URL per le pagine.RedirectToPage is detailed in the URL generation for Pages section.
  • Con gli errori di convalida passati al server:With validation errors that are passed to the server:

    • Il metodo del gestore OnPostAsync chiama il metodo helper Page.The OnPostAsync handler method calls the Page helper method. Page restituisce un'istanza di PageResult.Page returns an instance of PageResult. La restituzione di Page è simile al modo in cui le azioni nel controller restituiscono View.Returning Page is similar to how actions in controllers return View. PageResult è il tipo restituito predefinito per un metodo del gestore.PageResult is the default return type for a handler method. Un metodo gestore che restituisce void esegue il rendering della pagina.A handler method that returns void renders the page.
    • Nell'esempio precedente, se si pubblica il form senza alcun valore, in ModelState. IsValid viene restituito false.In the preceding example, posting the form with no value results in ModelState.IsValid returning false. In questo esempio non vengono visualizzati errori di convalida nel client.In this sample, no validation errors are displayed on the client. Il controllo degli errori di convalida viene trattato più avanti in questo documento.Validation error handing is covered later in this document.
    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }
    
        _context.Customers.Add(Customer);
        await _context.SaveChangesAsync();
    
        return RedirectToPage("./Index");
    }
    
  • Con errori di convalida rilevati dalla convalida lato client:With validation errors detected by client side validation:

    • I dati non vengono inviati al server.Data is not posted to the server.
    • La convalida lato client è illustrata più avanti in questo documento.Client-side validation is explained later in this document.

La proprietà Customer utilizza [BindProperty] attributo per acconsentire esplicitamente all'associazione di modelli:The Customer property uses [BindProperty] attribute to opt in to model binding:

public class CreateModel : PageModel
{
    private readonly CustomerDbContext _context;

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

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

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

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

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

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

non utilizzare [BindProperty] nei modelli contenenti proprietà che non devono essere modificate dal client.[BindProperty] should not be used on models containing properties that should not be changed by the client. Per ulteriori informazioni, vedere overposting.For more information, see Overposting.

Per impostazione predefinita, Razor Pages associa le proprietà solo a verbi non GET.Razor Pages, by default, bind properties only with non-GET verbs. L'associazione alle proprietà Elimina la necessità di scrivere codice per convertire i dati HTTP nel tipo di modello.Binding to properties removes the need to writing code to convert HTTP data to the model type. Riduce il codice usando la stessa proprietà per il eseguire il rendering dei campi del form (<input asp-for="Customer.Name">) e accettare l'input.Binding reduces code by using the same property to render form fields (<input asp-for="Customer.Name">) and accept the input.

Avviso

Per motivi di sicurezza, è necessario acconsentire esplicitamente all'associazione dei dati della richiesta GET alle proprietà del modello di pagina.For security reasons, you must opt in to binding GET request data to page model properties. Verificare l'input dell'utente prima di eseguirne il mapping alle proprietà.Verify user input before mapping it to properties. La scelta dell'associazione GET è utile per gli scenari che si basano sulla stringa di query o sui valori della route.Opting into GET binding is useful when addressing scenarios that rely on query string or route values.

Per associare una proprietà alle richieste di GET, impostare la proprietà SupportsGet dell'attributo [BindProperty] su true:To bind a property on GET requests, set the [BindProperty] attribute's SupportsGet property to true:

[BindProperty(SupportsGet = true)]

Per altre informazioni, vedere ASP.NET Core community standup: bind on Get Discussion (YouTube).For more information, see ASP.NET Core Community Standup: Bind on GET discussion (YouTube).

Esaminando il file di visualizzazione pages/create. cshtml :Reviewing the Pages/Create.cshtml view file:

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

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

<form method="post">
    Name:
    <input asp-for="Customer.Name" />
    <input type="submit" />
</form>
  • Nel codice precedente, l' Helper tag di input <input asp-for="Customer.Name" /> associa l'elemento HTML <input> all'espressione del modello Customer.Name.In the preceding code, the input tag helper <input asp-for="Customer.Name" /> binds the HTML <input> element to the Customer.Name model expression.
  • @addTagHelper rende disponibili gli helper tag.@addTagHelper makes Tag Helpers available.

La home pageThe home page

Index. cshtml è il Home page:Index.cshtml is the home page:

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

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

La classe PageModel associata (Index.cshtml.cs):The associated PageModel class (Index.cshtml.cs):

public class IndexModel : PageModel
{
    private readonly CustomerDbContext _context;

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

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

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

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

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

        return RedirectToPage();
    }
}

Il file index. cshtml contiene il markup seguente:The Index.cshtml file contains the following markup:

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

L' Helper tag di ancoraggio <a /a> ha usato l'attributo asp-route-{value} per generare un collegamento alla pagina di modifica.The <a /a> Anchor Tag Helper used the asp-route-{value} attribute to generate a link to the Edit page. Il collegamento contiene i dati della route con l'ID contatto.The link contains route data with the contact ID. Ad esempio https://localhost:5001/Edit/1.For example, https://localhost:5001/Edit/1. Gli helper tag consentono al codice lato server di partecipare alla creazione e al rendering di elementi HTML nei file Razor.Tag Helpers enable server-side code to participate in creating and rendering HTML elements in Razor files.

Il file index. cshtml contiene il markup per la creazione di un pulsante Delete per ogni contatto del cliente:The Index.cshtml file contains markup to create a delete button for each customer contact:

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

HTML sottoposto a rendering:The rendered HTML:

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

Quando il pulsante Elimina viene sottoposto a rendering in HTML, il relativo formaction include i parametri per:When the delete button is rendered in HTML, its formaction includes parameters for:

  • ID contatto del cliente, specificato dall'attributo asp-route-id.The customer contact ID, specified by the asp-route-id attribute.
  • handlerspecificato dall'attributo asp-page-handler.The handler, specified by the asp-page-handler attribute.

Quando il pulsante è selezionato, viene inviata una richiesta POST di modulo al server.When the button is selected, a form POST request is sent to the server. Per convenzione, il nome del metodo del gestore viene selezionato in base al valore del parametro handler in base allo schema OnPost[handler]Async.By convention, the name of the handler method is selected based on the value of the handler parameter according to the scheme OnPost[handler]Async.

Poiché in questo esempio l'handler è delete, il metodo OnPostDeleteAsync viene usato per elaborare la richiesta POST.Because the handler is delete in this example, the OnPostDeleteAsync handler method is used to process the POST request. Se asp-page-handler viene impostato su un valore diverso, ad esempio remove, viene selezionato un metodo gestore con il nome OnPostRemoveAsync.If the asp-page-handler is set to a different value, such as remove, a handler method with the name OnPostRemoveAsync is selected.

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

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

    return RedirectToPage();
}

Il metodo OnPostDeleteAsync:The OnPostDeleteAsync method:

  • Ottiene l'id dalla stringa di query.Gets the id from the query string.
  • Interroga il database in merito al contatto del cliente con FindAsync.Queries the database for the customer contact with FindAsync.
  • Se il contatto del cliente viene trovato, viene rimosso e il database viene aggiornato.If the customer contact is found, it's removed and the database is updated.
  • Chiama RedirectToPage per reindirizzare alla pagina di indice radice (/Index).Calls RedirectToPage to redirect to the root Index page (/Index).

File Edit. cshtmlThe Edit.cshtml file

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


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

    <div>
        <button type="submit">Save</button>
    </div>
</form>

La prima riga contiene la direttiva @page "{id:int}".The first line contains the @page "{id:int}" directive. Il vincolo di routing "{id:int}" indica alla pagina di accettare le richieste inviate alla pagina che contengono i dati della route int.The routing constraint"{id:int}" tells the page to accept requests to the page that contain int route data. Se una richiesta inviata alla pagina non contiene dati della route che possono essere convertiti in un oggetto int, il runtime restituisce un errore HTTP 404 (non trovato).If a request to the page doesn't contain route data that can be converted to an int, the runtime returns an HTTP 404 (not found) error. Per rendere l'ID facoltativo, aggiungere ? al vincolo di route:To make the ID optional, append ? to the route constraint:

@page "{id:int?}"

Il file Edit.cshtml.cs :The Edit.cshtml.cs file:

public class EditModel : PageModel
{
    private readonly CustomerDbContext _context;

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

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

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

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

        return Page();
    }

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

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

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

        return RedirectToPage("./Index");
    }

}

ValidationValidation

Regole di convalida:Validation rules:

  • Sono specificati in modo dichiarativo nella classe del modello.Are declaratively specified in the model class.
  • Vengono applicati ovunque nell'app.Are enforced everywhere in the app.

Lo spazio dei nomi System.ComponentModel.DataAnnotations fornisce un set di attributi di convalida predefiniti che vengono applicati in modo dichiarativo a una classe o a una proprietà.The System.ComponentModel.DataAnnotations namespace provides a set of built-in validation attributes that are applied declaratively to a class or property. DataAnnotations contiene anche attributi di formattazione come [DataType] che semplificano la formattazione e non forniscono alcuna convalida.DataAnnotations also contains formatting attributes like [DataType] that help with formatting and don't provide any validation.

Si consideri il modello di Customer:Consider the Customer model:

using System.ComponentModel.DataAnnotations;

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

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

Utilizzando il seguente file di visualizzazione create. cshtml :Using the following Create.cshtml view file:

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

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

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

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

Il codice precedente:The preceding code:

  • Include gli script di convalida jQuery e jQuery.Includes jQuery and jQuery validation scripts.

  • USA gli Helper Tag <div /> e <span /> per abilitare:Uses the <div /> and <span /> Tag Helpers to enable:

    • Convalida lato client.Client-side validation.
    • Rendering degli errori di convalida.Validation error rendering.
  • Viene generato il codice HTML seguente:Generates the following HTML:

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

Se si pubblica il modulo di creazione senza un valore di nome, viene visualizzato il messaggio di errore "il campo nome è obbligatorio".Posting the Create form without a name value displays the error message "The Name field is required." nel form.on the form. Se JavaScript è abilitato nel client, il browser Visualizza l'errore senza inviare al server.If JavaScript is enabled on the client, the browser displays the error without posting to the server.

L'attributo [StringLength(10)] genera data-val-length-max="10" sul codice HTML sottoposto a rendering.The [StringLength(10)] attribute generates data-val-length-max="10" on the rendered HTML. data-val-length-max impedisce che i browser entrino oltre la lunghezza massima specificata.data-val-length-max prevents browsers from entering more than the maximum length specified. Se viene usato uno strumento come Fiddler per modificare e riprodurre il post:If a tool such as Fiddler is used to edit and replay the post:

  • Con il nome più lungo di 10.With the name longer than 10.
  • Il messaggio di errore "il nome del campo deve essere una stringa con una lunghezza massima di 10".The error message "The field Name must be a string with a maximum length of 10." un errore imprevisto".is returned.

Si consideri il modello di Movie seguente:Consider the following Movie model:

public class Movie
{
    public int ID { get; set; }

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

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

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

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

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

Gli attributi di convalida specificano il comportamento da applicare alle proprietà del modello a cui sono applicati:The validation attributes specify behavior to enforce on the model properties they're applied to:

  • Gli attributi Required e MinimumLength indicano che una proprietà deve avere un valore, ma nulla impedisce a un utente di immettere spazi vuoti per soddisfare la convalida.The Required and MinimumLength attributes indicate that a property must have a value, but nothing prevents a user from entering white space to satisfy this validation.

  • L'attributo RegularExpression viene usato per limitare i caratteri che possono essere inseriti.The RegularExpression attribute is used to limit what characters can be input. Nel codice precedente "Genre":In the preceding code, "Genre":

    • Deve includere solo lettere.Must only use letters.
    • La prima lettera deve essere maiuscola.The first letter is required to be uppercase. Gli spazi, i numeri e i caratteri speciali non sono consentiti.White space, numbers, and special characters are not allowed.
  • RegularExpression "Rating":The RegularExpression "Rating":

    • Richiede che il primo carattere sia una lettera maiuscola.Requires that the first character be an uppercase letter.
    • Consente i caratteri speciali e i numeri negli spazi successivi.Allows special characters and numbers in subsequent spaces. "PG-13" è valido per una classificazione, ma non per "Genre"."PG-13" is valid for a rating, but fails for a "Genre".
  • L'attributo Range vincola un valore all'interno di un intervallo specificato.The Range attribute constrains a value to within a specified range.

  • L'attributo StringLength imposta la lunghezza massima di una proprietà di stringa e, facoltativamente, la lunghezza minima.The StringLength attribute sets the maximum length of a string property, and optionally its minimum length.

  • I tipi di valore, ad esempio decimal, int, float e DateTime, sono intrinsecamente necessari e non richiedono l'attributo [Required].Value types (such as decimal, int, float, DateTime) are inherently required and don't need the [Required] attribute.

Nella pagina Crea per il modello di Movie vengono visualizzati gli errori con valori non validi:The Create page for the Movie model shows displays errors with invalid values:

Il modulo di vista del film con più errori di convalida del lato client jQuery

Per altre informazioni, vedere:For more information, see:

Gestire le richieste HEAD con un fallback del gestore OnGetHandle HEAD requests with an OnGet handler fallback

HEAD richieste consentono di recuperare le intestazioni per una risorsa specifica.HEAD requests allow retrieving the headers for a specific resource. A differenza delle richieste GET, le richieste HEAD non restituiscono un corpo della risposta.Unlike GET requests, HEAD requests don't return a response body.

In genere, per le richieste HEAD viene creato e chiamato un gestore OnHead:Ordinarily, an OnHead handler is created and called for HEAD requests:

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

Razor Pages esegue il fallback alla chiamata al gestore OnGet se non è stato definito alcun gestore OnHead.Razor Pages falls back to calling the OnGet handler if no OnHead handler is defined.

XSRF/CSRF e Razor PagesXSRF/CSRF and Razor Pages

Razor Pages sono protette dalla convalida antifalsificazione.Razor Pages are protected by Antiforgery validation. FormTagHelper inserisce i token antifalsificazione negli elementi del form HTML.The FormTagHelper injects antiforgery tokens into HTML form elements.

Uso di layout, righe parzialmente eseguite, modelli e helper tag con Razor PagesUsing Layouts, partials, templates, and Tag Helpers with Razor Pages

Le pagine funzionano con tutte le funzionalità del motore di visualizzazione Razor.Pages work with all the capabilities of the Razor view engine. Layout, parti parziali, modelli, helper tag, _ViewStart. cshtmle _ViewImports. cshtml funzionano allo stesso modo per le visualizzazioni Razor convenzionali.Layouts, partials, templates, Tag Helpers, _ViewStart.cshtml, and _ViewImports.cshtml work in the same way they do for conventional Razor views.

La pagina verrà ora riorganizzata in modo da usufruire di alcune di queste funzionalità.Let's declutter this page by taking advantage of some of those capabilities.

Aggiungere una pagina di layout a Pages/Shared/_Layout.cshtml:Add a layout page to Pages/Shared/_Layout.cshtml:

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

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

Il Layout:The Layout:

  • Controlla il layout di ogni pagina, a meno che la pagina non accetti il layout.Controls the layout of each page (unless the page opts out of layout).
  • Importa le strutture HTML, ad esempio JavaScript e i fogli di stile.Imports HTML structures such as JavaScript and stylesheets.
  • Viene eseguito il rendering del contenuto della pagina Razor in cui viene chiamato @RenderBody().The contents of the Razor page are rendered where @RenderBody() is called.

Per ulteriori informazioni, vedere pagina layout.For more information, see layout page.

La proprietà Layout proprietà viene impostata in Pages/_ViewStart.cshtml:The Layout property is set in Pages/_ViewStart.cshtml:

@{
    Layout = "_Layout";
}

Il layout è nella cartella Pages/Shared.The layout is in the Pages/Shared folder. Le pagine cercano altre visualizzazioni (layout, modelli, righe parzialmente eseguite) in modo gerarchico, partendo dalla stessa cartella della pagina corrente.Pages look for other views (layouts, templates, partials) hierarchically, starting in the same folder as the current page. Un layout nella cartella Pages/Shared può essere usato da qualsiasi pagina Razor della cartella Pages.A layout in the Pages/Shared folder can be used from any Razor page under the Pages folder.

Il file di layout dovrebbe andare nella cartella Pages/Shared.The layout file should go in the Pages/Shared folder.

Si consiglia di non inserire il file di layout nella cartella Views/Shared.We recommend you not put the layout file in the Views/Shared folder. Views/Shared è un modello destinato alle visualizzazioni MVC.Views/Shared is an MVC views pattern. Le pagine Razor devono basarsi sulla gerarchia di cartelle, non su convenzioni di percorso.Razor Pages are meant to rely on folder hierarchy, not path conventions.

La ricerca delle visualizzazioni da una pagina Razor include la cartella Pages.View search from a Razor Page includes the Pages folder. I layout, i modelli e i parziali usati con i controller MVC e le visualizzazioni Razor convenzionali funzionano semplicemente.The layouts, templates, and partials used with MVC controllers and conventional Razor views just work.

Aggiungere un file Pages/_ViewImports.cshtml:Add a Pages/_ViewImports.cshtml file:

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

@namespace viene spiegato in seguito nell'esercitazione.@namespace is explained later in the tutorial. La direttiva @addTagHelper inserisce gli helper tag predefiniti in tutte le pagine presenti nella cartella Pages.The @addTagHelper directive brings in the built-in Tag Helpers to all the pages in the Pages folder.

La direttiva @namespace impostata in una pagina:The @namespace directive set on a page:

@page
@namespace RazorPagesIntro.Pages.Customers

@model NameSpaceModel

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

La direttiva @namespace imposta lo spazio dei nomi per la pagina.The @namespace directive sets the namespace for the page. La direttiva @model non deve necessariamente includere lo spazio dei nomi.The @model directive doesn't need to include the namespace.

Se la direttiva @namespace è contenuta in _ViewImports.cshtml, lo spazio dei nomi specificato indica il prefisso per lo spazio dei nomi generato nella pagina che importa la direttiva @namespace.When the @namespace directive is contained in _ViewImports.cshtml, the specified namespace supplies the prefix for the generated namespace in the Page that imports the @namespace directive. Il resto dello spazio dei nomi generato (la parte del suffisso) è il percorso relativo separato dal punto tra la cartella contenente _Viewimports.cshtml e la cartella contenente la pagina.The rest of the generated namespace (the suffix portion) is the dot-separated relative path between the folder containing _ViewImports.cshtml and the folder containing the page.

Ad esempio, la classe PageModel Pages/Customers/Edit.cshtml.cs imposta in modo esplicito lo spazio dei nomi:For example, the PageModel class Pages/Customers/Edit.cshtml.cs explicitly sets the namespace:

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

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

        // Code removed for brevity.

Il file Pages/_ViewImports.cshtml file imposta il seguente spazio dei nomi:The Pages/_ViewImports.cshtml file sets the following namespace:

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

Lo spazio dei nomi generato per la pagina Razor Pages/Customers/Edit.cshtml corrisponde alla classe PageModel.The generated namespace for the Pages/Customers/Edit.cshtml Razor Page is the same as the PageModel class.

@namespace Funziona anche con le normali visualizzazioni Razor.@namespace also works with conventional Razor views.

Si consideri il file di visualizzazione pages/create. cshtml :Consider the Pages/Create.cshtml view file:

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

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

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

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

Il file di visualizzazione pages/create. cshtml aggiornato con _ViewImports. cshtml e il file di layout precedente:The updated Pages/Create.cshtml view file with _ViewImports.cshtml and the preceding layout file:

@page
@model CreateModel

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

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

Nel codice precedente, il _ViewImports. cshtml ha importato lo spazio dei nomi e gli helper tag.In the preceding code, the _ViewImports.cshtml imported the namespace and Tag Helpers. Il file di layout ha importato i file JavaScript.The layout file imported the JavaScript files.

Il progetto iniziale per Razor Pages contiene il file Pages/_ValidationScriptsPartial.cshtml, che esegue la convalida sul lato client.The Razor Pages starter project contains the Pages/_ValidationScriptsPartial.cshtml, which hooks up client-side validation.

Per altre informazioni sulle visualizzazioni parziali, vedere Visualizzazioni parziali in ASP.NET Core.For more information on partial views, see Visualizzazioni parziali in ASP.NET Core.

Generazione di URL per le pagineURL generation for Pages

La pagina Create, riportata in precedenza, usa RedirectToPage:The Create page, shown previously, uses RedirectToPage:

public class CreateModel : PageModel
{
    private readonly CustomerDbContext _context;

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

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

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

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

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

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

L'applicazione ha la struttura di file o cartella seguente:The app has the following file/folder structure:

  • /Pages/Pages

    • Index.cshtmlIndex.cshtml

    • Privacy.cshtmlPrivacy.cshtml

    • /Customers/Customers

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

Le pagine pages/Customers/create. cshtml e pages/Customers/Edit. cshtml reindirizza a pages/Customers/index. cshtml dopo l'esito positivo.The Pages/Customers/Create.cshtml and Pages/Customers/Edit.cshtml pages redirect to Pages/Customers/Index.cshtml after success. La stringa ./Index è un nome di pagina relativo usato per accedere alla pagina precedente.The string ./Index is a relative page name used to access the preceding page. Viene usato per generare gli URL nella pagina pages/Customers/index. cshtml .It is used to generate URLs to the Pages/Customers/Index.cshtml page. Ad esempio:For example:

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

Il nome della pagina assoluto /Index viene usato per generare gli URL nella pagina pages/index. cshtml .The absolute page name /Index is used to generate URLs to the Pages/Index.cshtml page. Ad esempio:For example:

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

Il nome della pagina è il percorso alla pagina dalla cartella radice /Pages, inclusa una barra iniziale /, ad esempio /Index.The page name is the path to the page from the root /Pages folder including a leading / (for example, /Index). Gli esempi di generazione di URL precedenti offrono opzioni avanzate e funzionalità funzionali rispetto a un URL a livello di codice.The preceding URL generation samples offer enhanced options and functional capabilities over hard-coding a URL. La generazione di URL usa il routing ed è in grado di generare e codificare i parametri in base al modo in cui la route è definita nel percorso di destinazione.URL generation uses routing and can generate and encode parameters according to how the route is defined in the destination path.

La generazione di URL per le pagine supporta i nomi relativi.URL generation for pages supports relative names. Nella tabella seguente viene illustrata la pagina di indice selezionata utilizzando parametri RedirectToPage diversi in pages/Customers/create. cshtml.The following table shows which Index page is selected using different RedirectToPage parameters in Pages/Customers/Create.cshtml.

RedirectToPage(x)RedirectToPage(x) PaginaPage
RedirectToPage("/Index")RedirectToPage("/Index") Pages/IndexPages/Index
RedirectToPage("./Index");RedirectToPage("./Index"); Pages/Customers/IndexPages/Customers/Index
RedirectToPage("../Index")RedirectToPage("../Index") Pages/IndexPages/Index
RedirectToPage("Index")RedirectToPage("Index") Pages/Customers/IndexPages/Customers/Index

RedirectToPage("Index"), RedirectToPage("./Index")e RedirectToPage("../Index") sono nomi relativi.RedirectToPage("Index"), RedirectToPage("./Index"), and RedirectToPage("../Index") are relative names. Il parametro RedirectToPage è combinato con il percorso della pagina corrente per calcolare il nome della pagina di destinazione.The RedirectToPage parameter is combined with the path of the current page to compute the name of the destination page.

Il collegamento dei nomi relativi è utile quando si compilano siti con una struttura complessa.Relative name linking is useful when building sites with a complex structure. Quando vengono usati nomi relativi per il collegamento tra le pagine in una cartella:When relative names are used to link between pages in a folder:

  • La ridenominazione di una cartella non interrompe i collegamenti relativi.Renaming a folder doesn't break the relative links.
  • I collegamenti non vengono interrotti perché non includono il nome della cartella.Links are not broken because they don't include the folder name.

Per reindirizzare la pagina a un'Area diversa, specificare l'area:To redirect to a page in a different Area, specify the area:

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

Per altre informazioni, vedere Aree in ASP.NET Core e Convenzioni di route e app per Razor Pages in ASP.NET Core.For more information, see Aree in ASP.NET Core and Convenzioni di route e app per Razor Pages in ASP.NET Core.

Attributo viewDataViewData attribute

I dati possono essere passati a una pagina con ViewDataAttribute.Data can be passed to a page with ViewDataAttribute. Le proprietà con l'attributo [ViewData] hanno i valori archiviati e caricati dall'ViewDataDictionary.Properties with the [ViewData] attribute have their values stored and loaded from the ViewDataDictionary.

Nell'esempio seguente, il AboutModel applica l'attributo [ViewData] alla proprietà Title:In the following example, the AboutModel applies the [ViewData] attribute to the Title property:

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

    public void OnGet()
    {
    }
}

Nella pagina About (Informazioni) accedere alla proprietà Title come proprietà del modello:In the About page, access the Title property as a model property:

<h1>@Model.Title</h1>

Nel layout il titolo viene letto dal dizionario ViewData:In the layout, the title is read from the ViewData dictionary:

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

TempDataTempData

ASP.NET Core espone l'TempData.ASP.NET Core exposes the TempData. Questa proprietà archivia i dati finché non viene letta.This property stores data until it's read. I metodi Keep e Peek possono essere usati per esaminare i dati senza eliminazione.The Keep and Peek methods can be used to examine the data without deletion. TempData è utile per il reindirizzamento, quando i dati sono necessari per più di una singola richiesta.TempData is useful for redirection, when data is needed for more than a single request.

Il codice seguente imposta il valore di Message usando TempData:The following code sets the value of Message using TempData:

public class CreateDotModel : PageModel
{
    private readonly AppDbContext _db;

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

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

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

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

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

Il markup seguente nel file Pages/Customers/Index.cshtml visualizza il valore di Message usando TempData.The following markup in the Pages/Customers/Index.cshtml file displays the value of Message using TempData.

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

Il modello di pagina Pages/Customers/Index.cshtml.cs applica l'attributo [TempData] alla proprietà Message.The Pages/Customers/Index.cshtml.cs page model applies the [TempData] attribute to the Message property.

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

Per ulteriori informazioni, vedere TempData.For more information, see TempData.

Più gestori per paginaMultiple handlers per page

La pagina seguente genera markup per due gestori usando l'helper tag asp-page-handler:The following page generates markup for two handlers using the asp-page-handler Tag Helper:

@page
@model CreateFATHModel

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

Il form nell'esempio precedente contiene due pulsanti di invio, ognuno dei quali usa FormActionTagHelper per l'invio a un URL diverso.The form in the preceding example has two submit buttons, each using the FormActionTagHelper to submit to a different URL. L'attributo asp-page-handler è correlato a asp-page.The asp-page-handler attribute is a companion to asp-page. asp-page-handler genera gli URL che indirizzano a ognuno dei metodi gestore definiti da una pagina.asp-page-handler generates URLs that submit to each of the handler methods defined by a page. asp-page non è specificato poiché l'esempio è collegato alla pagina corrente.asp-page isn't specified because the sample is linking to the current page.

Il modello di pagina:The page model:

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

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

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

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

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

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

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

Il codice precedente usa metodi gestore denominati.The preceding code uses named handler methods. I metodi gestore denominati vengono creati usando il testo che nel nome segue On<HTTP Verb> e precede Async (se presente).Named handler methods are created by taking the text in the name after On<HTTP Verb> and before Async (if present). Nell'esempio precedente i metodi della pagina sono OnPostJoinListAsync e OnPostJoinListUCAsync.In the preceding example, the page methods are OnPostJoinListAsync and OnPostJoinListUCAsync. Rimuovendo OnPost e Async, i nomi dei gestori sono JoinList e JoinListUC.With OnPost and Async removed, the handler names are JoinList and JoinListUC.

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

Usando il codice precedente, il percorso URL che indirizza a OnPostJoinListAsync è https://localhost:5001/Customers/CreateFATH?handler=JoinList.Using the preceding code, the URL path that submits to OnPostJoinListAsync is https://localhost:5001/Customers/CreateFATH?handler=JoinList. Il percorso URL che indirizza a OnPostJoinListUCAsync è https://localhost:5001/Customers/CreateFATH?handler=JoinListUC.The URL path that submits to OnPostJoinListUCAsync is https://localhost:5001/Customers/CreateFATH?handler=JoinListUC.

Route personalizzateCustom routes

Usare la direttiva @page per:Use the @page directive to:

  • Specificare una route personalizzata a una pagina.Specify a custom route to a page. Ad esempio, è possibile impostare la route alla pagina About (Informazioni) su /Some/Other/Path con @page "/Some/Other/Path".For example, the route to the About page can be set to /Some/Other/Path with @page "/Some/Other/Path".
  • Aggiungere segmenti alla route predefinita di una pagina.Append segments to a page's default route. Ad esempio, è possibile aggiungere un segmento "item" alla route predefinita di una pagina con @page "item".For example, an "item" segment can be added to a page's default route with @page "item".
  • Aggiungere parametri alla route predefinita di una pagina.Append parameters to a page's default route. Ad esempio, un parametro ID, id, può essere necessario per una pagina con @page "{id}".For example, an ID parameter, id, can be required for a page with @page "{id}".

Un percorso relativo alla directory radice designato da una tilde (~) all'inizio del percorso è supportato.A root-relative path designated by a tilde (~) at the beginning of the path is supported. Ad esempio, @page "~/Some/Other/Path" equivale a @page "/Some/Other/Path".For example, @page "~/Some/Other/Path" is the same as @page "/Some/Other/Path".

È possibile modificare la stringa di query ?handler=JoinList nell'URL in un segmento di route /JoinList specificando il modello di route @page "{handler?}".You can change the query string ?handler=JoinList in the URL to a route segment /JoinList by specifying the route template @page "{handler?}".

Se si vuole omettere la stringa di query ?handler=JoinList dall'URL, è possibile modificare la route in modo da inserire il nome del gestore nella parte di percorso dell'URL.If you don't like the query string ?handler=JoinList in the URL, you can change the route to put the handler name in the path portion of the URL. È possibile personalizzare la route aggiungendo un modello di route racchiuso tra virgolette doppie dopo la direttiva @page.You can customize the route by adding a route template enclosed in double quotes after the @page directive.

@page "{handler?}"
@model CreateRouteModel

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

Usando il codice precedente, il percorso URL che indirizza a OnPostJoinListAsync è https://localhost:5001/Customers/CreateFATH/JoinList.Using the preceding code, the URL path that submits to OnPostJoinListAsync is https://localhost:5001/Customers/CreateFATH/JoinList. Il percorso URL che indirizza a OnPostJoinListUCAsync è https://localhost:5001/Customers/CreateFATH/JoinListUC.The URL path that submits to OnPostJoinListUCAsync is https://localhost:5001/Customers/CreateFATH/JoinListUC.

? che segue handler indica che il parametro di route è facoltativo.The ? following handler means the route parameter is optional.

Impostazioni e configurazione avanzateAdvanced configuration and settings

La configurazione e le impostazioni nelle sezioni seguenti non sono richieste dalla maggior parte delle app.The configuration and settings in following sections is not required by most apps.

Per configurare le opzioni avanzate, usare il metodo di estensione AddRazorPagesOptions:To configure advanced options, use the extension method AddRazorPagesOptions:

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

Usare il RazorPagesOptions per impostare la directory radice per le pagine o aggiungere le convenzioni del modello applicativo per le pagine.Use the RazorPagesOptions to set the root directory for pages, or add application model conventions for pages. Per ulteriori informazioni sulle convenzioni, vedere Razor Pages convenzioni di autorizzazione.For more information on conventions, see Razor Pages authorization conventions.

Per la precompilazione delle visualizzazioni, vedere compilazione della visualizzazione Razor.To precompile views, see Razor view compilation.

Specificare che Razor Pages si trova nella radice del contenutoSpecify that Razor Pages are at the content root

Per impostazione predefinita, la directory radice di Razor Pages è /Pages.By default, Razor Pages are rooted in the /Pages directory. Aggiungere WithRazorPagesAtContentRoot per specificare che i Razor Pages si trovano nella radice del contenuto (ContentRootPath) dell'app:Add WithRazorPagesAtContentRoot to specify that your Razor Pages are at the content root (ContentRootPath) of the app:

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

Specificare che Razor Pages è in una directory radice personalizzataSpecify that Razor Pages are at a custom root directory

Aggiungere WithRazorPagesRoot per specificare che Razor Pages si trovano in una directory radice personalizzata nell'app (fornire un percorso relativo):Add WithRazorPagesRoot to specify that Razor Pages are at a custom root directory in the app (provide a relative path):

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

Risorse aggiuntiveAdditional resources

Di Rick Anderson e Ryan NowakBy Rick Anderson and Ryan Nowak

Razor Pages è una nuova funzionalità di ASP.NET Core MVC che semplifica e rende più produttiva la scrittura di codice incentrata sulle pagine.Razor Pages is a new aspect of ASP.NET Core MVC that makes coding page-focused scenarios easier and more productive.

Se si sta cercando un'esercitazione in cui si usa l'approccio Model-View-Controller, vedere Introduzione ad ASP.NET Core MVC.If you're looking for a tutorial that uses the Model-View-Controller approach, see Get started with ASP.NET Core MVC.

Questo documento offre un'introduzione a Razor Pages.This document provides an introduction to Razor Pages. Non è un'esercitazione dettagliata.It's not a step by step tutorial. Se alcune sezioni risultano troppo avanzate, vedere Introduzione a Razor Pages.If you find some of the sections too advanced, see Get started with Razor Pages. Per una panoramica di ASP.NET Core, vedere Introduzione a ASP.NET Core.For an overview of ASP.NET Core, see the Introduction to ASP.NET Core.

PrerequisitesPrerequisites

Avviso

Se si usa Visual Studio 2017, vedere dotnet/sdk issue #3124 per informazioni sulle versioni di .NET Core SDK che non funzionano con Visual Studio.If you use Visual Studio 2017, see dotnet/sdk issue #3124 for information about .NET Core SDK versions that don't work with Visual Studio.

Creare un progetto Razor PagesCreate a Razor Pages project

Per istruzioni dettagliate su come creare un progetto Razor Pages, vedere Introduzione a Razor Pages.See Get started with Razor Pages for detailed instructions on how to create a Razor Pages project.

Razor PagesRazor Pages

La funzionalità Razor Pages è abilitata in Startup.cs:Razor Pages is enabled in Startup.cs:

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

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

Si consideri una pagina di base: Consider a basic page:

@page

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

Il codice precedente è molto simile a un file di visualizzazione Razor usato in un'app ASP.NET Core con controller e visualizzazioni.The preceding code looks a lot like a Razor view file used in an ASP.NET Core app with controllers and views. Ciò che lo differenzia è la direttiva @page.What makes it different is the @page directive. @page trasforma il file in un'azione MVC, ovvero gestisce le richieste direttamente, senza passare attraverso un controller.@page makes the file into an MVC action - which means that it handles requests directly, without going through a controller. @page deve essere la prima direttiva Razor in una pagina.@page must be the first Razor directive on a page. @page influisce sul comportamento di altri costrutti Razor.@page affects the behavior of other Razor constructs.

Nei due file seguenti viene visualizzata una pagina simile che usa una classe PageModel.A similar page, using a PageModel class, is shown in the following two files. Il file Pages/Index2.cshtml:The Pages/Index2.cshtml file:

@page
@using RazorPagesIntro.Pages
@model IndexModel2

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

Il modello di pagina Pages/Index2.cshtml.cs:The Pages/Index2.cshtml.cs page model:

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

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

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

Per convenzione, il file di classe PageModel ha lo stesso nome del file della pagina Razor con l'aggiunta di .cs.By convention, the PageModel class file has the same name as the Razor Page file with .cs appended. Ad esempio, la pagina Razor precedente è Pages/Index2.cshtml.For example, the previous Razor Page is Pages/Index2.cshtml. Il file che contiene la classe PageModel è denominato Pages/Index2.cshtml.cs.The file containing the PageModel class is named Pages/Index2.cshtml.cs.

Le associazioni dei percorsi URL alle pagine sono determinate dalla posizione della pagina nel file system.The associations of URL paths to pages are determined by the page's location in the file system. Nella tabella seguente sono riportati alcuni percorsi di pagina Razor con gli URL corrispondenti:The following table shows a Razor Page path and the matching URL:

Percorso e nome fileFile name and path URL corrispondentematching URL
/Pages/Index.cshtml/Pages/Index.cshtml / o /Index/ or /Index
/Pages/Contact.cshtml/Pages/Contact.cshtml /Contact
/Pages/Store/Contact.cshtml/Pages/Store/Contact.cshtml /Store/Contact
/Pages/Store/Index.cshtml/Pages/Store/Index.cshtml /Store o /Store/Index/Store or /Store/Index

Note:Notes:

  • Il runtime cerca i file delle pagine Razor nella cartella Pages per impostazione predefinita.The runtime looks for Razor Pages files in the Pages folder by default.
  • Index è la pagina predefinita quando un URL non include una pagina.Index is the default page when a URL doesn't include a page.

Scrivere un form di baseWrite a basic form

Razor Pages semplifica l'implementazione dei modelli normalmente usati con i Web browser durante la creazione di un'app.Razor Pages is designed to make common patterns used with web browsers easy to implement when building an app. L'associazione di modelli, gli helper tag e gli helper HTML funzionano tutti con le proprietà definite in una classe di pagina Razor.Model binding, Tag Helpers, and HTML helpers all just work with the properties defined in a Razor Page class. Si consideri una pagina che implementa un form "contact us" di base per il modello Contact:Consider a page that implements a basic "contact us" form for the Contact model:

Per gli esempi riportati in questo documento, DbContext viene inizializzato nel file Startup.cs.For the samples in this document, the DbContext is initialized in the Startup.cs file.

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

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

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

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

Il modello di dati:The data model:

using System.ComponentModel.DataAnnotations;

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

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

Il contesto del database:The db context:

using Microsoft.EntityFrameworkCore;

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

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

Il file di visualizzazione Pages/Create.cshtml:The Pages/Create.cshtml view file:

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

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

Il modello di pagina Pages/Create.cshtml.cs:The Pages/Create.cshtml.cs page model:

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

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

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

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

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

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

Per convenzione, la classe PageModel è denominata <PageName>Model e si trova nello stesso spazio dei nomi della pagina.By convention, the PageModel class is called <PageName>Model and is in the same namespace as the page.

La classe PageModel consente la separazione della logica di una pagina dalla relativa presentazione.The PageModel class allows separation of the logic of a page from its presentation. Definisce i gestori di pagina per le richieste inviate alla pagina e i dati usati per il rendering della pagina.It defines page handlers for requests sent to the page and the data used to render the page. Questa separazione consente:This separation allows:

La pagina contiene un oggetto OnPostAsync, ovvero un metodo gestore che viene eseguito per le richieste POST, quando un utente invia il form.The page has an OnPostAsync handler method, which runs on POST requests (when a user posts the form). È possibile aggiungere metodi gestore per qualsiasi verbo HTTP.You can add handler methods for any HTTP verb. I gestori più comuni sono:The most common handlers are:

  • OnGet per inizializzare lo stato necessario per la pagina.OnGet to initialize state needed for the page. Esempio di OnGet.OnGet sample.
  • OnPost per gestire gli invii di form.OnPost to handle form submissions.

Il suffisso Async nel nome è facoltativo, ma viene spesso usato per convenzione per le funzioni asincrone.The Async naming suffix is optional but is often used by convention for asynchronous functions. Il codice precedente è tipico di Razor Pages.The preceding code is typical for Razor Pages.

Se si ha familiarità con le app ASP.NET che usano i controller e le visualizzazioni:If you're familiar with ASP.NET apps using controllers and views:

  • Il codice OnPostAsync nell'esempio precedente ha un aspetto simile al codice del controller tipico.The OnPostAsync code in the preceding example looks similar to typical controller code.
  • La maggior parte delle primitive MVC, ad esempio l' associazione di modelli, la convalida, la convalidae i risultati dell'azione, sono condivisi.Most of the MVC primitives like model binding, validation, Validation, and action results are shared.

Il metodo OnPostAsync precedente:The previous OnPostAsync method:

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

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

Il flusso di base di OnPostAsync:The basic flow of OnPostAsync:

Verificare se sono presenti errori di convalida.Check for validation errors.

  • Se non sono presenti errori, salvare i dati e reindirizzare.If there are no errors, save the data and redirect.
  • Se sono presenti errori, visualizzare di nuovo la pagina con i messaggi di convalida.If there are errors, show the page again with validation messages. La convalida lato client è identica alle applicazioni ASP.NET Core MVC tradizionali.Client-side validation is identical to traditional ASP.NET Core MVC applications. In molti casi gli errori di convalida vengono rilevati nel client e mai inviati al server.In many cases, validation errors would be detected on the client, and never submitted to the server.

Quando i dati vengono immessi correttamente, il metodo gestore OnPostAsync chiama il metodo helper RedirectToPage per restituire un'istanza di RedirectToPageResult.When the data is entered successfully, the OnPostAsync handler method calls the RedirectToPage helper method to return an instance of RedirectToPageResult. RedirectToPage è un nuovo risultato dell'azione, simile a RedirectToAction o RedirectToRoute, ma personalizzato per le pagine.RedirectToPage is a new action result, similar to RedirectToAction or RedirectToRoute, but customized for pages. Nell'esempio precedente viene reindirizzato alla pagina di indice radice (/Index).In the preceding sample, it redirects to the root Index page (/Index). Il metodo RedirectToPage è descritto in dettaglio nella sezione Generazione di URL per le pagine.RedirectToPage is detailed in the URL generation for Pages section.

Quando il form inviato contiene errori di convalida (che vengono passati al server), il metodo gestore OnPostAsync chiama il metodo helper Page.When the submitted form has validation errors (that are passed to the server), theOnPostAsync handler method calls the Page helper method. Page restituisce un'istanza di PageResult.Page returns an instance of PageResult. La restituzione di Page è simile al modo in cui le azioni nel controller restituiscono View.Returning Page is similar to how actions in controllers return View. PageResult è il tipo restituito predefinito per un metodo del gestore.PageResult is the default return type for a handler method. Un metodo gestore che restituisce void esegue il rendering della pagina.A handler method that returns void renders the page.

La proprietà Customer usa l'attributo [BindProperty] optare per consentire l'associazione di modelli.The Customer property uses [BindProperty] attribute to opt in to model binding.

public class CreateModel : PageModel
{
    private readonly AppDbContext _db;

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

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

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

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

Per impostazione predefinita, Razor Pages associa le proprietà solo a verbi non GET.Razor Pages, by default, bind properties only with non-GET verbs. Il binding alle proprietà può ridurre la quantità di codice da scrivere.Binding to properties can reduce the amount of code you have to write. Riduce il codice usando la stessa proprietà per il eseguire il rendering dei campi del form (<input asp-for="Customer.Name">) e accettare l'input.Binding reduces code by using the same property to render form fields (<input asp-for="Customer.Name">) and accept the input.

Avviso

Per motivi di sicurezza, è necessario acconsentire esplicitamente all'associazione dei dati della richiesta GET alle proprietà del modello di pagina.For security reasons, you must opt in to binding GET request data to page model properties. Verificare l'input dell'utente prima di eseguirne il mapping alle proprietà.Verify user input before mapping it to properties. La scelta dell'associazione GET è utile per gli scenari che si basano sulla stringa di query o sui valori della route.Opting into GET binding is useful when addressing scenarios that rely on query string or route values.

Per associare una proprietà alle richieste di GET, impostare la proprietà SupportsGet dell'attributo [BindProperty] su true:To bind a property on GET requests, set the [BindProperty] attribute's SupportsGet property to true:

[BindProperty(SupportsGet = true)]

Per altre informazioni, vedere ASP.NET Core community standup: bind on Get Discussion (YouTube).For more information, see ASP.NET Core Community Standup: Bind on GET discussion (YouTube).

La home page (Index.cshtml):The home page (Index.cshtml):

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

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

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

La classe PageModel associata (Index.cshtml.cs):The associated PageModel class (Index.cshtml.cs):

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

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

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

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

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

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

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

            return RedirectToPage();
        }
    }
}

Il file Index.cshtml contiene il markup seguente per creare un collegamento di modifica per ogni contatto:The Index.cshtml file contains the following markup to create an edit link for each contact:

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

L' Helper tag di ancoraggio <a asp-page="./Edit" asp-route-id="@contact.Id">Edit</a> ha usato l'attributo asp-route-{value} per generare un collegamento alla pagina di modifica.The <a asp-page="./Edit" asp-route-id="@contact.Id">Edit</a> Anchor Tag Helper used the asp-route-{value} attribute to generate a link to the Edit page. Il collegamento contiene i dati della route con l'ID contatto.The link contains route data with the contact ID. Ad esempio https://localhost:5001/Edit/1.For example, https://localhost:5001/Edit/1. Gli helper tag consentono al codice lato server di partecipare alla creazione e al rendering di elementi HTML nei file Razor.Tag Helpers enable server-side code to participate in creating and rendering HTML elements in Razor files. Gli helper tag sono abilitati dal @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpersTag Helpers are enabled by @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Il file Pages/Edit.cshtml:The Pages/Edit.cshtml file:

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

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

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

La prima riga contiene la direttiva @page "{id:int}".The first line contains the @page "{id:int}" directive. Il vincolo di routing "{id:int}" indica alla pagina di accettare le richieste inviate alla pagina che contengono i dati della route int.The routing constraint"{id:int}" tells the page to accept requests to the page that contain int route data. Se una richiesta inviata alla pagina non contiene dati della route che possono essere convertiti in un oggetto int, il runtime restituisce un errore HTTP 404 (non trovato).If a request to the page doesn't contain route data that can be converted to an int, the runtime returns an HTTP 404 (not found) error. Per rendere l'ID facoltativo, aggiungere ? al vincolo di route:To make the ID optional, append ? to the route constraint:

@page "{id:int?}"

Il file Pages/Edit.cshtml.cs:The Pages/Edit.cshtml.cs file:

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

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

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

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

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

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

            return Page();
        }

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

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

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

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

Il file Index.cshtml contiene anche il markup per creare un pulsante di eliminazione per ogni contatto cliente:The Index.cshtml file also contains markup to create a delete button for each customer contact:

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

Quando viene eseguito il rendering del pulsante di eliminazione in HTML, il relativo formaction include i parametri per:When the delete button is rendered in HTML, its formaction includes parameters for:

  • L'ID di contatto cliente dall'attributo asp-route-id.The customer contact ID specified by the asp-route-id attribute.
  • L'handler specificato dall'attributo asp-page-handler.The handler specified by the asp-page-handler attribute.

Di seguito è riportato un esempio di pulsante di eliminazione di cui è stato eseguito il rendering con un ID di contatto cliente 1:Here is an example of a rendered delete button with a customer contact ID of 1:

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

Quando il pulsante è selezionato, viene inviata una richiesta POST di modulo al server.When the button is selected, a form POST request is sent to the server. Per convenzione, il nome del metodo del gestore viene selezionato in base al valore del parametro handler in base allo schema OnPost[handler]Async.By convention, the name of the handler method is selected based on the value of the handler parameter according to the scheme OnPost[handler]Async.

Poiché in questo esempio l'handler è delete, il metodo OnPostDeleteAsync viene usato per elaborare la richiesta POST.Because the handler is delete in this example, the OnPostDeleteAsync handler method is used to process the POST request. Se asp-page-handler viene impostato su un valore diverso, ad esempio remove, viene selezionato un metodo gestore con il nome OnPostRemoveAsync.If the asp-page-handler is set to a different value, such as remove, a handler method with the name OnPostRemoveAsync is selected. Il codice seguente illustra il gestore di OnPostDeleteAsync:The following code shows the OnPostDeleteAsync handler:

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

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

    return RedirectToPage();
}

Il metodo OnPostDeleteAsync:The OnPostDeleteAsync method:

  • Accetta l'id dalla stringa di query.Accepts the id from the query string. Se la direttiva della pagina index. cshtml conteneva il vincolo di routing "{id:int?}", id proverrebbe dai dati della route.If the Index.cshtml page directive contained routing constraint "{id:int?}", id would come from route data. I dati della route per id vengono specificati nell'URI, ad esempio https://localhost:5001/Customers/2.The route data for id is specified in the URI such as https://localhost:5001/Customers/2.
  • Interroga il database in merito al contatto del cliente con FindAsync.Queries the database for the customer contact with FindAsync.
  • Se viene trovato il contatto cliente, viene rimosso dall'elenco dei contatti del cliente.If the customer contact is found, they're removed from the list of customer contacts. Il database viene aggiornato.The database is updated.
  • Chiama RedirectToPage per reindirizzare alla pagina di indice radice (/Index).Calls RedirectToPage to redirect to the root Index page (/Index).

Contrassegnare le proprietà della pagina in base alle esigenzeMark page properties as required

Le proprietà di un PageModel possono essere contrassegnate con l'attributo obbligatorio :Properties on a PageModel can be marked with the Required attribute:

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

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

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

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

            // Process color.

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

Per altre informazioni, vedere Convalida del modello.For more information, see Model validation.

Gestire le richieste HEAD con un fallback del gestore OnGetHandle HEAD requests with an OnGet handler fallback

Le richieste HEAD consentono di recuperare le intestazioni di una risorsa specifica.HEAD requests allow you to retrieve the headers for a specific resource. A differenza delle richieste GET, le richieste HEAD non restituiscono un corpo della risposta.Unlike GET requests, HEAD requests don't return a response body.

In genere, per le richieste HEAD viene creato e chiamato un gestore OnHead:Ordinarily, an OnHead handler is created and called for HEAD requests:

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

In ASP.NET Core 2.1 o versioni successive se non è definito alcun gestore OnHead, Razor Pages esegue un fallback per chiamare il gestore OnGet.In ASP.NET Core 2.1 or later, Razor Pages falls back to calling the OnGet handler if no OnHead handler is defined. Questo comportamento è abilitato tramite la chiamata a SetCompatibilityVersion in Startup.ConfigureServices:This behavior is enabled by the call to SetCompatibilityVersion in Startup.ConfigureServices:

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

I modelli predefiniti generano la chiamata SetCompatibilityVersion in ASP.NET Core 2.1 e 2.2.The default templates generate the SetCompatibilityVersion call in ASP.NET Core 2.1 and 2.2. SetCompatibilityVersion imposta effettivamente l'opzione di Razor Pages AllowMappingHeadRequestsToGetHandler su true.SetCompatibilityVersion effectively sets the Razor Pages option AllowMappingHeadRequestsToGetHandler to true.

Anziché acconsentire esplicitamente a tutti i comportamenti con SetCompatibilityVersion, è possibile acconsentire a comportamenti specifici.Rather than opting in to all behaviors with SetCompatibilityVersion, you can explicitly opt in to specific behaviors. Il codice seguente acconsente esplicitamente al mapping delle richieste HEAD al gestore OnGet:The following code opts in to allowing HEAD requests to be mapped to the OnGet handler:

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

XSRF/CSRF e Razor PagesXSRF/CSRF and Razor Pages

Non è necessario scrivere codice per la convalida antifalsificazione.You don't have to write any code for antiforgery validation. La generazione e la convalida del token antifalsificazione sono automaticamente incluse in Razor Pages.Antiforgery token generation and validation are automatically included in Razor Pages.

Uso di layout, righe parzialmente eseguite, modelli e helper tag con Razor PagesUsing Layouts, partials, templates, and Tag Helpers with Razor Pages

Le pagine funzionano con tutte le funzionalità del motore di visualizzazione Razor.Pages work with all the capabilities of the Razor view engine. I layout, le righe parzialmente eseguite, i modelli, gli helper tag, _ViewStart.cshtml e _ViewImports.cshtml funzionano esattamente come nelle normali visualizzazioni Razor.Layouts, partials, templates, Tag Helpers, _ViewStart.cshtml, _ViewImports.cshtml work in the same way they do for conventional Razor views.

La pagina verrà ora riorganizzata in modo da usufruire di alcune di queste funzionalità.Let's declutter this page by taking advantage of some of those capabilities.

Aggiungere una pagina di layout a Pages/Shared/_Layout.cshtml:Add a layout page to Pages/Shared/_Layout.cshtml:

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

Il Layout:The Layout:

  • Controlla il layout di ogni pagina, a meno che la pagina non accetti il layout.Controls the layout of each page (unless the page opts out of layout).
  • Importa le strutture HTML, ad esempio JavaScript e i fogli di stile.Imports HTML structures such as JavaScript and stylesheets.

Vedere l'articolo sulla pagina Layout per altre informazioni.See layout page for more information.

La proprietà Layout proprietà viene impostata in Pages/_ViewStart.cshtml:The Layout property is set in Pages/_ViewStart.cshtml:

@{
    Layout = "_Layout";
}

Il layout è nella cartella Pages/Shared.The layout is in the Pages/Shared folder. Le pagine cercano altre visualizzazioni (layout, modelli, righe parzialmente eseguite) in modo gerarchico, partendo dalla stessa cartella della pagina corrente.Pages look for other views (layouts, templates, partials) hierarchically, starting in the same folder as the current page. Un layout nella cartella Pages/Shared può essere usato da qualsiasi pagina Razor della cartella Pages.A layout in the Pages/Shared folder can be used from any Razor page under the Pages folder.

Il file di layout dovrebbe andare nella cartella Pages/Shared.The layout file should go in the Pages/Shared folder.

Si consiglia di non inserire il file di layout nella cartella Views/Shared.We recommend you not put the layout file in the Views/Shared folder. Views/Shared è un modello destinato alle visualizzazioni MVC.Views/Shared is an MVC views pattern. Le pagine Razor devono basarsi sulla gerarchia di cartelle, non su convenzioni di percorso.Razor Pages are meant to rely on folder hierarchy, not path conventions.

La ricerca delle visualizzazioni da una pagina Razor include la cartella Pages.View search from a Razor Page includes the Pages folder. Il layout, i modelli e le righe parzialmente eseguite in uso con i controller MVC e le visualizzazioni Razor standard funzionano solo.The layouts, templates, and partials you're using with MVC controllers and conventional Razor views just work.

Aggiungere un file Pages/_ViewImports.cshtml:Add a Pages/_ViewImports.cshtml file:

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

@namespace viene spiegato in seguito nell'esercitazione.@namespace is explained later in the tutorial. La direttiva @addTagHelper inserisce gli helper tag predefiniti in tutte le pagine presenti nella cartella Pages.The @addTagHelper directive brings in the built-in Tag Helpers to all the pages in the Pages folder.

Quando la direttiva @namespace viene usata in modo esplicito in una pagina:When the @namespace directive is used explicitly on a page:

@page
@namespace RazorPagesIntro.Pages.Customers

@model NameSpaceModel

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

La direttiva imposta lo spazio dei nomi per la pagina.The directive sets the namespace for the page. La direttiva @model non deve necessariamente includere lo spazio dei nomi.The @model directive doesn't need to include the namespace.

Se la direttiva @namespace è contenuta in _ViewImports.cshtml, lo spazio dei nomi specificato indica il prefisso per lo spazio dei nomi generato nella pagina che importa la direttiva @namespace.When the @namespace directive is contained in _ViewImports.cshtml, the specified namespace supplies the prefix for the generated namespace in the Page that imports the @namespace directive. Il resto dello spazio dei nomi generato (la parte del suffisso) è il percorso relativo separato dal punto tra la cartella contenente _Viewimports.cshtml e la cartella contenente la pagina.The rest of the generated namespace (the suffix portion) is the dot-separated relative path between the folder containing _ViewImports.cshtml and the folder containing the page.

Ad esempio, la classe PageModel Pages/Customers/Edit.cshtml.cs imposta in modo esplicito lo spazio dei nomi:For example, the PageModel class Pages/Customers/Edit.cshtml.cs explicitly sets the namespace:

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

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

        // Code removed for brevity.

Il file Pages/_ViewImports.cshtml file imposta il seguente spazio dei nomi:The Pages/_ViewImports.cshtml file sets the following namespace:

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

Lo spazio dei nomi generato per la pagina Razor Pages/Customers/Edit.cshtml corrisponde alla classe PageModel.The generated namespace for the Pages/Customers/Edit.cshtml Razor Page is the same as the PageModel class.

@namespace Funziona anche con le normali visualizzazioni Razor.@namespace also works with conventional Razor views.

Il file di visualizzazione Pages/Create.cshtml originale:The original Pages/Create.cshtml view file:

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

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

Il file di visualizzazione Pages/Create.cshtml aggiornato:The updated Pages/Create.cshtml view file:

@page
@model CreateModel

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

Il progetto iniziale per Razor Pages contiene il file Pages/_ValidationScriptsPartial.cshtml, che esegue la convalida sul lato client.The Razor Pages starter project contains the Pages/_ValidationScriptsPartial.cshtml, which hooks up client-side validation.

Per altre informazioni sulle visualizzazioni parziali, vedere Visualizzazioni parziali in ASP.NET Core.For more information on partial views, see Visualizzazioni parziali in ASP.NET Core.

Generazione di URL per le pagineURL generation for Pages

La pagina Create, riportata in precedenza, usa RedirectToPage:The Create page, shown previously, uses RedirectToPage:

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

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

L'applicazione ha la struttura di file o cartella seguente:The app has the following file/folder structure:

  • /Pages/Pages

    • Index.cshtmlIndex.cshtml

    • /Customers/Customers

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

Le pagine Pages/Customers/Create.cshtml e Pages/Customers/Edit.cshtml reindirizzano a Pages/Index.cshtml dopo l'esecuzione.The Pages/Customers/Create.cshtml and Pages/Customers/Edit.cshtml pages redirect to Pages/Index.cshtml after success. La stringa /Index fa parte dell'URI di accesso alla pagina precedente.The string /Index is part of the URI to access the preceding page. La stringa /Index può essere usata per generare gli URI alla pagina Pages/Index.cshtml.The string /Index can be used to generate URIs to the Pages/Index.cshtml page. Ad esempio:For example:

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

Il nome della pagina è il percorso alla pagina dalla cartella radice /Pages, inclusa una barra iniziale /, ad esempio /Index.The page name is the path to the page from the root /Pages folder including a leading / (for example, /Index). Gli esempi di generazione di URL precedenti offrono opzioni e caratteristiche funzionali avanzate rispetto agli URL hardcoded.The preceding URL generation samples offer enhanced options and functional capabilities over hardcoding a URL. La generazione di URL usa il routing ed è in grado di generare e codificare i parametri in base al modo in cui la route è definita nel percorso di destinazione.URL generation uses routing and can generate and encode parameters according to how the route is defined in the destination path.

La generazione di URL per le pagine supporta i nomi relativi.URL generation for pages supports relative names. La tabella seguente indica quale pagina di indice viene selezionata con diversi parametri RedirectToPage da Pages/Customers/Create.cshtml:The following table shows which Index page is selected with different RedirectToPage parameters from Pages/Customers/Create.cshtml:

RedirectToPage(x)RedirectToPage(x) PaginaPage
RedirectToPage("/Index")RedirectToPage("/Index") Pages/IndexPages/Index
RedirectToPage("./Index");RedirectToPage("./Index"); Pages/Customers/IndexPages/Customers/Index
RedirectToPage("../Index")RedirectToPage("../Index") Pages/IndexPages/Index
RedirectToPage("Index")RedirectToPage("Index") Pages/Customers/IndexPages/Customers/Index

RedirectToPage("Index"), RedirectToPage("./Index"), e RedirectToPage("../Index") sono nomi relativi.RedirectToPage("Index"), RedirectToPage("./Index"), and RedirectToPage("../Index") are relative names. Il parametro RedirectToPage è combinato con il percorso della pagina corrente per calcolare il nome della pagina di destinazione.The RedirectToPage parameter is combined with the path of the current page to compute the name of the destination page.

Il collegamento dei nomi relativi è utile quando si compilano siti con una struttura complessa.Relative name linking is useful when building sites with a complex structure. Se si usano i nomi relativi per il collegamento tra le pagine in una cartella, è possibile rinominare tale cartella.If you use relative names to link between pages in a folder, you can rename that folder. Tutti i collegamenti continuano a funzionare perché non includono il nome della cartella.All the links still work (because they didn't include the folder name).

Per reindirizzare la pagina a un'Area diversa, specificare l'area:To redirect to a page in a different Area, specify the area:

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

Per ulteriori informazioni, vedere Aree in ASP.NET Core.For more information, see Aree in ASP.NET Core.

Attributo viewDataViewData attribute

È possibile passare i dati a una pagina tramite ViewDataAttribute.Data can be passed to a page with ViewDataAttribute. Le proprietà nei controller o nei modelli di pagine Razor con l'attributo [ViewData] hanno i valori archiviati e caricati dal ViewDataDictionary.Properties on controllers or Razor Page models with the [ViewData] attribute have their values stored and loaded from the ViewDataDictionary.

Nell'esempio seguente, il AboutModel contiene una proprietà Title contrassegnata con [ViewData].In the following example, the AboutModel contains a Title property marked with [ViewData]. La proprietà Title è impostata sul titolo della pagina About (Informazioni):The Title property is set to the title of the About page:

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

    public void OnGet()
    {
    }
}

Nella pagina About (Informazioni) accedere alla proprietà Title come proprietà del modello:In the About page, access the Title property as a model property:

<h1>@Model.Title</h1>

Nel layout il titolo viene letto dal dizionario ViewData:In the layout, the title is read from the ViewData dictionary:

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

TempDataTempData

ASP.NET Core espone la proprietà TempData per un controller.ASP.NET Core exposes the TempData property on a controller. Questa proprietà archivia i dati finché non viene letta.This property stores data until it's read. I metodi Keep e Peek possono essere usati per esaminare i dati senza eliminazione.The Keep and Peek methods can be used to examine the data without deletion. TempData è utile per il reindirizzamento quando i dati sono necessari per più di una singola richiesta.TempData is useful for redirection, when data is needed for more than a single request.

Il codice seguente imposta il valore di Message usando TempData:The following code sets the value of Message using TempData:

public class CreateDotModel : PageModel
{
    private readonly AppDbContext _db;

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

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

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

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

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

Il markup seguente nel file Pages/Customers/Index.cshtml visualizza il valore di Message usando TempData.The following markup in the Pages/Customers/Index.cshtml file displays the value of Message using TempData.

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

Il modello di pagina Pages/Customers/Index.cshtml.cs applica l'attributo [TempData] alla proprietà Message.The Pages/Customers/Index.cshtml.cs page model applies the [TempData] attribute to the Message property.

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

Per altre informazioni, vedere TempData.For more information, see TempData .

Più gestori per paginaMultiple handlers per page

La pagina seguente genera markup per due gestori usando l'helper tag asp-page-handler:The following page generates markup for two handlers using the asp-page-handler Tag Helper:

@page
@model CreateFATHModel

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

Il form nell'esempio precedente contiene due pulsanti di invio, ognuno dei quali usa FormActionTagHelper per l'invio a un URL diverso.The form in the preceding example has two submit buttons, each using the FormActionTagHelper to submit to a different URL. L'attributo asp-page-handler è correlato a asp-page.The asp-page-handler attribute is a companion to asp-page. asp-page-handler genera gli URL che indirizzano a ognuno dei metodi gestore definiti da una pagina.asp-page-handler generates URLs that submit to each of the handler methods defined by a page. asp-page non è specificato poiché l'esempio è collegato alla pagina corrente.asp-page isn't specified because the sample is linking to the current page.

Il modello di pagina:The page model:

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

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

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

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

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

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

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

Il codice precedente usa metodi gestore denominati.The preceding code uses named handler methods. I metodi gestore denominati vengono creati usando il testo che nel nome segue On<HTTP Verb> e precede Async (se presente).Named handler methods are created by taking the text in the name after On<HTTP Verb> and before Async (if present). Nell'esempio precedente i metodi della pagina sono OnPostJoinListAsync e OnPostJoinListUCAsync.In the preceding example, the page methods are OnPostJoinListAsync and OnPostJoinListUCAsync. Rimuovendo OnPost e Async, i nomi dei gestori sono JoinList e JoinListUC.With OnPost and Async removed, the handler names are JoinList and JoinListUC.

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

Usando il codice precedente, il percorso URL che indirizza a OnPostJoinListAsync è https://localhost:5001/Customers/CreateFATH?handler=JoinList.Using the preceding code, the URL path that submits to OnPostJoinListAsync is https://localhost:5001/Customers/CreateFATH?handler=JoinList. Il percorso URL che indirizza a OnPostJoinListUCAsync è https://localhost:5001/Customers/CreateFATH?handler=JoinListUC.The URL path that submits to OnPostJoinListUCAsync is https://localhost:5001/Customers/CreateFATH?handler=JoinListUC.

Route personalizzateCustom routes

Usare la direttiva @page per:Use the @page directive to:

  • Specificare una route personalizzata a una pagina.Specify a custom route to a page. Ad esempio, è possibile impostare la route alla pagina About (Informazioni) su /Some/Other/Path con @page "/Some/Other/Path".For example, the route to the About page can be set to /Some/Other/Path with @page "/Some/Other/Path".
  • Aggiungere segmenti alla route predefinita di una pagina.Append segments to a page's default route. Ad esempio, è possibile aggiungere un segmento "item" alla route predefinita di una pagina con @page "item".For example, an "item" segment can be added to a page's default route with @page "item".
  • Aggiungere parametri alla route predefinita di una pagina.Append parameters to a page's default route. Ad esempio, un parametro ID, id, può essere necessario per una pagina con @page "{id}".For example, an ID parameter, id, can be required for a page with @page "{id}".

Un percorso relativo alla directory radice designato da una tilde (~) all'inizio del percorso è supportato.A root-relative path designated by a tilde (~) at the beginning of the path is supported. Ad esempio, @page "~/Some/Other/Path" equivale a @page "/Some/Other/Path".For example, @page "~/Some/Other/Path" is the same as @page "/Some/Other/Path".

È possibile modificare la stringa di query ?handler=JoinList nell'URL in un segmento di route /JoinList specificando il modello di route @page "{handler?}".You can change the query string ?handler=JoinList in the URL to a route segment /JoinList by specifying the route template @page "{handler?}".

Se si vuole omettere la stringa di query ?handler=JoinList dall'URL, è possibile modificare la route in modo da inserire il nome del gestore nella parte di percorso dell'URL.If you don't like the query string ?handler=JoinList in the URL, you can change the route to put the handler name in the path portion of the URL. È possibile personalizzare la route aggiungendo un modello di route racchiuso tra virgolette doppie dopo la direttiva @page.You can customize the route by adding a route template enclosed in double quotes after the @page directive.

@page "{handler?}"
@model CreateRouteModel

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

Usando il codice precedente, il percorso URL che indirizza a OnPostJoinListAsync è https://localhost:5001/Customers/CreateFATH/JoinList.Using the preceding code, the URL path that submits to OnPostJoinListAsync is https://localhost:5001/Customers/CreateFATH/JoinList. Il percorso URL che indirizza a OnPostJoinListUCAsync è https://localhost:5001/Customers/CreateFATH/JoinListUC.The URL path that submits to OnPostJoinListUCAsync is https://localhost:5001/Customers/CreateFATH/JoinListUC.

? che segue handler indica che il parametro di route è facoltativo.The ? following handler means the route parameter is optional.

Configurazione e impostazioniConfiguration and settings

Per configurare le opzioni avanzate, usare il metodo di estensione AddRazorPagesOptions nel generatore MVC:To configure advanced options, use the extension method AddRazorPagesOptions on the MVC builder:

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

Attualmente è possibile usare RazorPagesOptions per impostare la directory radice per le pagine o aggiungere convenzioni di modello applicativo per le pagine.Currently you can use the RazorPagesOptions to set the root directory for pages, or add application model conventions for pages. In questo modo si potrà garantire una maggiore estendibilità in futuro.We'll enable more extensibility this way in the future.

Per la precompilazione delle visualizzazioni, vedere l'articolo sulla compilazione delle visualizzazioni Razor.To precompile views, see Razor view compilation .

Scaricare o visualizzare il codice di esempio.Download or view sample code.

Vedere Introduzione a Razor Pages, che si basa su questa introduzione.See Get started with Razor Pages, which builds on this introduction.

Specificare che Razor Pages si trova nella radice del contenutoSpecify that Razor Pages are at the content root

Per impostazione predefinita, la directory radice di Razor Pages è /Pages.By default, Razor Pages are rooted in the /Pages directory. Aggiungere WithRazorPagesAtContentRoot a AddMvc per specificare che il Razor Pages si trova nella radice del contenuto (ContentRootPath) dell'app:Add WithRazorPagesAtContentRoot to AddMvc to specify that your Razor Pages are at the content root (ContentRootPath) of the app:

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

Specificare che Razor Pages è in una directory radice personalizzataSpecify that Razor Pages are at a custom root directory

Aggiungere WithRazorPagesRoot a AddMvc per specificare che Razor Pages si trova in una directory radice personalizzata nell'app (fornire un percorso relativo):Add WithRazorPagesRoot to AddMvc to specify that your Razor Pages are at a custom root directory in the app (provide a relative path):

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

Risorse aggiuntiveAdditional resources