Nouveautés d’ASP.NET Core 8.0

Cet article met en évidence les modifications les plus importantes dans ASP.NET Core 8.0 et fournit des liens vers la documentation appropriée.

Blazor

Interface utilisateur web de pile complète

Avec la sortie de .NET 8, Blazor s'agit d'un framework d'interface utilisateur Web complet permettant de développer des applications qui restituent du contenu au niveau du composant ou de la page avec :

  • Rendu du serveur statique (également appelé rendu statique côté serveur, SSR statique) pour générer du code HTML statique sur le serveur.
  • Rendu du serveur interactif (également appelé rendu interactif côté serveur, SSR interactif) pour générer des composants interactifs avec le prérendu sur le serveur.
  • Rendu WebAssembly interactif (également appelé rendu côté client, CSR, qui est toujours supposé être interactif) pour générer des composants interactifs sur le client avec le prérendu sur le serveur.
  • Rendu automatique interactif (automatique) pour utiliser initialement le runtime ASP.NET Core côté serveur pour le rendu et l’interactivité du contenu. Le runtime .NET WebAssembly sur le client est utilisé pour le rendu et l’interactivité qui suivent après le téléchargement du pack Blazor et l’activation du runtime WebAssembly. Le rendu automatique interactif offre généralement l’expérience de démarrage d’application la plus rapide.

Les modes de rendu interactifs pré-affichent également le contenu par défaut.

Pour plus d’informations, consultez les articles suivants :

Des exemples de la documentation Blazor ont été mis à jour pour une utilisation dans Web Apps Blazor. Les exemples Blazor Server restent dans le contenu avec version pour .NET 7 ou version antérieure.

Nouvel article sur les bibliothèques de classes avec rendu statique côté serveur (SSR statique)

Nous avons ajouté un nouvel article qui aborde la création d’une bibliothèque de composants dans des bibliothèques de classes (RCL) Razor avec le rendu statique côté serveur (SSR statique).

Pour obtenir plus d’informations, voir les bibliothèques de classe ASP.NET Core Razor (RCL) avec rendu statique côté serveur (SSR statique).

Nouvel article sur les problèmes de mise en cache HTTP

Nous avons ajouté un nouvel article qui aborde certains des problèmes courants de mise en cache HTTP qui peuvent se produire lors de la mise à niveau d’applications Blazor dans des versions principales et qui explique comment résoudre des problèmes de mise en cache HTTP.

Si vous souhaitez obtenir plus d’informations, consultez Éviter les problèmes de mise en cache HTTP lors de la mise à niveau d’applicationsBlazor ASP.NET Core.

Nouveau modèle d'application Web Blazor

Nous avons introduit un nouveau modèle de projet Blazor : le modèle d’application web Blazor. Le nouveau modèle fournit un point de départ unique pour utiliser des composants Blazor afin de créer n'importe quel style d'interface utilisateur Web. Le modèle associe les atouts des modèles existants Blazor Server et Blazor WebAssembly d’hébergement aux nouvelles fonctionnalités Blazor ajoutées dans .NET 8 : rendu côté serveur statique, rendu de diffusion en continu, navigation et gestion des formulaires améliorés, et possibilité d’ajouter l’interactivité en utilisant Blazor Server ou Blazor WebAssembly par composant.

Dans le cadre de l'unification des différents modèles d'hébergement Blazor en un seul modèle dans .NET 8, nous consolidons également le nombre de modèles de projet Blazor. Nous avons supprimé le modèle Blazor Server et l'option ASP.NET Core Hosted a été supprimée du modèle Blazor WebAssembly. Ces deux scénarios sont représentés par des options lors de l’utilisation du modèle Web App Blazor.

Remarque

Les applications existantes Blazor Server et Blazor WebAssembly restent prises en charge dans .NET 8. En option, ces applications peuvent être mises à jour pour utiliser les nouvelles fonctionnalités de l'interface utilisateur Blazor Web complète.

Pour plus d’informations sur le nouveau modèle Web App Blazor, consultez les articles suivants :

Nouveaux initialiseurs JS pour Blazor Web Apps

Pour Blazor Server, Blazor WebAssemblyet Blazor Hybrid les applications :

  • beforeStart est utilisé pour les tâches telles que la personnalisation du processus de chargement, le niveau de journalisation et d’autres options.
  • afterStarted est utilisé pour des tâches telles que l’inscription d’écouteurs d’événements Blazor et de types d’événements personnalisés.

Les initialiseurs hérités JS précédents ne sont pas appelés par défaut dans une application web Blazor. Pour Blazor Web Apps, un nouvel ensemble d’initialiseurs JS est utilisé : beforeWebStart, afterWebStarted, beforeServerStart, afterServerStarted, beforeWebAssemblyStart et afterWebAssemblyStarted.

Pour plus d’informations, consultez Démarrage ASP.NET Core Blazor.

Fractionnement de l’assistance en matière de prérendu et d’intégration

Pour les versions antérieures de .NET, nous avons abordé le prérendu et l’intégration dans un seul article. Pour simplifier et concentrer notre portée, nous avons fractionné les sujets dans les articles suivants qui ont été mis à jour pour .NET 8 :

Conserver l'état du composant dans une application Web Blazor

Vous pouvez conserver et lire l'état du composant dans une application Web Blazor à l'aide du service existant PersistentComponentState. Ceci est utile pour conserver l'état des composants pendant le prérendu.

Blazor Web Apps conservent automatiquement tout état enregistré au niveau de l’application créé pendant le prérendu, éliminant ainsi le besoin du Tag Helper d’état du composant persistant.

Gestion des formulaires et liaison de modèles

les composants Blazor peuvent désormais gérer les requêtes de formulaire soumises, y compris la liaison de modèle et la validation des données de la requête. Les composants peuvent implémenter des formulaires avec des gestionnaires de formulaires distincts en utilisant la balise HTML standard <form> ou en utilisant le composant existant EditForm.

La liaison du modèle de formulaire dans Blazor honore les attributs du contrat de données (par exemple, [DataMember] et [IgnoreDataMember]) pour personnaliser la façon dont les données du formulaire sont liées au modèle.

Une nouvelle prise en charge anti-contrefaçon est incluse dans .NET 8. Un nouveau composant AntiforgeryToken restitue un jeton anti-contrefaçon sous forme de champ caché et le nouvel attribut [RequireAntiforgeryToken] active la protection anti-contrefaçon. Si une vérification anti-contrefaçon échoue, une réponse 400 (Bad Request) est renvoyée sans traitement du formulaire. Les nouvelles fonctionnalités anti-contrefaçon sont activées par défaut pour les formulaires basés sur des formulaires HTML standard sur Editform et peuvent être appliquées manuellement à ceux-ci.

Pour plus d’informations, consultez Vue d’ensemble des formulaires Blazor ASP.NET Core.

Navigation améliorée et gestion des formulaires

Le rendu statique côté serveur (SSR statique) effectue généralement une actualisation complète de la page chaque fois que l’utilisateur accède à une nouvelle page ou soumet un formulaire. Dans .NET 8, Blazor peut améliorer la navigation dans les pages et la gestion des formulaires en interceptant la requête et en exécutant une requête de récupération à la place. Blazor gère ensuite le contenu de la réponse rendue en le corrigeant dans le DOM du navigateur. La navigation améliorée et la gestion des formulaires évitent le besoin d'une actualisation complète de la page et préservent davantage l'état de la page, de sorte que les pages se chargent plus rapidement et plus facilement. La navigation améliorée est activée par défaut lorsque le script Blazor (blazor.web.js) est chargé. La gestion améliorée des formulaires peut éventuellement être activée pour des formulaires spécifiques.

La nouvelle API de navigation améliorée vous permet d'actualiser la page actuelle en appelant NavigationManager.Refresh(bool forceLoad = false).

Pour obtenir plus d’informations, consultez les sections suivantes de l’article BlazorRoutage et navigation :

Nouvel article sur le rendu statique avec navigation améliorée pour l’interopérabilité JS

Certaines applications peuvent dépendre de l’interopérabilité JS pour effectuer des tâches d’initialisation spécifiques à chaque page. Lorsque vous utilisez la fonctionnalité de navigation améliorée de Blazor avec des pages rendues statiquement qui effectuent des tâches d’initialisation d’interopérabilité JS, il est possible que JS spécifique à la page ne soit pas réexécuté comme prévu chaque fois qu’une navigation de page améliorée se produit. Un nouvel article explique comment résoudre ce scénario dans Blazor Web Apps :

JavaScript ASP.NET CoreBlazor avec rendu côté serveur statique (SSR statique)

Rendu en streaming

Vous pouvez désormais diffuser des mises à jour de contenu sur le flux de réponse lorsque vous utilisez le rendu statique côté serveur (SSR statique) avec Blazor. Le rendu en streaming peut améliorer l'expérience utilisateur pour les pages qui effectuent des tâches asynchrones de longue durée afin d'obtenir un rendu complet en rendant le contenu dès qu'il est disponible.

Par exemple, pour afficher une page, vous devrez peut-être effectuer une requête de base de données durables ou un appel API. Normalement, les tâches asynchrones exécutées dans le cadre du rendu d'une page doivent être terminées avant que la réponse rendue ne soit envoyée, ce qui peut retarder le chargement de la page. Le rendu en streaming restitue initialement la page entière avec un contenu d'espace réservé pendant l'exécution des opérations asynchrones. Une fois les opérations asynchrones terminées, le contenu mis à jour est envoyé au client sur la même connexion de réponse et corrigé dans le DOM. L'avantage de cette approche est que la mise en page principale de l'application s'affiche le plus rapidement possible et que la page est mise à jour dès que le contenu est prêt.

Pour plus d’informations, consultez le rendu de composants Razor ASP.NET Core.

Injecter des services à clé dans les composants

Blazor prend désormais en charge l'injection de services à clé à l'aide de l'attribut [Inject]. Les clés permettent de définir la portée de l'enregistrement et de la consommation des services lors de l'utilisation de l'injection de dépendances. Utilisez la nouvelle propriété InjectAttribute.Key pour spécifier la clé que le service doit injecter :

[Inject(Key = "my-service")]
public IMyService MyService { get; set; }

La directive @injectRazor ne prend pas en charge les services à clé pour cette version, mais le travail est suivi par Update @inject pour prendre en charge les services à clé (dotnet/razor #9286) pour une future version .NET.

Pour plus d’informations, consultez Injection de dépendances Blazor ASP.NET Core.

Accès HttpContext en tant que paramètre en cascade

Vous pouvez désormais accéder au courant HttpContext en tant que paramètre en cascade à partir d'un composant serveur statique :

[CascadingParameter]
public HttpContext? HttpContext { get; set; }

Il est possible que l’accès à HttpContext à partir d’un composant de serveur statique soit utile pour inspecter et modifier des en-têtes ou d’autres propriétés.

Pour obtenir un exemple qui transmet l’état HttpContext, l’accès et les jetons d’actualisation aux composants, consultez les scénarios de sécurité supplémentaires du côté serveur ASP.NET Core Blazor.

Restituer des composants Razor en dehors de ASP.NET Core

Vous pouvez désormais restituer les composants Razor en dehors du contexte d'une requête HTTP. Vous pouvez restituer des composants Razor au format HTML directement dans une chaîne ou un flux indépendamment de l’environnement d’hébergement ASP.NET Core. Ceci est pratique pour les scénarios dans lesquels vous souhaitez générer des fragments HTML, par exemple pour générer un e-mail ou du contenu de site statique.

Pour plus d’informations, consultez Rendre les composants Razor en dehors de ASP.NET Core.

Prise en charge des sections

Les nouveaux composants SectionOutlet et SectionContent ajoutent la prise de Blazor en charge de la spécification de sorties pour le contenu qui peut être rempli ultérieurement. Les sections sont souvent utilisées pour définir des espaces réservés dans des mises en page qui sont ensuite remplies par des pages spécifiques. Les sections sont référencées soit par un nom unique, soit par un ID d'objet unique.

Pour plus d’informations, consultez les sections ASP.NET CoreBlazor.

Prise en charge des pages d'erreur

Les applications Web Blazor peuvent définir une page d'erreur personnalisée à utiliser avec le middleware de gestion des exceptions ASP.NET Core. Le modèle de projet Web App Blazor inclut une page d'erreur par défaut (Components/Pages/Error.razor) avec un contenu similaire à celui utilisé dans les applications MVC et Pages Razor. Lorsque la page d'erreur est rendue en réponse à une requête du Exception Handling Middleware, la page d'erreur s'affiche toujours en tant que composant de serveur statique, même si l'interactivité est par ailleurs activée.

Error.razor dans une source de référence 8.0

QuickGrid

Le composant QuickGrid Blazor n'est plus expérimental et fait désormais partie du framework de .NET 8 Blazor.

QuickGrid est un composant de grille haute performance permettant d'afficher des données sous forme de tableau. QuickGrid est conçu pour être un moyen simple et pratique d'afficher vos données, tout en offrant des fonctionnalités puissantes, telles que le tri, le filtrage, la pagination et la virtualisation.

Pour plus d’informations, consultez Composant QuickGrid ASP.NET Core Blazor.

Itinéraire vers les éléments nommés

Blazor prend désormais en charge l'utilisation du routage côté client pour accéder à un élément HTML spécifique sur une page à l'aide de fragments d'URL standard. Si vous spécifiez un identifiant pour un élément HTML à l'aide de l'attribut standard id, Blazor fait défiler correctement jusqu'à cet élément lorsque le fragment d'URL correspond à l'identifiant de l'élément.

Pour plus d’informations, consultez Routage et navigation ASP.NET Core Blazor.

Valeurs en cascade du niveau racine

Les valeurs en cascade au niveau racine peuvent être inscrites pour la hiérarchie complète des composants. Les valeurs et abonnements nommés en cascade pour les notifications de mise à jour sont pris en charge.

Pour plus d’informations, consultez Valeurs et paramètres en cascade de Blazor ASP.NET Core.

Virtualiser le contenu vide

Utilisez le nouveau paramètre EmptyContent sur le composant Virtualize pour fournir du contenu lorsque le composant est chargé et qu'il Items est vide ou ItemsProviderResult<T>.TotalItemCount est nul.

Pour plus d’informations, consultez Virtualisation des composants ASP.NET Core Razor.

Fermer les circuits lorsqu'il ne reste plus de composants de serveur interactifs

Les composants du serveur interactif gèrent les événements de l'interface utilisateur Web à l'aide d'une connexion en temps réel avec le navigateur appelée circuit. Un circuit et son état associé sont configurés lorsqu’un composant de serveur interactif racine est rendu. Le circuit est fermé lorsqu’il ne reste plus de composants serveur interactifs sur la page, ce qui libère des ressources serveur.

Surveiller l'activité du circuit SignalR

Vous pouvez désormais surveiller l'activité des circuits entrants dans les applications côté serveur à l'aide de la nouvelle méthode CreateInboundActivityHandler sur CircuitHandler. L’activité du circuit entrant est toute activité envoyée du navigateur au serveur, comme les événements d’interface utilisateur ou les appels d’interopérabilité JavaScript-to-.NET.

Pour plus d’informations, consultez Conseils relatifs à ASP.NET Core BlazorSignalR.

Performances d'exécution plus rapides avec le Jiterpreter

Jiterpreter est une nouvelle fonctionnalité d'exécution de .NET 8 qui permet une prise en charge partielle de la compilation juste-à-temps (JIT) lors de l'exécution sur WebAssembly afin d'obtenir des performances d'exécution améliorées.

Pour plus d’informations, consultez Héberger et déployer ASP.NET Core Blazor WebAssembly.

SIMD anticipé (AOT) et gestion des exceptions

La compilation anticipée (AOT) Blazor WebAssembly utilise désormais par défaut le SIMD à largeur fixe WebAssembly et la gestion des exceptions WebAssembly pour améliorer les performances d'exécution.

Pour plus d’informations, consultez les articles suivants :

Emballage Webcil adapté au Web

Webcil est un package Web d'assemblys .NET qui supprime le contenu spécifique à l'exécution native de Windows pour éviter les problèmes lors du déploiement dans des environnements bloquant le téléchargement ou l'utilisation de fichiers .dll. Webcil est activé par défaut pour les applications Blazor WebAssembly.

Pour plus d’informations, consultez Héberger et déployer ASP.NET Core Blazor WebAssembly.

Remarque

Avant la mise en production de .NET 8, des conseils dans la Disposition du déploiement pour les applications Blazor WebAssembly hébergées ASP.NET Core abordent les environnements qui empêchent les clients de télécharger et d’exécuter des DLL avec une approche de regroupement de plusieurs parties. Dans .NET 8 ou version ultérieure, Blazor utilise le format de fichier Webcil pour résoudre ce problème. Le regroupement de plusieurs parties en utilisant le package NuGet expérimental décrit dans l’article Disposition du déploiement WebAssembly n’est pas pris en charge pour les applications Blazor dans .NET 8 ou ultérieur. Pour obtenir plus d’informations, consultez Améliorer un package Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle pour définir un format de package personnalisé (dotnet/aspnetcore #36978). Si vous souhaitez continuer à utiliser un package groupé de plusieurs parties dans des applications .NET 8 ou ultérieures, vous pouvez utiliser les conseils de l’article pour créer votre propre package groupé NuGet de plusieurs parties, mais il ne sera pas pris en charge par Microsoft.

Améliorations du débogage de Blazor WebAssembly

Lors du débogage de .NET sur WebAssembly, le débogueur télécharge désormais les données de symboles à partir des emplacements de symboles configurés dans les préférences de Visual Studio. Cela améliore l’expérience de débogage pour les applications qui utilisent des packages NuGet.

Vous pouvez désormais déboguer des applications Blazor WebAssembly à l'aide de Firefox. Le débogage des applications Blazor WebAssembly nécessite la configuration du navigateur pour le débogage à distance, puis la connexion au navigateur à l'aide des outils de développement du navigateur via le proxy de débogage .NET WebAssembly. Le débogage de Firefox à partir de Visual Studio n'est pas pris en charge pour le moment.

Pour plus d’informations, consultez Déboguer des applications Blazor ASP.NET Core.

Compatibilité avec Azure Policy de sécurité du contenu (CSP)

Blazor WebAssembly ne nécessite plus d'activer la source du script unsafe-eval lors de la spécification Azure Policy de sécurité du contenu (CSP).

Pour plus d’informations, consultez Appliquer une stratégie de sécurité de contenu pour ASP.NET Core Blazor.

Gérer les exceptions interceptées en dehors du cycle de vie d’un composant Razor

Utilisez ComponentBase.DispatchExceptionAsync dans un composant Razor pour traiter les exceptions levées en dehors de la pile des appels de cycle de vie du composant. Cela permet au code du composant de traiter les exceptions comme si elles sont des exceptions de méthode de cycle de vie. Par la suite, les mécanismes de gestion des erreurs de Blazor, tels que les limites d'erreur, peuvent traiter les exceptions.

Pour plus d’informations, consultez Gérer les erreurs dans les applications ASP.NET Core Blazor.

Configurer le runtime .NET WebAssembly

Le runtime .NET WebAssembly peut désormais être configuré pour le démarrage Blazor.

Pour plus d’informations, consultez Démarrage ASP.NET Core Blazor.

Configuration des délais de connexion dans HubConnectionBuilder

Les solutions de contournement précédentes pour la configuration des délais d'expiration de connexion au hub peuvent être remplacées par une configuration formelle du délai d'expiration du générateur de connexion au hub SignalR.

Pour plus d’informations, consultez les rubriques suivantes :

Les modèles de projet sont abandonnés Open Iconic

Les modèles de projet Blazor ne dépendent plus d'Open Iconic pour les icônes.

Prise en charge des événements d'annulation et de fermeture de dialogue

Blazor prend désormais en charge les événements cancel et close sur l'élément HTML dialog.

Dans l’exemple suivant :

  • OnClose est appelé lorsque la boîte de dialogue my-dialog est fermée avec le bouton Fermer.
  • OnCancel est appelé lorsque la boîte de dialogue est annulée avec la touche Échap. Lorsqu’une boîte de dialogue HTML est fermée avec la touche Échap, les événements cancel et close sont déclenchés.
<div>
    <p>Output: @message</p>

    <button onclick="document.getElementById('my-dialog').showModal()">
        Show modal dialog
    </button>

    <dialog id="my-dialog" @onclose="OnClose" @oncancel="OnCancel">
        <p>Hi there!</p>

        <form method="dialog">
            <button>Close</button>
        </form>
    </dialog>
</div>

@code {
    private string? message;

    private void OnClose(EventArgs e) => message += "onclose, ";

    private void OnCancel(EventArgs e) => message += "oncancel, ";
}

BlazorIdentity Interface utilisateur

Blazor prend en charge la génération d'une Blazorinterface utilisateur complète Identity lorsque vous choisissez l'option d'authentification pour les comptes individuels. Vous pouvez soit sélectionner l’option Comptes individuels dans la boîte de dialogue Nouveau projet pour Blazor Web à partir de Visual Studio, soit transmettre l’option -au|--auth définie sur Individual à partir de la ligne de commande lorsque vous créez un projet.

Pour plus d’informations, consultez les ressources suivantes :

Sécuriser Blazor WebAssembly avec ASP.NET Core Identity

La documentation Blazor héberge un nouvel article et un exemple d’application pour couvrir la sécurisation d’une application Blazor WebAssembly autonome avec ASP.NET Core Identity.

Pour plus d’informations, consultez les ressources suivantes :

Blazor Server avec le routage Yarp

Le routage et le lien profond pour Blazor Server avec Yarp fonctionnent correctement dans .NET 8.

Pour plus d’informations, consultez Migrer de ASP.NET Core 7.0 vers 8.0.

Blazor Hybrid

Les articles suivants décrire les modifications pour Blazor Hybrid .NET 8 :

  • Résoudre des problèmes ASP.NET Core Blazor Hybrid: un nouvel article explique comment utiliser la journalisation BlazorWebView.
  • Générer une application .NET MAUIBlazor Hybrid : le nom du modèle de projet .NET MAUI Blazor a changé en .NET MAUI Blazor Hybrid.
  • ASP.NET Core Blazor Hybrid: BlazorWebView obtient une méthode TryDispatchAsync qui appelle un Action<ServiceProvider> spécifié de manière asynchrone et transmet les services délimités disponibles dans les composants Razor. Cela permet au code de l’interface utilisateur native d’accéder à des services délimités tels que NavigationManager.
  • Routage et navigation ASP.NET Core Blazor Hybrid : utilisez la propriété BlazorWebView.StartPath pour obtenir ou définir le chemin de navigation initial dans le contexte de navigation Blazor quand le composant Razor est chargé.

L’attribut [Parameter] n’est plus nécessaire quand il est fourni à partir de la chaîne de requête

L’attribut [Parameter] n’est plus nécessaire quand un paramètre est fourni depuis la chaîne de requête :

- [Parameter]
  [SupplyParameterFromQuery]

SignalR

Nouvelle approche pour définir le délai d’expiration du serveur et l’intervalle Keep-Alive

ServerTimeout (valeur par défaut : 30 secondes) et KeepAliveInterval (valeur par défaut : 15 secondes) peuvent être définies directement dans HubConnectionBuilder.

Approche précédente pour les clients JavaScript

L’exemple suivant montre l’affectation de valeurs au double des valeurs par défaut dans ASP.NET Core 7.0 ou versions antérieures :

var connection = new signalR.HubConnectionBuilder()
  .withUrl("/chatHub")
  .build();

connection.serverTimeoutInMilliseconds = 60000;
connection.keepAliveIntervalInMilliseconds = 30000;

Nouvelle approche pour les clients JavaScript

L’exemple suivant montre la nouvelle approche permettant d’attribuer des valeurs au double des valeurs par défaut dans ASP.NET Core 8.0 ou version ultérieure :

var connection = new signalR.HubConnectionBuilder()
  .withUrl("/chatHub")
  .withServerTimeoutInMilliseconds(60000)
  .withKeepAliveIntervalInMilliseconds(30000)
  .build();

Approche précédente pour le client JavaScript d’une application Blazor Server

L’exemple suivant montre l’affectation de valeurs au double des valeurs par défaut dans ASP.NET Core 7.0 ou versions antérieures :

Blazor.start({
  configureSignalR: function (builder) {
    let c = builder.build();
    c.serverTimeoutInMilliseconds = 60000;
    c.keepAliveIntervalInMilliseconds = 30000;
    builder.build = () => {
      return c;
    };
  }
});

Nouvelle approche pour l’application JavaScript Blazor côté client ou serveur

L’exemple suivant montre la nouvelle approche permettant d’attribuer des valeurs au double des valeurs par défaut dans ASP.NET Core 8.0 ou version ultérieure pour les applications web Blazor et Blazor Server.

Application webBlazor :

Blazor.start({
  circuit: {
    configureSignalR: function (builder) {
      builder.withServerTimeout(60000).withKeepAliveInterval(30000);
    }
  }
});

Blazor Server:

Blazor.start({
  configureSignalR: function (builder) {
    builder.withServerTimeout(60000).withKeepAliveInterval(30000);
  }
});

Approche précédente pour les clients .NET

L’exemple suivant montre l’affectation de valeurs au double des valeurs par défaut dans ASP.NET Core 7.0 ou versions antérieures :

var builder = new HubConnectionBuilder()
    .WithUrl(Navigation.ToAbsoluteUri("/chathub"))
    .Build();

builder.ServerTimeout = TimeSpan.FromSeconds(60);
builder.KeepAliveInterval = TimeSpan.FromSeconds(30);

builder.On<string, string>("ReceiveMessage", (user, message) => ...

await builder.StartAsync();

Nouvelle approche pour les clients .NET

L’exemple suivant montre la nouvelle approche permettant d’attribuer des valeurs au double des valeurs par défaut dans ASP.NET Core 8.0 ou version ultérieure :

var builder = new HubConnectionBuilder()
    .WithUrl(Navigation.ToAbsoluteUri("/chathub"))
    .WithServerTimeout(TimeSpan.FromSeconds(60))
    .WithKeepAliveInterval(TimeSpan.FromSeconds(30))
    .Build();

builder.On<string, string>("ReceiveMessage", (user, message) => ...

await builder.StartAsync();

Reconnexion avec état de SignalR

La reconnexion avec état de SignalR réduit le temps d’arrêt perçu des clients en cas de déconnexion temporaire de leur connexion réseau, par exemple lors du basculement de connexions réseau ou d’une brève perte temporaire d’accès.

La reconnexion avec état permet cela en :

  • Mettant temporairement en mémoire tampon des données sur le serveur et le client.
  • Accusant réception des messages reçus (procédure « ACK-ing ») par le serveur et le client.
  • Reconnaissant lorsqu’une connexion est renvoyée et en relisant des messages qui ont pu être envoyés pendant l’arrêt de la connexion.

La reconnexion avec état est disponible dans ASP.NET Core 8.0 et versions ultérieures.

Optez pour la reconnexion avec état au point de terminaison du hub de serveur et au client :

  • Mettez à jour la configuration du point de terminaison du hub de serveur pour activer l’option AllowStatefulReconnects :

    app.MapHub<MyHub>("/hubName", options =>
    {
        options.AllowStatefulReconnects = true;
    });
    

    Si vous le souhaitez, la taille maximale de la mémoire tampon en octets autorisée par le serveur peut être définie globalement ou pour un hub spécifique avec l’option StatefulReconnectBufferSize :

    Option StatefulReconnectBufferSize définie globalement :

    builder.AddSignalR(o => o.StatefulReconnectBufferSize = 1000);
    

    Option StatefulReconnectBufferSize définie pour un hub spécifique :

    builder.AddSignalR().AddHubOptions<MyHub>(o => o.StatefulReconnectBufferSize = 1000);
    

    L’option StatefulReconnectBufferSize est facultative avec une valeur par défaut de 100 000 octets.

  • Mettez à jour le code client JavaScript ou TypeScript pour activer l’option withStatefulReconnect :

    const builder = new signalR.HubConnectionBuilder()
      .withUrl("/hubname")
      .withStatefulReconnect({ bufferSize: 1000 });  // Optional, defaults to 100,000
    const connection = builder.build();
    

    L’option bufferSize est facultative avec une valeur par défaut de 100 000 octets.

  • Mettez à jour le code client .NET pour activer l’option WithStatefulReconnect :

      var builder = new HubConnectionBuilder()
          .WithUrl("<hub url>")
          .WithStatefulReconnect();
      builder.Services.Configure<HubConnectionOptions>(o => o.StatefulReconnectBufferSize = 1000);
      var hubConnection = builder.Build();
    

    L’option StatefulReconnectBufferSize est facultative avec une valeur par défaut de 100 000 octets.

Pour plus d’informations, consultez Configurer la reconnexion avec état.

API minimales

Cette section décrit les nouvelles fonctionnalités pour les API minimales. Consultez également la section sur l’AOT native pour plus d’informations sur les API minimales.

Remplacement de culture de l’utilisateur

À compter de ASP.NET Core 8.0, la propriété RequestLocalizationOptions.CultureInfoUseUserOverride permet à l’application de décider s’il faut ou non utiliser les paramètres Windows autres que ceux par défaut pour les propriétés CultureInfoDateTimeFormat et NumberFormat. Cela n’a aucun impact sur Linux. Cela correspond directement à UseUserOverride.

    app.UseRequestLocalization(options =>
    {
        options.CultureInfoUseUserOverride = false;
    });

Liaison aux formulaires

La liaison explicite aux valeurs de formulaire à l’aide de l’attribut [FromForm] est désormais prise en charge. Les paramètres liés à la requête avec [FromForm] incluent un jeton anti-falsification. Le jeton anti-falsification est validé lors du traitement de la requête.

La liaison inférée aux formulaires à l’aide des types IFormCollection, IFormFileet IFormFileCollection est également prise en charge. Les métadonnées OpenAPI sont inférées pour les paramètres de formulaire afin de prendre en charge l’intégration à l’interface utilisateur Swagger.

Pour plus d'informations, voir :

La liaison à partir de formulaires est désormais prise en charge pour :

  • Les collections, par exemple Liste et Dictionnaire
  • Les types complexes, par exemple, Todo ou Project

Pour plus d’informations, consultez Liaison à des collections et à des types complexes à partir de formulaires.

Anti-contrefaçon avec des API minimales

Cette version ajoute un intergiciel pour valider les jetons anti-falsification qui sont utilisés pour atténuer les attaques de falsification de requête intersites. Appelez AddAntiforgery pour inscrire des services d’antifalsification dans DI. WebApplicationBuilder ajoute automatiquement l’intergiciel lorsque les services d’anti-falsification ont été enregistrés dans le conteneur DI. Les jetons d’antifalsification sont utilisés pour atténuer les attaques de falsification de requête intersites.

var builder = WebApplication.CreateBuilder();

builder.Services.AddAntiforgery();

var app = builder.Build();

app.UseAntiforgery();

app.MapGet("/", () => "Hello World!");

app.Run();

L’intergiciel d’antifalsification :

Le jeton d’antifalsification n’est validé que si :

  • Le point de terminaison contient des métadonnées implémentant IAntiforgeryMetadataRequiresValidation=true.
  • La méthode HTTP associée au point de terminaison est une méthode HTTP pertinente. Les méthodes pertinentes sont toutes les méthodes HTTP, à l’exception de TRACE, OPTIONS, HEAD et GET.
  • La requête est associée à un point de terminaison valide.

Pour plus d’informations, consultez Anti-falsification avec des API minimales.

Nouvelle interface IResettable dans ObjectPool

Microsoft.Extensions.ObjectPool prend en charge le regroupement d’instances d’objet en mémoire. Les applications peuvent utiliser un pool d’objets si l’allocation ou l’initialisation des valeurs est coûteuse.

Dans cette version, nous avons simplifié l’utilisation du pool d’objets en ajoutant l’interface IResettable. Les types réutilisables doivent souvent être réinitialisés à un état par défaut entre les utilisations. Les types IResettable sont automatiquement réinitialisés lorsqu’ils sont retournés à un pool d’objets.

Pour plus d’informations, consultez l’exemple ObjectPool.

AOT natif

La prise en charge d’AOT (ahead-of-time) natif .NET a été ajoutée. Les applications publiées à l’aide d’AOT peuvent avoir de significativement meilleures performances : une taille d’application et une utilisation de mémoire plus faibles et un démarrage plus rapide. L’AOT natif est actuellement pris en charge par les applications gRPC, API minimale et de service worker. Pour plus d’informations, consultez Prise en charge d’ASP.NET Core pour AOT native et Tutoriel : publier une application ASP.NET Core à l’aide de l’AOT native. Pour plus d’informations sur les problèmes connus concernant la compatibilité ASP.NET Core et d’AOT native, consultez le problème GitHub dotnet/core #8288.

Bibliothèques et AOT native

La plupart des bibliothèques populaires utilisées dans les projets ASP.NET Core présentent actuellement des problèmes de compatibilité lorsqu’elles sont utilisées dans un projet ciblant l’AOA natif, par exemple :

  • Utilisation de la réflexion pour inspecter et découvrir des types.
  • Chargement conditionnel de bibliothèques au moment de l’exécution.
  • Génération de code à la volée pour implémenter des fonctionnalités.

Les bibliothèques qui utilisent ces fonctionnalités dynamiques doivent être mises à jour pour fonctionner avec l’AOA natif. Elles peuvent être mises à jour à l’aide d’outils tels que les générateurs de sources Roslyn.

Les auteurs de bibliothèques qui espèrent prendre en charge l’AOA natif sont invités à :

Nouveau modèle de projet

Le nouveau modèle de projet d’API Web ASP.NET Core (AOT native) (nom court webapiaot) crée un projet avec la publication AOT activée. Pour plus d’informations, consultez Le modèle d’API Web (AOT native).

Nouvelle méthode CreateSlimBuilder

La méthode CreateSlimBuilder() utilisée dans le modèle d’API Web (compilation AOT native) initialise le WebApplicationBuilder avec les fonctionnalités ASP.NET Core minimales nécessaires à l’exécution d’une application. La méthode CreateSlimBuilder comprend les fonctionnalités suivantes, qui sont généralement nécessaires à une expérience de développement efficace :

  • JSConfiguration du fichier ON pour appsettings.json et appsettings.{EnvironmentName}.json.
  • Configuration des secrets utilisateur.
  • Journalisation de la console.
  • Configuration de la journalisation.

Pour plus d'informations, voir La méthode CreateSlimBuilder.

Nouvelle méthode CreateEmptyBuilder

Il existe une autre nouvelle méthode de fabrique WebApplicationBuilder pour générer de petites applications qui contiennent uniquement les fonctionnalités nécessaires : WebApplication.CreateEmptyBuilder(WebApplicationOptions options). Ce WebApplicationBuilder est créé sans comportement intégré. L’application qu’elle génère contient uniquement les services et les middlewares (intergiciels) explicitement configurés.

Voici un exemple d’utilisation de cette API pour créer une petite application web :

var builder = WebApplication.CreateEmptyBuilder(new WebApplicationOptions());
builder.WebHost.UseKestrelCore();

var app = builder.Build();

app.Use(async (context, next) =>
{
    await context.Response.WriteAsync("Hello, World!");
    await next(context);
});

Console.WriteLine("Running...");
app.Run();

La publication de ce code avec AOT native à l’aide de .NET 8 Preview 7 sur une machine linux-x64 permet d’obtenir un exécutable natif autonome d’environ 8,5 Mo.

Taille d’application réduite avec prise en charge HTTPS configurable

Nous avons réduit davantage la taille du binaire de l’AOT native pour les applications n’ayant pas besoin de la prise en charge HTTPS ou HTTP/3. Il est courant de ne pas utiliser le protocole HTTPS ou HTTP/3 pour les applications qui s’exécutent derrière un proxy de terminaison TLS, par exemple, hébergées sur Azure. La nouvelle méthode WebApplication.CreateSlimBuilder omet cette fonctionnalité par défaut. Elle peut être ajoutée en appelant builder.WebHost.UseKestrelHttpsConfiguration() pour HTTPS ou builder.WebHost.UseQuic() pour HTTP/3. Pour plus d'informations, voir La méthode CreateSlimBuilder.

JSSérialisation ON des types IAsyncEnumerable<T> générés par le compilateur

De nouvelles fonctionnalités ont été ajoutées à System.Text.Json pour mieux prendre en charge l’AOT native. Ces nouvelles fonctionnalités ajoutent des fonctionnalités pour le mode de génération source de System.Text.Json, car la réflexion n’est pas prise en charge par l’AOT.

L’une des nouvelles fonctionnalités est la prise en charge de la JSsérialisation ON des implémentations IAsyncEnumerable<T> implémentées par le compilateur C#. Cette prise en charge ouvre leur utilisation dans des projets ASP.NET Core configurés pour publier l’AOT native.

Cette API est utile dans les scénarios où un gestionnaire de routage utilise yield return pour retourner de façon asynchrone une énumération. Par exemple, pour matérialiser des lignes à partir d’une requête de base de données. Pour plus d’informations, consultez la Prise en charge du type indicible dans l’annonce de la préversion 4 de .NET 8.

Pour plus d’informations sur les autres améliorations apportées à la génération de source System.Text.Json, consultez Améliorations apportées à la sérialisation dans .NET 8.

API de niveau supérieur annotées pour les avertissements de découpage

Les principaux points d’entrée vers les sous-systèmes qui ne fonctionnent pas de manière fiable avec l’AOT native sont désormais annotés. Lorsque ces méthodes sont appelées à partir d’une application avec l’AOT native activée, un avertissement est fourni. Par exemple, le code suivant génère un avertissement lors de l’appel de AddControllers, car cette API n’est pas sécurisée pour le découpage et n’est pas prise en charge par l’AOT native.

La fenêtre de Visual Studio affiche un message d’avertissement IL2026 sur la méthode AddControllers qui indique que MVC ne prend pas actuellement en charge Native AOA.

Générateur de délégués de requête

Pour rendre les API minimales compatibles avec l’AOT native, nous introduisons le générateur de délégués de requête (RDG). Le RDG est un générateur de source qui fait la même chose que le RequestDelegateFactory (RDF). Autrement dit, il transforme les différents appels MapGet(). MapPost() et les appels semblables dans des instances RequestDelegate associées aux itinéraires spécifiés. Mais plutôt que de le faire en mémoire dans une application au démarrage, le RDG le fait au moment de la compilation et génère du code C# directement dans le projet. Le RDG :

  • Supprime la génération à l’exécution de ce code.
  • Garantit que les types utilisés dans les API sont analysables de manière statique par la chaîne d’outils de l’AOT native.
  • Permet de garantir que le code requis n’est pas découpé.

Nous travaillons à nous assurer que le plus grand nombre possible de fonctionnalités de l’API minimale est pris en charge par le RDG et donc compatibles avec l’AOT native.

Le RDG est activé automatiquement dans un projet lors d’une publication avec l’AOT native activée. Le RDG peut être activé manuellement même si vous n’utilisez pas l’AOT native en définissant <EnableRequestDelegateGenerator>true</EnableRequestDelegateGenerator> dans le fichier projet. Cela peut être utile lors de l’évaluation initiale de la préparation d’un projet pour l’AOT native ou pour accélérer le démarrage d’une application.

Amélioration des performances à l’aide d’intercepteurs

Le Générateur de délégués de requête utilise la nouvelle fonctionnalité du compilateur d’intercepteurs C# 12 pour prendre en charge l’interception des appels à des méthodes de Mappage d’API minimales avec des variantes générées de manière statique au moment de l’exécution. L’utilisation d’intercepteurs permet d’améliorer les performances de démarrage des applications compilées avec PublishAot.

Journalisation et gestion des exceptions dans les API minimales générées au moment de la compilation

Les API minimales générées au moment de l’exécution prennent en charge la journalisation automatique (ou la levée d’exceptions dans les environnements de développement) lorsque la liaison de paramètre échoue. .NET 8 introduit la même prise en charge des API générées au moment de la compilation via le générateur de délégués de requête (RDG). Pour plus d’informations, consultez Journalisation et gestion des exceptions dans les API minimales générées au moment de la compilation.

AOT et System.Text.Json

Les API minimales sont optimisées pour la réception et le retour JSde charges utiles ON à l’aide de System.Text.Json, de sorte que les spécifications de compatibilité pour JSON et l’AOT native s’appliquent également. La compatibilité avec l’AOT natif nécessite l’utilisation du générateur de source System.Text.Json. Tous les types acceptés en tant que paramètres ou retournés par les délégués de requête dans les API minimales doivent être configurés sur un JsonSerializerContext inscrit via l’injection de dépendances d’ASP.NET Core, par exemple :

// Register the JSON serializer context with DI
builder.Services.ConfigureHttpJsonOptions(options =>
{
    options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
});

...

// Add types used in the minimal API app to source generated JSON serializer content
[JsonSerializable(typeof(Todo[]))]
internal partial class AppJsonSerializerContext : JsonSerializerContext
{

}

Pour plus d’informations sur l’API TypeInfoResolverChain, consultez les ressources suivantes :

Bibliothèques et AOT native

De nombreuses bibliothèques courantes, disponibles pour les projets ASP.NET Core, ont aujourd’hui des problèmes de compatibilité lorsqu’elles sont utilisées dans un projet ciblant l’AOT native. Les bibliothèques populaires s’appuient souvent sur les fonctionnalités dynamiques de la réflexion .NET pour inspecter et découvrir des types, charger conditionnellement des bibliothèques au moment de l’exécution et générer du code à la volée pour implémenter leurs fonctionnalités. Ces bibliothèques doivent être mises à jour pour fonctionner avec l’AOT native à l’aide d’outils tels que les générateurs de source Roslyn.

Les auteurs de bibliothèques souhaitant en savoir plus sur la préparation de leurs bibliothèques pour l’AOT native sont encouragés à commencer par préparer leur bibliothèque pour le découpage et en apprenant davantage sur les spécifications de compatibilité avec l’AOT native.

Serveurs Kestrel et HTTP.sys

Il existe plusieurs nouvelles fonctionnalités pour Kestrel et HTTP.sys.

Prise en charge des canaux nommés dans Kestrel

Les canaux nommés sont une technologie populaire pour la création d’une communication entre processus (IPC) entre les applications Windows. Vous pouvez maintenant créer un serveur IPC à l’aide de .NET, Kestrel et des canaux nommés.

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
    serverOptions.ListenNamedPipe("MyPipeName");
});

Pour plus d’informations sur cette fonctionnalité et sur l’utilisation de .NET et gRPC pour créer un serveur et un client IPC, consultez Communication entre processus avec gRPC.

Améliorations apportées aux performances du transport de canaux nommés

Nous avons amélioré les performances de connexion des canaux nommés. Le transport de canal nommé de Kestrel accepte désormais les connexions en parallèle et réutilise les instances NamedPipeServerStream.

Durée de création de 100 000 connexions :

  • Avant : 5,916 secondes
  • Après : 2,374 secondes

Prise en charge de HTTP/2 sur TLS (HTTPS) sur macOS dans Kestrel

.NET 8 ajoute la prise en charge d’ALPN (Application-Layer Protocol Negotiation) à macOS. ALPN est une fonctionnalité TLS utilisée pour négocier le protocole HTTP qu’une connexion utilise. Par exemple, ALPN permet aux navigateurs et à d’autres clients HTTP de demander une connexion HTTP/2. Cette fonctionnalité est particulièrement utile pour les applications gRPC, qui nécessitent HTTP/2. Pour plus d’informations, consultez Utiliser HTTP/2 avec le serveur web ASP.NET Core Kestrel.

Surveillance de fichiers de certificat dans Kestrel

Les certificats TLS configurés par chemin d’accès sont désormais surveillés pour les modifications lorsque reloadOnChange est passé à KestrelServerOptions.Configure(). Une modification apportée au fichier de certificat est traitée de la même façon qu’une modification apportée au chemin configuré (autrement dit, les points de terminaison sont rechargés).

Notez que les suppressions de fichiers ne sont pas suivies spécifiquement, car elles surviennent temporairement et bloquent le serveur si elles ne sont pas temporaires.

Avertissement lorsque les protocoles HTTP spécifiés ne sont pas utilisés

Si TLS est désactivé et HTTP/1.x est disponible, HTTP/2 et HTTP/3 sont désactivés, même s’ils ont été spécifiés. Cela peut entraîner des surprises désagréables, c’est pourquoi nous avons ajouté une sortie d’avertissement pour vous informer quand cela se produit.

Clés de configuration HTTP_PORTS et HTTPS_PORTS

Les applications et les conteneurs ne reçoivent souvent qu’un port à écouter, comme le port 80, sans contraintes supplémentaires telles que l’hôte ou le chemin d’accès. HTTP_PORTS et HTTPS_PORTS sont de nouvelles clés de configuration qui permettent de spécifier les ports d’écoute pour les serveurs Kestrel et HTTP.sys. Celles-ci peuvent être définies avec les préfixes de variables d’environnement DOTNET_ ou ASPNETCORE_, ou spécifiées directement via une autre entrée de configuration comme appsettings.json. Il s’agit d’une liste délimitée par des points-virgules de valeurs de port. Exemple :

ASPNETCORE_HTTP_PORTS=80;8080
ASPNETCORE_HTTPS_PORTS=443;8081

Il s’agit d’un raccourci pour les éléments suivants, qui spécifie le schéma (HTTP ou HTTPS) ainsi que l’hôte ou l’adresse IP :

ASPNETCORE_URLS=http://*:80/;http://*:8080/;https://*:443/;https://*:8081/

Pour plus d’informations, consultez Configurer des points de terminaison pour l’implémentation du serveur web ASP.NET Core Kestrel et HTTP.sys dans ASP.NET Core.

Nom d’hôte SNI dans ITlsHandshakeFeature

Le nom d’hôte SNI (Indication du nom du serveur) est désormais exposé dans la propriété HostName de l’interface ITlsHandshakeFeature.

SNI fait partie du processus d’établissement d'une liaison TLS. Il permet aux clients de spécifier le nom d’hôte auquel ils tentent de se connecter lorsque le serveur héberge plusieurs hôtes virtuels ou domaines. Pour présenter le certificat de sécurité correct pendant le processus d’établissement d'une liaison, le serveur doit connaître le nom d’hôte sélectionné pour chaque requête.

Normalement, le nom d’hôte est géré uniquement dans la pile TLS et est utilisé pour sélectionner le certificat correspondant. Mais en l’exposant, d’autres composants d’une application peuvent utiliser ces informations à des fins de diagnostics, de limitation du débit, de routage et de facturation.

L’exposition du nom d’hôte est utile pour les services à grande échelle qui gèrent des milliers de liaisons SNI. Cette fonctionnalité peut améliorer considérablement l’efficacité du débogage pendant les escalades clients. La transparence accrue permet une résolution plus rapide des problèmes et une fiabilité accrue du service.

Pour plus d’informations, consultez ITlsHandshakeFeature.HostName.

IHttpSysRequestTimingFeature

IHttpSysRequestTimingFeature fournit des informations de minutage détaillées pour les requêtes lors de l’utilisation du serveur HTTP.sys et de l’hébergement in-process avec IIS :

IHttpSysRequestTimingFeature.TryGetTimestamp récupère l’horodatage pour le type de minutage fourni :

using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;
var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseHttpSys();

var app = builder.Build();

app.Use((context, next) =>
{
    var feature = context.Features.GetRequiredFeature<IHttpSysRequestTimingFeature>();

    var loggerFactory = context.RequestServices.GetRequiredService<ILoggerFactory>();
    var logger = loggerFactory.CreateLogger("Sample");

    var timingType = HttpSysRequestTimingType.RequestRoutingEnd;

    if (feature.TryGetTimestamp(timingType, out var timestamp))
    {
        logger.LogInformation("Timestamp {timingType}: {timestamp}",
                                          timingType, timestamp);
    }
    else
    {
        logger.LogInformation("Timestamp {timingType}: not available for the "
                                           + "current request",    timingType);
    }

    return next(context);
});

app.MapGet("/", () => Results.Ok());

app.Run();

Pour plus d’informations, consultez Obtenir des informations détaillées sur le minutage avec IHttpSysRequestTimingFeature et Informations de minutage et hébergement in-process avec IIS.

HTTP.sys : prise en charge de l’activation de la mise en mémoire tampon de réponse en mode noyau

Dans certains scénarios, des volumes élevés d’écritures de petite taille avec une latence élevée peuvent avoir un impact significatif sur les performances de HTTP.sys. Cet impact est dû à l’absence d’une mémoire tampon Pipe dans l’implémentation HTTP.sys. Pour améliorer les performances dans ces scénarios, la prise en charge de la mise en mémoire tampon de réponse a été ajoutée à HTTP.sys. Activez la mise en mémoire tampon en définissant HttpSysOptions.EnableKernelResponseBuffering sur true.

La mise en mémoire tampon de réponse doit être activée par une application qui effectue des E/S synchrones ou des E/S asynchrones avec pas plus d’une écriture en attente à la fois. Dans ces scénarios, la mise en mémoire tampon de réponse peut améliorer considérablement le débit sur les connexions à latence élevée.

Les applications qui utilisent des E/S asynchrones et qui peuvent avoir plusieurs écritures en attente à la fois ne doivent pas utiliser cet indicateur. L’activation de cet indicateur peut entraîner une utilisation plus élevée du processeur et de la mémoire par HTTP.Sys.

Authentification et autorisation

ASP.NET Core 8 ajoute de nouvelles fonctionnalités à l’authentification et à l’autorisation.

Points de terminaison de l’API Identity

MapIdentityApi<TUser> est une nouvelle méthode d’extension qui ajoute deux points de terminaison d’API (/register et /login). L’objectif principal de MapIdentityApi est de permettre aux développeurs d’utiliser facilement ASP.NET Core Identity pour l’authentification dans des applications monopage (SPA) basées sur JavaScript ou des applications Blazor. Au lieu d’utiliser l’interface utilisateur par défaut fournie par ASP.NET Core Identity, basée sur Razor Pages, MapIdentityApi ajoute JSdes points de terminaison d’API ON plus adaptés aux applications SPA et aux applications non-navigateur. Pour plus d’informations, consultez Points de terminaison de l’API Identity.

IAuthorizationRequirementData

Avant ASP.NET Core 8, ajouter une stratégie d’autorisation paramétrable à un point de terminaison requérait l’implémentation de :

  • AuthorizeAttribute pour chaque stratégie.
  • AuthorizationPolicyProvider pour traiter une stratégie personnalisée à partir d’un contrat basé sur des chaînes.
  • AuthorizationRequirement pour la stratégie.
  • AuthorizationHandler pour chaque exigence.

Par exemple, considérez l’exemple suivant écrit pour ASP.NET Core 7.0 :

using AuthRequirementsData.Authorization;
using Microsoft.AspNetCore.Authorization;

var builder = WebApplication.CreateBuilder();

builder.Services.AddAuthentication().AddJwtBearer();
builder.Services.AddAuthorization();
builder.Services.AddControllers();
builder.Services.AddSingleton<IAuthorizationPolicyProvider, MinimumAgePolicyProvider>();
builder.Services.AddSingleton<IAuthorizationHandler, MinimumAgeAuthorizationHandler>();

var app = builder.Build();

app.MapControllers();

app.Run();
using Microsoft.AspNetCore.Mvc;

namespace AuthRequirementsData.Controllers;

[ApiController]
[Route("api/[controller]")]
public class GreetingsController : Controller
{
    [MinimumAgeAuthorize(16)]
    [HttpGet("hello")]
    public string Hello() => $"Hello {(HttpContext.User.Identity?.Name ?? "world")}!";
}
using Microsoft.AspNetCore.Authorization;
using System.Globalization;
using System.Security.Claims;

namespace AuthRequirementsData.Authorization;

class MinimumAgeAuthorizationHandler : AuthorizationHandler<MinimumAgeRequirement>
{
    private readonly ILogger<MinimumAgeAuthorizationHandler> _logger;

    public MinimumAgeAuthorizationHandler(ILogger<MinimumAgeAuthorizationHandler> logger)
    {
        _logger = logger;
    }

    // Check whether a given MinimumAgeRequirement is satisfied or not for a particular
    // context.
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                               MinimumAgeRequirement requirement)
    {
        // Log as a warning so that it's very clear in sample output which authorization
        // policies(and requirements/handlers) are in use.
        _logger.LogWarning("Evaluating authorization requirement for age >= {age}",
                                                                    requirement.Age);

        // Check the user's age
        var dateOfBirthClaim = context.User.FindFirst(c => c.Type ==
                                                                 ClaimTypes.DateOfBirth);
        if (dateOfBirthClaim != null)
        {
            // If the user has a date of birth claim, check their age
            var dateOfBirth = Convert.ToDateTime(dateOfBirthClaim.Value, CultureInfo.InvariantCulture);
            var age = DateTime.Now.Year - dateOfBirth.Year;
            if (dateOfBirth > DateTime.Now.AddYears(-age))
            {
                // Adjust age if the user hasn't had a birthday yet this year.
                age--;
            }

            // If the user meets the age criterion, mark the authorization requirement
            // succeeded.
            if (age >= requirement.Age)
            {
                _logger.LogInformation("Minimum age authorization requirement {age} satisfied",
                                         requirement.Age);
                context.Succeed(requirement);
            }
            else
            {
                _logger.LogInformation("Current user's DateOfBirth claim ({dateOfBirth})" +
                    " does not satisfy the minimum age authorization requirement {age}",
                    dateOfBirthClaim.Value,
                    requirement.Age);
            }
        }
        else
        {
            _logger.LogInformation("No DateOfBirth claim present");
        }

        return Task.CompletedTask;
    }
}

L’exemple de code complet se trouve ici dans le référentiel AspNetCore.Docs.Samples.

ASP.NET Core 8 introduit l’interface IAuthorizationRequirementData. L’interface IAuthorizationRequirementData permet à la définition d’attribut de spécifier les exigences associées à la stratégie d’autorisation. À l’aide de IAuthorizationRequirementData, le code de stratégie d’autorisation personnalisé précédent peut être écrit avec moins de lignes de code. Le fichier Program.cs mis à jour :

  using AuthRequirementsData.Authorization;
  using Microsoft.AspNetCore.Authorization;
  
  var builder = WebApplication.CreateBuilder();
  
  builder.Services.AddAuthentication().AddJwtBearer();
  builder.Services.AddAuthorization();
  builder.Services.AddControllers();
- builder.Services.AddSingleton<IAuthorizationPolicyProvider, MinimumAgePolicyProvider>();
  builder.Services.AddSingleton<IAuthorizationHandler, MinimumAgeAuthorizationHandler>();
  
  var app = builder.Build();
  
  app.MapControllers();
  
  app.Run();

Le MinimumAgeAuthorizationHandler mis à jour :

using Microsoft.AspNetCore.Authorization;
using System.Globalization;
using System.Security.Claims;

namespace AuthRequirementsData.Authorization;

- class MinimumAgeAuthorizationHandler : AuthorizationHandler<MinimumAgeRequirement>
+ class MinimumAgeAuthorizationHandler : AuthorizationHandler<MinimumAgeAuthorizeAttribute>
{
    private readonly ILogger<MinimumAgeAuthorizationHandler> _logger;

    public MinimumAgeAuthorizationHandler(ILogger<MinimumAgeAuthorizationHandler> logger)
    {
        _logger = logger;
    }

    // Check whether a given MinimumAgeRequirement is satisfied or not for a particular
    // context
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
-                                              MinimumAgeRequirement requirement)
+                                              MinimumAgeAuthorizeAttribute requirement)
    {
        // Remaining code omitted for brevity.

L’exemple complet mis à jour est disponible ici.

Consultez Stratégies d’autorisation personnalisées avec IAuthorizationRequirementData pour un examen détaillé du nouvel exemple.

Sécurisation des points de terminaison de l’interface utilisateur Swagger

Les points de terminaison de l'interface utilisateur Swagger peuvent désormais être sécurisés dans les environnements de production en appelant MapSwagger().RequireAuthorization. Si vous souhaitez obtenir plus d’informations, voir Sécurisation des points de terminaison de l’interface utilisateur Swagger

Divers

Les sections suivantes décrivent diverses nouvelles fonctionnalités dans ASP.NET Core 8.

Prise en charge des services à clé dans l’injection de dépendances

Les services à clé désigne un mécanisme d’inscription et de récupération des services d’injection de dépendances (DI) à l’aide de clés. Un service est associé à une clé en appelant AddKeyedSingleton (ou AddKeyedScoped ou AddKeyedTransient) pour l’inscrire. Accédez à un service inscrit en spécifiant la clé avec l’attribut [FromKeyedServices]. Le code suivant montre comment utiliser les services à clé :

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddKeyedSingleton<ICache, BigCache>("big");
builder.Services.AddKeyedSingleton<ICache, SmallCache>("small");
builder.Services.AddControllers();

var app = builder.Build();

app.MapGet("/big", ([FromKeyedServices("big")] ICache bigCache) => bigCache.Get("date"));
app.MapGet("/small", ([FromKeyedServices("small")] ICache smallCache) =>
                                                               smallCache.Get("date"));

app.MapControllers();

app.Run();

public interface ICache
{
    object Get(string key);
}
public class BigCache : ICache
{
    public object Get(string key) => $"Resolving {key} from big cache.";
}

public class SmallCache : ICache
{
    public object Get(string key) => $"Resolving {key} from small cache.";
}

[ApiController]
[Route("/cache")]
public class CustomServicesApiController : Controller
{
    [HttpGet("big-cache")]
    public ActionResult<object> GetOk([FromKeyedServices("big")] ICache cache)
    {
        return cache.Get("data-mvc");
    }
}

public class MyHub : Hub
{
    public void Method([FromKeyedServices("small")] ICache cache)
    {
        Console.WriteLine(cache.Get("signalr"));
    }
}

Modèles de projet Visual Studio pour les applications SPA avec backend ASP.NET Core

Les modèles de projet Visual Studio constituent désormais le moyen recommandé pour créer des applications monopage (SPA) dotées d'un backend ASP.NET Core. Des modèles sont fournis pour créer des applications basées sur les frameworks JavaScript Angular, React et Vue. Ces modèles :

  • Créent une solution Visual Studio avec un projet front-end et un projet back-end.
  • Utilisent le type de projet Visual Studio pour JavaScript et TypeScript (.esproj) pour le front-end.
  • Utilisent un projet ASP.NET Core pour le back-end.

Pour plus d’informations sur les modèles Visual Studio et sur la façon d’accéder aux modèles hérités, consultez Présentation des applications à page unique (SPA) dans ASP.NET Core

Prise en charge des attributs génériques

Les attributs qui nécessitaient précédemment un paramètre Type sont désormais disponibles dans des variantes génériques plus propres. Cela est rendu possible par la prise en charge des attributs génériques dans C# 11. Par exemple, la syntaxe permettant d’annoter le type de réponse d’une action peut être modifiée comme suit :

[ApiController]
[Route("api/[controller]")]
public class TodosController : Controller
{
  [HttpGet("/")]
- [ProducesResponseType(typeof(Todo), StatusCodes.Status200OK)]
+ [ProducesResponseType<Todo>(StatusCodes.Status200OK)]
  public Todo Get() => new Todo(1, "Write a sample", DateTime.Now, false);
}

Les variantes génériques sont prises en charge pour les attributs suivants :

  • [ProducesResponseType<T>]
  • [Produces<T>]
  • [MiddlewareFilter<T>]
  • [ModelBinder<T>]
  • [ModelMetadataType<T>]
  • [ServiceFilter<T>]
  • [TypeFilter<T>]

Analyse du code dans les applications ASP.NET Core

Les nouveaux analyseurs indiqués dans le tableau suivant sont disponibles dans ASP.NET Core 8.0.

ID de diagnostic Cassant ou non Description
ASP0016 Non cassant Ne pas retourner de valeur à partir de RequestDelegate
ASP0019 Non cassant Suggérer l’utilisation d’IHeaderDictionary.Append ou de l’indexeur
ASP0020 Non cassant Les types complexes référencés par les paramètres d’itinéraire doivent être analysables
ASP0021 Non cassant Le type de retour de la méthode BindAsync doit être ValueTask<T>
ASP0022 Non cassant Conflit d’itinéraire détecté entre les gestionnaires d’itinéraires
ASP0023 Non cassant MVC : Conflit d’itinéraire détecté entre les gestionnaires d’itinéraires
ASP0024 Non cassant Le gestionnaire d’itinéraires a plusieurs paramètres avec l’attribut [FromBody]
ASP0025 Non cassant Utiliser AddAuthorizationBuilder

Outils de routage

ASP.NET Core repose sur le routage. Les API minimales, les API Web, Razor Pages et Blazor utilisent tous des itinéraires pour personnaliser le mappage des requêtes HTTP au code.

Dans .NET 8, nous avons investi dans une suite de nouvelles fonctionnalités pour faciliter l’apprentissage et l’utilisation du routage. Ces nouvelles fonctionnalités sont notamment les suivantes :

Pour plus d’informations, consultez Outils de routage dans .NET 8.

Métriques ASP.NET Core

Les métriques sont des mesures signalées au fil du temps et sont les plus souvent utilisées pour surveiller l’intégrité d’une application et générer des alertes. Par exemple, un compteur qui signale des requêtes HTTP ayant échoué peut s’afficher dans des tableaux de bord ou générer des alertes lorsque les échecs passent un seuil donné.

Cette préversion ajoute de nouvelles métriques dans ASP.NET Core à l’aide de System.Diagnostics.Metrics. Metrics est une API moderne pour la création de rapports et la collecte d’informations sur les applications.

Les métriques offrent plusieurs améliorations par rapport aux compteurs d’événements existants :

  • Nouveaux types de mesures avec compteurs, jauges et histogrammes.
  • Création de rapports puissants avec des valeurs multidimensionnelles.
  • Intégration à l’écosystème natif cloud plus large en s’alignant sur les normes OpenTelemetry.

Les métriques ont été ajoutées pour l’hébergement ASP.NET Core, Kestrel et SignalR. Pour plus d’informations, consultez System.Diagnostics.Metrics.

IExceptionHandler

IExceptionHandler est une nouvelle interface qui donne au développeur un rappel pour la gestion des exceptions connues dans un emplacement central.

Les implémentations IExceptionHandler sont inscrites en appelant IServiceCollection.AddExceptionHandler<T>. Plusieurs implémentations peuvent être ajoutées et elles sont appelées dans l’ordre inscrit. Si un gestionnaire d’exceptions gère une requête, il peut renvoyer true pour arrêter le traitement. Si une exception n’est gérée par aucun gestionnaire d’exceptions, le contrôle revient au comportement et aux options par défaut de l’intergiciel.

Pour plus d’informations, consultez IExceptionHandler.

Expérience de débogage améliorée

Des attributs de personnalisation de débogage ont été ajoutés aux types tels que HttpContext, HttpRequest, HttpResponse, ClaimsPrincipal et WebApplication. Les affichages de débogueur améliorés pour ces types facilitent la recherche d’informations importantes dans le débogueur d’un IDE. Les captures d’écran suivantes montrent la différence due à ces attributs dans l’affichage du débogueur de HttpContext.

.NET 7 :

Affichage du débogueur non utile du type HttpContext dans .NET 7.

.NET 8 :

Affichage utile du débogueur pour le type HttpContext dans .NET 8.

L’affichage du débogueur pour WebApplication met en évidence des informations importantes telles que les points de terminaison configurés, les intergiciels et les valeurs IConfiguration.

.NET 7 :

Affichage peu utile du débogueur pour le type WebApplication dans .NET 7.

.NET 8 :

Affichage utile du débogueur pour le type WebApplication dans .NET 8.

Pour obtenir plus d’informations sur les améliorations apportées au débogage dans .NET 8, consultez :

IPNetwork.Parse et TryParse

Les nouvelles méthodes Parse et TryParse sur IPNetwork ajoutent la prise en charge de la création d’un IPNetwork en notation CIDR ou « notation barre oblique ».

Voici des exemples IPv4 :

// Using Parse
var network = IPNetwork.Parse("192.168.0.1/32");
// Using TryParse
bool success = IPNetwork.TryParse("192.168.0.1/32", out var network);
// Constructor equivalent
var network = new IPNetwork(IPAddress.Parse("192.168.0.1"), 32);

Voici des exemples pour IPv6 :

// Using Parse
var network = IPNetwork.Parse("2001:db8:3c4d::1/128");
// Using TryParse
bool success = IPNetwork.TryParse("2001:db8:3c4d::1/128", out var network);
// Constructor equivalent
var network = new IPNetwork(IPAddress.Parse("2001:db8:3c4d::1"), 128);

Mise en cache de sortie basée sur Redis

ASP.NET Core 8 ajoute la prise en charge de l’utilisation de Redis en tant que cache distribué pour la mise en cache de sortie. La mise en cache de sortie est une fonctionnalité qui permet à une application de mettre en cache la sortie d’un point de terminaison d’API minimale, d’une action de contrôleur ou de Razor Page. Pour plus d’informations, consultez Cache de sortie.

Intergiciel de court-circuit après routage

Lorsque le routage trouve un point de terminaison, il laisse généralement le reste du pipeline d’intergiciels s’exécuter avant d’appeler la logique de point de terminaison. Les services peuvent réduire l’utilisation des ressources en filtrant les requêtes connues tôt dans le pipeline. Utilisez la méthode d’extension ShortCircuit pour laisser le routage appeler immédiatement la logique de point de terminaison, puis mettre fin à la requête. Par exemple, un itinéraire donné n’a peut-être pas besoin de passer par l’authentification ou l’intergiciel CORS. L’exemple suivant montre comment court-circuiter les requêtes qui correspondent à l’itinéraire /short-circuit :

app.MapGet("/short-circuit", () => "Short circuiting!").ShortCircuit();

Utilisez la méthode MapShortCircuit pour configurer le court-circuit pour plusieurs itinéraires à la fois, en lui transmettant un tableau de paramètres ou des préfixes d’URL. Par exemple, les navigateurs et les bots sondent souvent des serveurs pour trouver des chemins connus comme robots.txt et favicon.ico. Si l’application n’a pas ces fichiers, une ligne de code peut configurer les deux itinéraires :

app.MapShortCircuit(404, "robots.txt", "favicon.ico");

Pour plus d’informations, consultez Court-circuiter l’intergiciel après le routage.

Extensibilité de l’intergiciel de journalisation HTTP

L’intergiciel de journalisation HTTP offre plusieurs nouvelles fonctionnalités :

  • HttpLoggingFields.Duration : lorsqu’il est activé, l’intergiciel émet un nouveau journal à la fin de la requête et de la réponse qui mesure le temps total nécessaire pour le traitement. Ce nouveau champ a été ajouté à l’ensemble HttpLoggingFields.All.
  • HttpLoggingOptions.CombineLogs : lorsqu’il est activé, l’intergiciel consolide tous ses journaux activés pour une requête et une réponse dans un journal à la fin. Un message de journal unique inclut la requête, le corps de la requête, la réponse, le corps de la réponse et la durée.
  • IHttpLoggingInterceptor : nouvelle interface d’un service qui peut être implémentée et inscrite (en utilisant AddHttpLoggingInterceptor) pour gérer les rappels par requête et par réponse pour personnaliser les détails enregistrés. Tous les paramètres de journal spécifiques au point de terminaison sont appliqués en premier et peuvent ensuite être remplacés dans ces rappels. Une implémentation peut :
    • Inspectez une requête et une réponse.
    • Activer ou désactiver un HttpLoggingFields quelconque.
    • Ajuster la quantité du corps de la requête ou de la réponse journalisée.
    • Ajouter des champs personnalisés aux journaux.

Pour obtenir plus d’informations, consultez Journalisation HTTP dans .NET Core et ASP.NET Core.

Nouvelles API dans ProblemDetails pour prendre en charge des intégrations plus résilientes

Dans .NET 7, le service ProblemDetails a été introduit pour améliorer l’expérience de génération de réponses d’erreur conformes à la spécification ProblemDetails. Dans .NET 8, une nouvelle API a été ajoutée pour faciliter l’implémentation du comportement de rappel si IProblemDetailsService n’est pas en mesure de générer ProblemDetails. L’exemple suivant montre un exemple d’utilisation de la nouvelle API TryWriteAsync :

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async httpContext =>
    {
        var pds = httpContext.RequestServices.GetService<IProblemDetailsService>();
        if (pds == null
            || !await pds.TryWriteAsync(new() { HttpContext = httpContext }))
        {
            // Fallback behavior
            await httpContext.Response.WriteAsync("Fallback: An error occurred.");
        }
    });
});

app.MapGet("/exception", () =>
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /exception");

app.Run();

Pour plus d’informations, consultez secours IProblemDetailsService

Ressources supplémentaires