Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Questo articolo illustra le modifiche più significative in ASP.NET Core in .NET 11 con collegamenti alla documentazione pertinente.
Questo articolo verrà aggiornato man mano che vengono rese disponibili nuove versioni di anteprima.
Blazor
In questa sezione vengono descritte le nuove funzionalità per Blazor.
Nuovo DisplayName componente e supporto per gli attributi [Display] e [DisplayName]
Il DisplayName componente può essere usato per visualizzare i nomi delle proprietà dagli attributi dei metadati:
[Required, DisplayName("Production Date")]
public DateTime ProductionDate { get; set; }
L'attributo[Display] nella proprietà della classe del modello è supportato:
[Required, Display(Name = "Production Date")]
public DateTime ProductionDate { get; set; }
Tra i due approcci, è consigliabile l'attributo [Display] , che rende disponibili proprietà aggiuntive. L'attributo abilita anche l'assegnazione [Display] di un tipo di risorsa per la localizzazione. Quando sono presenti entrambi gli attributi, [Display] ha la precedenza su [DisplayName]. Se nessun attributo è presente, il componente passa al nome della proprietà.
Usa il componente DisplayName nelle etichette o nelle intestazioni di tabella.
<label>
<DisplayName For="@(() => Model!.ProductionDate)" />
<InputDate @bind-Value="Model!.ProductionDate" />
</label>
Blazor Formato delle opzioni di avvio dello script Web ora supportato per gli script Blazor Server e Blazor WebAssembly
L'oggetto opzioni Blazor Web App (blazor.web.js) passato a Blazor.start() utilizza il seguente formato dalla versione di .NET 8:
Blazor.start({
ssr: { ... },
circuit: { ... },
webAssembly: { ... },
});
Ora, Blazor Server gli script (blazor.server.js) e Blazor WebAssembly (blazor.webassembly.js) possono usare lo stesso formato di opzioni.
L'esempio seguente mostra il formato delle opzioni precedenti, che rimane supportato:
Blazor.start({
loadBootResource: function (...) {
...
},
});
Formato delle opzioni appena supportate per l'esempio precedente:
Blazor.start({
webAssembly: {
loadBootResource: function (...) {
...
},
},
});
Per altre informazioni, vedere ASP.NET Core Blazor startup.
Nuovo BasePath componente
Blazor Web Apps può usare il nuovo BasePath componente (<BasePath />) per eseguire automaticamente il rendering del tag HTML del percorso di base dell'app (<base href>). Per altre informazioni, vedere ASP.NET Core Blazor percorso di base dell'app.
Gestore eventi inline JS rimosso dal componente NavMenu
Il gestore eventi inline JS che attiva o disattiva la visualizzazione dei collegamenti di navigazione non è più presente nel componente NavMenu del modello di progetto Blazor Web App. Le app generate dal modello di progetto ora usano un approccio di modulo co-localizzato JS per mostrare o nascondere la barra di navigazione nella pagina sottoposta a rendering. Il nuovo approccio migliora la conformità al Content Security Policy (CSP) perché non richiede di includere un hash non sicuro per l'elemento inline JS.
Per eseguire la migrazione di un'app esistente a .NET 11, compresa l'adozione del nuovo approccio del modulo JS per la barra di navigazione, vedere Migrazione da ASP.NET Core in .NET 10 a ASP.NET Core in .NET 11.
Supporto di NavigateTo e NavLink per la navigazione relativa
Il nuovo RelativeToCurrentUri parametro (impostazione predefinita: false) per NavigationManager.NavigateTo e il NavLink componente consente di passare agli URI relativi al percorso della pagina corrente anziché all'URI di base dell'app.
Prendere in considerazione i seguenti endpoint annidati:
/docs/getting-started/installation/configuration
Quando l'URI del browser è /docs/getting-started/installation e vuoi navigare l'utente verso /docs/getting-started/configuration, NavigateTo("/configuration") reindirizza a /configuration, la radice dell'app, anziché al percorso relativo il /docs/getting-started/configuration. Imposta il RelativeToCurrentUri con NavigateTo o il componente NavLink per la navigazione desiderata.
Navigation.NavigateTo("/configuration", new NavigationOptions
{
RelativeToCurrentUri = true
});
<NavLink href="configuration" RelativeToCurrentUri="true">Configuration</NavLink>
Rendere persistenti i dati temporanei tra le richieste HTTP durante il rendering statico lato server (static SSR)
Per rendere persistenti i dati temporanei tra le richieste HTTP durante il rendering statico lato server (SSR statico), Blazor supporta TempData. TempData è ideale per scenari come i messaggi flash dopo gli invii di moduli, il passaggio dei dati durante i reindirizzamenti (modello POST-Redirect-GET) e le notifiche monouso.
TempData è disponibile quando AddRazorComponents viene chiamato nel file dell'app Program e viene fornito come valore a cascata con l'attributo [CascadingParameter].
[CascadingParameter]
public ITempData? TempData { get; set; }
Quando viene fornito a un parametro per la lettura/scrittura semplice di un singolo valore, usare l'attributo [SupplyParameterFromTempData] :
[SupplyParameterFromTempData]
public string? Message { get; set; }
Per altre informazioni, vedere ASP.NET Core Blazor gestione dello stato lato server.
Nuovo Blazor modello di web worker (blazorwebworker)
Il modello di progetto .NET Web Worker, che contiene un client Web Worker per delegare attività di lunga durata a un thread in background, è stato rinominato modello di progetto Blazor Web Worker (blazorwebworker). La modifica del nome rende più chiaro che il template fa parte dello stack Blazor per l'uso nelle app Web Blazor WebAssembly e Blazor (per il rendering lato client, CSR).
Sono state aggiunte due funzionalità spesso richieste all'oggetto generato WebWorkerClient:
-
InvokeVoidAsyncper le chiamate ai worker fire-and-forget che non restituiscono alcun valore, rispecchiando la struttura diIJSRuntime. - Supporto per l'annullamento e per il timeout sia durante la creazione del worker sia nelle invocazioni del worker, in modo che chi effettua la chiamata possa passare un
CancellationTokene arrestare correttamente un worker bloccato.
I progetti esistenti creati con il modello precedente continuano a funzionare. La ridenominazione influisce solo sul nome del modello visualizzato in dotnet new list e nell'elenco di Visual Studio di Creare un nuovo progetto modelli.
Per ulteriori informazioni, vedi le seguenti risorse:
- ASP.NET Core Blazor con .NET nei Web Worker
-
Aggiornamento del modello .NET Web Worker in Blazor modello Web Worker (
dotnet/aspnetcore#66070) (Non commentare issue e PR chiuse.)
Miglioramenti della virtualizzazione
Il Virtualize<TItem> componente non presuppone più che ogni elemento abbia la stessa altezza. In precedenza, il componente disabilitava l'ancoraggio dello scorrimento nativo del browser (per evitare un ciclo di rendering infinito), il che significava che qualsiasi variazione di altezza al di sopra dell'area visibile — espansione degli elementi, aggiornamenti dei dati, contenuti caricati in modo differito — provocava uno spostamento improvviso degli elementi visibili sullo schermo. Il
Virtualizecomponente ora si adatta alle dimensioni degli elementi misurate in fase di esecuzione, riducendo la spaziatura non corretta e lo scorrimento quando le altezze degli elementi variano.Gli aggiornamenti utilizzano un approccio ibrido: l'ancoraggio dello scorrimento CSS nativo nei browser che lo supportano per i layout non-
<table>, con un fallback manuale di compensazione dello scorrimento basato suResizeObserverper i layout<table>e per Safari, dove l'ancoraggio nativo calcola erroneamente le posizioni sugli elementi<tr>.Le app che usano il
Virtualizecomponente ricevono automaticamente i vantaggi di questi aggiornamenti. Non sono necessarie modifiche all'API per sviluppatori.Questi aggiornamenti includono un aggiornamento del valore predefinito di Virtualize<TItem>.OverscanCount, che era
3in .NET 10 o versioni precedenti e ora cambia in15in .NET 11 o versione successiva. La modifica nel valore predefinito aumenta la precisione dei calcoli dell'altezza media degli elementi.Per ulteriori informazioni, vedi le seguenti risorse:
- sezione Dimensione elemento e sezione Numero di overscan dell'articolo Virtualizzazione.
-
[Virtualizzazione] Il contenuto visibile non si sposta quando gli elementi nel DOM sopra l’area visibile cambiano altezza (
dotnet/aspnetcore#65951) (Non commentare issue e pull request chiuse).
Usare il nuovo
AnchorModeparametro per controllare il comportamento del viewport in corrispondenza dei bordi dell'elenco quando gli elementi vengono aggiunti dinamicamente:-
None: Nessun fissaggio ai bordi. Il riquadro di visualizzazione rimane nella posizione di scorrimento corrente indipendentemente dalle modifiche apportate all'elemento. -
Start(impostazione predefinita): aggiunge il riquadro di visualizzazione all'inizio dell'elenco. Ad esempio, questo comportamento di fissaggio è utile per l'esperienza utente di un feed di notizie. -
End: aggiunge il riquadro di visualizzazione alla fine dell'elenco. Ad esempio, questo comportamento di fissaggio è utile per un'esperienza utente di chat o di log.
Nell'esempio seguente il contenuto virtualizzato viene aggiunto all'inizio dell'elenco:
<Virtualize AnchorMode="Start" ...> ... </Virtualize>Per ulteriori informazioni, vedi le seguenti risorse:
- Razor Virtualizzazione dei componenti ASP.NET Core
-
[release/11.0-preview4] Virtualization AnchorMode con supporto per altezza variabile (
dotnet/aspnetcore#66521) (Non commentare issue chiuse e PR chiuse.)
-
Conformità dei criteri di sicurezza del contenuto (CSP)
Il componente
Virtualizegenera attributistyleinline dinamici sui relativi elementi spaziatore e segnaposto (ad esempio,style="height: 478896px; flex-shrink: 0;"), perché le altezze dello spaziatore vengono calcolate in fase di esecuzione in base alla posizione di scorrimento, al numero di elementi e alla dimensione media degli elementi, fattori che cambiano a ogni interazione di scorrimento. Questi vengono bloccati da un criterio di sicurezza del contenuto (CSP) quandostyle-src 'self'viene impostata, interrompendo completamente la virtualizzazione per le app con criteri CSP rigorosi.Ora si evitano le violazioni CSP perché i componenti
Virtualize:- Visualizza le altezze calcolate dei separatori e dei segnaposto come valori numerici negli attributi
data-blazor-virtualize-reserved-height. - Se necessario, visualizzare l'offset verticale dello spaziatore finale come valore numerico nell'attributo
data-blazor-virtualize-loop-breaker-transformper nascondere lo spaziatore.
- Visualizza le altezze calcolate dei separatori e dei segnaposto come valori numerici negli attributi
Nuovo modello di progetto di libreria per i valori predefiniti del servizio per Blazor WebAssembly le app
Il modello di progetto blazor-wasm-servicedefaults crea una libreria delle configurazioni predefinite del servizio per le app Blazor WebAssembly con integrazione Aspire. Per altre informazioni, vedere Strumenti per ASP.NET Core Blazor.
Nuovo server di sviluppo per Blazor WebAssembly le app
Microsoft.AspNetCore.Components.Gateway è un host ASP.NET Core leggero che sostituisce Microsoft.AspNetCore.Components.WebAssembly.DevServer per la gestione di app autonome Blazor WebAssembly durante lo sviluppo e la produzione.
Per adottare il gateway in un'app autonoma esistente Blazor WebAssembly, fare riferimento al pacchetto di anteprima Microsoft.AspNetCore.Components.Gateway nel file di progetto dell'app.
Note
Per indicazioni sull'aggiunta di pacchetti alle app .NET, vedere gli articoli sotto Installare e gestire pacchetti in Flusso di lavoro dell'utilizzo di pacchetti (documentazione di NuGet). Verificare le versioni corrette dei pacchetti in NuGet.org.
Il codice di routing personalizzato e il middleware non sono richiesti dall'app. Gli endpoint di fallback provengono dal manifesto degli asset web statici generato da SDK quando la proprietà StaticWebAssetSpaFallbackEnabled è impostata nel file di progetto dell'app; questa proprietà è presente per impostazione predefinita nelle app autonome Blazor WebAssembly create dal modello di progetto:
<StaticWebAssetSpaFallbackEnabled>true</StaticWebAssetSpaFallbackEnabled>
Prima del rilascio di .NET 11, la proprietà inspectUri del file Properties/launchSettings.json:
- Consente all'IDE di rilevare che l'app è un'app Blazor .
- Indica all'infrastruttura di debug degli script di connettersi al browser tramite Blazoril proxy di debug.
La proprietà non è più necessaria quando si usa il nuovo server di sviluppo.
Aprire il Properties/launchSettings.json file del progetto di avvio. Rimuovere la proprietà inspectUri in ogni profilo di avvio nel nodo profiles del file:
- "inspectUri": "..."
Per ulteriori informazioni, vedi [Blazor] Sostituire DevServer con BlazorGateway per le app WASM autonome (dotnet/aspnetcore #65982) (Non commentare issue e PR chiuse).
Sospensione del circuito attivato dal server
Questa funzionalità riguarda le applicazioni lato Blazor server.
Blazor supporta già la pausa e la ripresa controllate del circuito con Blazor.pauseCircuit() e Blazor.resumeCircuit(). .NET 11 introduce una funzionalità di sospensione e ripresa sul lato server simmetrica, in cui il server può richiedere che i client connessi inizino il flusso normale di sospensione del circuito.
Circuit.RequestCircuitPauseAsync(CancellationToken) viene usato per richiedere che il client connesso inizi il flusso normale di sospensione del circuito.
CancellationToken Annulla la richiesta prima che venga accettata dal framework. Il metodo restituisce true se la richiesta è stata accettata e al client è stato chiesto di iniziare la sospensione.
Questa funzionalità è utile negli scenari seguenti:
- Interruzioni e rilasci pianificati.
- Drenaggio delle istanze.
- Finestre di manutenzione delle app.
Per altre informazioni e un esempio di implementazione per i riavvii del server, vedere ASP.NET Core Blazor gestione dello stato lato server.
Output di pubblicazione più piccolo Blazor WebAssembly
Due modifiche al trimming riducono le dimensioni delle app pubblicate Blazor WebAssembly che non usano OpenTelemetry (OTEL) o Ricaricamento rapido:
- I tipi
ComponentsMetricseComponentsActivitySourcesono ora subordinati a un attributo[FeatureSwitchDefinition], quindi il trimmer può rimuovere daRenderere simili i percorsi di chiamata relativi a metriche e tracciamento quandoSystem.Diagnostics.Metrics.Meter.IsSupportedèfalse(impostazione predefinita per le app sottoposte a trimming) [browser][wasm] Implementare il trimming IL per OTEL (dotnet/aspnetcore#65901) (Non commentare issue e PR chiuse). -
HotReloadManagerora espone una proprietà controllata da un flag di funzionalitàIsSupportedcollegata aSystem.Reflection.Metadata.MetadataUpdater.IsSupported, in modo che il trimmer possa eliminare le cache di Hot Reload e le registrazioni dei gestori di aggiornamento dei metadati in tutto il renderer in fase di pubblicazione [blazor][wasm] Correzione del trimming IL per Hot Reload (dotnet/aspnetcore#65903) (Non commentare issue e PR chiuse).
Le applicazioni che usano OTEL o Ricaricamento rapido non sono interessate dai precedenti aggiornamenti.
QuickGrid miglioramenti
Il componente QuickGrid riceve diverse nuove funzionalità in .NET 11.
Per altre informazioni sulle funzionalità seguenti, vedere ASP.NET Core Blazor componente 'QuickGrid'.
Modalità di paginazione
Prima del rilascio di .NET 11, lo stato di paginazione e ordinamento viene gestito in memoria all'interno del componente QuickGrid senza modificare l'URL, denominato inner-state navigation. È necessaria una modalità di rendering interattiva.
Con il rilascio di .NET 11, QuickGrid supporta la navigazione basata su URL.
Lo stato di paginazione e ordinamento viene salvato in modo permanente nella stringa di query URL. Quando gli utenti impaginano o ordinano, l'URL viene aggiornato (ad esempio: ?page=2&sort=Name&order=asc). Ciò consente la condivisione dei collegamenti, il back/forward del browser e ssr statico senza interattività.
Intestazioni di colonna ordinabili e controlli di impaginazione sono visualizzati come elementi <a> con attributi href.
StaticHtmlRenderer esegue il rendering di queste ancore. In ogni richiesta, il server legge la stringa di query per determinare la pagina corrente e lo stato di ordinamento, senza che sia necessario il runtime JavaScript.
Parametri della stringa di query:
-
page: Numero di pagina a partire da 1. La prima pagina omette il parametro per gli URL puliti. -
sort: titolo della colonna per l'ordinamento della griglia. -
order: crescente (asc) o decrescente (desc).
La sort colonna è identificata dalla proprietà della Title colonna. Le colonne senza Title visualizzano un'intestazione <div> non cliccabile.
QuickGrid legge l'URL durante l'inizializzazione e si sottoscrive a NavigationManager.LocationChanged, quindi i pulsanti Indietro/Avanti del browser e l'immissione diretta dell'URL funzionano correttamente. Quando i parametri di ordinamento vengono rimossi dall'URL, si torna alla colonna e alla direzione di ordinamento predefinite.
I collegamenti impaginatori disabilitati usano aria-disabled="true" e pointer-events: none invece dell'attributo HTML disabled , che non esiste negli <a> elementi.
Più griglie nella stessa pagina
Più QuickGrid componenti nella stessa pagina richiedono valori univoci QueryParameterNamePrefix per evitare conflitti di stringhe di query. Il prefisso predefinito è una stringa vuota, producendo parametri denominati page, sort, order. Ad esempio, l'impostazione del prefisso su "cities" produce cities_page, cities_sorte cities_order.
Ognuno QuickGrid deve avere una propria PaginationState istanza. Più griglie non devono condividere un PaginationState se hanno prefissi diversi: quella di cui viene eseguito il rendering per ultima sovrascrive il nome del parametro di query nello stato condiviso, facendo sì che Paginator legga dal parametro sbagliato.
Nelle versioni precedenti a .NET 11, i componenti QuickGrid seguenti hanno funzionato in modo implicito:
<QuickGrid ... Pagination="@pagination1">
...
</QuickGrid>
<QuickGrid ... Pagination="@pagination2">
...
</QuickGrid>
Con il rilascio di .NET 11, i componenti QuickGrid seguenti richiedono un QueryParameterNamePrefix univoco. Il primo QuickGrid usa il prefisso stringa vuoto predefinito, mentre il secondo imposta cities come prefisso:
<QuickGrid ... Pagination="@pagination1">
...
</QuickGrid>
<QuickGrid ... Pagination="@pagination2" QueryParameterNamePrefix="cities">
...
</QuickGrid>
Stringa di query di esempio per i componenti precedenti QuickGrid :
?page=2&sort=Name&order=asc&cities_page=3&cities_sort=Country&cities_order=desc
Ordina per colonna
Aggiungere Sortable="true" a un oggetto PropertyColumn. Con la navigazione basata su URL, selezionando un'intestazione si passa a un URL con i parametri sort e order aggiornati. Con la navigazione nello stato interno, la selezione di un header attiva @onclick, che chiama SortByColumnAsync. In entrambi i casi, SortByColumnAsync passa tramite NavigationManager.NavigateTo(GetSortQueryStringUrl(...)), quindi l'URL riflette sempre lo stato di ordinamento.
Identificazione dell'ordinamento in base al titolo
Lo stato di ordinamento nell'URL usa la proprietà della Title colonna come identificatore. Il sort parametro di query è impostato su column.Title , ad esempio per il titolo Namedella colonna : ?sort=Name&order=asc. In caso di modifica dell'URL, QuickGrid associa nuovamente il valore sort a una colonna eseguendo _columns.FirstOrDefault(c => c.Title == sort.ColumnTitle). Se nessun titolo di colonna corrisponde, l'ordinamento viene ignorato e la griglia torna all'ordinamento predefinito.
Rinominare Title di una colonna comporta la rottura dell'URL. Qualsiasi URL salvato nei segnalibri o condiviso che contenga il titolo precedente nel parametro sort non corrisponde più e la griglia torna silenziosamente all’ordinamento predefinito invece di ordinare in base alla colonna desiderata. Per PropertyColumn, il valore predefinito di Title è il nome della proprietà (ad esempio: Property="@(p => p.FirstName)" produce Title="First Name"), quindi sia rinominare la proprietà sia modificare esplicitamente il parametro Title interrompono gli URL esistenti.
Impaginatore
Paginator inserisce NavigationManager, sottoscrive LocationChangede legge l'indice della pagina dalla stringa di query in ogni modifica della posizione.
GoToPageAsync passa all'URL di destinazione anziché modificare PaginationStatedirettamente . Lo stato viene aggiornato tramite il flusso di LocationChanged callback.
GetPageUrl restituisce un URL con il numero di pagina in base uno. L'indice di pagina 0 (pagina 1) omette completamente il parametro di query.
Modifica di rilievo CSS
Quando la navigazione basata su URL è abilitata, i selettori che fanno riferimento a button.col-title devono fare riferimento anche a a.col-title, e nav button/nav button:disabled richiedono nav a/nav a[aria-disabled="true"]. Il foglio di stile predefinito QuickGrid fornisce entrambi per impostazione predefinita.
Come disabilitare la navigazione basata su URL
Per disabilitare la navigazione basata su URL, impostare l'opzione AppContext per la funzionalità su false:
AppContext.SetSwitch(
"Microsoft.AspNetCore.Components.QuickGrid.EnableUrlBasedQuickGridNavigationAndSorting",
false);
Questo ripristina gli elementi <button> con handler @onclick. È necessaria una modalità di rendering interattiva.
L'interruttore controlla solo l'elemento HTML renderizzato (<a> anziché <button>). Anche se disabilitato, QuickGrid legge e scrive lo stato nella stringa di query URL internamente.
SortByColumnAsync e Paginator.GoToPageAsync navigano tramite NavigationManager.NavigateTo indipendentemente dal flag.
Evento clic sulla riga (OnRowClick)
Il QuickGrid componente supporta ora gli eventi di clic di riga tramite il nuovo OnRowClick parametro. Se impostata, la griglia applica automaticamente lo stile appropriato (puntatore del cursore) e richiama il callback con l'elemento selezionato:
@using Microsoft.AspNetCore.Components.QuickGrid
@inject NavigationManager NavigationManager
<QuickGrid Items="@people.AsQueryable()"
OnRowClick="@((Person args) => HandleRowClick(args))">
<PropertyColumn Property="@(p => p.Name)" />
<PropertyColumn Property="@(p => p.Email)" />
</QuickGrid>
@code {
private List<Person> people = new()
{
new(1, "Alice Smith", "alice@example.com", "Engineering"),
new(2, "Bob Johnson", "bob@example.com", "Marketing"),
new(3, "Carol Williams", "carol@example.com", "Engineering"),
};
private void HandleRowClick(Person person)
{
NavigationManager.NavigateTo($"/person/{person.Id}");
}
private record Person(int Id, string Name, string Email, string Department);
}
La funzionalità include stili CSS predefiniti che applicano un cursore del puntatore alle righe selezionabili tramite la classe CSS selezionabile per righe, fornendo commenti visivi chiari agli utenti.
Il prerendering sul lato client in un Blazor Web App preserva le impostazioni cultura del server
Per impostazione predefinita, il prerendering lato client sul server (.Client progetto in un Blazor Web App) mantiene i valori del server CurrentCulture e CurrentUICulture nello stato del componente e li applica sul client prima del caricamento degli assembly satellite.
Le applicazioni che richiedono al client di scegliere le impostazioni cultura indipendentemente dal server possono disattivarlo con WebAssemblyComponentsOptions.UseCultureFromServer nel file Blazor Web App di Program:
builder.Services.AddRazorComponents()
.AddInteractiveWebAssemblyComponents(options =>
{
options.UseCultureFromServer = false;
});
Mantenere persistenti i dati della sessione tra le richieste HTTP durante il rendering statico lato server (SSR statico)
La persistenza dei dati di sessione consente di leggere e scrivere valori di sessione HTTP basati su cookie durante il rendering statico lato server (SSR statico), ed è utile in scenari come gli ID del carrello o l'avanzamento di un modulo in più passaggi. A differenza della persistenza temporanea dei dati (ITempData), i valori di sessione non vengono cancellati dopo la lettura. I valori persistono tra richieste multiple per la durata della sessione.
La configurazione dell'archiviazione delle sessioni richiede l'aggiunta di servizi tramite la chiamata a AddSession e la configurazione della pipeline di richiesta con UseSession:
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession();
builder.Services.AddRazorComponents();
var app = builder.Build();
app.UseSession();
Quando viene specificato a un parametro, usare l'attributo [SupplyParameterFromSession] senza o con una chiave (stringa):
[SupplyParameterFromSession]
public string? Message { get; set; }
[SupplyParameterFromSession(Name = "flash_message")]
public string? FlashMessage { get; set; }
Per altre informazioni, vedere ASP.NET Core Blazor gestione dello stato lato server.
GetUriWithFragment metodo di estensione
Un nuovo GetUriWithFragment metodo di estensione consente di NavigationManager costruire facilmente URI con frammenti hash. Questo metodo di supporto fornisce un modo efficiente, senza allocazioni, per aggiungere frammenti hash all'URI corrente. L'esempio seguente illustra due casi d'uso:
- Chiamata inline che passa alla sezione 1 (
id="section-1") della pagina di cui è stato eseguito il rendering. - Chiamata di metodo che riceve un ID di sezione (
sectionId) e passa alla relativa sezione della pagina.
@inject NavigationManager Navigation
<a href="@Navigation.GetUriWithFragment("section-1")">
Jump to Section 1
</a>
@code {
private void NavigateToSection(string sectionId)
{
var uri = Navigation.GetUriWithFragment(sectionId);
Navigation.NavigateTo(uri);
}
}
Il metodo usa string.Create per ottenere prestazioni ottimali e funziona correttamente con URI di base non radice, ad esempio quando si usa <base href="/app/">.
Componente EnvironmentView
Blazor include ora un componente predefinito EnvironmentView per il rendering condizionale basato sull'ambiente di hosting. Questo componente offre un modo coerente per eseguire il rendering del contenuto in base all'ambiente corrente in entrambi i modelli di hosting lato server e lato client.
Il componente EnvironmentView accetta i parametri Include e Exclude per specificare i nomi degli ambienti. Il componente esegue la corrispondenza senza distinzione tra maiuscole e minuscole e segue la stessa semantica di MVC.EnvironmentTagHelper
@using Microsoft.AspNetCore.Components.Web
<EnvironmentView Include="Development">
<div class="alert alert-warning">
Debug mode enabled
</div>
</EnvironmentView>
<EnvironmentView Include="Development,Staging">
<p>Pre-production environment</p>
</EnvironmentView>
<EnvironmentView Exclude="Production">
<p>@DateTime.Now</p>
</EnvironmentView>
Supporto per il namespace MathML
Blazor supporta ora gli elementi MathML nel rendering interattivo. Gli elementi MathML, ad esempio <math>, <mrow><mi>, e <mn>, vengono creati con lo spazio dei nomi corretto (http://www.w3.org/1998/Math/MathML) usando document.createElementNS(), analogamente al modo in cui vengono gestiti gli elementi SVG:
<math>
<mrow>
<mi>x</mi>
<mo>=</mo>
<mfrac>
<mrow>
<mo>−</mo>
<mi>b</mi>
<mo>±</mo>
<msqrt>
<mrow>
<msup><mi>b</mi><mn>2</mn></msup>
<mo>−</mo>
<mn>4</mn>
<mi>a</mi>
<mi>c</mi>
</mrow>
</msqrt>
</mrow>
<mrow>
<mn>2</mn>
<mi>a</mi>
</mrow>
</mfrac>
</mrow>
</math>
Questa correzione garantisce che i contenuti MathML vengano visualizzati correttamente nei browser quando vengono aggiunti dinamicamente tramite il renderer di Blazor, risolvendo i problemi per cui gli elementi MathML venivano in precedenza creati come normali elementi HTML senza il namespace corretto.
InvokeVoidAsync() analizzatore
È stato aggiunto un nuovo Blazor analizzatore (BL0010) che consiglia di usare InvokeVoidAsync invece di InvokeAsync<object> chiamare funzioni JavaScript che non restituiscono valori. Questo analizzatore consente agli sviluppatori di scrivere codice JSInterop più efficiente.
Codice problematico:
// ⚠️ BL0010: Use InvokeVoidAsync for JavaScript functions that don't return a value
await JSRuntime.InvokeAsync<object>("console.log", "Hello");
Codice consigliato:
// ✅ Correct: Use InvokeVoidAsync
await JSRuntime.InvokeVoidAsync("console.log", "Hello");
L'analizzatore aiuta a individuare i problemi di prestazioni in cui InvokeAsync viene usato inutilmente con object oppure vengono ignorati i valori restituiti, indirizzando gli sviluppatori verso il metodo InvokeVoidAsync più appropriato.
IComponentPropertyActivator
Blazor ora fornisce IComponentPropertyActivator per personalizzare il modo in cui le proprietà [Inject] vengono popolate nei componenti. Ciò consente scenari avanzati, ad esempio:
- Fornire un contesto aggiuntivo per la risoluzione delle proprietà.
- Supporto per contenitori DI personalizzati che devono intercettare l'iniezione di proprietà.
- Scenari avanzati che richiedono la personalizzazione dell'inserimento delle proprietà.
public interface IComponentPropertyActivator
{
Action<IServiceProvider, IComponent> GetActivator(
[DynamicallyAccessedMembers(Component)] Type componentType);
}
L'implementazione predefinita memorizza nella cache gli attivatori per tipo di componente, supporta i servizi con chiave tramite [Inject(Key = "...")], si integra con Ricaricamento rapido per invalidazione della cache e include annotazioni di taglio appropriate per la compatibilità AOT.
SignalR
ConfigureConnection per i componenti del server interattivo
Blazor consente ora di configurare le opzioni di connessione SignalR sottostanti quando si utilizzano i componenti di Interactive Server tramite la nuova proprietà ConfigureConnection in ServerComponentsEndpointOptions. In questo modo è possibile configurare HttpConnectionDispatcherOptions le proprietà che in precedenza erano accessibili solo tramite soluzioni alternative.
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode(options =>
{
options.ConfigureConnection = dispatcherOptions =>
{
dispatcherOptions.CloseOnAuthenticationExpiration = true;
dispatcherOptions.AllowStatefulReconnects = true;
dispatcherOptions.ApplicationMaxBufferSize = 1024 * 1024;
};
});
In questo modo è disponibile un'API pulita e indipendente dai tipi per configurare SignalR le impostazioni di connessione senza dover esaminare i metadati dell'endpoint.
IHostedService supporto in Blazor WebAssembly
Blazor WebAssembly supporta IHostedService ora per l'esecuzione di servizi in background nel browser. Ciò offre parità di funzionalità con Blazor Server e consente scenari come l'aggiornamento periodico dei dati, gli aggiornamenti in tempo reale e l'elaborazione in background.
public class DataRefreshService : IHostedService
{
private Timer? _timer;
public Task StartAsync(CancellationToken cancellationToken)
{
_timer = new Timer(RefreshData, null, TimeSpan.Zero, TimeSpan.FromMinutes(5));
return Task.CompletedTask;
}
private void RefreshData(object? state)
{
// Refresh data periodically
}
public Task StopAsync(CancellationToken cancellationToken)
{
_timer?.Dispose();
return Task.CompletedTask;
}
}
// Registration
builder.Services.AddHostedService<DataRefreshService>();
I servizi ospitati vengono avviati quando l'app si avvia e arrestati quando viene chiusa, garantendo un ciclo di vita chiaro per le operazioni in background nelle app Blazor WebAssembly.
Configurare Blazor il comportamento del client dal server
Blazor Le app possono ora configurare il comportamento di avvio lato client dal server in C# quando si esegue il mapping Razor dei componenti invece di scrivere Blazor.start a mano JavaScript.
WithBrowserOptions imposta le opzioni serializzate dal server nella pagina di cui è stato eseguito il rendering e lo Blazor script viene applicato nel browser, nelle modalità server, WebAssembly e Rendering automatico. Le opzioni riguardano il livello di log del client, la riconnessione interattiva al server, se la navigazione avanzata preserva il DOM e il nome dell'ambiente, la cultura e le variabili di ambiente di un runtime WebAssembly:
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode()
.WithBrowserOptions(options =>
{
options.LogLevel = LogLevel.Warning;
options.Server.ReconnectionMaxRetries = 10;
options.Server.ReconnectionRetryInterval = TimeSpan.FromSeconds(1.5);
options.Ssr.PreserveDom = true;
options.WebAssembly.EnvironmentName = "Staging";
options.WebAssembly.EnvironmentVariables["OTEL_EXPORTER_OTLP_ENDPOINT"] =
"https://localhost:4318";
});
È anche possibile impostare le opzioni di un componente con <ConfigureBrowser> o leggere le opzioni risolte da HttpContext con GetBrowserOptions().
L'API è stata introdotta in Anteprima 4 e modificata in Anteprima 6 per seguire le convenzioni delle opzioni. Se è stata adottata la forma precedente, WithBrowserConfiguration ora è WithBrowserOptions, BrowserConfiguration ora è BrowserOptions, ServerBrowserOptions ora è InteractiveServerBrowserOptions, SsrBrowserOptions.DisableDomPreservation ora è PreserveDom (con il significato opposto) e CircuitInactivityTimeoutMs ora è CircuitInactivityTimeout (un TimeSpan).
Per ulteriori informazioni, vedi le seguenti risorse:
-
Proposta API: BrowserOptions per la configurazione da server a client (
dotnet/aspnetcore#66393) -
Ristrutturare l'API BrowserConfiguration in base alla revisione (BrowserOptions), mantenendo il formato wire JS (
dotnet/aspnetcore#67337)
Per favore, non commentare su issue chiuse e PR chiuse. Aprire un nuovo problema per fornire commenti e suggerimenti su questa API.
Variabili di ambiente nella Blazor WebAssembly configurazione
Blazor WebAssembly le applicazioni possono ora accedere alle variabili di ambiente tramite IConfiguration. Ciò consente la configurazione di runtime senza ricompilare l'applicazione, semplificando la distribuzione della stessa compilazione in ambienti diversi.
Nell'esempio seguente le API_ENDPOINT variabili di ambiente e ENABLE_FEATURE_X vengono incluse automaticamente nella configurazione:
var builder = WebAssemblyHostBuilder.CreateDefault(args);
var apiEndpoint = builder.Configuration["API_ENDPOINT"];
var featureFlag = builder.Configuration["ENABLE_FEATURE_X"];
Le variabili di ambiente vengono caricate nel sistema di configurazione insieme ad altre origini di configurazione, ad esempio le impostazioni dell'app (appsettings.json), fornendo un modo unificato per accedere ai valori di configurazione indipendentemente dall'origine.
Blazor WebAssembly metriche dei componenti e tracciamento
Blazor WebAssembly Le app ora forniscono metriche e traccia specifiche dei componenti quando il supporto per le metriche è stato abilitato nel runtime.
Abilitare il supporto dei contenitori nel Blazor Web App modello
Il modello di progetto Blazor Web App supporta ora l'opzione Enable container support in Visual Studio. In questo modo è più semplice inserire in contenitori Blazor Web App e distribuirli in piattaforme di orchestrazione dei contenitori, ad esempio Kubernetes o App contenitore di Azure.
L'SSR statico supporta la validazione lato client
Blazor i moduli con rendering statico lato server (SSR statico) ora ricevono immediatamente un riscontro di convalida nel browser senza un'andata e ritorno al server, in linea con l’esperienza offerta dalle app interattive Blazor e dalle app MVC con convalida non intrusiva. Il modello .NET rimane l'unica fonte di verità per le regole di convalida. Il server genera i metadati per le regole di convalida, che vengono poi fatte rispettare dal codice BlazorJS lato client.
La funzionalità è abilitata per impostazione predefinita per tutti i moduli SSR statici che includono il DataAnnotationsValidator componente. Sono supportati sia moduli avanzati che non avanzati.
La copertura completa delle funzionalità è disponibile in ASP.NET Core Blazor form validation.
Per ulteriori informazioni, vedi le seguenti risorse:
-
Aggiungere il supporto .NET per la convalida lato client in Blazor SSR (
dotnet/aspnetcore#66441) -
Aggiungere la libreria JS per la validazione lato client in Blazor SSR (
dotnet/aspnetcore#66420)
Per favore, non commentare su issue chiuse e PR chiuse. Se si hanno commenti e suggerimenti su questa funzionalità, aprire un nuovo problema nel repository dotnet/aspnetcore GitHub.
Supporto per la convalida asincrona dei moduli
Blazor I moduli ricevono il supporto per le regole di convalida asincrone, ad esempio ricerche di database o chiamate API remote. In qualsiasi modalità di rendering, EditForm la convalida all'invio ora attende correttamente i validatori asincroni dall'inizio alla fine. Nelle modalità interattive, i componenti del validator possono registrare la convalida asincrona per campo tramite EditContext.RegisterAsyncFieldValidator. Il framework li tiene traccia, annulla le convalide sostituite ed espone lo stato di avanzamento tramite IsValidationPending(field) e IsValidationFaulted(field).
Il componente predefinito DataAnnotationsValidator esegue le API asincrone DataAnnotations (AsyncValidationAttribute e IAsyncValidatableObject), quindi le regole asincrone dichiarate nel modello funzionano senza configurazione aggiuntiva.
<EditForm EditContext="editContext" OnSubmit="HandleSubmit">
<InputText @bind-Value="model.Username" />
@if (editContext.IsValidationPending(() => model.Username))
{
<span>Checking availability...</span>
}
<ValidationMessage For="() => model.Username" />
<button type="submit">Register</button>
</EditForm>
@code {
[Inject] public UserService Users { get; set; } = default!;
private readonly RegistrationModel model = new();
private EditContext editContext = default!;
private ValidationMessageStore messages = default!;
protected override void OnInitialized()
{
editContext = new EditContext(model);
messages = new ValidationMessageStore(editContext);
editContext.OnFieldChanged += (_, e) =>
{
if (e.FieldIdentifier.FieldName == nameof(model.Username))
{
editContext.RegisterAsyncFieldValidator(e.FieldIdentifier,
token => CheckAsync(e.FieldIdentifier, model.Username, token));
}
};
}
private async Task CheckAsync(FieldIdentifier field, string value, CancellationToken ct)
{
messages.Clear(field);
if (await Users.IsUsernameTakenAsync(value, ct))
{
messages.Add(field, "Username is taken.");
}
editContext.NotifyValidationStateChanged();
}
private async Task HandleSubmit() => await editContext.ValidateAsync();
}
La copertura completa delle funzionalità è disponibile in ASP.NET Core Blazor form validation.
Per ulteriori informazioni, vedere Aggiungere il supporto predefinito per la convalida asincrona dei moduli in Blazor (dotnet/aspnetcore #66526).
Per favore, non commentare su issue chiuse e PR chiuse. Se si hanno commenti e suggerimenti su questa funzionalità, aprire un nuovo problema nel repository dotnet/aspnetcore GitHub.
Blazor e le API minimali supportano la localizzazione degli errori
La validazione dei Blazor form e degli endpoint Minimal API riceve un supporto di primo livello per la localizzazione dei messaggi di errore e dei nomi delle proprietà. La localizzazione viene attivata automaticamente dopo che un oggetto IStringLocalizerFactory è disponibile. Per impostazione predefinita, la localizzazione registrata da AddLocalization usa file RESX specifici della lingua distribuiti come parte dell'assembly.
builder.Services.AddLocalization();
builder.Services.AddValidation();
[ValidatableType]
public class ContactModel
{
// Values of ErrorMessage are used as localization keys.
[Required(ErrorMessage = "RequiredError")]
[EmailAddress(ErrorMessage = "EmailError")]
[Display(Name = "ContactEmail")]
public string? Email { get; set; }
}
Le app possono anche registrare implementazioni personalizzate IStringLocalizerFactory per leggere le stringhe localizzate da altre origini, ad esempio database o file JSON. Un tipo registrato dall'utente ha la precedenza sulla localizzazione RESX predefinita.
builder.Services.AddSingleton<IStringLocalizerFactory, DbStringLocalizerFactory>();
builder.Services.AddValidation();
Per risolvere le chiavi da un file di risorse condivise anziché dalle risorse del tipo convalidato, impostare ValidationOptions.LocalizerProvider:
builder.Services.AddValidation(options =>
{
options.LocalizerProvider = (_, factory) => factory.Create(typeof(ValidationMessages));
});
Quando un attributo non imposta ErrorMessage, le chiavi di ricerca convenzionali vengono tentate dalla maggior parte alla meno specifica, rimuovendo la necessità di specificare le chiavi di localizzazione in ogni attributo di convalida:
[ValidatableType]
public class ContactModel
{
// Looks up 'ContactModel_Username_RequiredAttribute_Error', then
// 'ContactModel_RequiredAttribute_Error', then 'RequiredAttribute_Error'.
[Required]
public string? Username { get; set; }
}
La copertura completa delle funzionalità è disponibile negli articoli seguenti:
- Rendere localizzabile il contenuto di un'app ASP.NET Core
- Informazioni di riferimento rapido sulle API minime
Per altre informazioni, vedere Aggiungere il supporto per la localizzazione per Microsoft. Extensions.Validation (dotnet/aspnetcore #66646).
Per favore, non commentare su issue chiuse e PR chiuse. Se si hanno commenti e suggerimenti su questa funzionalità, aprire un nuovo problema nel repository dotnet/aspnetcore GitHub.
Correzioni a TempData e alla persistenza di [SupplyParameterFromSession] nell'SSR in streaming
Quando una pagina usa funzionalità basate su sessione, in cui un componente ha un [SupplyParameterFromSession] parametro (che crea una sottoscrizione) o il provider TempData di archiviazione sessione è attivo, la sessione cookie (.AspNetCore.Session) viene ora eseguita prima dell'inizio del flusso, anche se non viene scritto alcun valore. Le pagine che non usano funzionalità basate sulla sessione rimangono inalterate.
Per altre informazioni, vedere Correggere la persistenza di TempData e SupplyParameterFromSession per il caso SSR in streaming (dotnet/aspnetcore #66832). (Per favore, non commentare sulle issue e sulle PR chiuse.)
Middleware antiforgery (app.UseAntiforgery()) facoltativo nei Blazor Web App
La protezione CSRF è abilitata per impostazione predefinita tramite il middleware di protezione CSRF inserito automaticamente, pertanto la chiamata esplicita app.UseAntiforgery() nei Blazor Web App modelli è facoltativa, a meno che non sia necessaria in casi d'uso specifici. In una versione di anteprima futura, il middleware verrà rimosso dalla pipeline di elaborazione delle richieste per le app create dal modello di Blazor Web App progetto.
Per ulteriori informazioni, vedi le seguenti risorse:
- Eseguire la migrazione da ASP.NET Core in .NET 10 a ASP.NET Core in .NET 11
- Blazor il rendering lato server rinvia la convalida antiforgeria al middleware (annuncio di modifica che causa un'interruzione)
Copertura generale per la nuova protezione CSRF automatica in ASP.NET Core:
- Prevenire gli attacchi XSRF/CSRF (Cross-Site Request Forgery) in ASP.NET Core
- Panoramica dei form di Blazor ASP.NET Core
- Autenticazione e autorizzazione per ASP.NET Core Blazor
Blazor Virtualize può scorrere fino a un elemento
Il componente Virtualize<TItem> può ora aprirsi su un elemento specifico e scorrere fino a un elemento qualsiasi su richiesta. Due nuove API pubbliche rendono possibile questa operazione:
-
InitialItemIndexposiziona l'elenco in corrispondenza di un determinato elemento nel primo rendering interattivo, quindi l'elenco si apre in corrispondenza di tale elemento senza un flash del primo elemento. -
ScrollToIndexAsync(int itemIndex, CancellationToken cancellationToken = default)scorre fino a un elemento in qualsiasi momento dopo il primo rendering e restituisce un oggettoTaskche viene completato quando la destinazione è allineata alla parte superiore del riquadro di visualizzazione.
<Virtualize TItem="Product" Items="products" InitialItemIndex="500" @ref="list">
<div class="product">@context.Name</div>
</Virtualize>
<button @onclick="GoToTop">Back to top</button>
@code {
private Virtualize<Product> list = default!;
private List<Product> products = ProductCatalog.All;
private async Task GoToTop() => await list.ScrollToIndexAsync(0);
}
Gli indici non compresi nell'intervallo sono bloccati all'intervallo valido. Se viene avviata una seconda ScrollToIndexAsync chiamata mentre una è ancora in volo, l'ultima chiamata vince. La chiamata ScrollToIndexAsync prima del primo rendering interattivo genera InvalidOperationException; usare InitialItemIndex per impostare invece la posizione iniziale.
Per altre informazioni, vedere Aggiungere InitialIndex (sic) parametro e ScrollToIndexAsync API a Virtualize<TItem> (dotnet/aspnetcore #66753). (Per favore, non commentare sulle issue e sulle PR chiuse.)
Sospensione automatica del circuito in caso di inattività della scheda
La sospensione automatica può sospendere un circuito quando la scheda del browser diventa nascosta, liberando la memoria del server e SignalR le connessioni mantenute dagli utenti inattivi. Si tratta di una funzionalità di consenso esplicito fornita dal Microsoft.AspNetCore.Components.Server.AutoPause pacchetto. Dopo aver aggiunto un riferimento al pacchetto, attivare la funzionalità chiamando AddAutoPause quando viene mappato il componente radice dell'applicazione:
app.MapRazorComponents<App>()
.WithBrowserOptions(options => options.AddAutoPause(p => p.HiddenDelay = TimeSpan.FromSeconds(30)));
Dopo che la scheda rimane nascosta per un intervallo di ritardo configurabile (impostazione predefinita: 2 minuti), il circuito va in pausa. Se l'utente torna prima della scadenza del ritardo, la pausa non si verifica.
Per altre informazioni, vedere ASP.NET Core Blazor gestione dello stato lato server.
Supporto più ampio per AuthorizationPolicy e IAuthorizationRequirementData
A partire da .NET 11, è possibile applicare gli attributi IAuthorizationRequirementData agli hub e ai relativi metodi di SignalR, ai controller e alle azioni MVC e ai componenti AuthorizeRouteView e AuthorizeView di Blazor, non solo agli endpoint. Per le app destinate a versioni precedenti a .NET 11, questi attributi sono applicati solo alle Minimal API e agli endpoint con routing.
Per altre informazioni, vedere Criteri di autorizzazione personalizzati con "IAuthorizationRequirementData".
QuickGrid Le API di Virtualize sono esposte
Le seguenti nuove API del QuickGrid componente sono disponibili quando una griglia è virtualizzata (Virtualize è impostato su true):
-
InitialItemIndex: scorre la griglia fino all'indice di riga in base zero specificato nel primo rendering interattivo. Il valore viene applicato una volta e bloccato all'intervallo valido. Questo viene passato al componente internoVirtualize. Per ulteriori informazioni, vedere ASP.NET Core Razor virtualizzazione dei componenti. -
ScrollToItemAsync: scorre a livello di codice la griglia fino all'indice di riga in base zero specificato, allineandolo alla parte superiore. L'ultima chiamata vince e il metodo genera un'eccezione InvalidOperationException quando la virtualizzazione è disabilitata o la griglia non viene ancora sottoposta a rendering. Questo viene passato al componente internoVirtualize. Per ulteriori informazioni, vedere ASP.NET Core Razor virtualizzazione dei componenti. -
AnchorMode: controlla il comportamento del viewport in corrispondenza dei bordi dell'elenco quando gli elementi vengono aggiunti dinamicamente (impostazione predefinita:Start). Si tratta di un'API sperimentale che richiede l'attivazione esplicita della diagnosticaASP0030e viene inoltrata al componente internoVirtualize. Per ulteriori informazioni, vedere ASP.NET Core Razor virtualizzazione dei componenti. -
ItemComparer: comparatore usato per rilevare se gli elementi sono stati aggiunti all'inizio o alla fine tra un caricamento dei dati e l'altro, utile per elementi di tipo classe forniti da un oggetto ItemsProvider. Si tratta di un'API sperimentale che richiede l'attivazione esplicita della diagnosticaASP0030e viene inoltrata al componente internoVirtualize. Per ulteriori informazioni, vedere ASP.NET Core Razor virtualizzazione dei componenti.
Per altre informazioni, vedere componente ASP.NET Core Blazor 'QuickGrid'.
ValidatableTypeAttribute e SkipValidationAttribute non sono più sperimentali
Gli ValidatableTypeAttribute attributi e SkipValidationAttribute del Microsoft.Extensions.Validation pacchetto NuGet non sono più sperimentali.
Per ulteriori informazioni, vedi le seguenti risorse:
Memorizza nella cache l'output renderizzato di un sottoalbero di componenti durante l'SSR statico
Il nuovo componente CacheView memorizza nella cache l'output di rendering di un sottoalbero di componenti Razor durante il rendering statico lato server (SSR statico). In caso di hit della cache, il markup memorizzato viene restituito senza istanziare né eseguire il ciclo di vita dei componenti figli inclusi nell'output memorizzato nella cache.
CacheView è utile per sezioni principalmente statiche di una pagina che non richiedono la memorizzazione nella cache dell'intera risposta:
<CacheView VaryByQuery="category" ExpiresAfter="TimeSpan.FromMinutes(5)">
<ProductList Category="@Category" />
</CacheView>
Per altre informazioni, vedere ASP.NET Core Blazor componente CacheView.
Blazor Hybrid
In questa sezione vengono descritte le nuove funzionalità per Blazor Hybrid.
Le note sulla versione vengono visualizzate in questa sezione man mano che diventano disponibili le funzionalità di anteprima.
SignalR
In questa sezione vengono descritte le nuove funzionalità per SignalR.
SignalR aggiornamento dell'autenticazione
SignalR le connessioni possono aggiornare l'autenticazione senza eliminare la connessione alla scadenza del token di accesso. Il server espone un endpoint /refresh insieme a /negotiate e segnala la durata del token nella risposta di negoziazione. Il client .NET si riautentica prima della scadenza del token, così una connessione all'hub che in precedenza si chiudeva quando il bearer token scadeva può rimanere aperta. Questa funzionalità viene implementata per il client .NET. Il client JavaScript/TypeScript e il supporto del servizio Azure SignalR sono in corso.
Abilitare la funzionalità per hub nel server:
app.MapHub<ChatHub>("/chat", options =>
{
options.EnableAuthenticationRefresh = true;
// Optional: decide whether a given connection can refresh.
options.OnAuthenticationRefresh = context => ValueTask.FromResult(true);
});
Un hub può reagire a un'identità aggiornata eseguendo l'override di OnAuthenticationRefreshedAsync:
public class ChatHub : Hub
{
public override Task OnAuthenticationRefreshedAsync()
{
// The connection's User has been updated with the refreshed token.
return Task.CompletedTask;
}
}
L'aggiornamento automatico è attivato per impostazione predefinita nel client .NET ed è configurabile con WithAuthenticationRefresh:
var connection = new HubConnectionBuilder()
.WithUrl("https://example.com/chat")
.WithAuthenticationRefresh(options =>
{
// EnableAutoRefresh is true by default.
options.RefreshBeforeExpiration = TimeSpan.FromMinutes(1);
options.OnAuthenticationRefreshed = context => Task.CompletedTask;
options.OnAuthenticationRefreshFailed = context => Task.CompletedTask;
})
.Build();
Annullare le chiamate all'hub dal client
Il client SignalR può annullare una regolare invocazione non in streaming di un metodo hub. In precedenza solo le chiamate di streaming potevano essere annullate dal client. Ora, quando si passa un oggetto CancellationToken a InvokeAsync e lo si annulla, il client invia un messaggio di annullamento e il parametro CancellationToken del metodo dell'hub viene attivato sul server.
// Client — canceling the token cancels the server-side invocation.
using var cts = new CancellationTokenSource();
var work = connection.InvokeAsync("LongRunningWork", cts.Token);
// ...
cts.Cancel();
// Hub — accept a CancellationToken to observe client cancellation.
public class WorkHub : Hub
{
public async Task LongRunningWork(CancellationToken cancellationToken)
{
await Task.Delay(TimeSpan.FromMinutes(5), cancellationToken);
}
}
SignalR.NET client supporta l'aggiornamento dell'autenticazione dopo i reindirizzamenti
Il SignalR client .NET estende SignalR l'aggiornamento dell'autenticazione in modo che funzioni quando negozia i reindirizzamenti a un altro server, forniti da @MoChilia. Questa modifica client abilita il supporto per il reindirizzamento di server, ad esempio Azure SignalR Servizio, che non ha ancora abilitato la funzionalità.
Il client preserva il provider del token dell'app durante il reindirizzamento, recepisce dalla risposta un token di trasporto aggiornato e conserva tokenLifetimeSeconds in modo che l'aggiornamento automatico resti pianificato dopo la scadenza del token originale.
Grazie @MoChilia per questo contributo!
API minimali
Questa sezione descrive le nuove funzionalità per le API minime.
I filtri degli endpoint osservano gli errori di associazione dei parametri
Quando un endpoint API minimo dispone di filtri o factory di filtri configurati, la pipeline di filtro viene ora eseguita anche se l'associazione di parametri non riesce. I filtri possono leggere HttpContext.Response.StatusCode == 400 e sostituire il corpo della risposta con uno proprio.
Nell'ambiente Development impostare RouteHandlerOptions.ThrowOnBadRequest = false in modo che il framework restituisca un valore 400 che il filtro possa osservare anziché generare BadHttpRequestException nella pagina delle eccezioni dello sviluppatore. Si tratta già dell'impostazione predefinita in ambienti nonDevelopment .
Grazie @marcominerva per questo contributo!
Tipi di unione C#
ASP.NET Core supporta i tipi di unione C# (riferimenti al linguaggio C#), che sono nuovi in .NET 11, ovunque System.Text.Json venga usato: i corpi di richiesta e risposta JSON nelle API minime e MVC, SignalRl'JsonHubProtocolBlazorinteroperabilità JavaScript, lo stato del componente persistente e i parametri dei componenti prerisorse.
public union UnionIntString(int, string);
app.MapGet("/value", () => new UnionIntString(42));
I tipi di unione non sono supportati per origini di binding diverse dal corpo della richiesta, ad esempio parametri di route, stringhe di query, intestazioni e campi del modulo.
Per OpenAPI, un endpoint che restituisce un'unione viene descritto con un anyOf elenco di schemi per ogni tipo di case. A differenza dei tipi polimorfici, i casi di unione non hanno un discriminatore $type, quindi ogni caso riutilizza il proprio componente standalone (ad esempio, #/components/schemas/Dog) invece di una versione duplicata con prefisso. ApiExplorer rileva un'unione tramite JsonTypeInfoKind.Union, quindi lo schema passa anche attraverso Swashbuckle e NSwag. Quando più casi vengono serializzati nella stessa struttura JSON, disambiguateli con un classificatore [JsonUnion].
SignalR le unioni richiedono il protocollo dell'hub JSON; i protocolli e Newtonsoft.Json MessagePack non supportano le unioni.
Per esempi e ulteriori informazioni relativi alle app Blazor, vedere la sezione Parametri dei componenti nell'articolo Panoramica dei componenti e la sezione Passare parametri dell'articolo sui componenti ASP.NET Core con rendering dinamico Razor.
Validazione asincrona per Minimal APIs
La convalida minima dell'API supporta ora validator asincroni end-to-end (dotnet/aspnetcore #66487, dotnet/aspnetcore #67183). Anteprima 5 ha fornito i blocchi predefiniti per la convalida asincrona dei moduli in Blazor. L'anteprima 6 aggiunge nuove API asincrone DataAnnotations nelle librerie di base (AsyncValidationAttribute e IAsyncValidatableObject) e Microsoft.Extensions.Validation ora le esegue quando un endpoint convalida una richiesta.
Il modo più semplice per aggiungere una regola asincrona è un attributo di convalida personalizzato. Derivare da AsyncValidationAttribute e implementare IsValidAsync per eseguire query su un database o chiamare un'API remota senza bloccare un thread. Anche il membro sincrono IsValid è astratto; genera un'eccezione da esso solo quando l'attributo viene convalidato in modo asincrono:
using System.ComponentModel.DataAnnotations;
using Microsoft.Extensions.DependencyInjection;
public sealed class UniqueEmailAttribute : AsyncValidationAttribute
{
// Synchronous IsValid. This attribute validates asynchronously only.
protected override ValidationResult? IsValid(object? value, ValidationContext context) =>
throw new InvalidOperationException("Validate this attribute with IsValidAsync.");
protected override async Task<ValidationResult?> IsValidAsync(
object? value, ValidationContext context, CancellationToken cancellationToken)
{
var users = context.GetRequiredService<IUserService>();
if (value is string email && await users.EmailExistsAsync(email, cancellationToken))
{
return new ValidationResult("That email is already registered.");
}
return ValidationResult.Success;
}
}
Applicare [UniqueEmail] a una proprietà come qualsiasi attributo di convalida predefinito.
Per la convalida che si estende su diverse proprietà o sull'intero oggetto, implementare IAsyncValidatableObject e restituire i risultati come IAsyncEnumerable<ValidationResult>. Poiché IAsyncValidatableObject estende IValidatableObject, implementare anche il metodo sincrono Validate . Quando un tipo esegue la validazione solo in modo asincrono, genera un'eccezione da Validate in modo che la sua validazione non venga silenziosamente ignorata dalle API sincrone:
using System.ComponentModel.DataAnnotations;
using System.Runtime.CompilerServices;
public class ReservationRequest : IAsyncValidatableObject
{
[Required]
public string Email { get; set; } = "";
public DateOnly Date { get; set; }
// Synchronous IValidatableObject. This type validates asynchronously only.
public IEnumerable<ValidationResult> Validate(ValidationContext context) =>
throw new InvalidOperationException("Validate this type with ValidateAsync.");
public async IAsyncEnumerable<ValidationResult> ValidateAsync(
ValidationContext context,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
var rooms = context.GetRequiredService<IRoomService>();
if (!await rooms.HasAvailabilityAsync(Date, cancellationToken))
{
yield return new ValidationResult(
"No rooms are available on that date.", [nameof(Date)]);
}
}
}
Registrare la convalida e il framework convalida la richiesta prima dell'esecuzione dell'endpoint:
builder.Services.AddValidation();
app.MapPost("/reservations", (ReservationRequest request) =>
Results.Ok(request));
I validator vengono eseguiti in modo concorrente, ove possibile: gli attributi asincroni applicati allo stesso membro vengono avviati insieme, gli elementi della raccolta vengono sottoposti a validazione in parallelo e il framework preserva l'ordinamento esistente tra la validazione del membro, del tipo e di IValidatableObject.
Endpoint a corto circuito con un attributo
Il nuovo [ShortCircuit] attributo contrassegna un endpoint da eseguire immediatamente dopo il routing, ignorando il resto della pipeline middleware. Si tratta della forma di attributo della convenzione endpoint esistente ShortCircuit() , quindi può essere applicata direttamente ai controller e alle azioni MVC.
Il corto circuito è utile per gli endpoint che non necessitano di autenticazione, CORS o altro middleware, ad esempio un controllo di integrità o una robots.txt risposta ed evita il costo di esecuzione del middleware. L'endpoint continua a essere eseguito e produce la risposta. Passare un codice di stato facoltativo, ad esempio [ShortCircuit(404)], per impostare il codice di stato della risposta.
[ApiController]
[Route("robots.txt")]
[ShortCircuit]
public class RobotsController : ControllerBase
{
[HttpGet]
public IActionResult Get() => Content("User-agent: *\nDisallow:", "text/plain");
}
Lo stesso attributo funziona sugli endpoint API minimi e la convenzione esistente ShortCircuit() continua a funzionare invariata:
app.MapGet("/health", [ShortCircuit] () => "Healthy");
Grazie @Porozhniakov per aver contribuito a questa funzionalità.
La localizzazione della validazione è integrata
Microsoft.Extensions.Validation localizza i messaggi di convalida e i nomi di visualizzazione senza un pacchetto separato. Chiamando AddLocalization per registrare un oggetto IStringLocalizerFactory, seguito da AddValidation, attiva automaticamente la localizzazione. Il generatore di codice sorgente per la convalida genera il meccanismo di ricerca delle risorse di localizzazione nel tuo assembly.
builder.Services.AddLocalization();
builder.Services.AddValidation();
[ValidatableType]
public class CustomerModel
{
[Display(Name = "CustomerName")] // resource key for the display name
[Required(ErrorMessage = "NameRequired")] // resource key for the message
public string? Name { get; set; }
}
Le chiavi vengono risolte rispetto alle risorse del modello stesso e, in caso di mancata corrispondenza, si ricorre al messaggio predefinito incorporato dell'attributo. Usare ValidationOptions.LocalizerProvider invece per risolvere le chiavi da un file di risorse condivise:
builder.Services.AddValidation(options =>
{
options.LocalizerProvider = (_, factory) => factory.Create(typeof(ValidationMessages));
});
Gli attributi che si localizzano già (ErrorMessageResourceType, [Display(ResourceType = ...)]) ignorano completamente la pipeline. Un attributo personalizzato che deve sostituire i propri valori nel modello di messaggio può implementare IValidationMessageFormatter:
public sealed class DivisibleByAttribute : ValidationAttribute, IValidationMessageFormatter
{
public int Divisor { get; init; }
public string FormatMessage(CultureInfo culture, string template, string displayName)
=> string.Format(culture, template, displayName, Divisor); // {0} = name, {1} = divisor
}
Le stesse regole di localizzazione si applicano alla convalida per le API minime e Blazor, quindi un messaggio si localizza in modo identico ovunque venga usato il modello.
Gli attributi di convalida non sono più sperimentali
ValidatableTypeAttribute e SkipValidationAttribute non sono più contrassegnati come sperimentali. Se è stato soppresso ASP0029 per usare uno dei due attributi, rimuovere la soppressione.
OpenAPI
Questa sezione descrive le nuove funzionalità per OpenAPI.
Descrivere le risposte ai file binari
ASP.NET Core 11 introduce il supporto per la generazione di descrizioni OpenAPI per le operazioni che restituiscono risposte di file binari. La funzionalità mappa il tipo di risultato FileContentResult a uno schema OpenAPI con type: string e format: binary.
Usare il Produces<T> metodo di estensione con T di FileContentResult per specificare il tipo di risposta e il tipo di contenuto:
app.MapPost("/filecontentresult", () =>
{
var content = "This endpoint returns a FileContentResult!"u8.ToArray();
return TypedResults.File(content);
})
.Produces<FileContentResult>(contentType: MediaTypeNames.Application.Octet);
Il documento OpenAPI generato descrive la risposta dell'endpoint come segue:
responses:
'200':
description: OK
content:
application/octet-stream:
schema:
$ref: '#/components/schemas/FileContentResult'
l'oggetto FileContentResult è definito in components/schemas come:
components:
schemas:
FileContentResult:
type: string
format: binary
Supporto di OpenAPI 3.2.0 (cambiamento significativo)
Microsoft.AspNetCore.OpenApi ora supporta OpenAPI 3.2.0 tramite una dipendenza aggiornata da Microsoft.OpenApi 3.3.1. Questo aggiornamento include modifiche di rilievo dalla libreria sottostante. Per altre informazioni, vedere il Microsoft. Guida all'aggiornamento openApi.
Per generare un documento OpenAPI 3.2.0, specificare la versione quando si chiama AddOpenApi:
builder.Services.AddOpenApi(options =>
{
options.OpenApiVersion = Microsoft.OpenApi.OpenApiSpecVersion.OpenApi3_2;
});
Gli aggiornamenti successivi sfruttano le nuove funzionalità nella specifica 3.2.0, ad esempio il supporto dello schema degli elementi per gli eventi di streaming.
Grazie @baywet per questo contributo!
Query HTTP nei documenti OpenAPI generati
La generazione di documenti OpenAPI ora riconosce HTTP QUERY come tipo di operazione nota. QUERY è un metodo sicuro e idempotente proposto che consente ai client di inviare il corpo di una richiesta per descrivere una ricerca, utile quando una query è troppo grande o troppo strutturata per rientrare in un URL. Il routing accetta già stringhe verbo arbitrarie tramite MapMethodse OpenAPI 3.2 aggiunge un query campo all'oggetto Elemento percorso in modo che sia possibile descriverlo nel documento OpenAPI.
Si noti che query è valido solo in un documento OpenAPI 3.2, quindi impostare OpenApiVersion in OpenApiOptions. Nelle versioni precedenti di OpenAPI, l'operazione query viene generata all'interno di un'estensione della specifica x-oai-additionalOperations nell'oggetto Path Item.
using Microsoft.OpenApi;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi(options =>
{
options.OpenApiVersion = OpenApiSpecVersion.OpenApi3_2;
});
var app = builder.Build();
app.MapOpenApi();
app.MapMethods("/search", ["QUERY"], (SearchRequest request) =>
SearchService.Run(request));
app.Run();
In un documento OpenAPI 3.2 l'operazione QUERY viene descritta inline come elemento di pari livello di get, poste altre operazioni standard:
"paths": {
"/search": {
"query": {
"requestBody": { ... },
"responses": { "200": { ... } }
}
}
}
Nei documenti OpenAPI 3.0 e 3.1, la stessa operazione è rappresentata sotto l'estensione x-oai-additionalOperations dell'elemento Path:
"paths": {
"/search": {
"x-oai-additionalOperations": {
"QUERY": {
"requestBody": { ... },
"responses": { "200": { ... } }
}
}
}
}
Grazie @kilifu per questo contributo!
I tipi di risultati del flusso di file vengono visualizzati nei documenti OpenAPI
FileStreamResult, FileContentHttpResulte FileStreamHttpResult sono ora descritti come schemi di stringa binaria nei documenti OpenAPI generati, in modo che i client vedano forme di risposta accurate per gli endpoint che eseguono il flusso dei file. Annotare l'endpoint con .Produces<FileContentHttpResult>(contentType: "application/pdf") (o il tipo equivalente FileStreamHttpResult/FileStreamResult ) in modo che OpenAPI veda il tipo di risultato e genera lo schema binario.
Grazie @marcominerva per questo contributo!
Gli schemi OpenAPI corrispondono meglio al comportamento di ASP.NET Core
La generazione OpenAPI ora gestisce diversi casi di schema in modo più accurato. I parametri enum non inclusi nel corpo mantengono i nomi originali dei membri enum C# anche quando le opzioni JSON HTTP configurano un criterio di denominazione JsonStringEnumConverter, perché il binding di query, route, header e dei dati del modulo usa Enum.TryParse anziché la serializzazione JSON. Gli ID di riferimento dello schema dell'array ora utilizzano nomi di componenti validi, come stringArray e TodoArray, anziché nomi che usano la sintassi array.
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.Converters.Add(
new JsonStringEnumConverter(JsonNamingPolicy.KebabCaseLower));
});
app.MapGet("/orders", (OrderStatus status) => Results.Ok(status));
Con questa configurazione, uno schema del corpo può comunque descrivere OrderStatus.PendingReview come pending-review, mentre lo schema dei parametri di query descrive il valore accettato come PendingReview.
Gli endpoint Minimal API possono supportare più chiamate al metodo di estensione Produces per lo stesso codice di stato, ad esempio per specificare che una risposta 200 può essere restituita come application/json o text/plain con schemi differenti. Lo stesso supporto si applica ai controller MVC tramite più [ProducesResponseType] attributi.
Nelle versioni precedenti, il framework comprimeva ogni codice di stato a un singolo tipo di risposta e rilasciava automaticamente il resto, rendendo impossibile descrivere gli endpoint che servono più tipi di contenuto.
Microsoft.AspNetCore.Mvc.ApiExplorer mantiene ora ogni tipo di risposta dichiarato con ordinamento deterministico e il documento OpenAPI generato genera voci di contenuto separate per tipo di supporto o uno schema anyOf quando più tipi condividono lo stesso tipo di contenuto.
Grazie @marcominerva per il contributo di riferimento allo schema di matrice.
OpenAPI 3.2 per impostazione predefinita
Per impostazione predefinita, i documenti OpenAPI generati sono destinati a OpenAPI 3.2. I documenti continuano a essere generati come prima. Impostare la versione del documento in modo esplicito se è necessario usare una versione precedente per gli strumenti che non supportano ancora OpenAPI 3.2.
Per specificare come destinazione una versione precedente, specificarla quando si chiama AddOpenApi:
builder.Services.AddOpenApi(options =>
{
options.OpenApiVersion = Microsoft.OpenApi.OpenApiSpecVersion.OpenApi3_1;
});
supporto degli eventi Server-Sent in OpenAPI 3.2
Gli endpoint che restituiscono SseItem<T> sono descritti nel documento OpenAPI generato con la struttura OpenAPI 3.2 itemSchema per le risposte text/event-stream. Il itemSchema descrive la struttura del payload per evento di un flusso invece di ricorrere a un semplice schema string.
app.MapGet("/todos/stream", (CancellationToken ct) =>
TypedResults.ServerSentEvents(GetTodosAsync(ct)))
.WithName("StreamTodos");
static async IAsyncEnumerable<SseItem<Todo>> GetTodosAsync(
[EnumeratorCancellation] CancellationToken ct = default)
{
foreach (var todo in Todos.All)
{
yield return new SseItem<Todo>(todo) { EventId = todo.Id.ToString() };
await Task.Delay(1000, ct);
}
}
Restituisce il flusso attraverso TypedResults.ServerSentEvents. Un gestore che restituisce IAsyncEnumerable<SseItem<T>> direttamente viene serializzato come JSON anziché come SSE. Utilizzare l'overload dedicato SseItem<T> senza eventType. Per usare un nome di evento per l'intero flusso, passare una normale IAsyncEnumerable<T> con eventType.
Il documento 3.2 generato descrive il payload dell'evento con itemSchema che fa riferimento a #/components/schemas/Todo, oltre ai campi stringa standard SSE event e id:
responses:
'200':
description: OK
content:
text/event-stream:
itemSchema:
type: object
required: [data]
properties:
data:
$ref: '#/components/schemas/Todo'
event: { type: string }
id: { type: string }
Se il payload dell'evento è un'unione discriminata (una funzionalità di anteprima di C# 14), OpenAPI emette anche i nomi dei casi dell'unione come enum nel campo event.
Autenticazione e autorizzazione
In questa sezione vengono descritte le nuove funzionalità per l'autenticazione e l'autorizzazione.
supporto in TimeProvider ASP.NET Core Identity
ASP.NET Core Identity ora usa TimeProvider anziché DateTime e DateTimeOffset per tutte le operazioni correlate al tempo. Questa modifica rende Identity i componenti più testabili e offre un migliore controllo nel tempo nei test e negli scenari specializzati.
L'esempio seguente illustra come usare un falso TimeProvider per le funzionalità di test Identity :
// In tests
var fakeTimeProvider = new FakeTimeProvider(
new DateTimeOffset(2024, 1, 1, 0, 0, 0, TimeSpan.Zero));
services.AddSingleton<TimeProvider>(fakeTimeProvider);
services.AddIdentity<IdentityUser, IdentityRole>();
// Identity will now use the fake time provider
Usando TimeProvider, è possibile scrivere più facilmente test deterministici per funzionalità sensibili al Identity tempo, ad esempio la scadenza del token, la durata del blocco e la convalida dello stamp di sicurezza.
Dedurre il nome chiave di accesso visualizzato dall'autenticatore
ASP.NET Core Identity ora deduce automaticamente nomi di visualizzazione amichevoli per le passkey in base al relativo AAGUID (Authenticator Attestation GUID). I mapping predefiniti sono inclusi per gli autenticatori passkey usati più di frequente, tra cui Google Password Manager, iCloud Keychain, Windows Hello, 1Password e Bitwarden.
Per gli autenticatori noti, il nome viene assegnato automaticamente senza chiedere conferma all'utente. Per gli autenticatori sconosciuti, l'utente viene reindirizzato a una pagina di ridenominazione. Estendere i mapping aggiungendo voci al dizionario PasskeyAuthenticators nel progetto.
dotnet user-jwts supporta app basate su file
Lo dotnet user-jwts strumento crea JWT di sviluppo firmati in modo da poter chiamare gli endpoint autenticati di un'app senza configurare un provider di identità reale. Il create comando genera un token, archivia la chiave di firma nei segreti utente dell'app e stampa il token da usare come token di connessione. Ora funziona con le app basate su file (un singolo app.cs senza file di progetto) tramite la nuova --file opzione:
dotnet user-jwts create --file app.cs
Metadati di autorizzazione coerenti nello stack
I metadati di autorizzazione possono essere espressi come IAuthorizeData, un AuthorizationPolicy o un attributo IAuthorizationRequirementData. I filtri MVC, i metodi dell'hub SignalR e gli AuthorizeView e i AuthorizeRouteView di Blazor applicano tutte e tre le forme in modo coerente.
Un nuovo AuthorizationPolicy.CombineAsync sovraccarico rappresenta l'implementazione condivisa:
public class AuthorizationPolicy
{
public static Task<AuthorizationPolicy?> CombineAsync(
IAuthorizationPolicyProvider policyProvider,
IEnumerable<object> metadata);
}
MVC, SignalR e Blazor usano questo overload internamente. Un attributo personalizzato che implementa sia IAuthorizeData che IAuthorizationRequirementData contribuisce una sola volta alla decisione. Il percorso MVC legacy con EnableEndpointRouting = false è invariato.
Miscellaneous
Questa sezione descrive varie nuove funzionalità in .NET 11.
interfaccia IOutputCachePolicyProvider
ASP.NET Core in .NET 11 fornisce l'interfaccia IOutputCachePolicyProvider per implementare la logica di selezione dei criteri personalizzati di memorizzazione nella cache dell'output. Usando questa interfaccia, le app possono determinare i criteri di memorizzazione nella cache di base predefiniti, verificare l'esistenza di criteri denominati e supportare scenari avanzati in cui i criteri devono essere risolti in modo dinamico. Gli esempi includono il caricamento di criteri da fonti di configurazione esterne, dalle database, o l'applicazione di regole di caching specifiche per l'inquilino.
Il codice seguente illustra l'interfaccia IOutputCachePolicyProvider :
public interface IOutputCachePolicyProvider
{
IReadOnlyList<IOutputCachePolicy> GetBasePolicies();
ValueTask<IOutputCachePolicy?> GetPolicyAsync(string policyName);
}
Grazie @lqlive per questo contributo!
Certificati di sviluppo con attendibilità automatica in WSL
L'installazione del certificato di sviluppo considera automaticamente attendibili i certificati negli ambienti WSL (sottosistema Windows per Linux). Quando si esegue dotnet dev-certs https --trust in WSL, il certificato viene installato e considerato attendibile automaticamente nell'ambiente WSL e Windows, eliminando la configurazione dell'attendibilità manuale.
# Automatically trusts certificates in both WSL and Windows
dotnet dev-certs https --trust
Questo miglioramento semplifica l'esperienza di sviluppo quando si usa WSL, rimuovendo un punto di attrito comune per gli sviluppatori che lavorano in ambienti Linux in Windows.
Grazie @StickFun per questo contributo!
Tracciamento OpenTelemetry nativo per ASP.NET Core
ASP.NET Core ora aggiunge in modo nativo gli attributi della convenzione semantica OpenTelemetry all'attività del server HTTP, allineati alla specifica OpenTelemetry HTTP span specification. Tutti gli attributi obbligatori sono inclusi per impostazione predefinita, corrispondenti ai metadati disponibili in precedenza solo tramite la OpenTelemetry.Instrumentation.AspNetCore libreria.
Per raccogliere i dati di traccia predefiniti, sottoscrivere l'origine attività Microsoft.AspNetCore nella configurazione di OpenTelemetry:
builder.Services.AddOpenTelemetry()
.WithTracing(tracing => tracing
.AddSource("Microsoft.AspNetCore")
.AddConsoleExporter());
Non è necessaria alcuna libreria di strumentazione aggiuntiva, ad esempio OpenTelemetry.Instrumentation.AspNetCore. Il framework ora popola direttamente gli attributi della convenzione semantica per l'attività di richiesta, ad esempio http.request.method, url.path, http.response.status_codee server.address.
Se non si desidera aggiungere attributi OpenTelemetry all'attività, è possibile disattivarlo impostando l'interruttore AppContext su Microsoft.AspNetCore.Hosting.SuppressActivityOpenTelemetryDatatrue.
Miglioramenti delle prestazioni
KestrelIl parser di richiesta HTTP/1.1 ora utilizza un percorso di codice che non genera eccezioni per la gestione delle richieste malformate. Anziché generare BadHttpRequestException in ogni errore di analisi, il parser restituisce una struttura di risultato che indica stati di successo, incompleti o di errore. Negli scenari con molte richieste malformate, come l'analisi delle porte, il traffico dannoso o i client configurati in modo errato, elimina il costoso sovraccarico di gestione delle eccezioni e migliora il throughput fino al 20-40%. Non c'è alcun impatto sull'elaborazione valida delle richieste.
Il middleware di registrazione HTTP ora utilizza pool per le ResponseBufferingStream istanze, riducendo le allocazioni per ogni richiesta quando il corpo di risposta o gli intercettori sono abilitati.
Compressione della risposta Zstandard e decompressione delle richieste
ASP.NET Core supporta ora Zstandard (zstd) sia per la compressione della risposta che per la decompressione delle richieste. In questo modo, il supporto zstd viene aggiunto al middleware di compressione e decompressione della risposta esistente e abilita zstd per impostazione predefinita.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddResponseCompression();
builder.Services.AddRequestDecompression();
builder.Services.Configure<ZstandardCompressionProviderOptions>(options =>
{
options.CompressionOptions = new ZstandardCompressionOptions
{
Quality = 6 // 1-22, higher = better compression, slower
};
});
Grazie @manandre per questo contributo!
HTTP/3 avvia l'elaborazione delle richieste in precedenza
Kestrel ora avvia l'elaborazione delle richieste HTTP/3 senza attendere prima il flusso di controllo e il frame SETTINGS, riducendo così la latenza della prima richiesta sulle nuove connessioni.
Modello server MCP fornito con .NET SDK
Il protocollo MCP (Model Context Protocol) è uno standard aperto che le applicazioni e gli agenti di intelligenza artificiale, ad esempio quelli in Visual Studio, Visual Studio Code e GitHub Copilot, usano per individuare e chiamare strumenti, dati e servizi esterni tramite un'interfaccia coerente. Un server MCP espone le proprie funzionalità, ad esempio strumenti personalizzati o accesso a un'origine dati, in modo che un host di intelligenza artificiale possa richiamarlo per conto dell'utente.
Usare il mcpserver modello quando si vuole creare un server MCP C# che integra il codice o i servizi con strumenti basati sull'intelligenza artificiale. Il progetto generato usa l'SDK C# ufficiale per MCP e include uno strumento di esempio funzionante, quindi è disponibile un punto di partenza eseguibile da estendere con i propri strumenti.
Il modello di progetto mcpserver, precedentemente disponibile solo installando Microsoft.McpServer.ProjectTemplates, ora viene fornito come modello in bundle nell'SDK di .NET:
dotnet new mcpserver -o MyMcpServer
Lo spostamento del modello in ASP.NET Core lo rende individuabile da dotnet new list senza un passaggio di installazione separato e ne allinea la manutenzione al resto dello stack Web.
Per altre informazioni, vedere Creare un server MCP (Model Context Protocol) in C#.
Osservabilità dell'handshake TLS in Kestrel
Due modifiche correlate semplificano la diagnosi e la personalizzazione delle connessioni TLS in Kestrel.
ITlsHandshakeFeature ora espone una proprietà Exception contenente l'eccezione generata durante un handshake TLS fallito, così che il middleware e il logging possano registrare il motivo del fallimento di una connessione invece di vedere un semplice IOException a un livello superiore dello stack. La funzionalità continua a funzionare anche se l'handshake non riesce: Kestrel acquisisce uno snapshot dei campi pertinenti dall'oggetto SslStream sottostante prima che venga eliminato.
L'opzione TlsClientHelloBytesCallback su HttpsConnectionAdapterOptions è stata rielaborata come middleware di connessione. La firma della callback precedente è ormai obsoleta; configura invece l'ispezione di ClientHello tramite la nuova estensione ListenOptions.UseTlsClientHelloListener. L'esempio seguente usa entrambe le funzionalità, ovvero il middleware di connessione legge ITlsHandshakeFeature.Exception dopo l'handshake e UseTlsClientHelloListener controlla ClientHello prima di TLS:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(options =>
{
options.ListenAnyIP(5001, listenOptions =>
{
listenOptions.Use(next => async context =>
{
await next(context);
var tlsHandshakeFeature = context.Features.Get<ITlsHandshakeFeature>();
if (tlsHandshakeFeature?.Exception is { } ex)
{
Console.WriteLine($"[TLS Handshake Failed] ConnectionId={context.ConnectionId}, Exception={ex.GetType().Name}: {ex.Message}");
}
});
// UseTlsClientHelloListener must be called before UseHttps()
listenOptions.UseTlsClientHelloListener((connection, clientHelloBytes) =>
{
Console.WriteLine($"TLS Client Hello received on {connection.ConnectionId}, {clientHelloBytes.Length} bytes");
});
listenOptions.UseHttps();
});
});
La compressione della risposta genera sempre Vary: Accept-Encoding
Il middleware di compressione della risposta aggiunge Vary: Accept-Encoding ora a ogni risposta quando è abilitata la compressione, anche quando la risposta stessa non è compressa. Ciò impedisce alle cache condivise e alle reti CDN di gestire un payload compresso in un client che non ha richiesto uno (o viceversa).
Grazie @pedrobsaila per questo contributo!
Runtime-async attivato per le librerie del framework condiviso
Le librerie basate esclusivamente sul framework condiviso di ASP.NET Core vengono ora compilate con la funzionalità runtime-async su net11.0+. Runtime-async consente al runtime, anziché al compilatore C#, di generare la macchina a stati per async/await, il che può ridurre le allocazioni per ogni await e migliorare la diagnostica. Si tratta di una modifica interna alla generazione del codice senza alcun impatto sulle API pubbliche — le app destinate a net11.0 ne beneficiano automaticamente quando effettuano chiamate alle librerie ASP.NET Core interessate.
Le librerie distribuite sia come componenti del framework condiviso sia come pacchetti NuGet autonomi sono escluse, perché runtime-async non è compatibile con WebAssembly e altrimenti causerebbe malfunzionamenti per i consumer Wasm di tali pacchetti.
Poiché runtime-async modifica la modalità di generazione di async/await per una parte estesa dello stack di ASP.NET Core, provare le app in base a questa anteprima e file un problema se si verifica un comportamento imprevisto, in particolare per quanto riguarda gli stack di eccezioni, ExecutionContext/AsyncLocal flow, o qualsiasi elemento simile a una regressione da .NET 10.
Il middleware di limitazione della velocità restituisce header Retry-After corretti
Ora FixedWindowRateLimiter segnala un RetryAfter valore di metadati che riflette in modo accurato il limite della finestra successiva. Le app che propagano questi metadati all'intestazione della Retry-After risposta nel OnRejected callback ora producono automaticamente intervalli di ripetizione corretti, senza che siano necessarie modifiche al codice.
Ulteriori correzioni in System.Threading.RateLimiting risolvono un problema per cui TokenBucketRateLimiter non gestiva correttamente i reintegri parziali dei token durante l'acquisizione di zero permit e migliorano inoltre il limitatore di velocità concatenato restituito da CreateChained in modo che inoltri correttamente la durata di inattività e il comportamento di reintegro dei suoi limitatori interni.
Per una panoramica del middleware di limitazione della frequenza, vedere Rate limit middleware in ASP.NET Core.
Grazie @asbjornvad e @apoorvdarshan per questi contributi!
Kestrel applica i timeout dell'intestazione trailer
Kestrel ora si applica RequestHeadersTimeout agli header trailer HTTP/2 e HTTP/3 frammentati che non completano l'invio del blocco di header. Lo stesso timeout che protegge le intestazioni iniziali della richiesta ora impedisce anche alle connessioni di rimanere aperte indefinitamente mentre Kestrel è in attesa del completamento dei frame trailer HEADERS.
builder.WebHost.ConfigureKestrel(options =>
{
options.Limits.RequestHeadersTimeout = TimeSpan.FromSeconds(10);
});
Accesso al token di associazione del canale TLS da ITlsConnectionFeature
Le applicazioni che usano TLS possono leggere il token di associazione del canale della connessione per difendersi dagli attacchi di inoltro:
using System.Security.Authentication.ExtendedProtection;
app.Use(async (context, next) =>
{
var tls = context.Features.Get<ITlsConnectionFeature>();
if (tls is not null && tls.TryGetChannelBindingBytes(
ChannelBindingKind.Endpoint,
out ReadOnlyMemory<byte> cbt))
{
// Compare cbt against the token the client presented during authentication.
}
await next(context);
});
Kestrel restituisce l'associazione da SslStream.TransportContext.GetChannelBinding. IIS e HTTP.sys lo restituiscono dalla richiesta. In HTTP.sys, HttpSysOptions.HttpAuthenticationHardeningLevel controlla Extended Protection e l'esposizione del token di associazione del canale:
-
Legacydisabilita la convalida dell'associazione di canale e non espone il token. -
Medium, l'impostazione predefinita espone il token e lo convalida quando viene fornito, ma tollera la sua assenza. -
Strictrichiede il token per le richieste autenticate e rifiuta le richieste senza una richiesta. Inoltre, impedisce l'avvio se il sistema operativo non riesce ad applicare la configurazione, mentreLegacyeMediumregistrano l'errore di configurazione e continuano.
Modifiche radicali
Usare gli articoli in Modifiche principali in .NET per trovare modifiche irreversibili che potrebbero essere applicate durante l'aggiornamento di un'app a una versione più recente di .NET.