Novità di ASP.NET Core 9.0
Questo articolo illustra le modifiche più significative in ASP.NET Core 9.0 con collegamenti alla documentazione pertinente.
Questo articolo è stato aggiornato per .NET 9 Preview 4.
Blazor
In questa sezione vengono descritte le nuove funzionalità per Blazor.
Aggiungere pagine di rendering statico lato server (SSR) a un'app Web interattiva Blazor a livello globale
Con il rilascio di .NET 9, è ora più semplice aggiungere pagine SSR statiche alle app che adottano interattività globale.
Questo approccio è utile solo quando l'app ha pagine specifiche che non possono funzionare con il rendering interattivo server o WebAssembly. Ad esempio, adottare questo approccio per le pagine che dipendono dalla lettura/scrittura di HTTP cookiee possono funzionare solo in un ciclo di richiesta/risposta anziché in un rendering interattivo. Per le pagine che funzionano con il rendering interattivo, non è consigliabile forzarle a usare il rendering statico di SSR, perché è meno efficiente e meno reattivo per l'utente finale.
Contrassegnare qualsiasi Razor pagina del componente con il nuovo [ExcludeFromInteractiveRouting]
attributo assegnato con la @attribute
Razor direttiva :
@attribute [ExcludeFromInteractiveRouting]
L'applicazione dell'attributo fa sì che la navigazione alla pagina esesce dal routing interattivo. Lo spostamento in ingresso è costretto a eseguire un ricaricamento a pagina intera, risolvendo invece la pagina tramite routing interattivo. Il ricaricamento a pagina intera forza il componente radice di primo livello, in genere il App
componente (App.razor
), a eseguire il rerender dal server, consentendo all'app di passare a una diversa modalità di rendering di primo livello.
Il HttpContext.AcceptsInteractiveRouting
metodo di estensione consente al componente di rilevare se [ExcludeFromInteractiveRouting]
viene applicato alla pagina corrente.
App
Nel componente usare il modello nell'esempio seguente:
- Pagine che non sono annotate per
[ExcludeFromInteractiveRouting]
impostazione predefinita allaInteractiveServer
modalità di rendering con interattività globale. È possibile sostituireInteractiveServer
conInteractiveWebAssembly
oInteractiveAuto
per specificare una modalità di rendering globale predefinita diversa. - Pagine annotate con
[ExcludeFromInteractiveRouting]
l'adozione di SSR statico (PageRenderMode
è assegnatonull
).
<!DOCTYPE html>
<html>
<head>
...
<HeadOutlet @rendermode="@PageRenderMode" />
</head>
<body>
<Routes @rendermode="@PageRenderMode" />
...
</body>
</html>
@code {
[CascadingParameter]
private HttpContext HttpContext { get; set; } = default!;
private IComponentRenderMode? PageRenderMode
=> HttpContext.AcceptsInteractiveRouting() ? InteractiveServer : null;
}
Un'alternativa all'uso del metodo di estensione consiste nel HttpContext.AcceptsInteractiveRouting
leggere manualmente i metadati dell'endpoint usando HttpContext.GetEndpoint()?.Metadata
.
Questa funzionalità è descritta nella documentazione di riferimento nelle modalità di rendering di ASP.NET CoreBlazor.
Inserimento del costruttore
Razor i componenti supportano l'inserimento del costruttore.
Nell'esempio seguente la classe parziale (code-behind) inserisce il NavigationManager
servizio usando un costruttore primario:
public partial class ConstructorInjection(NavigationManager navigation)
{
protected NavigationManager Navigation { get; } = navigation;
}
Per altre informazioni, vedere ASP.NET Core Blazor dependency injection.
Compressione Websocket per componenti Interactive Server
Per impostazione predefinita, i componenti Interactive Server abilitano la compressione per le connessioni WebSocket e impostano una frame-ancestors
direttiva CSP (Content Security Policy) impostata su 'self'
, che consente solo l'incorporamento dell'app in un'origine <iframe>
da cui viene servita l'app quando è abilitata la compressione o quando viene fornita una configurazione per il contesto WebSocket.
La compressione può essere disabilitata impostando ConfigureWebSocketOptions
su null
, che riduce la vulnerabilità dell'app per l'attacco , ma può comportare una riduzione delle prestazioni:
.AddInteractiveServerRenderMode(o => o.ConfigureWebSocketOptions = null)
Configurare un provider di servizi di 'none'
configurazione più frame-ancestors
rigoroso con il valore (virgolette singole necessarie), che consente la compressione WebSocket, ma impedisce ai browser di incorporare l'app in qualsiasi <iframe>
:
.AddInteractiveServerRenderMode(o => o.ContentSecurityFrameAncestorsPolicy = "'none'")
Per ulteriori informazioni, vedi le seguenti risorse:
- Linee guida per ASP.NET Core BlazorSignalR
- Linee guida per la mitigazione delle minacce per ASP.NET rendering lato server interattivo Core Blazor
Gestire gli eventi di composizione della tastiera in Blazor
La nuova KeyboardEventArgs.IsComposing
proprietà indica se l'evento della tastiera fa parte di una sessione di composizione. Tenere traccia dello stato di composizione degli eventi della tastiera è fondamentale per la gestione dei metodi di input dei caratteri internazionali.
Aggiunta del parametro OverscanCount
a QuickGrid
Il QuickGrid
componente espone ora una OverscanCount
proprietà che specifica il numero di righe aggiuntive di cui viene eseguito il rendering prima e dopo l'area visibile quando la virtualizzazione è abilitata.
Il valore predefinito OverscanCount
è 3. L'esempio seguente aumenta a OverscanCount
4:
<QuickGrid ItemsProvider="itemsProvider" Virtualize="true" OverscanCount="4">
...
</QuickGrid>
SignalR
In questa sezione vengono descritte le nuove funzionalità per SignalR.
Supporto dei tipi polimorfici in SignalR Hub
I metodi hub ora possono accettare una classe base anziché la classe derivata per abilitare scenari polimorfici. Il tipo di base deve essere annotato per consentire il polimorfismo.
public class MyHub : Hub
{
public void Method(JsonPerson person)
{
if (person is JsonPersonExtended)
{
}
else if (person is JsonPersonExtended2)
{
}
else
{
}
}
}
[JsonPolymorphic]
[JsonDerivedType(typeof(JsonPersonExtended), nameof(JsonPersonExtended))]
[JsonDerivedType(typeof(JsonPersonExtended2), nameof(JsonPersonExtended2))]
private class JsonPerson
{
public string Name { get; set; }
public Person Child { get; set; }
public Person Parent { get; set; }
}
private class JsonPersonExtended : JsonPerson
{
public int Age { get; set; }
}
private class JsonPersonExtended2 : JsonPerson
{
public string Location { get; set; }
}
API minime
Questa sezione descrive le nuove funzionalità per le API minime.
Aggiunta di InternalServerError
e InternalServerError<TValue>
a TypedResults
La TypedResults classe è un veicolo utile per restituire risposte basate su codice di stato HTTP fortemente tipizzato da un'API minima. TypedResults
include ora i metodi e i tipi factory per restituire le risposte "500 Internal Server Error" dagli endpoint. Ecco un esempio che restituisce una risposta 500:
var app = WebApplication.Create();
app.MapGet("/", () => TypedResults.InternalServerError("Something went wrong!"));
app.Run();
OpenAPI
Supporto predefinito per la generazione di documenti OpenAPI
La specifica OpenAPI è uno standard per descrivere le API HTTP. Lo standard consente agli sviluppatori di definire la forma delle API che possono essere collegate a generatori client, generatori di server, strumenti di test, documentazione e altro ancora. In .NET 9 Preview ASP.NET Core offre il supporto predefinito per la generazione di documenti OpenAPI che rappresentano API minime o basate su controller tramite il pacchetto Microsoft.AspNetCore.OpenApi .
Le chiamate di codice evidenziate seguenti:
AddOpenApi
per registrare le dipendenze necessarie nel contenitore di inserimento delle dipendenze dell'app.MapOpenApi
per registrare gli endpoint OpenAPI necessari nelle route dell'app.
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi();
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/hello/{name}", (string name) => $"Hello {name}"!);
app.Run();
Installare il Microsoft.AspNetCore.OpenApi
pacchetto nel progetto usando il comando seguente:
dotnet add package Microsoft.AspNetCore.OpenApi --prerelease
Eseguire l'app e passare a per openapi/v1.json
visualizzare il documento OpenAPI generato:
I documenti OpenAPI possono anche essere generati in fase di compilazione aggiungendo il Microsoft.Extensions.ApiDescription.Server
pacchetto:
dotnet add package Microsoft.Extensions.ApiDescription.Server --prerelease
Nel file di progetto dell'app aggiungere quanto segue:
<PropertyGroup>
<OpenApiDocumentsDirectory>$(MSBuildProjectDirectory)</OpenApiDocumentsDirectory>
<OpenApiGenerateDocuments>true</OpenApiGenerateDocuments>
</PropertyGroup>
Eseguire dotnet build
ed esaminare il file ON generato JSnella directory del progetto.
ASP.NET generazione di documenti OpenAPI predefinita di Core offre supporto per varie personalizzazioni e opzioni. Fornisce trasformatori di documenti e operazioni e ha la possibilità di gestire più documenti OpenAPI per la stessa applicazione.
Per altre informazioni sulle nuove funzionalità del documento OpenAPI di ASP.NET Core, vedere la nuova documentazione di Microsoft.AspNetCore.OpenApi.
Autenticazione e autorizzazione
In questa sezione vengono descritte le nuove funzionalità per l'autenticazione e l'autorizzazione.
Personalizzazione dei parametri OIDC e OAuth
I gestori di autenticazione OAuth e OIDC ora hanno un'opzione AdditionalAuthorizationParameters
per semplificare la personalizzazione dei parametri dei messaggi di autorizzazione che vengono in genere inclusi come parte della stringa di query di reindirizzamento. In .NET 8 e versioni precedenti, è necessario un callback personalizzato OnRedirectToIdentityProvider o un metodo sottoposto BuildChallengeUrl a override in un gestore personalizzato. Ecco un esempio di codice .NET 8:
builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
options.Events.OnRedirectToIdentityProvider = context =>
{
context.ProtocolMessage.SetParameter("prompt", "login");
context.ProtocolMessage.SetParameter("audience", "https://api.example.com");
return Task.CompletedTask;
};
});
L'esempio precedente può ora essere semplificato con il codice seguente:
builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
options.AdditionalAuthorizationParameters.Add("prompt", "login");
options.AdditionalAuthorizationParameters.Add("audience", "https://api.example.com");
});
Configurare HTTP.sys flag di autenticazione estesa
È ora possibile configurare i HTTP_AUTH_EX_FLAG_ENABLE_KERBEROS_CREDENTIAL_CACHING
flag e HTTP_AUTH_EX_FLAG_CAPTURE_CREDENTIAL
HTTP.sys usando le nuove EnableKerberosCredentialCaching
proprietà e CaptureCredentials
nel HTTP.sys per ottimizzare la modalità di gestione delle autenticazione di WindowsAuthenticationManager. Ad esempio:
webBuilder.UseHttpSys(options =>
{
options.Authentication.Schemes = AuthenticationSchemes.Negotiate;
options.Authentication.EnableKerberosCredentialCaching = true;
options.Authentication.CaptureCredentials = true;
});
Varie
Le sezioni seguenti descrivono varie nuove funzionalità.
Nuova HybridCache
libreria
L'API HybridCache
consente di colmare alcune lacune nelle API e IMemoryCache esistentiIDistributedCache. Aggiunge anche nuove funzionalità, ad esempio:
- Protezione "stampede" per impedire il recupero parallelo dello stesso lavoro.
- Serializzazione configurabile.
HybridCache
è progettato per essere una sostituzione dell'eliminazione per l'uso e IMemoryCache
esistente IDistributedCache
e offre una semplice API per l'aggiunta di nuovo codice di memorizzazione nella cache. Fornisce un'API unificata per la memorizzazione nella cache in-process e out-of-process.
Per vedere come l'API HybridCache
è semplificata, confrontarla con il codice che usa IDistributedCache
. Di seguito è riportato un esempio dell'aspetto dell'uso IDistributedCache
:
public class SomeService(IDistributedCache cache)
{
public async Task<SomeInformation> GetSomeInformationAsync
(string name, int id, CancellationToken token = default)
{
var key = $"someinfo:{name}:{id}"; // Unique key for this combination.
var bytes = await cache.GetAsync(key, token); // Try to get from cache.
SomeInformation info;
if (bytes is null)
{
// Cache miss; get the data from the real source.
info = await SomeExpensiveOperationAsync(name, id, token);
// Serialize and cache it.
bytes = SomeSerializer.Serialize(info);
await cache.SetAsync(key, bytes, token);
}
else
{
// Cache hit; deserialize it.
info = SomeSerializer.Deserialize<SomeInformation>(bytes);
}
return info;
}
// This is the work we're trying to cache.
private async Task<SomeInformation> SomeExpensiveOperationAsync(string name, int id,
CancellationToken token = default)
{ /* ... */ }
}
Questo è un sacco di lavoro per ottenere il giusto ogni volta, inclusi elementi come la serializzazione. Inoltre, nello scenario di mancata memorizzazione nella cache, è possibile terminare con più thread simultanei, ottenere tutti un mancato riscontro nella cache, recuperare tutti i dati sottostanti, serializzarli e tutti gli invii tali dati alla cache.
Per semplificare e migliorare questo codice con HybridCache
, è prima necessario aggiungere la nuova libreria Microsoft.Extensions.Caching.Hybrid
:
<PackageReference Include="Microsoft.Extensions.Caching.Hybrid" Version="9.0.0" />
Registrare il HybridCache
servizio, come si vuole registrare un'implementazione IDistributedCache
:
services.AddHybridCache(); // Not shown: optional configuration API.
È ora possibile eseguire l'offload della maggior parte dei problemi di memorizzazione nella cache in HybridCache
:
public class SomeService(HybridCache cache)
{
public async Task<SomeInformation> GetSomeInformationAsync
(string name, int id, CancellationToken token = default)
{
return await cache.GetOrCreateAsync(
$"someinfo:{name}:{id}", // Unique key for this combination.
async cancel => await SomeExpensiveOperationAsync(name, id, cancel),
token: token
);
}
}
Viene fornito un'implementazione concreta della HybridCache
classe astratta tramite l'inserimento delle dipendenze, ma è previsto che gli sviluppatori possano fornire implementazioni personalizzate dell'API. L'implementazione HybridCache
gestisce tutti gli elementi correlati alla memorizzazione nella cache, inclusa la gestione simultanea delle operazioni. Il cancel
token qui rappresenta l'annullamento combinato di tutti i chiamanti simultanei, non solo l'annullamento del chiamante che è possibile vedere ( ovvero token
).
Gli scenari con velocità effettiva elevata possono essere ulteriormente ottimizzati usando il TState
modello, per evitare un sovraccarico dovuto alle variabili acquisite e ai callback per istanza:
public class SomeService(HybridCache cache)
{
public async Task<SomeInformation> GetSomeInformationAsync(string name, int id, CancellationToken token = default)
{
return await cache.GetOrCreateAsync(
$"someinfo:{name}:{id}", // unique key for this combination
(name, id), // all of the state we need for the final call, if needed
static async (state, token) =>
await SomeExpensiveOperationAsync(state.name, state.id, token),
token: token
);
}
}
HybridCache
usa l'implementazione configurata IDistributedCache
, se presente, per la memorizzazione nella cache out-of-process secondaria, ad esempio usando Redis. Ma anche senza , IDistributedCache
il HybridCache
servizio fornirà comunque la protezione nella cache in-process e "stampede".
Nota sul riutilizzo degli oggetti
Nel codice esistente tipico che usa IDistributedCache
, ogni recupero di un oggetto dalla cache comporta la deserializzazione. Questo comportamento significa che ogni chiamante simultaneo ottiene un'istanza separata dell'oggetto, che non può interagire con altre istanze. Il risultato è thread safety, poiché non esiste alcun rischio di modifiche simultanee alla stessa istanza dell'oggetto.
Poiché un sacco di HybridCache
utilizzo verrà adattato dal codice esistente IDistributedCache
, HybridCache
mantiene questo comportamento per impostazione predefinita per evitare di introdurre bug di concorrenza. Tuttavia, un determinato caso d'uso è intrinsecamente thread-safe:
- Se i tipi memorizzati nella cache non sono modificabili.
- Se il codice non li modifica.
In questi casi, informare HybridCache
che è sicuro riutilizzare le istanze in base a:
- Contrassegnare il tipo come
sealed
. Lasealed
parola chiave in C# indica che la classe non può essere ereditata. - Applicazione dell'attributo
[ImmutableObject(true)]
. L'attributo Yhe[ImmutableObject(true)]
indica che lo stato dell'oggetto non può essere modificato dopo la creazione.
Riutilizzando istanze, HybridCache
è possibile ridurre il sovraccarico delle allocazioni di CPU e oggetti associate alla deserializzazione per chiamata. Ciò può comportare miglioramenti delle prestazioni negli scenari in cui gli oggetti memorizzati nella cache sono di grandi dimensioni o a cui si accede di frequente.
Altre HybridCache
funzionalità
Come IDistributedCache
, HybridCache
supporta la rimozione tramite chiave con un RemoveKeyAsync
metodo .
HybridCache
fornisce anche API facoltative per IDistributedCache
le implementazioni, per evitare byte[]
allocazioni. Questa funzionalità viene implementata dalle versioni di anteprima dei Microsoft.Extensions.Caching.StackExchangeRedis
pacchetti e Microsoft.Extensions.Caching.SqlServer
.
La serializzazione viene configurata come parte della registrazione del servizio, con supporto per serializzatori specifici del tipo e generalizzati tramite i WithSerializer
metodi e .WithSerializerFactory
concatenati dalla AddHybridCache
chiamata. Per impostazione predefinita, la libreria gestisce string
e byte[]
internamente e usa System.Text.Json
per tutto il resto, ma è possibile usare protobuf, xml o qualsiasi altro elemento.
HybridCache
supporta runtime .NET meno recenti, fino a .NET Framework 4.7.2 e .NET Standard 2.0.
Per altre informazioni su HybridCache
, vedere Libreria HybridCache in ASP.NET Core
Miglioramenti alla pagina delle eccezioni per gli sviluppatori
La pagina delle eccezioni dello sviluppatore ASP.NET Core viene visualizzata quando un'app genera un'eccezione non gestita durante lo sviluppo. La pagina delle eccezioni per sviluppatori fornisce informazioni dettagliate sull'eccezione e sulla richiesta.
Anteprima 3 aggiunta dei metadati dell'endpoint alla pagina delle eccezioni dello sviluppatore. ASP.NET Core usa i metadati dell'endpoint per controllare il comportamento dell'endpoint, ad esempio routing, memorizzazione nella cache delle risposte, limitazione della frequenza, generazione OpenAPI e altro ancora. L'immagine seguente mostra le nuove informazioni sui metadati nella Routing
sezione della pagina delle eccezioni per sviluppatori:
Durante il test della pagina delle eccezioni dello sviluppatore, sono stati identificati piccoli miglioramenti della qualità della vita. Sono stati spediti in Anteprima 4:
- Migliore disposizione del testo. I cookienomi delle stringhe di query e dei metodi lunghi non aggiungono più barre di scorrimento orizzontale del browser.
- Testo più grande che si trova nei disegni moderni.
- Dimensioni di tabella più coerenti.
L'immagine animata seguente mostra la nuova pagina delle eccezioni per sviluppatori:
Miglioramenti del debug del dizionario
La visualizzazione del debug di dizionari e altre raccolte chiave-valore ha un layout migliorato. La chiave viene visualizzata nella colonna chiave del debugger invece di essere concatenata con il valore . Le immagini seguenti mostrano la visualizzazione precedente e nuova di un dizionario nel debugger.
Prima:
Dopo:
ASP.NET Core include molte raccolte chiave-valore. Questa esperienza di debug migliorata si applica a:
- Intestazioni HTTP
- Stringhe di query
- Form
- Cookies
- Visualizzare i dati
- Dati route
- Funzionalità
Correzione di 503 durante il riciclo dell'app in IIS
Per impostazione predefinita, è ora presente un ritardo di 1 secondo tra quando IIS riceve una notifica di riciclo o arresto e quando ANCM indica al server gestito di avviare l'arresto. Il ritardo è configurabile tramite la ANCM_shutdownDelay
variabile di ambiente o impostando l'impostazione del shutdownDelay
gestore. Entrambi i valori sono in millisecondi. Il ritardo consiste principalmente nel ridurre la probabilità di una gara in cui:
- IIS non ha avviato l'accodamento delle richieste per passare alla nuova app.
- ANCM inizia a rifiutare nuove richieste che vengono inserite nell'app precedente.
I computer o i computer più lenti con un utilizzo più elevato della CPU possono voler regolare questo valore per ridurre la probabilità di 503.
Esempio di impostazione shutdownDelay
:
<aspNetCore processPath="dotnet" arguments="myapp.dll" stdoutLogEnabled="false" stdoutLogFile=".logsstdout">
<handlerSettings>
<!-- Milliseconds to delay shutdown by.
this doesn't mean incoming requests will be delayed by this amount,
but the old app instance will start shutting down after this timeout occurs -->
<handlerSetting name="shutdownDelay" value="5000" />
</handlerSettings>
</aspNetCore>
La correzione si trova nel modulo ANCM installato a livello globale proveniente dal bundle di hosting.
Commenti e suggerimenti
https://aka.ms/ContentUserFeedback.
Presto disponibile: Nel corso del 2024 verranno gradualmente disattivati i problemi di GitHub come meccanismo di feedback per il contenuto e ciò verrà sostituito con un nuovo sistema di feedback. Per altre informazioni, vedereInvia e visualizza il feedback per