Helper tag nei moduli in ASP.NET Core

Di Rick Anderson, N. Taylor Mullen, Dave Paquette e Jerrie Pelser

Questo documento dimostra come lavorare con i moduli e gli elementi HTML comunemente utilizzati in un modulo. L'elemento Form del linguaggio HTML rappresenta il meccanismo principale usato dalle app Web per eseguire il postback di dati nel server. La maggior parte di questo documento descrive gli helper tag e spiega come questi consentono di creare moduli HTML solidi in modo produttivo. Prima di leggere questo documento, è consigliabile leggere Introduzione agli helper tag.

In molti casi, gli helper HTML forniscono un approccio alternativo a un helper tag specifico. Tuttavia, è importante riconoscere che gli helper tag non sostituiscono gli helper HTML e non esiste un helper tag per ogni helper HTML. Se un'alternativa sotto forma di helper HTML esiste, viene citata.

Helper del tag Form

L'helper tag Form:

  • Genera il valore dell'attributo HTML< FORM>action per un'azione del controller MVC o una route denominata.

  • Genera un token di verifica della richiesta nascosto per impedire la falsificazione della richiesta intersito (se usata con l'attributo [ValidateAntiForgeryToken] nel metodo di azione POST HTTP).

  • Fornisce l'attributo asp-route-<Parameter Name>, dove <Parameter Name> viene aggiunto ai valori della route. I routeValues parametri per Html.BeginForm e Html.BeginRouteForm forniscono funzionalità simili.

  • Ha un'alternativa Html.BeginForm all'helper HTML e Html.BeginRouteForm.

Esempio:

<form asp-controller="Demo" asp-action="Register" method="post">
    <!-- Input and Submit elements -->
</form>

L'helper tag modulo precedente genera il codice HTML seguente:

<form method="post" action="/Demo/Register">
    <!-- Input and Submit elements -->
    <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>

Il runtime MVC genera il valore dell'attributo action dagli attributi asp-controller e asp-action dell'helper tag Form. Il Tag Helper di Form genera anche un token di verifica della richiesta nascosto per prevenire contraffazioni di richieste inter-sito, quando utilizzato con l'attributo [ValidateAntiForgeryToken] nel metodo di azione HTTP Post. Proteggere un modulo HTML puro dalla falsificazione di richiesta intersito è difficile, ma il Form Tag Helper fornisce questo servizio per te.

Uso di una route denominata

L'attributo asp-route degli helper tag può anche generare un markup per l'attributo action HTML. Un'app con una route denominata register può usare il markup seguente per la pagina di registrazione:

<form asp-route="register" method="post">
    <!-- Input and Submit elements -->
</form>

Molte delle visualizzazioni nella cartella Views/Account (generate quando si crea una nuova app Web con account singoli) contengono l'attributo asp-route-returnurl :

<form asp-controller="Account" asp-action="Login"
     asp-route-returnurl="@ViewData["ReturnUrl"]"
     method="post" class="form-horizontal" role="form">

Nota

Con i modelli predefiniti, returnUrl viene popolato automaticamente solo quando provi ad accedere a una risorsa autorizzata, ma non sei autenticato o autorizzato. Se l'utente tenta un accesso non autorizzato, il middleware di sicurezza lo reindirizza alla pagina di accesso con returnUrl impostato.

Helper tag per l'azione del modulo

Il Tag Helper dell'azione modulo genera l'attributo formaction sull'elemento <button ...> o sul tag <input type="image" ...> generato. L'attributo formaction controlla se un modulo invia i dati. Viene associato agli elementi <input> di tipo image e agli elementi <button>. L'helper di tag per l'azione del modulo consente di utilizzare diversi attributi AnchorTagHelperasp- per controllare quale collegamento formaction viene generato per l'elemento corrispondente.

Attributi di AnchorTagHelper supportati per controllare il valore di formaction:

Attributo Descrizione
asp-controller Nome del controller.
asp-action Nome del metodo di azione.
asp-area Nome dell'area.
asp-page Nome della Razor pagina.
asp-page-handler Nome del Razor gestore della pagina.
asp-route Nome della route.
asp-route-{value} Singolo valore di route URL. Ad esempio: asp-route-id="1234".
asp-all-route-data Tutti i valori di percorso.
asp-fragment Frammento di URL.

Esempio di invio al controller

Il markup seguente invia il modulo all'azione Index di HomeController quando viene selezionato l'input o il pulsante:

<form method="post">
    <button asp-controller="Home" asp-action="Index">Click Me</button>
    <input type="image" src="..." alt="Or Click Me" asp-controller="Home" 
                                asp-action="Index">
</form>

Il markup precedente genera il codice HTML seguente:

<form method="post">
    <button formaction="/Home">Click Me</button>
    <input type="image" src="..." alt="Or Click Me" formaction="/Home">
</form>

Invia a esempio di pagina

Il markup seguente invia il modulo alla AboutRazor pagina:

<form method="post">
    <button asp-page="About">Click Me</button>
    <input type="image" src="..." alt="Or Click Me" asp-page="About">
</form>

Il markup precedente genera il codice HTML seguente:

<form method="post">
    <button formaction="/About">Click Me</button>
    <input type="image" src="..." alt="Or Click Me" formaction="/About">
</form>

Esempio di invio a una route

Prendere in considerazione l'endpoint /Home/Test:

public class HomeController : Controller
{
    [Route("/Home/Test", Name = "Custom")]
    public string Test()
    {
        return "This is the test page";
    }
}

Il markup seguente invia il modulo all'endpoint /Home/Test.

<form method="post">
    <button asp-route="Custom">Click Me</button>
    <input type="image" src="..." alt="Or Click Me" asp-route="Custom">
</form>

Il markup precedente genera il codice HTML seguente:

<form method="post">
    <button formaction="/Home/Test">Click Me</button>
    <input type="image" src="..." alt="Or Click Me" formaction="/Home/Test">
</form>

Helper di tag Input

L'helper tag di input collega un elemento di input <> HTML a un'espressione del modello nella visualizzazione Razor.

Sintassi:

<input asp-for="<Expression Name>">

L'helper per i tag di input:

  • Genera gli attributi HTML id e name per il nome dell'espressione specificata nell'attributo asp-for. asp-for="Property1.Property2" è pari a m => m.Property1.Property2. Il nome dell'espressione viene usato come valore dell'attributo asp-for. Per altre informazioni, vedere la sezione Nomi di espressione .

  • Imposta il valore dell'attributo HTML type in base al tipo di modello e agli attributi di annotazione dei dati applicati alla proprietà del modello.

  • Non sovrascriverà il valore dell'attributo HTML type quando ne viene specificato uno.

  • Genera attributi di convalida HTML5 dagli attributi di annotazione dei dati applicati alle proprietà del modello.

  • Sovrappone una funzionalità di helper HTML con Html.TextBoxFor e Html.EditorFor. Per i dettagli, vedere la sezione Alternative agli helper HTML per i tag di input.

  • Consente una tipizzazione forte. Se il nome della proprietà cambia e non si aggiorna l'helper tag, verrà visualizzato un errore simile al seguente:

    An error occurred during the compilation of a resource required to process
    this request. Please review the following specific error details and modify
    your source code appropriately.
    
    Type expected
    'RegisterViewModel' does not contain a definition for 'Email' and no
    extension method 'Email' accepting a first argument of type 'RegisterViewModel'
    could be found (are you missing a using directive or an assembly reference?)
    

L'helper tag Input imposta l'attributo HTML type in base al tipo .NET. La tabella seguente elenca alcuni tipi .NET comuni e il tipo HTML generato. Non sono elencati tutti i tipi .NET.

Tipo .NET Tipo di input
Bool type="checkbox"
Stringa type="text"
Data/Ora type="datetime-local"
Byte type="numero"
int type="numero"
Singolo, Doppio type="numero"

La tabella seguente illustra alcuni attributi di annotazioni dei dati comuni di cui l'helper tag Input esegue il mapping a tipi di input specifici (non tutti gli attributi di convalida sono elencati):

Attributo Tipo di input
[EmailAddress] tipo="email"
[URL] type="url"
[HiddenInput] type="hidden"
[Telefono] type="tel"
[DataType(DataType.Password)] type="password"
[DataType(DataType.Date)] type="date"
[DataType(DataType.Time)] type="time"

Esempio:

using System.ComponentModel.DataAnnotations;

namespace FormsTagHelper.ViewModels
{
    public class RegisterViewModel
    {
        [Required]
        [EmailAddress]
        [Display(Name = "Email Address")]
        public string Email { get; set; }

        [Required]
        [DataType(DataType.Password)]
        public string Password { get; set; }
    }
}
@model RegisterViewModel

<form asp-controller="Demo" asp-action="RegisterInput" method="post">
    <label>Email: <input asp-for="Email" /></label> <br />
    <label>Password: <input asp-for="Password" /></label><br />
    <button type="submit">Register</button>
</form>

Il codice precedente genera il codice HTML seguente:

<form method="post" action="/Demo/RegisterInput">
    Email:
    <input type="email" data-val="true"
            data-val-email="The Email Address field is not a valid email address."
            data-val-required="The Email Address field is required."
            id="Email" name="Email" value=""><br>
    Password:
    <input type="password" data-val="true"
            data-val-required="The Password field is required."
            id="Password" name="Password"><br>
    <button type="submit">Register</button>
    <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>

Le annotazioni dei dati applicate alle proprietà Email e Password generano metadati per il modello. L'helper tag di input utilizza i metadati del modello e produce attributi HTML5data-val-* (vedere Convalida del modello). Questi attributi descrivono i validator da collegare ai campi di input. Questo fornisce una convalida discreta sia per HTML5 che per jQuery. Gli attributi non invasivi hanno il formato data-val-rule="Error Message", dove regola è il nome della regola di convalida, ad esempio data-val-required, data-val-email, data-val-maxlength e così via. Se viene specificato un messaggio di errore nell'attributo , viene visualizzato come valore per l'attributo data-val-rule . Esistono anche attributi di data-val-ruleName-argumentName="argumentValue" di Form che offrono dettagli aggiuntivi sulla regola, ad esempio, data-val-maxlength-max="1024" .

Quando si associano più input controlli alla stessa proprietà, i controlli generati condividono lo stesso id oggetto, rendendo così il mark-up generato non valido. Per evitare duplicati, specificare l'attributo id per ogni controllo in modo esplicito.

Rendering della casella di controllo nascosta

Le caselle di controllo in HTML5 non inviano un valore quando sono deselezionate. Per abilitare l'invio di un valore predefinito per una casella di controllo deselezionata, l'helper tag di input genera un input nascosto aggiuntivo per le caselle di controllo.

Si consideri ad esempio il markup seguente Razor che usa l'helper tag di input per una proprietà IsCheckeddel modello booleana :

<form method="post">
    <input asp-for="@Model.IsChecked" />
    <button type="submit">Submit</button>
</form>

Il markup precedente Razor genera markup HTML simile al seguente:

<form method="post">
    <input name="IsChecked" type="checkbox" value="true" />
    <button type="submit">Submit</button>

    <input name="IsChecked" type="hidden" value="false" /> 
</form>

Il markup HTML sopraelencato mostra un input nascosto aggiuntivo con un nome di IsChecked e un valore di false. Per impostazione predefinita, il rendering dell'input nascosto viene eseguito alla fine del modulo. Quando viene inviato il modulo:

  • Se l'input della IsChecked casella di controllo è selezionato, entrambi true e false vengono inviati come valori.
  • Se la casella di controllo IsChecked non è selezionata, viene inviato solo il valore di input nascosto false.

Il processo di associazione di modelli di ASP.NET Core legge solo il primo valore quando si esegue l'associazione a un valore bool, il che comporta true per le caselle di controllo selezionate e false per quelle deselezionate.

Per configurare il comportamento del rendering dell'input nascosto, impostare la proprietà CheckBoxHiddenInputRenderMode su MvcViewOptions.HtmlHelperOptions. Ad esempio:

services.Configure<MvcViewOptions>(options =>
    options.HtmlHelperOptions.CheckBoxHiddenInputRenderMode =
        CheckBoxHiddenInputRenderMode.None);

Il codice precedente disabilita il rendering dell'input nascosto per le caselle di controllo impostando CheckBoxHiddenInputRenderMode su CheckBoxHiddenInputRenderMode.None. Per tutte le modalità di rendering disponibili, vedere l'enumerazione CheckBoxHiddenInputRenderMode .

Alternative HTML Helper per il Tag Helper di Input

Html.TextBox, Html.TextBoxFor, Html.Editore Html.EditorFor hanno funzionalità sovrapposte con l'helper tag di input. L'helper tag Input imposta automaticamente l'attributo type, mentre Html.TextBox e Html.TextBoxFor non lo fanno. Html.Editor e Html.EditorFor gestiscono raccolte, oggetti complessi e modelli. L'helper tag di input non lo fa. L'helper tag di input, Html.EditorFor, e Html.TextBoxFor sono fortemente tipizzati (usano espressioni lambda); Html.TextBox e Html.Editor non lo sono (usano nomi di espressione).

HtmlAttributes

Quando eseguono i modelli predefiniti, @Html.Editor() e @Html.EditorFor() usano una voce ViewDataDictionary speciale denominata htmlAttributes. È possibile aumentare questo comportamento usando i parametri additionalViewData. La chiave "htmlAttributes" non fa distinzione tra maiuscole e minuscole. La chiave "htmlAttributes" viene gestita in modo analogo all'oggetto htmlAttributes passato agli helper di input come @Html.TextBox().

@Html.EditorFor(model => model.YourProperty, 
  new { htmlAttributes = new { @class="myCssClass", style="Width:100px" } })

Nomi delle espressioni

Il valore dell'attributo asp-for è un ModelExpression, cioè il lato destro di un'espressione lambda. Di conseguenza, asp-for="Property1" diventa m => m.Property1 nel codice generato, motivo per cui non è necessario anteporre il prefisso con Model. È possibile usare il carattere "@" per iniziare un'espressione inline, spostandolo prima di m.:

@{
  var joe = "Joe";
}

<input asp-for="@joe">

Genera quanto segue:

<input type="text" id="joe" name="joe" value="Joe">

Con le proprietà delle raccolte, asp-for="CollectionProperty[23].Member" genera lo stesso nome di asp-for="CollectionProperty[i].Member" se il valore di i è 23.

Quando ASP.NET Core MVC calcola il valore di ModelExpression, analizza diverse origini, tra cui ModelState. Considera <input type="text" asp-for="Name">. L'attributo value calcolato è il primo valore non nullo da:

  • Voce con chiave ModelState "Name".
  • Risultato dell'espressione Model.Name.

È anche possibile passare alle proprietà figlio tramite il percorso delle proprietà del modello di visualizzazione. Si consideri una classe modello più complessa contenente una proprietà figlia Address.

public class AddressViewModel
{
    public string AddressLine1 { get; set; }
}
public class RegisterAddressViewModel
{
    public string Email { get; set; }

    [DataType(DataType.Password)]
    public string Password { get; set; }

    public AddressViewModel Address { get; set; }
}

Nella visualizzazione, viene eseguita l'associazione a Address.AddressLine1:

@model RegisterAddressViewModel

<form asp-controller="Demo" asp-action="RegisterAddress" method="post">
    <label>Email: <input asp-for="Email" /></label> <br />
    <label>Password: <input asp-for="Password" /></label><br />
    <label>Address: <input asp-for="Address.AddressLine1" /></label><br />
    <button type="submit">Register</button>
</form>

Per Address.AddressLine1 viene generato il codice HTML seguente:

<input type="text" id="Address_AddressLine1" name="Address.AddressLine1" value="">

Nomi delle espressioni e delle collezioni

Esempio di modello contenente una matrice di Colors:

public class Person
{
    public List<string> Colors { get; set; }

    public int Age { get; set; }
}

Metodo di azione:

public IActionResult Edit(int id, int colorIndex)
{
    ViewData["Index"] = colorIndex;
    return View(GetPerson(id));
}

Di seguito Razor viene illustrato come accedere a un elemento specifico Color :

@model Person
@{
    var index = (int)ViewData["index"];
}

<form asp-controller="ToDo" asp-action="Edit" method="post">
    @Html.EditorFor(m => m.Colors[index])
    <label asp-for="Age"></label>
    <input asp-for="Age" /><br />
    <button type="submit">Post</button>
</form>

Il Views/Shared/EditorTemplates/String.cshtml modello:

@model string

<label asp-for="@Model"></label>
<input asp-for="@Model" /> <br />

Esempio di uso di List<T>:

public class ToDoItem
{
    public string Name { get; set; }

    public bool IsDone { get; set; }
}

Di seguito Razor viene illustrato come eseguire l'iterazione su una raccolta:

@model List<ToDoItem>

<form asp-controller="ToDo" asp-action="Edit" method="post">
    <table>
        <tr> <th>Name</th> <th>Is Done</th> </tr>

        @for (int i = 0; i < Model.Count; i++)
        {
            <tr>
                @Html.EditorFor(model => model[i])
            </tr>
        }

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

Il Views/Shared/EditorTemplates/ToDoItem.cshtml modello:

@model ToDoItem

<td>
    <label asp-for="@Model.Name"></label>
    @Html.DisplayFor(model => model.Name)
</td>
<td>
    <input asp-for="@Model.IsDone" />
</td>

@*
    This template replaces the following Razor which evaluates the indexer three times.
    <td>
         <label asp-for="@Model[i].Name"></label>
         @Html.DisplayFor(model => model[i].Name)
     </td>
     <td>
         <input asp-for="@Model[i].IsDone" />
     </td>
*@

foreach deve essere usato se possibile, quando il valore verrà usato in un contesto asp-for o in un contesto equivalente Html.DisplayFor. In genere for è preferibile a foreach (se lo scenario lo consente) perché non è necessario allocare un enumeratore. Tuttavia, la valutazione di un indicizzatore in un'espressione LINQ può essere dispendiosa e deve essere ridotta al minimo.

 

Nota

Il codice di esempio commentato precedente illustra come sostituire l'espressione lambda con l'operatore @ per accedere a ogni ToDoItem nell'elenco.

Tag Helper Textarea

Il tag helper Textarea Tag Helper è simile all'helper tag di input.

  • Genera gli attributi id e name, e gli attributi di convalida dei dati dal modello per un elemento <textarea>.

  • Consente una tipizzazione forte.

  • HTML Helper alternativo: Html.TextAreaFor.

Esempio:

using System.ComponentModel.DataAnnotations;

namespace FormsTagHelper.ViewModels
{
    public class DescriptionViewModel
    {
        [MinLength(5)]
        [MaxLength(1024)]
        public string Description { get; set; }
    }
}
@model DescriptionViewModel

<form asp-controller="Demo" asp-action="RegisterTextArea" method="post">
    <textarea asp-for="Description"></textarea>
    <button type="submit">Test</button>
</form>

Viene generato il codice HTML seguente:

<form method="post" action="/Demo/RegisterTextArea">
  <textarea data-val="true"
   data-val-maxlength="The field Description must be a string or array type with a maximum length of &#x27;1024&#x27;."
   data-val-maxlength-max="1024"
   data-val-minlength="The field Description must be a string or array type with a minimum length of &#x27;5&#x27;."
   data-val-minlength-min="5"
   id="Description" name="Description">
  </textarea>
  <button type="submit">Test</button>
  <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>

Helper per il tag Label

  • Genera la didascalia e l'attributo for su un elemento <etichetta> per un nome di espressione.

  • Alternativa per Helper HTML: Html.LabelFor.

Offre Label Tag Helper i vantaggi seguenti rispetto a un elemento etichetta HTML puro:

  • Si ottiene automaticamente il valore descrittivo dell'etichetta dall'attributo Display. Il nome visualizzato desiderato può cambiare nel tempo e la combinazione dell'attributo Display e dell'helper tag Label applica l'attributo Display ovunque venga usato.

  • Meno markup nel codice sorgente.

  • Tipizzazione forte con la proprietà del modello.

Esempio:

using System.ComponentModel.DataAnnotations;

namespace FormsTagHelper.ViewModels
{
    public class SimpleViewModel
    {
        [Required]
        [EmailAddress]
        [Display(Name = "Email Address")]
        public string Email { get; set; }
    }
}

@model SimpleViewModel

<form asp-controller="Demo" asp-action="RegisterLabel" method="post">
    <label asp-for="Email"></label>
    <input asp-for="Email" /> <br />
</form>

Per l'elemento <label> viene generato il codice HTML seguente:

<label for="Email">Email Address</label>

L'helper tag Label genera il valore dell'attributo for di "Email", che è l'ID associato all'elemento <input>. Gli helper tag generano elementi id e for coerenti. In questo modo possono essere associati correttamente. La didascalia di questo esempio deriva dall'attributo Display. Se il modello non contiene un attributo Display, la didascalia corrisponde al nome della proprietà dell'espressione. Per eseguire l'override della didascalia predefinita, aggiungere una didascalia all'interno del tag di etichetta.

I helper tag di validazione

Ci sono due Tag Helper di convalida. Validation Message Tag Helper, che visualizza un messaggio di convalida per una singola proprietà del modello, e Validation Summary Tag Helper, che visualizza un riepilogo degli errori di convalida. Input Tag Helper aggiunge attributi di convalida sul lato del client HTML5 agli elementi di input in base agli attributi di annotazione dei dati delle classi del modello. La convalida viene eseguita anche per il server. Quando si verifica un errore di convalida, l'helper tag di convalida visualizza questi messaggi di errore.

Il Tag Helper del Messaggio di Convalida

  • Aggiunge l'attributo HTML5data-valmsg-for="property" all'elemento span, che aggiunge i messaggi di errore di convalida sul campo di input della proprietà del modello specificato. Quando si verifica un errore di convalida sul lato client, jQuery visualizza il messaggio di errore nell'elemento <span>.

  • La convalida viene eseguita anche nel server. I client potrebbero avere JavaScript disabilitato e alcune convalide possono essere eseguite solo sul lato server.

  • Helper HTML alternativo: Html.ValidationMessageFor.

Viene utilizzato con l'attributo asp-validation-for su un elemento span HTML.

<span asp-validation-for="Email"></span>

L'helper tag Validation Message genera il codice HTML seguente:

<span class="field-validation-valid"
  data-valmsg-for="Email"
  data-valmsg-replace="true"></span>

In genere si usa il Validation Message Tag Helper dopo un Input Tag Helper per la stessa proprietà. In questo modo è possibile visualizzare i messaggi di errore di convalida vicino all'input che ha causato l'errore.

Nota

È necessario disporre di una visualizzazione con i riferimenti corretti agli script JavaScript e jQuery per la convalida lato client. Per altre informazioni, vedere Convalida del modello.

Se si verifica un errore di convalida sul lato server, ad esempio quando la convalida sul lato server è personalizzata o quando la convalida sul lato client è disabilitata, MVC inserisce il messaggio di errore nel corpo dell'elemento <span>.

<span class="field-validation-error" data-valmsg-for="Email"
            data-valmsg-replace="true">
   The Email Address field is required.
</span>

Tag Helper per il Riepilogo Validazione

  • Indirizza gli elementi <div> con l'attributo asp-validation-summary.

  • Helper HTML alternativo: @Html.ValidationSummary.

Viene Validation Summary Tag Helper utilizzato per visualizzare un riepilogo dei messaggi di convalida. Il valore dell'attributo asp-validation-summary può corrispondere a uno dei valori seguenti:

asp-validation-summary Messaggi di convalida visualizzati
All Proprietà e livello del modello
ModelOnly Modello
None Nessuno

Esempio

Nell'esempio seguente il modello di dati ha DataAnnotation attributi, che genera messaggi di errore di convalida sull'elemento <input> . Quando si verifica un errore di convalida, l'helper tag di convalida visualizza il messaggio di errore:

using System.ComponentModel.DataAnnotations;

namespace FormsTagHelper.ViewModels
{
    public class RegisterViewModel
    {
        [Required]
        [EmailAddress]
        [Display(Name = "Email Address")]
        public string Email { get; set; }

        [Required]
        [DataType(DataType.Password)]
        public string Password { get; set; }
    }
}
@model RegisterViewModel

<form asp-controller="Demo" asp-action="RegisterValidation" method="post">
    <div asp-validation-summary="ModelOnly"></div>
    <label>Email: <input asp-for="Email" /></label> <br />
    <span asp-validation-for="Email"></span><br />
    <label>Password: <input asp-for="Password" /></label><br />
    <span asp-validation-for="Password"></span><br />
    <button type="submit">Register</button>
</form>

Codice HTML generato (se il modello è valido):

<form action="/DemoReg/Register" method="post">
  <label>Email: <input name="Email" id="Email" type="email" value=""
   data-val-required="The Email field is required."
   data-val-email="The Email field is not a valid email address."
   data-val="true"></label><br>
  <span class="field-validation-valid" data-valmsg-replace="true"
   data-valmsg-for="Email"></span><br>
  <label>Password: <input name="Password" id="Password" type="password"
   data-val-required="The Password field is required." data-val="true"></label><br>
  <span class="field-validation-valid" data-valmsg-replace="true"
   data-valmsg-for="Password"></span><br>
  <button type="submit">Register</button>
  <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>

Tag Helper Select

  • Genera l'elemento select e gli elementi option associati per le proprietà del modello.

  • Ha un'alternativa Html.DropDownListFor all'helper HTML e Html.ListBoxFor.

Specifica il nome della proprietà del modello per l'elemento select e asp-for specifica gli elementi option. Ad esempio:

<select asp-for="Country" asp-items="Model.Countries"></select> 

Esempio:

using Microsoft.AspNetCore.Mvc.Rendering;
using System.Collections.Generic;

namespace FormsTagHelper.ViewModels
{
    public class CountryViewModel
    {
        public string Country { get; set; }

        public List<SelectListItem> Countries { get; } = new List<SelectListItem>
        {
            new SelectListItem { Value = "MX", Text = "Mexico" },
            new SelectListItem { Value = "CA", Text = "Canada" },
            new SelectListItem { Value = "US", Text = "USA" },
        };
    }
}

Il Index metodo inizializza CountryViewModel, imposta il paese selezionato e lo passa alla Index visualizzazione.

public IActionResult Index()
{
    var model = new CountryViewModel();
    model.Country = "CA";
    return View(model);
}

Il metodo Index di HTTP POST visualizza la selezione:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index(CountryViewModel model)
{
    if (ModelState.IsValid)
    {
        var msg = model.Country + " selected";
        return RedirectToAction("IndexSuccess", new { message = msg });
    }

    // If we got this far, something failed; redisplay form.
    return View(model);
}

Visualizzazione Index:

@model CountryViewModel

<form asp-controller="Home" asp-action="Index" method="post">
    <select asp-for="Country" asp-items="Model.Countries"></select> 
    <br /><button type="submit">Register</button>
</form>

Che genera il codice HTML seguente (con "CA" selezionato):

<form method="post" action="/">
     <select id="Country" name="Country">
       <option value="MX">Mexico</option>
       <option selected="selected" value="CA">Canada</option>
       <option value="US">USA</option>
     </select>
       <br /><button type="submit">Register</button>
     <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
   </form>

Nota

Non è consigliabile usare ViewBag o ViewData con l'helper tag Select. Un modello di visualizzazione è più affidabile per fornire metadati MVC e meno problematici.

Il valore dell'attributo asp-for è un caso speciale e non richiede un Model prefisso. Gli altri attributi dei Tag Helper funzionano (come asp-items).

<select asp-for="Country" asp-items="Model.Countries"></select> 

Associazione enum

Spesso è comodo usare <select> con una proprietà enum e generare gli elementi SelectListItem dai valori enum.

Esempio:

public class CountryEnumViewModel
{
    public CountryEnum EnumCountry { get; set; }
}
using System.ComponentModel.DataAnnotations;

namespace FormsTagHelper.ViewModels
{
    public enum CountryEnum
    {
        [Display(Name = "United Mexican States")]
        Mexico,
        [Display(Name = "United States of America")]
        USA,
        Canada,
        France,
        Germany,
        Spain
    }
}

Il metodo GetEnumSelectList genera un oggetto SelectList per un enum.

@model CountryEnumViewModel

<form asp-controller="Home" asp-action="IndexEnum" method="post">
    <select asp-for="EnumCountry" 
            asp-items="Html.GetEnumSelectList<CountryEnum>()">
    </select> 
    <br /><button type="submit">Register</button>
</form>

È possibile contrassegnare l'elenco dei valori enumerati con l'attributo Display per ottenere un'interfaccia più completa.

using System.ComponentModel.DataAnnotations;

namespace FormsTagHelper.ViewModels
{
    public enum CountryEnum
    {
        [Display(Name = "United Mexican States")]
        Mexico,
        [Display(Name = "United States of America")]
        USA,
        Canada,
        France,
        Germany,
        Spain
    }
}

Viene generato il codice HTML seguente:

<form method="post" action="/Home/IndexEnum">
    <select data-val="true" data-val-required="The EnumCountry field is required."
            id="EnumCountry" name="EnumCountry">
        <option value="0">United Mexican States</option>
        <option value="1">United States of America</option>
        <option value="2">Canada</option>
        <option value="3">France</option>
        <option value="4">Germany</option>
        <option selected="selected" value="5">Spain</option>
    </select>
    <br /><button type="submit">Register</button>
    <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>

Gruppo di opzioni

L'elemento <optgroup> viene generato quando il modello di visualizzazione contiene uno o più SelectListGroup oggetti.

CountryViewModelGroup suddivide gli elementi SelectListItem nei gruppi "North America" ed "Europe":

public class CountryViewModelGroup
{
    public CountryViewModelGroup()
    {
        var NorthAmericaGroup = new SelectListGroup { Name = "North America" };
        var EuropeGroup = new SelectListGroup { Name = "Europe" };

        Countries = new List<SelectListItem>
        {
            new SelectListItem
            {
                Value = "MEX",
                Text = "Mexico",
                Group = NorthAmericaGroup
            },
            new SelectListItem
            {
                Value = "CAN",
                Text = "Canada",
                Group = NorthAmericaGroup
            },
            new SelectListItem
            {
                Value = "US",
                Text = "USA",
                Group = NorthAmericaGroup
            },
            new SelectListItem
            {
                Value = "FR",
                Text = "France",
                Group = EuropeGroup
            },
            new SelectListItem
            {
                Value = "ES",
                Text = "Spain",
                Group = EuropeGroup
            },
            new SelectListItem
            {
                Value = "DE",
                Text = "Germany",
                Group = EuropeGroup
            }
      };
    }

    public string Country { get; set; }

    public List<SelectListItem> Countries { get; }

I due gruppi sono indicati di seguito:

esempio di gruppi di opzioni

Codice HTML generato:

 <form method="post" action="/Home/IndexGroup">
      <select id="Country" name="Country">
          <optgroup label="North America">
              <option value="MEX">Mexico</option>
              <option value="CAN">Canada</option>
              <option value="US">USA</option>
          </optgroup>
          <optgroup label="Europe">
              <option value="FR">France</option>
              <option value="ES">Spain</option>
              <option value="DE">Germany</option>
          </optgroup>
      </select>
      <br /><button type="submit">Register</button>
      <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
 </form>

Selezione multipla

L'helper tag Select genera automaticamente l'attributo multiple = "multiple" se la proprietà specificata nell'attributo asp-for è IEnumerable. Dato, ad esempio, il modello seguente:

using Microsoft.AspNetCore.Mvc.Rendering;
using System.Collections.Generic;

namespace FormsTagHelper.ViewModels
{
    public class CountryViewModelIEnumerable
    {
        public IEnumerable<string> CountryCodes { get; set; }

        public List<SelectListItem> Countries { get; } = new List<SelectListItem>
        {
            new SelectListItem { Value = "MX", Text = "Mexico" },
            new SelectListItem { Value = "CA", Text = "Canada" },
            new SelectListItem { Value = "US", Text = "USA"    },
            new SelectListItem { Value = "FR", Text = "France" },
            new SelectListItem { Value = "ES", Text = "Spain"  },
            new SelectListItem { Value = "DE", Text = "Germany"}
         };
    }
}

Con la visualizzazione seguente:

@model CountryViewModelIEnumerable

<form asp-controller="Home" asp-action="IndexMultiSelect" method="post">
    <select asp-for="CountryCodes" asp-items="Model.Countries"></select> 
    <br /><button type="submit">Register</button>
</form>

Viene generato il codice HTML seguente:

<form method="post" action="/Home/IndexMultiSelect">
    <select id="CountryCodes"
    multiple="multiple"
    name="CountryCodes"><option value="MX">Mexico</option>
<option value="CA">Canada</option>
<option value="US">USA</option>
<option value="FR">France</option>
<option value="ES">Spain</option>
<option value="DE">Germany</option>
</select>
    <br /><button type="submit">Register</button>
  <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>

Nessuna selezione

Se si usa l'opzione "not specified" in più pagine, è possibile creare un modello per evitare di ripetere lo stesso codice HTML:

@model CountryViewModel

<form asp-controller="Home" asp-action="IndexEmpty" method="post">
    @Html.EditorForModel()
    <br /><button type="submit">Register</button>
</form>

Il Views/Shared/EditorTemplates/CountryViewModel.cshtml modello:

@model CountryViewModel

<select asp-for="Country" asp-items="Model.Countries">
    <option value="">--none--</option>
</select>

L'aggiunta di elementi HTML <opzione> non è limitata al caso Nessuna selezione. Ad esempio, il metodo di visualizzazione e azione seguente genererà codice HTML simile al codice precedente:

public IActionResult IndexNone()
{
    var model = new CountryViewModel();
    model.Countries.Insert(0, new SelectListItem("<none>", ""));
    return View(model);
}
@model CountryViewModel

<form asp-controller="Home" asp-action="IndexEmpty" method="post">
    <select asp-for="Country">
        <option value="">&lt;none&gt;</option>
        <option value="MX">Mexico</option>
        <option value="CA">Canada</option>
        <option value="US">USA</option>
    </select> 
    <br /><button type="submit">Register</button>
</form>

L'elemento corretto <option> verrà selezionato (conterrà l'attributo selected="selected" ) a seconda del valore corrente Country .

public IActionResult IndexOption(int id)
{
    var model = new CountryViewModel();
    model.Country = "CA";
    return View(model);
}
 <form method="post" action="/Home/IndexEmpty">
      <select id="Country" name="Country">
          <option value="">&lt;none&gt;</option>
          <option value="MX">Mexico</option>
          <option value="CA" selected="selected">Canada</option>
          <option value="US">USA</option>
      </select>
      <br /><button type="submit">Register</button>
   <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
 </form>

Risorse aggiuntive