Partage via


Nouveautés d’ASP.NET Core 9.0

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

Cet article a été mis à jour pour .NET 9 Preview 5.

Blazor

Cette section décrit les nouvelles fonctionnalités pour Blazor.

Modèle de solution .NET MAUIBlazor Hybrid et d’application web

Un nouveau modèle de solution permet de faciliter la création d'applications clientes web .NET MAUI natives et Blazor qui partagent la même IU. Ce modèle montre comment créer des applications clientes qui maximisent la réutilisation de code et ciblent Android, iOS, Mac, Windows et le Web.

Les principales fonctionnalités de ce modèle comprennent :

  • La possibilité de choisir un mode de rendu interactif Blazor pour l’application web.
  • Création automatique des projets appropriés, notamment une application web Blazor (rendu automatique interactif global) et une application .NET MAUIBlazor Hybrid.
  • Les projets créés utilisent une bibliothèque de classes Razor partagée (RCL) pour gérer les composants Razor de l’interface utilisateur.
  • L’exemple de code est inclus et montre comment utiliser l’injection de dépendances pour fournir différentes implémentations d’interface pour l’application Blazor Hybrid et l’application web Blazor.

Pour commencer, installez le kit SDK .NET 9 et la charge de travail .NET MAUI qui contient le modèle :

dotnet workload install maui

Créez une solution à partir du modèle de projet dans un interpréteur de commandes à l’aide de la commande suivante :

dotnet new maui-blazor-web

Ce modèle est également disponible dans Visual Studio.

Remarque

Actuellement, une exception se produit si les modes de rendu Blazor sont définis au niveau par page ou par composant. Pour plus d’informations, consultez BlazorWebView a besoin d’un moyen d’activer la substitution de ResolveComponentForRenderMode (dotnet/aspnetcore #51235).

Pour plus d’informations, consultez Créer une application .NET MAUIBlazor Hybrid avec une application web Blazor.

Optimisation de la distribution des ressources statiques

MapStaticAssets est un nouvel intergiciel qui permet d’optimiser la distribution de ressources statiques dans n’importe quelle application ASP.NET Core, y compris les applications Blazor.

Pour plus d’informations, consultez l’une des ressources suivantes :

Détecter l’emplacement de rendu, l’interactivité et le mode de rendu affecté au moment de l’exécution

Nous avons introduit une nouvelle API conçue pour simplifier le processus d’interrogation des états des composants au moment de l’exécution. Cette API fournit les fonctionnalités suivantes :

  • Déterminer l’emplacement d’exécution actuel du composant : cela peut être particulièrement utile pour le débogage et l’optimisation des performances du composant.
  • Vérifier si le composant s’exécute dans un environnement interactif : cela peut être utile pour les composants qui présentent des comportements différents en fonction de l’interactivité de leur environnement.
  • Récupérer le mode de rendu affecté pour le composant : comprendre le mode de rendu peut aider à optimiser le processus de rendu et à améliorer les performances globales du composant.

Amélioration de l’expérience de reconnexion côté serveur :

Les améliorations suivantes ont été apportées à l’expérience de reconnexion côté serveur par défaut :

  • Lorsque l’utilisateur retourne à une application avec un circuit déconnecté, la reconnexion est tentée immédiatement plutôt que d’attendre pendant la durée du prochain intervalle de reconnexion. Cela améliore l’expérience utilisateur lors de la navigation vers une application dans un onglet de navigateur qui est passé en veille.

  • Lorsqu’une tentative de reconnexion atteint le serveur, mais que le serveur a déjà libéré le circuit, une actualisation de page se produit automatiquement. Cela empêche l’utilisateur d’avoir à actualiser manuellement la page si une reconnexion réussie est susceptible de se produire.

  • Le minutage de reconnexion utilise une stratégie d’interruption (backoff) calculée. Par défaut, les premières tentatives de reconnexion se produisent rapidement sans intervalle avant nouvelle tentative avant l’introduction de délais calculés entre les tentatives. Vous pouvez personnaliser le comportement d’intervalle avant nouvelle tentative en spécifiant une fonction pour calculer l’intervalle avant nouvelle tentative, comme l’exemple de backoff exponentielle suivant illustre :

    Blazor.start({
      circuit: {
        reconnectionOptions: {
          retryIntervalMilliseconds: (previousAttempts, maxRetries) => 
            previousAttempts >= maxRetries ? null : previousAttempts * 1000
        },
      },
    });
    
  • Le style de l’IU de reconnexion par défaut a été modernisé.

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

Sérialisation simplifiée de l’état d’authentification pour les applications web Blazor

Les nouvelles API facilitent l’ajout de l’authentification à une application web Blazor existante. Lorsque vous créez un projet d’application web Blazor avec l’authentification à l’aide de Comptes individuels et que vous activez l’interactivité basée sur WebAssembly, le projet inclut un AuthenticationStateProvider personnalisé dans les projets de serveur et de client.

Ces fournisseurs circulent l’état d’authentification de l’utilisateur vers le navigateur. L’authentification sur le serveur plutôt que sur le client permet à l’application d’accéder à l’état d’authentification pendant le prérendu et avant l’initialisation du runtime Blazor WebAssembly.

Les implémentations personnalisées de AuthenticationStateProvider utilisent le service État de composant persistant (PersistentComponentState) pour sérialiser l’état d’authentification dans les commentaires HTML, et le lisent à partir de WebAssembly pour créer une instance AuthenticationState.

Cela fonctionne bien si vous avez commencé à partir du modèle de projet d’application web Blazor et que vous avez sélectionné l’option Comptes individuels. Cependant, il s’agit de beaucoup de code à implémenter ou à copier vous-même si vous essayez d’ajouter l’authentification à un projet existant. Il existe désormais des API qui font partie du modèle de projet d’application web Blazor, qui peuvent être appelées dans les projets serveur et client pour ajouter cette fonctionnalité :

  • AddAuthenticationStateSerialization : ajoute les services nécessaires pour sérialiser l’état d’authentification sur le serveur.
  • AddAuthenticationStateDeserialization : ajoute les services nécessaires pour désérialiser l’état d’authentification sur le navigateur.

Par défaut, l’API sérialise uniquement le nom et les revendications de rôle côté serveur pour l’accès dans le navigateur. Une option peut être passée à AddAuthenticationStateSerialization pour inclure toutes les revendications.

Pour plus d’informations, consultez les sections suivantes de l’article ** :

Ajouter des pages de rendu statique côté serveur (SSR) à une application web Blazor interactive globale

Avec la publication de .NET 9, il est désormais plus simple d’ajouter des pages SSR statiques aux applications qui adoptent l’interactivité globale.

Cette approche n’est utile que lorsque l’application a des pages spécifiques qui ne peuvent pas fonctionner avec le rendu interactif server ou WebAssembly. Par exemple, adoptez cette approche pour les pages qui dépendent de la lecture/l’écriture de cookie HTTP et peuvent uniquement fonctionner dans un cycle de requête/réponse au lieu d’un rendu interactif. Pour les pages qui fonctionnent avec le rendu interactif, vous ne devez pas les forcer à utiliser le rendu SSR statique, car il est moins efficace et moins réactif pour l’utilisateur final.

Marquez n’importe quelle page de composant Razor avec le nouvel attribut [ExcludeFromInteractiveRouting] affecté à la directive @attributeRazor :

@attribute [ExcludeFromInteractiveRouting]

L’application de l’attribut entraîne la sortie de la navigation vers la page du routage interactif. La navigation entrante est forcée d’effectuer un rechargement complet de la page au lieu de résoudre la page via routage interactif. Le rechargement complet de la page force le composant racine de niveau supérieur, généralement le composant App (App.razor), à effectuer un nouveau rendu à partir du serveur, ce qui permet à l’application de basculer vers un autre mode de rendu de niveau supérieur.

La méthode d’extension HttpContext.AcceptsInteractiveRouting permet au composant de détecter si [ExcludeFromInteractiveRouting] est appliqué à la page active.

Dans le composant App, utilisez le modèle dans l’exemple suivant :

  • Les pages dépourvues de l’annotation [ExcludeFromInteractiveRouting] présentent par défaut le mode de rendu InteractiveServer avec interactivité globale. Vous pouvez remplacer InteractiveServer par InteractiveWebAssembly ou InteractiveAuto pour spécifier un autre mode de rendu global par défaut.
  • Les pages dotées de l’annotation [ExcludeFromInteractiveRouting] adoptent le SSR statique (null est affecté à PageRenderMode).
<!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;
}

Une alternative à l’utilisation de la méthode d’extension HttpContext.AcceptsInteractiveRouting consiste à lire manuellement les métadonnées de point de terminaison à l’aide de HttpContext.GetEndpoint()?.Metadata.

Cette fonctionnalité est couverte par la documentation de référence dans Modes de rendu Blazor ASP.NET Core.

Injection de constructeurs

Les composants Razor prennent en charge l’injection de constructeur.

Dans l’exemple suivant, la classe partielle (code-behind) injecte le service NavigationManager avec un constructeur principal :

public partial class ConstructorInjection(NavigationManager navigation)
{
    protected NavigationManager Navigation { get; } = navigation;
}

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

Compression WebSocket pour les composants de serveur interactif

Par défaut, les composants Interactive Server activent la compression pour les connexions WebSocket et définissent une directive frame-ancestors relatif au fournisseur de services de chiffrement (CSP - Content Security Policy) définie sur 'self', qui autorise uniquement l’incorporation de l’application dans une <iframe> de l’origine à partir de laquelle l’application est servie lorsque la compression est activée ou lorsqu’une configuration pour le contexte WebSocket est fournie.

La compression peut être désactivée en définissant ConfigureWebSocketOptions sur null, ce qui réduit la vulnérabilité de l’application à attaquer, mais peut entraîner une réduction des performances :

.AddInteractiveServerRenderMode(o => o.ConfigureWebSocketOptions = null)

Configurez un CSP frame-ancestors plus strict avec une valeur de 'none' (guillemets simples requis), qui autorise la compression WebSocket mais empêche les navigateurs d’incorporer l’application dans n’importe quel <iframe>:

.AddInteractiveServerRenderMode(o => o.ContentSecurityFrameAncestorsPolicy = "'none'")

Pour plus d’informations, consultez les ressources suivantes :

Gérer les événements de composition de clavier dans Blazor

La nouvelle propriété KeyboardEventArgs.IsComposing indique si l’événement de clavier fait partie d’une session de composition. Le suivi de l’état de composition des événements de clavier est essentiel pour gérer les méthodes d’entrée de caractères internationaux.

Ajout du paramètre OverscanCount pour QuickGrid

Le composant QuickGrid expose désormais une propriété OverscanCount qui spécifie le nombre de lignes supplémentaires rendues avant et après la région visible lorsque la virtualisation est activée.

La valeur par défaut de OverscanCount est 3. L’exemple suivant augmente la valeur OverscanCount à 4 :

<QuickGrid ItemsProvider="itemsProvider" Virtualize="true" OverscanCount="4">
    ...
</QuickGrid>

SignalR

Cette section décrit les nouvelles fonctionnalités pour SignalR.

Prise en charge du type polymorphe dans SignalR Hubs

Les méthodes Hub peuvent désormais accepter une classe de base au lieu de la classe dérivée pour prendre en charge les scénarios polymorphes. Le type de base doit être annoté pour autoriser le polymorphisme.

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 minimales

Cette section décrit les nouvelles fonctionnalités pour les API minimales.

Ajout de InternalServerError et InternalServerError<TValue> à TypedResults

La classe TypedResults est un véhicule utile pour retourner des réponses basées sur un code d’état HTTP fortement typé à partir d’une API minimale. TypedResults inclut désormais des types et des méthodes de fabrique pour renvoyer des réponses « Erreur de serveur interne 500 » à partir de points de terminaison. Voici un exemple qui retourne une réponse 500 :

var app = WebApplication.Create();

app.MapGet("/", () => TypedResults.InternalServerError("Something went wrong!"));

app.Run();

OpenAPI

Prise en charge intégrée de la génération de documents OpenAPI

La spécification OpenAPI est une norme permettant de décrire les API HTTP. La norme permet aux développeurs de définir la forme des API qui peuvent être connectées aux générateurs clients, aux générateurs de serveurs, aux outils de test, à la documentation, etc. Dans .NET 9 Preview, ASP.NET Core fournit une prise en charge intégrée de la génération de documents OpenAPI représentant des API basées sur contrôleur ou minimales via le package Microsoft.AspNetCore.OpenApi.

Le code mis en évidence suivant appelle :

  • AddOpenApi pour inscrire les dépendances requises dans le conteneur DI de l’application.
  • MapOpenApi pour inscrire les points de terminaison OpenAPI requis dans les itinéraires de l’application.
var builder = WebApplication.CreateBuilder();

builder.Services.AddOpenApi();

var app = builder.Build();

app.MapOpenApi();

app.MapGet("/hello/{name}", (string name) => $"Hello {name}"!);

app.Run();

Installez le package Microsoft.AspNetCore.OpenApi dans le projet à l’aide de la commande suivante :

dotnet add package Microsoft.AspNetCore.OpenApi --prerelease

Exécutez l’application et accédez à openapi/v1.json pour afficher le document OpenAPI généré :

Document OpenAPI

Vous pouvez également créer les documents OpenAPI au moment de la génération en ajoutant le package Microsoft.Extensions.ApiDescription.Server :

dotnet add package Microsoft.Extensions.ApiDescription.Server --prerelease

Dans le fichier projet de l’application, ajoutez les éléments suivants :

<PropertyGroup>
  <OpenApiDocumentsDirectory>$(MSBuildProjectDirectory)</OpenApiDocumentsDirectory>
  <OpenApiGenerateDocuments>true</OpenApiGenerateDocuments>
</PropertyGroup>

Exécutez dotnet build et inspectez le fichier JSON généré dans le répertoire du projet.

Génération de documents OpenAPI au moment de la génération

La génération de documents OpenAPI intégrée à ASP.NET Core prend en charge diverses personnalisations et options. Il fournit des transformateurs de documents et d’opérations et permet de gérer plusieurs documents OpenAPI pour la même application.

Pour en savoir plus sur les nouvelles fonctionnalités de document OpenAPI d’ASP.NET Core, consultez la nouvelle documentation Microsoft.AspNetCore.OpenApi.

Authentification et autorisation

Cette section décrit les nouvelles fonctionnalités pour l’authentification et l’autorisation.

Personnalisation des paramètres OAuth et OIDC

Les gestionnaires d’authentification OIDC et OAuth dispose désormais d’une option AdditionalAuthorizationParameters pour faciliter la personnalisation des paramètres de messages d’autorisation qui sont généralement inclus dans le cadre de la chaîne de requête de redirection. Dans .NET 8 et les versions antérieures, elle exige un rappel OnRedirectToIdentityProvider personnalisé ou une méthode BuildChallengeUrl substituée dans un gestionnaire personnalisé. Voici un exemple de code .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’exemple précédent peut maintenant être simplifié par le code suivant :

builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
    options.AdditionalAuthorizationParameters.Add("prompt", "login");
    options.AdditionalAuthorizationParameters.Add("audience", "https://api.example.com");
});

Configurer des indicateurs d’authentification étendus HTTP.sys

Vous pouvez maintenant configurer les indicateurs HTTP.sys HTTP_AUTH_EX_FLAG_ENABLE_KERBEROS_CREDENTIAL_CACHING et HTTP_AUTH_EX_FLAG_CAPTURE_CREDENTIAL en utilisant les nouvelles propriétés EnableKerberosCredentialCaching et CaptureCredentials sur le serveur HTTP.sys AuthenticationManager pour optimiser la méthode de gestion de l’Authentification Windows. Par exemple :

webBuilder.UseHttpSys(options =>
{
    options.Authentication.Schemes = AuthenticationSchemes.Negotiate;
    options.Authentication.EnableKerberosCredentialCaching = true;
    options.Authentication.CaptureCredentials = true;
});

Divers

Les sections suivantes décrivent diverses nouvelles fonctionnalités.

Nouvelle bibliothèque HybridCache

L’API HybridCache permet de combler certaines lacunes dans les API IDistributedCache et IMemoryCache. Elle ajoute également de nouvelles fonctionnalités, telles que :

  • La protection « Stampede » pour empêcher les extractions parallèles du même travail.
  • Sérialisation configurable.

HybridCache est conçue comme un remplacement de dépôt pour l’utilisation de IDistributedCache et IMemoryCache existante, et elle fournit une API simple pour l’ajout de nouveau code de mise en cache. Elle fournit une API unifiée pour la mise en cache in-process et out-of-process.

Pour voir comment l’API HybridCache est simplifiée, comparez-la au code qui utilise IDistributedCache. Voici un exemple d’utilisation de 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)
    { /* ... */ }
}

Cela représente beaucoup d’opérations à réaliser correctement à chaque fois, y compris la sérialisation. Et dans le scénario d’échec d’accès au cache, vous risquez de vous retrouver avec plusieurs threads simultanés, qui reçoivent tous un échec d’accès au cache, qui récupèrent tous les données sous-jacentes, qui les sérialisent tous et qui envoient tous ces données au cache.

Pour simplifier et améliorer ce code avec HybridCache, nous devons d’abord ajouter la nouvelle bibliothèque Microsoft.Extensions.Caching.Hybrid :

<PackageReference Include="Microsoft.Extensions.Caching.Hybrid" Version="9.0.0" />

Inscrivez le service HybridCache, comme vous le feriez pour inscrire une implémentation IDistributedCache :

services.AddHybridCache(); // Not shown: optional configuration API.

À présent, la plupart des problèmes de mise en cache peuvent être déchargés vers 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
        );
    }
}

Nous fournissons une implémentation concrète de la classe abstraite HybridCache via l’injection de dépendances, mais il est prévu que les développeurs puissent fournir des implémentations personnalisées de l’API. L’implémentation de HybridCache traite de tout ce qui concerne la mise en cache, y compris la gestion simultanée des opérations. Le jeton cancel représente ici l’annulation combinée de tous les appelants simultanés, pas seulement l’annulation de l’appelant que nous pouvons voir (autrement dit, token).

Les scénarios à débit élevé peuvent être optimisés davantage à l’aide du modèle TState pour éviter une surcharge des variables capturées et des rappels par instance :

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 utilise l’implémentation de IDistributedCache configurée, le cas échéant, pour la mise en cache out-of-process secondaire, par exemple, à l’aide de Redis. Mais même sans IDistributedCache, le service HybridCache fournira toujours la mise en cache in-process et la protection « stampede ».

Remarque sur la réutilisation des objets

Dans le code existant classique qui utilise IDistributedCache, chaque récupération d’un objet à partir du cache entraîne la désérialisation. Ce comportement signifie que chaque appelant simultané obtient une instance distincte de l’objet, qui ne peut pas interagir avec d’autres instances. Il en résulte une cohérence de thread, car il n’existe aucun risque de modifications simultanées sur la même instance d’objet.

Étant donné que nombre d’utilisations de HybridCache seront adaptées à partir du code IDistributedCache existant, HybridCache conserve ce comportement par défaut pour éviter d’introduire des bogues d’accès concurrentiel. Toutefois, un cas d’usage donné est intrinsèquement thread-safe :

  • Si les types mis en cache sont immuables.
  • Si le code ne les modifie pas.

Dans de tels cas, informez HybridCache qu’il est sûr de réutiliser des instances en :

  • Marquant le type en tant que sealed. Le mot clé sealed en C# signifie que la classe ne peut pas être héritée.
  • Appliquant l’attribut [ImmutableObject(true)] à celui-ci. L’attribut [ImmutableObject(true)] indique que l’état de l’objet ne peut pas être modifié après sa création.

En réutilisant des instances, HybridCache peut réduire la charge de traitement des allocations de processeur et d’objets associées à la désérialisation par appel. Cela peut entraîner des améliorations des performances dans les scénarios où les objets mis en cache sont volumineux ou consultés fréquemment.

Autres fonctionnalités HybridCache

Comme IDistributedCache, HybridCache prend en charge la suppression par clé avec une méthode RemoveKeyAsync.

HybridCache fournit également des API facultatives pour les implémentations de IDistributedCache, afin d’éviter les allocations byte[]. Cette fonctionnalité est implémentée par les versions préliminaires des packages Microsoft.Extensions.Caching.StackExchangeRedis et Microsoft.Extensions.Caching.SqlServer.

La sérialisation est configurée dans le cadre de l’inscription du service, avec prise en charge des sérialiseurs propres au type et généralisés via les méthodes WithSerializer et .WithSerializerFactory, mis en chaîne à partir de l’appel AddHybridCache. Par défaut, la bibliothèque gère string et byte[] en interne, et utilise System.Text.Json pour tout le reste, mais vous pouvez utiliser protobuf, xml ou autre.

HybridCache prend en charge les runtimes .NET plus anciens, jusqu’à .NET Framework 4.7.2 et .NET Standard 2.0.

Pour plus d’informations sur HybridCache, consultez Bibliothèque HybridCache dans ASP.NET Core

Améliorations apportées à la page d’exceptions du développeur

La page d’exceptions du développeur ASP.NET Core s’affiche lorsqu’une application lève une exception non gérée pendant le développement. La page d’exceptions du développeur fournit des informations détaillées sur l’exception et la requête.

La Preview 3 a ajouté des métadonnées de point de terminaison à la page d’exceptions du développeur. ASP.NET Core utilise les métadonnées du point de terminaison pour contrôler le comportement du point de terminaison, comme le routage, la mise en cache des réponses, la limitation du débit, la génération OpenAPI, etc. L’image suivante montre les nouvelles informations de métadonnées de la section Routing sur la page d’exceptions du développeur :

Les nouvelles informations de métadonnées sur la page d’exception du développeur

Lors du test de la page de l’exceptions du développeur, de légères améliorations destinées à faciliter le travail ont été identifiées. Elles ont été livrées dans la Preview 4 :

  • Meilleur habillage de texte. Les cookie, les valeurs de chaîne de requête et les noms de méthode longs n’ajoutent plus de barres de défilement de navigateur horizontales.
  • Texte de plus grande taille dans les designs modernes.
  • Tailles de table plus homogènes.

L’image animée suivante montre la nouvelle page d’exceptions du développeur :

Page d’exceptions du développeur

Améliorations du débogage des dictionnaires

L’affichage de débogage des dictionnaires et d’autres collections clé-valeur a une disposition améliorée. La clé s’affiche dans la colonne clé du débogueur au lieu d’être concaténée avec la valeur. Les images suivantes montrent l’ancien et le nouvel affichage d’un dictionnaire dans le débogueur.

Avant :

L’expérience précédente du débogueur

Après :

La nouvelle expérience de débogueur

ASP.NET Core a de nombreuses collections clé-valeur. Cette expérience de débogage améliorée s’applique à :

  • En-têtes HTTP
  • Chaînes de requête
  • Formulaires
  • Cookies
  • Afficher les données
  • Données de routage
  • Fonctionnalités

Correctif pour les erreurs 503 pendant le recyclage d’application dans IIS

Par défaut, il existe maintenant un délai de 1 seconde entre le moment où IIS est averti d’un recyclage ou d’un arrêt et le moment où ANCM indique au serveur managé de démarrer l’arrêt. Le délai est configurable via la variable d’environnement ANCM_shutdownDelay ou en définissant le paramètre du gestionnaire shutdownDelay. Les deux valeurs sont en millisecondes. Le délai est principalement destiné à réduire la probabilité d’une course où :

  • IIS n’a pas démarré la mise en file d’attente des requêtes pour accéder à la nouvelle application.
  • ANCM commence à rejeter les nouvelles requêtes qui entrent dans l’ancienne application.

Les machines plus lentes ou recourant davantage au processeur peuvent vouloir ajuster cette valeur pour réduire la probabilité d’erreurs 503.

Exemple de paramètre 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>

Le correctif se trouve dans le module ANCM installé à l’échelle mondiale qui provient du pack d’hébergement.

Optimisation de la remise des ressources web statiques

La création d’applications web performantes inclut l’optimisation de la remise des ressources au navigateur. Cela implique de nombreux aspects tels que :

MapStaticAssets est un nouvel intergiciel qui permet d’optimiser la distribution de ressources statiques dans une application. Il est conçu pour fonctionner avec toutes les infrastructures d’interface utilisateur, notamment Blazor, Razor Pages et MVC. Il s’agit généralement d’un remplacement de UseStaticFiles.

MapStaticAssets fonctionne en combinant des processus de génération et de publication pour collecter des informations sur toutes les ressources statiques d’une application. Ces informations sont ensuite utilisées par la bibliothèque runtime pour traiter efficacement ces fichiers dans le navigateur.

MapStaticAssets peut remplacer UseStaticFiles dans la plupart des cas, mais elle est optimisée pour servir les ressources dont l’application a connaissance au moment de la génération et de la publication. Si l’application sert des ressources à partir d’autres emplacements, tels que des ressources sur disque ou incorporées, UseStaticFiles doit être utilisé.

MapStaticAssets offre les avantages suivants non trouvés avec UseStaticFiles:

  • Compression du temps de génération pour toutes les ressources de l’application :
    • gzip pendant le développement et gzip + brotli pendant la publication.
    • Toutes les ressources sont compressées avec l’objectif de réduire la taille des ressources au minimum.
  • Basé sur le contenuETags : les Etags pour chaque ressource sont la chaîne codée Base64 du hachage du contenu SHA-256. Cela garantit que le navigateur recharge uniquement un fichier si son contenu a changé.

Le tableau suivant montre les tailles d’origine et compressées des fichiers CSS et JS dans le modèle de pages par défaut Razor :

File Original Compressé % de réduction
bootstrap.min.css 163 17.5 89,26%
jquery.js 89,6 28 68,75%
bootstrap.min.js 78,5 20 74,52%
Total 331,1 65,5 80,20%

Le tableau suivant présente les tailles d’origine et compressées à l’aide de la bibliothèque de composants Fluent UIBlazor:

File Original Compressé % de réduction
fluent.js 384 73 80.99 %
fluent.css 94 11 88,30%
Total 478 84 82,43%

Pour un total de 478 Ko décompressé à 84 Ko compressés.

Le tableau suivant présente les tailles d’origine et compressées à l’aide de la bibliothèque de composants MudBlazorBlazor :

File Original Compressé Réduction
MudBlazor.min.css 541 37,5 93,07%
MudBlazor.min.js 47.4 9.2 80,59%
Total 588,4 46,7 92,07%

L’optimisation se produit automatiquement lors de l’utilisation de MapStaticAssets. Lorsqu’une bibliothèque est ajoutée ou mise à jour, par exemple avec JavaScript ou CSS, les ressources sont optimisées dans le cadre de la build. L’optimisation est particulièrement bénéfique pour les environnements mobiles qui peuvent avoir une bande passante inférieure ou une connexion non fiable.

Activation de la compression dynamique sur le serveur par rapport à l’utilisation de MapStaticAssets

MapStaticAssets présente les avantages suivants par rapport à la compression dynamique sur le serveur :

  • Est plus simple, car il n’existe aucune configuration spécifique au serveur.
  • Est plus performant, car les ressources sont compressées au moment de la génération.
  • Permet au développeur de passer du temps supplémentaire pendant le processus de génération pour s’assurer que les ressources sont de taille minimale.

Considérez le tableau suivant comparant la compression mudBlazor à la compression dynamique IIS et MapStaticAssets:

IIS gzip MapStaticAssets MapStaticAssets Reduction
≅ 90 37,5 59 %