Componenti di visualizzazione in ASP.NET Core
Componenti di visualizzazione
I componenti di visualizzazione hanno aspetti comuni con le visualizzazioni parziali, ma sono molto più efficienti. I componenti di visualizzazione non usano l'associazione di modelli, dipendono dai dati passati quando si chiama il componente di visualizzazione. Questo articolo è stato scritto usando controller e visualizzazioni, ma i componenti di visualizzazione funzionano con Razor Pages.
Un componente di visualizzazione:
- Esegue il rendering di un blocco anziché di un'intera risposta.
- Include la stessa separazione dei concetti e gli stessi vantaggi per i test individuati nel controller e nella visualizzazione.
- Può contenere parametri e logica di business.
- In genere viene richiamato da una pagina di layout.
I componenti di visualizzazione sono destinati ovunque la logica di rendering riutilizzabile troppo complessa per una visualizzazione parziale, ad esempio:
- Menu di spostamento dinamici
- Contrassegna il cloud, in cui esegue query sul database
- Pannello di accesso
- Carrello acquisti
- Articoli recentemente pubblicati
- Contenuto della barra laterale in un blog
- Pannello di accesso di cui viene eseguito il rendering in ogni pagina e vengono visualizzati i collegamenti per disconnettersi o accedere, a seconda dello stato di accesso dell'utente
Un componente di visualizzazione è costituito da due parti:
- Classe, in genere derivata da ViewComponent
- Risultato restituito, in genere una visualizzazione.
Come i controller, un componente di visualizzazione può essere poco, ma la maggior parte degli sviluppatori sfrutta i metodi e le proprietà disponibili derivando da ViewComponent.
Quando si valuta se i componenti di visualizzazione soddisfano le specifiche di un'app, prendere in considerazione l'uso dei Razor componenti. Razor i componenti combinano anche il markup con il codice C# per produrre unità di interfaccia utente riutilizzabili. Razor i componenti sono progettati per la produttività degli sviluppatori quando forniscono logica e composizione dell'interfaccia utente sul lato client. Per altre informazioni, vedere ASP.NET Componenti di baseRazor. Per informazioni su come incorporare Razor i componenti in un'app MVC o Razor Pages, vedere Integrare componenti ASP.NET Core Razor in app ASP.NET Core.
Creare un componente di visualizzazione
Questa sezione contiene i requisiti principali per creare un componente di visualizzazione. Più avanti in questo articolo, vengono esaminati nel dettaglio tutti i passaggi e viene creato un componente di visualizzazione.
Classe del componente di visualizzazione
È possibile creare una classe del componente di visualizzazione in uno dei modi seguenti:
- Derivazione da ViewComponent
- Assegnando a una classe con l'attributo
[ViewComponent]
o derivando da una classe con l'attributo[ViewComponent]
- Creazione di una classe in cui il nome termina con il suffisso
ViewComponent
Come i controller, i componenti di visualizzazione devono essere classi pubbliche, non devono essere classi annidate e astratte. Il nome del componente di visualizzazione è il nome della classe con il ViewComponent
suffisso rimosso. È anche possibile specificarlo in modo esplicito usando la proprietà Name.
Una classe del componente di visualizzazione:
- Supporta l'inserimento delle dipendenze del costruttore
- Non partecipa al ciclo di vita del controller, pertanto i filtri non possono essere usati in un componente di visualizzazione
Per impedire che una classe con suffisso senza distinzione tra maiuscole e minuscole ViewComponent
venga considerata come componente di visualizzazione, decorare la classe con l'attributo [NonViewComponent]
:
using Microsoft.AspNetCore.Mvc;
[NonViewComponent]
public class ReviewComponent
{
public string Status(string name) => JobStatus.GetCurrentStatus(name);
}
Metodi del componente di visualizzazione
Un componente di visualizzazione definisce la logica in un:
InvokeAsync
metodo che restituisceTask<IViewComponentResult>
.Invoke
metodo sincrono che restituisce un oggetto IViewComponentResult.
I parametri vengono rilevati direttamente dalla chiamata del componente di visualizzazione e non dall'associazione di modelli. Un componente di visualizzazione non gestisce mai direttamente una richiesta. In genere, inizializza un modello e lo passa a una visualizzazione chiamando il metodo View
. Riepilogando, i metodi del componente di visualizzazione:
- Definiscono un metodo
InvokeAsync
che restituisceTask<IViewComponentResult>
o un metodo sincronoInvoke
che restituisceIViewComponentResult
. - Inizializza in genere un modello e lo passa a una visualizzazione chiamando il metodo ViewComponent.View .
- I parametri vengono rilevati dal metodo di chiamata, non da HTTP, e non vi è alcuna associazione di modelli.
- Non è raggiungibile direttamente come endpoint HTTP. In genere vengono richiamati in una visualizzazione. Un componente di visualizzazione non gestisce mai una richiesta.
- Sono sottoposti a overload sulla firma e non sui dettagli dalla richiesta HHTP corrente.
Percorso di ricerca della visualizzazione
Il runtime esegue la ricerca della visualizzazione nei percorsi seguenti:
- /Views/{Nome controller}/Components/{Nome componente visualizzazione}/{Nome visualizzazione}
- /Views/Shared/Components/{Nome componente visualizzazione}/{Nome visualizzazione}
- /Pages/Shared/Components/{Nome componente visualizzazione}/{Nome visualizzazione}
- /Areas/{Nome area}/Views/Shared/Components/{View Component Name}/{View Name}
Il percorso di ricerca si applica ai progetti che usano controller e visualizzazioni e Razor pagine.
Il nome di visualizzazione predefinito per un componente di visualizzazione è Default
, il che significa che i file di visualizzazione verranno in genere denominati Default.cshtml
. È possibile specificare un nome di visualizzazione diverso quando si crea il risultato del componente di visualizzazione o quando si chiama il View
metodo .
È consigliabile denominare il file Default.cshtml
di visualizzazione e usare il percorso Views/Shared/Components/{View Component Name}/{View Name} . Il PriorityList
componente di visualizzazione usato in questo esempio usa Views/Shared/Components/PriorityList/Default.cshtml
per la visualizzazione del componente di visualizzazione.
Personalizzare il percorso di ricerca della visualizzazione
Per personalizzare il percorso di ricerca della visualizzazione, modificare Razorla raccolta di ViewLocationFormats . Ad esempio, per cercare visualizzazioni all'interno del percorso /Components/{View Component Name}/{View Name}
, aggiungere un nuovo elemento alla raccolta:
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews()
.AddRazorOptions(options =>
{
options.ViewLocationFormats.Add("/{0}.cshtml");
});
builder.Services.AddDbContext<ToDoContext>(options =>
options.UseInMemoryDatabase("db"));
var app = builder.Build();
// Remaining code removed for brevity.
Nel codice precedente il segnaposto {0}
rappresenta il percorso Components/{View Component Name}/{View Name}
.
Richiamare un componente di visualizzazione
Per usare il componente di visualizzazione, chiamare il codice seguente all'interno di una visualizzazione:
@await Component.InvokeAsync("Name of view component",
{Anonymous Type Containing Parameters})
I parametri vengono passati al InvokeAsync
metodo . Il PriorityList
componente di visualizzazione sviluppato nell'articolo viene richiamato dal file di Views/ToDo/Index.cshtml
visualizzazione. Nel codice seguente il InvokeAsync
metodo viene chiamato con due parametri:
</table>
<div>
Maximum Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync("PriorityList",
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
Richiamare un componente di visualizzazione come helper tag
Un componente di visualizzazione può essere richiamato come helper tag:
<div>
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@{
int maxPriority = Convert.ToInt32(ViewData["maxPriority"]);
bool isDone = Convert.ToBoolean(ViewData["isDone"]);
}
<vc:priority-list max-priority=maxPriority is-done=isDone>
</vc:priority-list>
</div>
La classe scritta usando la convenzione Pascal e i parametri del metodo per gli helper tag vengono convertiti nel formato corrispondente kebab case. Per richiamare un componente di visualizzazione, l'helper tag usa l'elemento <vc></vc>
. Il componente di visualizzazione viene specificato nel modo seguente:
<vc:[view-component-name]
parameter1="parameter1 value"
parameter2="parameter2 value">
</vc:[view-component-name]>
Per usare un componente di visualizzazione come helper tag, registrare l'assembly contenente il componente di visualizzazione usando la direttiva @addTagHelper
. Se il componente di visualizzazione si trova in un assembly denominato MyWebApp
, aggiungere la direttiva seguente al _ViewImports.cshtml
file :
@addTagHelper *, MyWebApp
Un componente di visualizzazione può essere registrato come helper tag a qualsiasi file che fa riferimento al componente di visualizzazione. Vedere Gestione dell'ambito dell'helper tag per altre informazioni su come registrare gli helper tag.
Il metodo InvokeAsync
usato in questa esercitazione:
@await Component.InvokeAsync("PriorityList",
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
Nel markup precedente, il componente di PriorityList
visualizzazione diventa priority-list
. I parametri per il componente di visualizzazione vengono passati come attributi nel formato kebab case.
Richiamare un componente di visualizzazione direttamente da un controller
I componenti di visualizzazione vengono in genere richiamati da una visualizzazione, ma possono essere richiamati direttamente da un metodo controller. Anche se i componenti di visualizzazione non definiscono endpoint come controller, è possibile implementare un'azione controller che restituisce il contenuto di un oggetto ViewComponentResult
.
Nell'esempio seguente il componente di visualizzazione viene chiamato direttamente dal controller:
public IActionResult IndexVC(int maxPriority = 2, bool isDone = false)
{
return ViewComponent("PriorityList",
new {
maxPriority = maxPriority,
isDone = isDone
});
}
Creare un componente di visualizzazione di base
Scaricare, compilare e testare il codice di avvio. Si tratta di un progetto di base con un ToDo
controller che visualizza un elenco di elementi ToDo .
Aggiornare il controller per passare lo stato di priorità e completamento
Aggiornare il Index
metodo per usare i parametri di stato di priorità e completamento:
using Microsoft.AspNetCore.Mvc;
using ViewComponentSample.Models;
namespace ViewComponentSample.Controllers;
public class ToDoController : Controller
{
private readonly ToDoContext _ToDoContext;
public ToDoController(ToDoContext context)
{
_ToDoContext = context;
_ToDoContext.Database.EnsureCreated();
}
public IActionResult Index(int maxPriority = 2, bool isDone = false)
{
var model = _ToDoContext!.ToDo!.ToList();
ViewData["maxPriority"] = maxPriority;
ViewData["isDone"] = isDone;
return View(model);
}
Aggiungere una classe ViewComponent
Aggiungere una classe ViewComponent a ViewComponents/PriorityListViewComponent.cs
:
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents;
public class PriorityListViewComponent : ViewComponent
{
private readonly ToDoContext db;
public PriorityListViewComponent(ToDoContext context) => db = context;
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
Note riguardanti il codice:
Le classi del componente di visualizzazione possono essere contenute in qualsiasi cartella del progetto.
Poiché il nome della classe PriorityListViewComponent termina con il suffisso ViewComponent, il runtime usa la stringa
PriorityList
quando si fa riferimento al componente della classe da una visualizzazione.L'attributo
[ViewComponent]
può modificare il nome usato per fare riferimento a un componente di visualizzazione. Ad esempio, la classe potrebbe essere stata denominataXYZ
con l'attributo seguente[ViewComponent]
:[ViewComponent(Name = "PriorityList")] public class XYZ : ViewComponent
L'attributo
[ViewComponent]
nel codice precedente indica al selettore del componente di visualizzazione di usare:- Nome
PriorityList
durante la ricerca delle visualizzazioni associate al componente - Stringa "PriorityList" quando si fa riferimento al componente della classe da una vista.
- Nome
Il componente usa l'inserimento delle dipendenze per rendere disponibile il contesto dei dati.
InvokeAsync
espone un metodo che può essere chiamato da una vista e può accettare un numero arbitrario di argomenti.Il metodo
InvokeAsync
restituisce il set di elementiToDo
che soddisfano i parametriisDone
emaxPriority
.
Creare la visualizzazione del componente Razor di visualizzazione
Creare la cartella Views/Shared/Components. Il nome di questa cartella deve essere Components.
Creare la cartella Views/Shared/Components/PriorityList. Questo nome della cartella deve corrispondere al nome della classe del componente di visualizzazione o al nome della classe meno il suffisso. Se viene usato l'attributo
ViewComponent
, il nome della classe deve corrispondere alla designazione dell'attributo.Creare una
Views/Shared/Components/PriorityList/Default.cshtml
Razor visualizzazione:@model IEnumerable<ViewComponentSample.Models.TodoItem> <h3>Priority Items</h3> <ul> @foreach (var todo in Model) { <li>@todo.Name</li> } </ul>
La Razor visualizzazione accetta un elenco di
TodoItem
e le visualizza. Se il metodo del componenteInvokeAsync
di visualizzazione non passa il nome della visualizzazione, default viene usato per il nome della visualizzazione per convenzione. Per sostituire lo stile predefinito per un controller specifico, aggiungere una visualizzazione alla cartella di visualizzazione specifica del controller, ad esempio Views/ToDo/Components/PriorityList/Default.cshtml.Se il componente di visualizzazione è specifico del controller, può essere aggiunto alla cartella specifica del controller. Ad esempio,
Views/ToDo/Components/PriorityList/Default.cshtml
è specifico del controller.Aggiungere un oggetto
div
contenente una chiamata al componente dell'elenco di priorità nella parte inferiore delViews/ToDo/index.cshtml
file:</table> <div> Maximum Priority: @ViewData["maxPriority"] <br /> Is Complete: @ViewData["isDone"] @await Component.InvokeAsync("PriorityList", new { maxPriority = ViewData["maxPriority"], isDone = ViewData["isDone"] } ) </div>
Il markup @await Component.InvokeAsync
illustra la sintassi per chiamare i componenti di visualizzazione. Il primo argomento corrisponde al nome del componente che si vuole richiamare o chiamare. I parametri successivi vengono passati al componente. InvokeAsync
può accettare un numero arbitrario di argomenti.
Test dell'app. La figura seguente illustra l'elenco ToDo e gli elementi con priorità:
Il componente di visualizzazione può essere chiamato direttamente dal controller:
public IActionResult IndexVC(int maxPriority = 2, bool isDone = false)
{
return ViewComponent("PriorityList",
new {
maxPriority = maxPriority,
isDone = isDone
});
}
Specificare il nome di un componente di visualizzazione
Per un componente di visualizzazione, in alcune condizioni è possibile dover specificare una visualizzazione non predefinita. Il codice seguente illustra come specificare la visualizzazione "PVC" dal metodo InvokeAsync
. Aggiornare il metodo InvokeAsync
nella classe PriorityListViewComponent
.
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
string MyView = "Default";
// If asking for all completed tasks, render with the "PVC" view.
if (maxPriority > 3 && isDone == true)
{
MyView = "PVC";
}
var items = await GetItemsAsync(maxPriority, isDone);
return View(MyView, items);
}
Copiare il Views/Shared/Components/PriorityList/Default.cshtml
file in una vista denominata Views/Shared/Components/PriorityList/PVC.cshtml
. Aggiungere un'intestazione per indicare che viene usata una visualizzazione PVC.
@model IEnumerable<ViewComponentSample.Models.TodoItem>
<h2> PVC Named Priority Component View</h2>
<h4>@ViewBag.PriorityMessage</h4>
<ul>
@foreach (var todo in Model)
{
<li>@todo.Name</li>
}
</ul>
Eseguire l'app e verificare la visualizzazione PVC.
Se non viene eseguito il rendering della visualizzazione PVC, verificare che venga chiamato il componente di visualizzazione con priorità 4 o superiore.
Esaminare il percorso di visualizzazione
Modificare il parametro relativo alla priorità impostandolo su tre o priorità inferiore perché la visualizzazione con priorità non venga restituita.
Rinominare temporaneamente l'oggetto
Views/ToDo/Components/PriorityList/Default.cshtml
in1Default.cshtml
.Testare l'app, si verifica l'errore seguente:
An unhandled exception occurred while processing the request. InvalidOperationException: The view 'Components/PriorityList/Default' wasn't found. The following locations were searched: /Views/ToDo/Components/PriorityList/Default.cshtml /Views/Shared/Components/PriorityList/Default.cshtml
Copiare
Views/ToDo/Components/PriorityList/1Default.cshtml
inViews/Shared/Components/PriorityList/Default.cshtml
.Aggiungere markup alla visualizzazione del componente di visualizzazione ToDo in Shared per indicare che la visualizzazione proviene dalla cartella Shared.
Testare la visualizzazione del componente Shared.
Evitare stringhe hardcoded
Per la sicurezza in fase di compilazione, sostituire il nome del componente di visualizzazione hardcoded con il nome della classe. Aggiornare il file PriorityListViewComponent.cs per non usare il suffisso "ViewComponent":
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents;
public class PriorityList : ViewComponent
{
private readonly ToDoContext db;
public PriorityList(ToDoContext context)
{
db = context;
}
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
Il file di visualizzazione :
</table>
<div>
Testing nameof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(nameof(PriorityList),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
Un overload di Component.InvokeAsync
metodo che accetta un tipo CLR usa l'operatore typeof
:
</table>
<div>
Testing typeof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(typeof(PriorityList),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
Eseguire operazioni sincrone
Il framework gestisce la chiamata di un metodo sincrono Invoke
se il lavoro asincrono non è necessario. Il metodo seguente crea un componente di visualizzazione Invoke
sincrono:
using Microsoft.AspNetCore.Mvc;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents
{
public class PriorityListSync : ViewComponent
{
private readonly ToDoContext db;
public PriorityListSync(ToDoContext context)
{
db = context;
}
public IViewComponentResult Invoke(int maxPriority, bool isDone)
{
var x = db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToList();
return View(x);
}
}
}
Il file del componente di Razor visualizzazione:
<div>
Testing nameof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(nameof(PriorityListSync),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
Il componente di visualizzazione viene richiamato in un Razor file ,ad esempio , Views/Home/Index.cshtml
usando uno degli approcci seguenti:
Per usare l'approccio IViewComponentHelper, chiamare Component.InvokeAsync
:
@await Component.InvokeAsync(nameof(PriorityList),
new { maxPriority = 4, isDone = true })
Per usare l'helper tag, registrare l'assembly contenente il componente di visualizzazione usando la direttiva @addTagHelper
(il componente di visualizzazione è in un assembly denominato MyWebApp
):
@addTagHelper *, MyWebApp
Usare l'helper tag del componente di visualizzazione nel Razor file di markup:
<vc:priority-list max-priority="999" is-done="false">
</vc:priority-list>
La firma del metodo di PriorityList.Invoke
è sincrona, ma Razor trova e chiama il metodo con Component.InvokeAsync
nel file di markup.
Risorse aggiuntive
Componenti di visualizzazione
I componenti di visualizzazione hanno aspetti comuni con le visualizzazioni parziali, ma sono molto più efficienti. I componenti di visualizzazione non usano l'associazione di modelli, dipendono dai dati passati quando si chiama il componente di visualizzazione. Questo articolo è stato scritto usando controller e visualizzazioni, ma i componenti di visualizzazione funzionano con Razor Pages.
Un componente di visualizzazione:
- Esegue il rendering di un blocco anziché di un'intera risposta.
- Include la stessa separazione dei concetti e gli stessi vantaggi per i test individuati nel controller e nella visualizzazione.
- Può contenere parametri e logica di business.
- In genere viene richiamato da una pagina di layout.
I componenti di visualizzazione sono destinati ovunque la logica di rendering riutilizzabile troppo complessa per una visualizzazione parziale, ad esempio:
- Menu di spostamento dinamici
- Contrassegna il cloud, in cui esegue query sul database
- Pannello di accesso
- Carrello acquisti
- Articoli recentemente pubblicati
- Contenuto della barra laterale in un blog
- Pannello di accesso di cui viene eseguito il rendering in ogni pagina e vengono visualizzati i collegamenti per disconnettersi o accedere, a seconda dello stato di accesso dell'utente
Un componente di visualizzazione è costituito da due parti:
- Classe, in genere derivata da ViewComponent
- Risultato restituito, in genere una visualizzazione.
Come i controller, un componente di visualizzazione può essere poco, ma la maggior parte degli sviluppatori sfrutta i metodi e le proprietà disponibili derivando da ViewComponent.
Quando si valuta se i componenti di visualizzazione soddisfano le specifiche di un'app, prendere in considerazione l'uso dei Razor componenti. Razor i componenti combinano anche il markup con il codice C# per produrre unità di interfaccia utente riutilizzabili. Razor i componenti sono progettati per la produttività degli sviluppatori quando forniscono logica e composizione dell'interfaccia utente sul lato client. Per altre informazioni, vedere ASP.NET Componenti di baseRazor. Per informazioni su come incorporare Razor componenti in un'app MVC o Razor Pages, vedere Prerender and integrate ASP.NET Core components (Prerender and integrate ASP.NET Core Razor components).
Creare un componente di visualizzazione
Questa sezione contiene i requisiti principali per creare un componente di visualizzazione. Più avanti in questo articolo, vengono esaminati nel dettaglio tutti i passaggi e viene creato un componente di visualizzazione.
Classe del componente di visualizzazione
È possibile creare una classe del componente di visualizzazione in uno dei modi seguenti:
- Derivazione da ViewComponent
- Assegnando a una classe con l'attributo
[ViewComponent]
o derivando da una classe con l'attributo[ViewComponent]
- Creazione di una classe in cui il nome termina con il suffisso
ViewComponent
Come i controller, i componenti di visualizzazione devono essere classi pubbliche, non devono essere classi annidate e astratte. Il nome del componente di visualizzazione è il nome della classe con il ViewComponent
suffisso rimosso. È anche possibile specificarlo in modo esplicito usando la proprietà Name.
Una classe del componente di visualizzazione:
- Supporta l'inserimento delle dipendenze del costruttore
- Non partecipa al ciclo di vita del controller, pertanto i filtri non possono essere usati in un componente di visualizzazione
Per impedire che una classe con suffisso senza distinzione tra maiuscole e minuscole ViewComponent
venga considerata come componente di visualizzazione, decorare la classe con l'attributo [NonViewComponent]
:
using Microsoft.AspNetCore.Mvc;
[NonViewComponent]
public class ReviewComponent
{
public string Status(string name) => JobStatus.GetCurrentStatus(name);
}
Metodi del componente di visualizzazione
Un componente di visualizzazione definisce la logica in un:
InvokeAsync
metodo che restituisceTask<IViewComponentResult>
.Invoke
metodo sincrono che restituisce un oggetto IViewComponentResult.
I parametri vengono rilevati direttamente dalla chiamata del componente di visualizzazione e non dall'associazione di modelli. Un componente di visualizzazione non gestisce mai direttamente una richiesta. In genere, inizializza un modello e lo passa a una visualizzazione chiamando il metodo View
. Riepilogando, i metodi del componente di visualizzazione:
- Definiscono un metodo
InvokeAsync
che restituisceTask<IViewComponentResult>
o un metodo sincronoInvoke
che restituisceIViewComponentResult
. - Inizializza in genere un modello e lo passa a una visualizzazione chiamando il metodo ViewComponent.View .
- I parametri vengono rilevati dal metodo di chiamata, non da HTTP, e non vi è alcuna associazione di modelli.
- Non è raggiungibile direttamente come endpoint HTTP. In genere vengono richiamati in una visualizzazione. Un componente di visualizzazione non gestisce mai una richiesta.
- Sono sottoposti a overload sulla firma e non sui dettagli dalla richiesta HHTP corrente.
Percorso di ricerca della visualizzazione
Il runtime esegue la ricerca della visualizzazione nei percorsi seguenti:
- /Views/{Nome controller}/Components/{Nome componente visualizzazione}/{Nome visualizzazione}
- /Views/Shared/Components/{Nome componente visualizzazione}/{Nome visualizzazione}
- /Pages/Shared/Components/{Nome componente visualizzazione}/{Nome visualizzazione}
- /Areas/{Nome area}/Views/Shared/Components/{View Component Name}/{View Name}
Il percorso di ricerca si applica ai progetti che usano controller e visualizzazioni e Razor pagine.
Il nome di visualizzazione predefinito per un componente di visualizzazione è Default
, il che significa che i file di visualizzazione verranno in genere denominati Default.cshtml
. È possibile specificare un nome di visualizzazione diverso quando si crea il risultato del componente di visualizzazione o quando si chiama il View
metodo .
È consigliabile denominare il file Default.cshtml
di visualizzazione e usare il percorso Views/Shared/Components/{View Component Name}/{View Name} . Il PriorityList
componente di visualizzazione usato in questo esempio usa Views/Shared/Components/PriorityList/Default.cshtml
per la visualizzazione del componente di visualizzazione.
Personalizzare il percorso di ricerca della visualizzazione
Per personalizzare il percorso di ricerca della visualizzazione, modificare Razorla raccolta di ViewLocationFormats . Ad esempio, per cercare visualizzazioni all'interno del percorso /Components/{View Component Name}/{View Name}
, aggiungere un nuovo elemento alla raccolta:
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews()
.AddRazorOptions(options =>
{
options.ViewLocationFormats.Add("/{0}.cshtml");
});
builder.Services.AddDbContext<ToDoContext>(options =>
options.UseInMemoryDatabase("db"));
var app = builder.Build();
// Remaining code removed for brevity.
Nel codice precedente il segnaposto {0}
rappresenta il percorso Components/{View Component Name}/{View Name}
.
Richiamare un componente di visualizzazione
Per usare il componente di visualizzazione, chiamare il codice seguente all'interno di una visualizzazione:
@await Component.InvokeAsync("Name of view component",
{Anonymous Type Containing Parameters})
I parametri vengono passati al InvokeAsync
metodo . Il PriorityList
componente di visualizzazione sviluppato nell'articolo viene richiamato dal file di Views/ToDo/Index.cshtml
visualizzazione. Nel codice seguente il InvokeAsync
metodo viene chiamato con due parametri:
</table>
<div>
Maximum Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync("PriorityList",
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
Richiamare un componente di visualizzazione come helper tag
Un componente di visualizzazione può essere richiamato come helper tag:
<div>
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@{
int maxPriority = Convert.ToInt32(ViewData["maxPriority"]);
bool isDone = Convert.ToBoolean(ViewData["isDone"]);
}
<vc:priority-list max-priority=maxPriority is-done=isDone>
</vc:priority-list>
</div>
La classe scritta usando la convenzione Pascal e i parametri del metodo per gli helper tag vengono convertiti nel formato corrispondente kebab case. Per richiamare un componente di visualizzazione, l'helper tag usa l'elemento <vc></vc>
. Il componente di visualizzazione viene specificato nel modo seguente:
<vc:[view-component-name]
parameter1="parameter1 value"
parameter2="parameter2 value">
</vc:[view-component-name]>
Per usare un componente di visualizzazione come helper tag, registrare l'assembly contenente il componente di visualizzazione usando la direttiva @addTagHelper
. Se il componente di visualizzazione si trova in un assembly denominato MyWebApp
, aggiungere la direttiva seguente al _ViewImports.cshtml
file :
@addTagHelper *, MyWebApp
Un componente di visualizzazione può essere registrato come helper tag a qualsiasi file che fa riferimento al componente di visualizzazione. Vedere Gestione dell'ambito dell'helper tag per altre informazioni su come registrare gli helper tag.
Il metodo InvokeAsync
usato in questa esercitazione:
@await Component.InvokeAsync("PriorityList",
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
Nel markup precedente, il componente di PriorityList
visualizzazione diventa priority-list
. I parametri per il componente di visualizzazione vengono passati come attributi nel formato kebab case.
Richiamare un componente di visualizzazione direttamente da un controller
I componenti di visualizzazione vengono in genere richiamati da una visualizzazione, ma possono essere richiamati direttamente da un metodo controller. Anche se i componenti di visualizzazione non definiscono endpoint come controller, è possibile implementare un'azione controller che restituisce il contenuto di un oggetto ViewComponentResult
.
Nell'esempio seguente il componente di visualizzazione viene chiamato direttamente dal controller:
public IActionResult IndexVC(int maxPriority = 2, bool isDone = false)
{
return ViewComponent("PriorityList",
new {
maxPriority = maxPriority,
isDone = isDone
});
}
Creare un componente di visualizzazione di base
Scaricare, compilare e testare il codice di avvio. Si tratta di un progetto di base con un ToDo
controller che visualizza un elenco di elementi ToDo .
Aggiornare il controller per passare lo stato di priorità e completamento
Aggiornare il Index
metodo per usare i parametri di stato di priorità e completamento:
using Microsoft.AspNetCore.Mvc;
using ViewComponentSample.Models;
namespace ViewComponentSample.Controllers;
public class ToDoController : Controller
{
private readonly ToDoContext _ToDoContext;
public ToDoController(ToDoContext context)
{
_ToDoContext = context;
_ToDoContext.Database.EnsureCreated();
}
public IActionResult Index(int maxPriority = 2, bool isDone = false)
{
var model = _ToDoContext!.ToDo!.ToList();
ViewData["maxPriority"] = maxPriority;
ViewData["isDone"] = isDone;
return View(model);
}
Aggiungere una classe ViewComponent
Aggiungere una classe ViewComponent a ViewComponents/PriorityListViewComponent.cs
:
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents;
public class PriorityListViewComponent : ViewComponent
{
private readonly ToDoContext db;
public PriorityListViewComponent(ToDoContext context) => db = context;
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
Note riguardanti il codice:
Le classi del componente di visualizzazione possono essere contenute in qualsiasi cartella del progetto.
Poiché il nome della classe PriorityListViewComponent termina con il suffisso ViewComponent, il runtime usa la stringa
PriorityList
quando si fa riferimento al componente della classe da una visualizzazione.L'attributo
[ViewComponent]
può modificare il nome usato per fare riferimento a un componente di visualizzazione. Ad esempio, la classe potrebbe essere stata denominataXYZ
con l'attributo seguente[ViewComponent]
:[ViewComponent(Name = "PriorityList")] public class XYZ : ViewComponent
L'attributo
[ViewComponent]
nel codice precedente indica al selettore del componente di visualizzazione di usare:- Nome
PriorityList
durante la ricerca delle visualizzazioni associate al componente - Stringa "PriorityList" quando si fa riferimento al componente della classe da una vista.
- Nome
Il componente usa l'inserimento delle dipendenze per rendere disponibile il contesto dei dati.
InvokeAsync
espone un metodo che può essere chiamato da una vista e può accettare un numero arbitrario di argomenti.Il metodo
InvokeAsync
restituisce il set di elementiToDo
che soddisfano i parametriisDone
emaxPriority
.
Creare la visualizzazione del componente Razor di visualizzazione
Creare la cartella Views/Shared/Components. Il nome di questa cartella deve essere Components.
Creare la cartella Views/Shared/Components/PriorityList. Questo nome della cartella deve corrispondere al nome della classe del componente di visualizzazione o al nome della classe meno il suffisso. Se viene usato l'attributo
ViewComponent
, il nome della classe deve corrispondere alla designazione dell'attributo.Creare una
Views/Shared/Components/PriorityList/Default.cshtml
Razor visualizzazione:@model IEnumerable<ViewComponentSample.Models.TodoItem> <h3>Priority Items</h3> <ul> @foreach (var todo in Model) { <li>@todo.Name</li> } </ul>
La Razor visualizzazione accetta un elenco di
TodoItem
e le visualizza. Se il metodo del componenteInvokeAsync
di visualizzazione non passa il nome della visualizzazione, default viene usato per il nome della visualizzazione per convenzione. Per sostituire lo stile predefinito per un controller specifico, aggiungere una visualizzazione alla cartella di visualizzazione specifica del controller, ad esempio Views/ToDo/Components/PriorityList/Default.cshtml.Se il componente di visualizzazione è specifico del controller, può essere aggiunto alla cartella specifica del controller. Ad esempio,
Views/ToDo/Components/PriorityList/Default.cshtml
è specifico del controller.Aggiungere un oggetto
div
contenente una chiamata al componente dell'elenco di priorità nella parte inferiore delViews/ToDo/index.cshtml
file:</table> <div> Maximum Priority: @ViewData["maxPriority"] <br /> Is Complete: @ViewData["isDone"] @await Component.InvokeAsync("PriorityList", new { maxPriority = ViewData["maxPriority"], isDone = ViewData["isDone"] } ) </div>
Il markup @await Component.InvokeAsync
illustra la sintassi per chiamare i componenti di visualizzazione. Il primo argomento corrisponde al nome del componente che si vuole richiamare o chiamare. I parametri successivi vengono passati al componente. InvokeAsync
può accettare un numero arbitrario di argomenti.
Test dell'app. La figura seguente illustra l'elenco ToDo e gli elementi con priorità:
Il componente di visualizzazione può essere chiamato direttamente dal controller:
public IActionResult IndexVC(int maxPriority = 2, bool isDone = false)
{
return ViewComponent("PriorityList",
new {
maxPriority = maxPriority,
isDone = isDone
});
}
Specificare il nome di un componente di visualizzazione
Per un componente di visualizzazione, in alcune condizioni è possibile dover specificare una visualizzazione non predefinita. Il codice seguente illustra come specificare la visualizzazione "PVC" dal metodo InvokeAsync
. Aggiornare il metodo InvokeAsync
nella classe PriorityListViewComponent
.
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
string MyView = "Default";
// If asking for all completed tasks, render with the "PVC" view.
if (maxPriority > 3 && isDone == true)
{
MyView = "PVC";
}
var items = await GetItemsAsync(maxPriority, isDone);
return View(MyView, items);
}
Copiare il Views/Shared/Components/PriorityList/Default.cshtml
file in una vista denominata Views/Shared/Components/PriorityList/PVC.cshtml
. Aggiungere un'intestazione per indicare che viene usata una visualizzazione PVC.
@model IEnumerable<ViewComponentSample.Models.TodoItem>
<h2> PVC Named Priority Component View</h2>
<h4>@ViewBag.PriorityMessage</h4>
<ul>
@foreach (var todo in Model)
{
<li>@todo.Name</li>
}
</ul>
Eseguire l'app e verificare la visualizzazione PVC.
Se non viene eseguito il rendering della visualizzazione PVC, verificare che venga chiamato il componente di visualizzazione con priorità 4 o superiore.
Esaminare il percorso di visualizzazione
Modificare il parametro relativo alla priorità impostandolo su tre o priorità inferiore perché la visualizzazione con priorità non venga restituita.
Rinominare temporaneamente l'oggetto
Views/ToDo/Components/PriorityList/Default.cshtml
in1Default.cshtml
.Testare l'app, si verifica l'errore seguente:
An unhandled exception occurred while processing the request. InvalidOperationException: The view 'Components/PriorityList/Default' wasn't found. The following locations were searched: /Views/ToDo/Components/PriorityList/Default.cshtml /Views/Shared/Components/PriorityList/Default.cshtml
Copiare
Views/ToDo/Components/PriorityList/1Default.cshtml
inViews/Shared/Components/PriorityList/Default.cshtml
.Aggiungere markup alla visualizzazione del componente di visualizzazione ToDo in Shared per indicare che la visualizzazione proviene dalla cartella Shared.
Testare la visualizzazione del componente Shared.
Evitare stringhe hardcoded
Per la sicurezza in fase di compilazione, sostituire il nome del componente di visualizzazione hardcoded con il nome della classe. Aggiornare il file PriorityListViewComponent.cs per non usare il suffisso "ViewComponent":
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents;
public class PriorityList : ViewComponent
{
private readonly ToDoContext db;
public PriorityList(ToDoContext context)
{
db = context;
}
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
Il file di visualizzazione :
</table>
<div>
Testing nameof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(nameof(PriorityList),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
Un overload di Component.InvokeAsync
metodo che accetta un tipo CLR usa l'operatore typeof
:
</table>
<div>
Testing typeof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(typeof(PriorityList),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
Eseguire operazioni sincrone
Il framework gestisce la chiamata di un metodo sincrono Invoke
se il lavoro asincrono non è necessario. Il metodo seguente crea un componente di visualizzazione Invoke
sincrono:
using Microsoft.AspNetCore.Mvc;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents
{
public class PriorityListSync : ViewComponent
{
private readonly ToDoContext db;
public PriorityListSync(ToDoContext context)
{
db = context;
}
public IViewComponentResult Invoke(int maxPriority, bool isDone)
{
var x = db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToList();
return View(x);
}
}
}
Il file del componente di Razor visualizzazione:
<div>
Testing nameof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(nameof(PriorityListSync),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
Il componente di visualizzazione viene richiamato in un Razor file ,ad esempio , Views/Home/Index.cshtml
usando uno degli approcci seguenti:
Per usare l'approccio IViewComponentHelper, chiamare Component.InvokeAsync
:
@await Component.InvokeAsync(nameof(PriorityList),
new { maxPriority = 4, isDone = true })
Per usare l'helper tag, registrare l'assembly contenente il componente di visualizzazione usando la direttiva @addTagHelper
(il componente di visualizzazione è in un assembly denominato MyWebApp
):
@addTagHelper *, MyWebApp
Usare l'helper tag del componente di visualizzazione nel Razor file di markup:
<vc:priority-list max-priority="999" is-done="false">
</vc:priority-list>
La firma del metodo di PriorityList.Invoke
è sincrona, ma Razor trova e chiama il metodo con Component.InvokeAsync
nel file di markup.
Risorse aggiuntive
Visualizzare o scaricare il codice di esempio (procedura per il download)
Componenti di visualizzazione
I componenti di visualizzazione hanno aspetti comuni con le visualizzazioni parziali, ma sono molto più efficienti. I componenti di visualizzazione non usano l'associazione di modelli. Dipendono soltanto dai dati specificati in fase di chiamata. Questo articolo è stato scritto usando controller e visualizzazioni, ma i componenti di visualizzazione funzionano anche con Razor Pages.
Un componente di visualizzazione:
- Esegue il rendering di un blocco anziché di un'intera risposta.
- Include la stessa separazione dei concetti e gli stessi vantaggi per i test individuati nel controller e nella visualizzazione.
- Può contenere parametri e logica di business.
- In genere viene richiamato da una pagina di layout.
I componenti di visualizzazione possono essere impiegati in un punto qualsiasi della logica di rendering riutilizzabile che risulta troppo complessa per una visualizzazione parziale, ad esempio:
- Menu di spostamento dinamici
- Tag cloud (nel quale viene eseguita una query del database)
- Pannello di accesso
- Carrello acquisti
- Articoli recentemente pubblicati
- Contenuto dell'intestazione laterale in un blog tradizionale
- Pannello di accesso che viene eseguito in ogni pagina e che visualizza il collegamento di accesso o di disconnessione, a seconda dello stato di accesso dell'utente
Un componente di visualizzazione è costituito da due parti: la classe (in genere derivata da ViewComponent) e il risultato restituito (in genere una visualizzazione). Come i controller, un componente di visualizzazione può essere poco, ma la maggior parte degli sviluppatori sfrutta i metodi e le proprietà disponibili derivando da ViewComponent
.
Quando si valuta se i componenti di visualizzazione soddisfano le specifiche di un'app, prendere in considerazione l'uso dei Razor componenti. Razor i componenti combinano anche il markup con il codice C# per produrre unità di interfaccia utente riutilizzabili. Razor i componenti sono progettati per la produttività degli sviluppatori quando forniscono logica e composizione dell'interfaccia utente sul lato client. Per altre informazioni, vedere ASP.NET Componenti di baseRazor. Per informazioni su come incorporare Razor componenti in un'app MVC o Razor Pages, vedere Prerender and integrate ASP.NET Core components (Prerender and integrate ASP.NET Core Razor components).
Creazione di un componente di visualizzazione
Questa sezione contiene i requisiti principali per creare un componente di visualizzazione. Più avanti in questo articolo, vengono esaminati nel dettaglio tutti i passaggi e viene creato un componente di visualizzazione.
Classe del componente di visualizzazione
È possibile creare una classe del componente di visualizzazione in uno dei modi seguenti:
- Derivando da ViewComponent
- Assegnando a una classe con l'attributo
[ViewComponent]
o derivando da una classe con l'attributo[ViewComponent]
- Creando una classe in cui il nome termina con il suffisso ViewComponent
Come i controller, i componenti di visualizzazione devono essere classi pubbliche, non devono essere classi annidate e astratte. Il nome del componente di visualizzazione corrisponde al nome della classe privato del suffisso "ViewComponent". È anche possibile specificarlo in modo esplicito usando la proprietà ViewComponentAttribute.Name
.
Una classe del componente di visualizzazione:
- Supporta pienamente l'inserimento delle dipendenze del costruttore
- Non partecipa al ciclo di vita del controller, non è quindi possibile usare i filtri in un componente di visualizzazione
Per arrestare una classe con un suffisso ViewComponent senza distinzione tra maiuscole e minuscole, decorare la classe con l'attributo [NonViewComponent]:
[NonViewComponent]
public class ReviewComponent
{
// ...
Metodi del componente di visualizzazione
Un componente di visualizzazione definisce la propria logica in un metodo InvokeAsync
che restituisce Task<IViewComponentResult>
o in un metodo asincrono Invoke
che restituisce IViewComponentResult
. I parametri vengono rilevati direttamente dalla chiamata del componente di visualizzazione e non dall'associazione di modelli. Un componente di visualizzazione non gestisce mai direttamente una richiesta. In genere, inizializza un modello e lo passa a una visualizzazione chiamando il metodo View
. Riepilogando, i metodi del componente di visualizzazione:
- Definiscono un metodo
InvokeAsync
che restituisceTask<IViewComponentResult>
o un metodo sincronoInvoke
che restituisceIViewComponentResult
. - Inizializza in genere un modello e lo passa a una vista chiamando il
ViewComponent
View
metodo . - I parametri vengono rilevati dal metodo di chiamata, non da HTTP, e non vi è alcuna associazione di modelli.
- Non sono raggiungibili direttamente come un endpoint HTTP. Vengono richiamati dal codice (in genere in una vista). Un componente di visualizzazione non gestisce mai una richiesta.
- Sono sottoposti a overload sulla firma e non sui dettagli dalla richiesta HHTP corrente.
Percorso di ricerca della visualizzazione
Il runtime esegue la ricerca della visualizzazione nei percorsi seguenti:
- /Views/{Nome controller}/Components/{Nome componente visualizzazione}/{Nome visualizzazione}
- /Views/Shared/Components/{Nome componente visualizzazione}/{Nome visualizzazione}
- /Pages/Shared/Components/{Nome componente visualizzazione}/{Nome visualizzazione}
- /Areas/{Nome area}/Views/Shared/Components/{View Component Name}/{View Name}
Il percorso di ricerca si applica ai progetti che usano controller e visualizzazioni e Razor pagine.
Il nome di visualizzazione predefinito per un componente di visualizzazione è Predefinito, il che significa che il file di visualizzazione verrà in genere denominato Default.cshtml
. È possibile specificare un nome di visualizzazione diverso quando si crea il risultato del componente di visualizzazione o quando si chiama il metodo View
.
È consigliabile denominare il file Default.cshtml
di visualizzazione e usare il percorso Views/Shared/Components/{View Component Name}/{View Name} . Il PriorityList
componente di visualizzazione usato in questo esempio usa Views/Shared/Components/PriorityList/Default.cshtml
per la visualizzazione del componente di visualizzazione.
Personalizzare il percorso di ricerca della visualizzazione
Per personalizzare il percorso di ricerca della visualizzazione, modificare Razorla raccolta di ViewLocationFormats . Ad esempio, per cercare visualizzazioni all'interno del percorso "/Components/{View Component Name}/{View Name}", aggiungere un nuovo elemento alla raccolta:
services.AddMvc()
.AddRazorOptions(options =>
{
options.ViewLocationFormats.Add("/{0}.cshtml");
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
Nel codice precedente il segnaposto "{0}" rappresenta il percorso "Components/{View Component Name}/{View Component Name}".
Chiamata di un componente di visualizzazione
Per usare il componente di visualizzazione, chiamare il codice seguente all'interno di una visualizzazione:
@await Component.InvokeAsync("Name of view component", {Anonymous Type Containing Parameters})
I parametri saranno passati al metodo InvokeAsync
. Il PriorityList
componente di visualizzazione sviluppato nell'articolo viene richiamato dal file di Views/ToDo/Index.cshtml
visualizzazione. Nell'esempio seguente il metodo InvokeAsync
viene chiamato con due parametri:
@await Component.InvokeAsync("PriorityList", new { maxPriority = 4, isDone = true })
Chiamata di un componente di visualizzazione come helper tag
Per ASP.NET Core 1.1 e versioni successive, è possibile richiamare un componente di visualizzazione come helper tag:
<vc:priority-list max-priority="2" is-done="false">
</vc:priority-list>
La classe scritta usando la convenzione Pascal e i parametri del metodo per gli helper tag vengono convertiti nel formato corrispondente kebab case. Per richiamare un componente di visualizzazione, l'helper tag usa l'elemento <vc></vc>
. Il componente di visualizzazione viene specificato nel modo seguente:
<vc:[view-component-name]
parameter1="parameter1 value"
parameter2="parameter2 value">
</vc:[view-component-name]>
Per usare un componente di visualizzazione come helper tag, registrare l'assembly contenente il componente di visualizzazione usando la direttiva @addTagHelper
. Se il componente di visualizzazione si trova in un assembly denominato MyWebApp
, aggiungere la direttiva seguente al _ViewImports.cshtml
file :
@addTagHelper *, MyWebApp
È possibile registrare un componente di visualizzazione come helper tag per qualsiasi file che fa riferimento al componente di visualizzazione. Vedere Gestione dell'ambito dell'helper tag per altre informazioni su come registrare gli helper tag.
Il metodo InvokeAsync
usato in questa esercitazione:
@await Component.InvokeAsync("PriorityList", new { maxPriority = 4, isDone = true })
Nel markup dell'helper tag:
<vc:priority-list max-priority="2" is-done="false">
</vc:priority-list>
Nell'esempio precedente il componente di visualizzazione PriorityList
diventa priority-list
. I parametri per il componente di visualizzazione vengono passati come attributi nel formato kebab case.
Richiamo di un componente di visualizzazione direttamente da un controller
I componenti di visualizzazione sono solitamente richiamati da una visualizzazione, ma possono essere richiamati direttamente da un metodo del controller. A differenza dei controller i componenti di visualizzazione non definiscono endpoint. È tuttavia possibile implementare semplicemente un'azione del controller in modo che venga restituito il contenuto di un oggetto ViewComponentResult
.
In questo esempio il componente di visualizzazione viene chiamato direttamente dal controller:
public IActionResult IndexVC()
{
return ViewComponent("PriorityList", new { maxPriority = 3, isDone = false });
}
Procedura dettagliata: creazione di un componente di visualizzazione semplice
Scaricare, compilare e testare il codice di avvio. Si tratta di un progetto semplice con un controller ToDo
che visualizza un elenco di elementi ToDo.
Aggiungere una classe ViewComponent
Creare una cartella ViewComponents e aggiungere la classe PriorityListViewComponent
seguente:
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents
{
public class PriorityListViewComponent : ViewComponent
{
private readonly ToDoContext db;
public PriorityListViewComponent(ToDoContext context)
{
db = context;
}
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db.ToDo.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
}
Note riguardanti il codice:
Le classi del componente di visualizzazione possono essere contenute in qualsiasi cartella del progetto.
Poiché il nome della classe PriorityListViewComponent termina con il suffisso ViewComponent, il runtime usa la stringa
PriorityList
quando si fa riferimento al componente della classe da una visualizzazione.L'attributo
[ViewComponent]
può modificare il nome usato per fare riferimento a un componente di visualizzazione. Ad esempio, la classe potrebbe essere stata denominataXYZ
con l'attributoViewComponent
:[ViewComponent(Name = "PriorityList")] public class XYZ : ViewComponent
L'attributo
[ViewComponent]
nel codice precedente indica al selettore del componente di visualizzazione di usare:- Nome
PriorityList
durante la ricerca delle visualizzazioni associate al componente - Stringa "PriorityList" quando si fa riferimento al componente della classe da una vista.
- Nome
Il componente usa l'inserimento delle dipendenze per rendere disponibile il contesto dei dati.
InvokeAsync
espone un metodo che può essere chiamato da una visualizzazione e può accettare un numero arbitrario di argomenti.Il metodo
InvokeAsync
restituisce il set di elementiToDo
che soddisfano i parametriisDone
emaxPriority
.
Creare la visualizzazione del componente Razor di visualizzazione
Creare la cartella Views/Shared/Components. Questa cartella deve essere denominata
Components
.Creare la cartella Views/Shared/Components/PriorityList. Il nome di questa cartella deve corrispondere al nome della classe del componente di visualizzazione oppure al nome della classe privato del suffisso (se è stata adottata la convenzione ed è stato usato il suffisso ViewComponent nel nome della classe). Se è stato usato l'attributo
ViewComponent
, il nome della classe dovrà corrispondere alla designazione dell'attributo.Creare una
Views/Shared/Components/PriorityList/Default.cshtml
Razor visualizzazione:@model IEnumerable<ViewComponentSample.Models.TodoItem> <h3>Priority Items</h3> <ul> @foreach (var todo in Model) { <li>@todo.Name</li> } </ul>
La Razor visualizzazione accetta un elenco di
TodoItem
e le visualizza. Se il metodoInvokeAsync
del componente di visualizzazione non passa il nome della visualizzazione (come in questo esempio), per convenzione viene usato Default come nome della visualizzazione. Più avanti nell'esercitazione viene illustrato come passare il nome della visualizzazione. Per sostituire lo stile predefinito per un controller specifico, aggiungere una visualizzazione alla cartella di visualizzazione specifica del controller, ad esempio Views/ToDo/Components/PriorityList/Default.cshtml.Se il componente di visualizzazione è specifico del controller, è possibile aggiungerlo alla cartella specifica del controller (
Views/ToDo/Components/PriorityList/Default.cshtml
).Aggiungere un oggetto
div
contenente una chiamata al componente dell'elenco di priorità nella parte inferiore delViews/ToDo/index.cshtml
file:</table> <div> @await Component.InvokeAsync("PriorityList", new { maxPriority = 2, isDone = false }) </div>
Il markup @await Component.InvokeAsync
illustra la sintassi per chiamare i componenti di visualizzazione. Il primo argomento corrisponde al nome del componente che si vuole richiamare o chiamare. I parametri successivi vengono passati al componente. InvokeAsync
può accettare un numero arbitrario di argomenti.
Test dell'app. La figura seguente illustra l'elenco ToDo e gli elementi con priorità:
È anche possibile chiamare il componente di visualizzazione direttamente dal controller:
public IActionResult IndexVC()
{
return ViewComponent("PriorityList", new { maxPriority = 3, isDone = false });
}
Impostazione di un nome di visualizzazione
Per un componente di visualizzazione, in alcune condizioni è possibile dover specificare una visualizzazione non predefinita. Il codice seguente illustra come specificare la visualizzazione "PVC" dal metodo InvokeAsync
. Aggiornare il metodo InvokeAsync
nella classe PriorityListViewComponent
.
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
string MyView = "Default";
// If asking for all completed tasks, render with the "PVC" view.
if (maxPriority > 3 && isDone == true)
{
MyView = "PVC";
}
var items = await GetItemsAsync(maxPriority, isDone);
return View(MyView, items);
}
Copiare il Views/Shared/Components/PriorityList/Default.cshtml
file in una vista denominata Views/Shared/Components/PriorityList/PVC.cshtml
. Aggiungere un'intestazione per indicare che viene usata una visualizzazione PVC.
@model IEnumerable<ViewComponentSample.Models.TodoItem>
<h2> PVC Named Priority Component View</h2>
<h4>@ViewBag.PriorityMessage</h4>
<ul>
@foreach (var todo in Model)
{
<li>@todo.Name</li>
}
</ul>
AggiornamentoViews/ToDo/Index.cshtml
:
@await Component.InvokeAsync("PriorityList", new { maxPriority = 4, isDone = true })
Eseguire l'app e verificare la visualizzazione PVC.
Se non viene eseguito il rendering della visualizzazione PVC, verificare che si stia chiamando il componente di visualizzazione con priorità pari a 4 o superiore.
Esaminare il percorso di visualizzazione
Modificare il parametro relativo alla priorità impostandolo su tre o priorità inferiore perché la visualizzazione con priorità non venga restituita.
Rinominare temporaneamente l'oggetto
Views/ToDo/Components/PriorityList/Default.cshtml
in1Default.cshtml
.Testare l'app. Verrà visualizzato il messaggio seguente:
An unhandled exception occurred while processing the request. InvalidOperationException: The view 'Components/PriorityList/Default' wasn't found. The following locations were searched: /Views/ToDo/Components/PriorityList/Default.cshtml /Views/Shared/Components/PriorityList/Default.cshtml EnsureSuccessful
Copiare
Views/ToDo/Components/PriorityList/1Default.cshtml
inViews/Shared/Components/PriorityList/Default.cshtml
.Aggiungere markup alla visualizzazione del componente di visualizzazione ToDo in Shared per indicare che la visualizzazione proviene dalla cartella Shared.
Testare la visualizzazione del componente Shared.
Evitare stringhe hardcoded
Per garantire la sicurezza in fase di compilazione, è possibile sostituire il nome del componente di compilazione hardcoded con il nome della classe. Creare il componente di visualizzazione senza il suffisso "ViewComponent":
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents
{
public class PriorityList : ViewComponent
{
private readonly ToDoContext db;
public PriorityList(ToDoContext context)
{
db = context;
}
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db.ToDo.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
}
Aggiungere un'istruzione using
al file di Razor visualizzazione e usare l'operatore nameof
:
@using ViewComponentSample.Models
@using ViewComponentSample.ViewComponents
@model IEnumerable<TodoItem>
<h2>ToDo nameof</h2>
<!-- Markup removed for brevity. -->
<div>
@*
Note:
To use the below line, you need to #define no_suffix in ViewComponents/PriorityList.cs or it won't compile.
By doing so it will cause a problem to index as there will be multiple viewcomponents
with the same name after the compiler removes the suffix "ViewComponent"
*@
@*@await Component.InvokeAsync(nameof(PriorityList), new { maxPriority = 4, isDone = true })*@
</div>
È possibile usare un overload di Component.InvokeAsync
metodo che accetta un tipo CLR. Ricordarsi di usare l'operatore typeof
in questo caso:
@using ViewComponentSample.Models
@using ViewComponentSample.ViewComponents
@model IEnumerable<TodoItem>
<h2>ToDo typeof</h2>
<!-- Markup removed for brevity. -->
<div>
@await Component.InvokeAsync(typeof(PriorityListViewComponent), new { maxPriority = 4, isDone = true })
</div>
Eseguire operazioni sincrone
Il framework gestisce la chiamata di un metodo Invoke
sincrono se non è necessario eseguire operazioni asincrone. Il metodo seguente crea un componente di visualizzazione Invoke
sincrono:
public class PriorityList : ViewComponent
{
public IViewComponentResult Invoke(int maxPriority, bool isDone)
{
var items = new List<string> { $"maxPriority: {maxPriority}", $"isDone: {isDone}" };
return View(items);
}
}
Il file del componente di Razor visualizzazione elenca le stringhe passate al Invoke
metodo (Views/Home/Components/PriorityList/Default.cshtml
):
@model List<string>
<h3>Priority Items</h3>
<ul>
@foreach (var item in Model)
{
<li>@item</li>
}
</ul>
Il componente di visualizzazione viene richiamato in un Razor file ,ad esempio , Views/Home/Index.cshtml
usando uno degli approcci seguenti:
Per usare l'approccio IViewComponentHelper, chiamare Component.InvokeAsync
:
@await Component.InvokeAsync(nameof(PriorityList), new { maxPriority = 4, isDone = true })
Per usare l'helper tag, registrare l'assembly contenente il componente di visualizzazione usando la direttiva @addTagHelper
(il componente di visualizzazione è in un assembly denominato MyWebApp
):
@addTagHelper *, MyWebApp
Usare l'helper tag del componente di visualizzazione nel Razor file di markup:
<vc:priority-list max-priority="999" is-done="false">
</vc:priority-list>
La firma del metodo di PriorityList.Invoke
è sincrona, ma Razor trova e chiama il metodo con Component.InvokeAsync
nel file di markup.
Tutti i parametri del componente di visualizzazione sono obbligatori
Ogni parametro in un componente di visualizzazione è un attributo obbligatorio. Vedere il problema in GitHub. Se un parametro viene omesso:
- La firma del metodo
InvokeAsync
non corrisponde, quindi il metodo non verrà eseguito. - ViewComponent non esegue il rendering dei markup.
- Non vengono generati errori.