Nouveautés d’ASP.NET Core 7.0
Cet article met en évidence les modifications les plus importantes dans ASP.NET Core 7.0 et fournit des liens vers la documentation appropriée.
Intergiciel de réécriture d’URL dans ASP.NET Core
L’intergiciel Microsoft.AspNetCore.RateLimiting
fournit un intergiciel de limitation de débit. Les applications configurent des stratégies de limitation du débit, puis attachent les stratégies aux points de terminaison. Pour plus d’informations, consultez Intergiciel de limitation du débit dans ASP.NET Core.
L’authentification utilise un schéma unique comme DefaultScheme
Dans le cadre du travail de simplification de l’authentification, lorsqu’un seul schéma d’authentification est inscrit, il est automatiquement utilisé comme DefaultScheme et n’a pas besoin d’être spécifié. Pour plus d’informations, consultez DefaultScheme.
MVC et Razor Pages
Prise en charge des modèles nullables dans les vues MVC et Razor Pages
Les modèles de page ou de vue nullables sont pris en charge pour améliorer l’expérience lors de l’utilisation de la vérification de l’état Null avec les applications ASP.NET Core :
@model Product?
Lier avec IParsable<T>.TryParse
dans MVC et les contrôleurs d’API
L’API IParsable<TSelf>.TryParse
prend en charge les valeurs de paramètre d’action du contrôleur de liaison. Pour plus d’informations, consultez Lier avec IParsable<T>.TryParse
.
Personnaliser la valeur de consentement cookie
Dans les versions antérieures d’ASP.NET Core antérieures à 7, la validation du consentement cookie utilise la valeur cookieyes
pour indiquer le consentement. Vous pouvez maintenant spécifier la valeur qui représente le consentement. Par exemple, vous pouvez utiliser true
au lieu de yes
:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
options.ConsentCookieValue = "true";
});
var app = builder.Build();
Pour plus d’informations, consultez Personnaliser la valeur de consentement cookie.
Contrôleurs d’API
Liaison de paramètres avec la DI dans les contrôleurs d’API
La liaison de paramètre pour les actions de contrôleur d’API lie des paramètres via l’injection de dépendance quand le type est configuré en tant que service. Cela signifie qu’il n’est plus nécessaire d’appliquer explicitement l’attribut [FromServices]
à un paramètre. Dans le code suivant, les deux actions retournent l’heure :
[Route("[controller]")]
[ApiController]
public class MyController : ControllerBase
{
public ActionResult GetWithAttribute([FromServices] IDateTime dateTime)
=> Ok(dateTime.Now);
[Route("noAttribute")]
public ActionResult Get(IDateTime dateTime) => Ok(dateTime.Now);
}
Dans de rares cas, l’injection de dépendances automatique peut interrompre les applications qui présentent un type dans l’injection de dépendances qui est également accepté dans les méthodes d’action d’un contrôleur d’API. Il n’est pas courant d’avoir un type dans l’injection de dépendances et comme argument dans une action du contrôleur d’API. Pour désactiver la liaison automatique de paramètres, définissez DisableImplicitFromServicesParameters
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddSingleton<IDateTime, SystemDateTime>();
builder.Services.Configure<ApiBehaviorOptions>(options =>
{
options.DisableImplicitFromServicesParameters = true;
});
var app = builder.Build();
app.MapControllers();
app.Run();
Dans ASP.NET Core 7.0, les types dans l’injection de dépendance sont vérifiés au démarrage de l’application avec IServiceProviderIsService pour déterminer si un argument dans une action de contrôleur d’API provient de l’injection de dépendances ou d’autres sources.
Le nouveau mécanisme permettant de déduire la source de liaison des paramètres d’action du contrôleur d’API utilise les règles suivantes :
- Un
BindingInfo.BindingSource
spécifié précédemment n’est jamais remplacé. BindingSource.Services
est affecté à un paramètre de type complexe, inscrit dans le conteneur d’injection de dépendances.BindingSource.Body
est affecté à un paramètre de type complexe, qui n’est pas inscrit dans le conteneur d’injection de dépendances.BindingSource.Path
est affecté à un paramètre avec un nom qui apparaît en tant que valeur de routage dans n’importe quel modèle de routage.- Tous les autres paramètres sont
BindingSource.Query
.
Noms de propriétés JSON dans les erreurs de validation
Par défaut, lorsqu’une erreur de validation se produit, la validation du modèle génère un ModelStateDictionary avec le nom de propriété comme clé d’erreur. Certaines applications, comme les applications monopages, tirent parti de l’utilisation de noms de propriétés JSON pour les erreurs de validation générées à partir des API web. Le code suivant configure la validation pour qu’elle utilise les noms de propriété JSON dans le format SystemTextJsonValidationMetadataProvider
:
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(options =>
{
options.ModelMetadataDetailsProviders.Add(new SystemTextJsonValidationMetadataProvider());
});
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Le code suivant configure la validation pour utiliser NewtonsoftJsonValidationMetadataProvider
afin d’utiliser les noms de propriété JSON lors de l’utilisation de Json.NET :
using Microsoft.AspNetCore.Mvc.NewtonsoftJson;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(options =>
{
options.ModelMetadataDetailsProviders.Add(new NewtonsoftJsonValidationMetadataProvider());
}).AddNewtonsoftJson();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Pour plus d’informations, consultez Utiliser les noms de propriété JSON dans les erreurs de validation.
API minimales
Filtres dans les applications d’API minimales
Les filtres d’API minimaux permettent aux développeurs d’implémenter une logique métier qui prend en charge :
- Exécution du code avant et après le gestionnaire de routes.
- Inspection et modification des paramètres fournis lors d’un appel de gestionnaire de routes.
- Interception du comportement de réponse d’un gestionnaire de routes.
Les filtres peuvent être utiles dans les scénarios suivants :
- Validation des paramètres et du corps de la requête envoyés à un point de terminaison.
- Journalisation des informations sur la requête et la réponse.
- Validation qu’une requête cible une version d’API prise en charge.
Pour plus d’informations, consultez Filtres dans les applications API minimales
Lier des tableaux et des valeurs de chaîne à partir d’en-têtes et de chaînes de requête
Dans ASP.NET 7, la liaison de chaînes de requête à un tableau de types primitifs, de tableaux de chaînes et de StringValues est prise en charge :
// Bind query string values to a primitive type array.
// GET /tags?q=1&q=2&q=3
app.MapGet("/tags", (int[] q) =>
$"tag1: {q[0]} , tag2: {q[1]}, tag3: {q[2]}");
// Bind to a string array.
// GET /tags2?names=john&names=jack&names=jane
app.MapGet("/tags2", (string[] names) =>
$"tag1: {names[0]} , tag2: {names[1]}, tag3: {names[2]}");
// Bind to StringValues.
// GET /tags3?names=john&names=jack&names=jane
app.MapGet("/tags3", (StringValues names) =>
$"tag1: {names[0]} , tag2: {names[1]}, tag3: {names[2]}");
La liaison de chaînes de requête ou de valeurs d’en-tête à un tableau de types complexes est prise en charge lorsque le type implémente TryParse
. Pour plus d’informations, consultez Lier des tableaux et des valeurs de chaîne à partir d’en-têtes et de chaînes de requête.
Pour plus d’informations, consultez Ajouter un résumé ou une description de point de terminaison.
Lier le corps de la requête en tant que Stream
ou PipeReader
Le corps de la requête peut être lié en tant que Stream
ou PipeReader
pour prendre en charge efficacement les scénarios où l’utilisateur doit traiter des données et :
- Stockez les données dans le stockage d’objets blob ou placez les données en file d’attente dans un fournisseur de file d’attente.
- Traitez les données stockées avec un processus Worker ou une fonction cloud.
Par exemple, les données peuvent être mises en file d’attente pour le Stockage File d’attente Azure ou stockées dans le Stockage Blob Azure.
Pour plus d’informations, consultez Lier le corps de la requête en tant que Stream
ou PipeReader
Nouvelles surcharges Results.Stream
Nous avons introduit de nouvelles surcharges de Results.Stream
pour prendre en charge les scénarios qui nécessitent d’accéder au flux de réponse HTTP sous-jacent sans mettre en mémoire tampon. Ces surcharges améliorent également les cas où une API diffuse des données vers le flux de réponse HTTP, comme à partir du Stockage Blob Azure. L’exemple suivant utilise ImageSharp pour retourner une taille réduite de l’image spécifiée :
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Processing;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/process-image/{strImage}", (string strImage, HttpContext http, CancellationToken token) =>
{
http.Response.Headers.CacheControl = $"public,max-age={TimeSpan.FromHours(24).TotalSeconds}";
return Results.Stream(stream => ResizeImageAsync(strImage, stream, token), "image/jpeg");
});
async Task ResizeImageAsync(string strImage, Stream stream, CancellationToken token)
{
var strPath = $"wwwroot/img/{strImage}";
using var image = await Image.LoadAsync(strPath, token);
int width = image.Width / 2;
int height = image.Height / 2;
image.Mutate(x =>x.Resize(width, height));
await image.SaveAsync(stream, JpegFormat.Instance, cancellationToken: token);
}
Pour plus d’informations, consultez Exemples de diffusion en continu
Résultats typés pour les API minimales
Dans .NET 6, l’interface IResult a été introduite pour représenter les valeurs retournées par les API minimales qui n’utilisent pas la prise en charge implicite de la sérialisation JSON de l’objet retourné dans la réponse HTTP. La classe statique Results est utilisée pour créer différents objets IResult
qui représentent différents types de réponses. Par exemple, la définition du code d’état de la réponse ou la redirection vers une autre URL. Toutefois, les types de framework implémentant IResult
retournés par ces méthodes étaient internes, ce qui rendait difficile la vérification du type IResult
spécifique retourné par les méthodes dans un test unitaire.
Dans .NET 7, les types implémentant IResult
sont publics, ce qui permet les assertions de type lors des tests. Par exemple :
[TestClass()]
public class WeatherApiTests
{
[TestMethod()]
public void MapWeatherApiTest()
{
var result = WeatherApi.GetAllWeathers();
Assert.IsInstanceOfType(result, typeof(Ok<WeatherForecast[]>));
}
}
Testabilité unitaire améliorée pour les gestionnaires de routes minimaux
Les types d’implémentation IResult sont désormais disponibles publiquement dans l’espace de noms Microsoft.AspNetCore.Http.HttpResults. Les types d’implémentation IResult
peuvent être utilisés pour tester unitairement des gestionnaires de routes minimaux lors de l’utilisation de méthodes nommées au lieu de lambdas.
Le code suivant utilise la classe Ok<TValue>
:
[Fact]
public async Task GetTodoReturnsTodoFromDatabase()
{
// Arrange
await using var context = new MockDb().CreateDbContext();
context.Todos.Add(new Todo
{
Id = 1,
Title = "Test title",
Description = "Test description",
IsDone = false
});
await context.SaveChangesAsync();
// Act
var result = await TodoEndpointsV1.GetTodo(1, context);
//Assert
Assert.IsType<Results<Ok<Todo>, NotFound>>(result);
var okResult = (Ok<Todo>)result.Result;
Assert.NotNull(okResult.Value);
Assert.Equal(1, okResult.Value.Id);
}
Pour plus d’informations, consultez Types d’implémentation IResult
.
Nouvelles interfaces HttpResult
Les interfaces suivantes dans l’espace de noms Microsoft.AspNetCore.Http permettent de détecter le type IResult
au moment de l’exécution, ce qui est un modèle courant dans les implémentations de filtre :
- IContentTypeHttpResult
- IFileHttpResult
- INestedHttpResult
- IStatusCodeHttpResult
- IValueHttpResult
- IValueHttpResult<TValue>
Pour plus d’informations, consultez Interfaces IHttpResult.
Améliorations d’OpenAPI pour les API minimales
package NuGet Microsoft.AspNetCore.OpenApi
Le package Microsoft.AspNetCore.OpenApi
autorise les interactions avec les spécifications OpenAPI pour les points de terminaison. Le package agit comme un lien entre les modèles OpenAPI définis dans le package Microsoft.AspNetCore.OpenApi
et les points de terminaison définis dans les API minimales. Le package fournit une API qui examine les paramètres, les réponses et les métadonnées d’un point de terminaison pour construire un type d’annotation OpenAPI utilisé pour décrire un point de terminaison.
app.MapPost("/todoitems/{id}", async (int id, Todo todo, TodoDb db) =>
{
todo.Id = id;
db.Todos.Add(todo);
await db.SaveChangesAsync();
return Results.Created($"/todoitems/{todo.Id}", todo);
})
.WithOpenApi();
Appeler WithOpenApi
avec des paramètres
La méthode WithOpenApi
accepte une fonction qui peut être utilisée pour modifier l’annotation OpenAPI. Par exemple, dans le code suivant, une description est ajoutée au premier paramètre du point de terminaison :
app.MapPost("/todo2/{id}", async (int id, Todo todo, TodoDb db) =>
{
todo.Id = id;
db.Todos.Add(todo);
await db.SaveChangesAsync();
return Results.Created($"/todoitems/{todo.Id}", todo);
})
.WithOpenApi(generatedOperation =>
{
var parameter = generatedOperation.Parameters[0];
parameter.Description = "The ID associated with the created Todo";
return generatedOperation;
});
Fournir des descriptions et des résumés des points de terminaison
Les API minimales prennent désormais en charge les opérations d’annotation avec des descriptions et des résumés pour la génération de spécifications OpenAPI. Vous pouvez appeler des méthodes d’extension WithDescription et WithSummary ou utiliser des attributs [EndpointDescription] et [EndpointSummary]).
Pour plus d’informations, consultez OpenAPI dans les applications API minimales.
Chargements de fichiers à l’aide d’IFormFile et IFormFileCollection
Les API minimales prennent désormais en charge le chargement de fichiers avec IFormFile
et IFormFileCollection
. Le code suivant utilise IFormFile et IFormFileCollection pour charger le fichier :
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.MapPost("/upload", async (IFormFile file) =>
{
var tempFile = Path.GetTempFileName();
app.Logger.LogInformation(tempFile);
using var stream = File.OpenWrite(tempFile);
await file.CopyToAsync(stream);
});
app.MapPost("/upload_many", async (IFormFileCollection myFiles) =>
{
foreach (var file in myFiles)
{
var tempFile = Path.GetTempFileName();
app.Logger.LogInformation(tempFile);
using var stream = File.OpenWrite(tempFile);
await file.CopyToAsync(stream);
}
});
app.Run();
Les requêtes de chargement de fichiers authentifiés sont prises en charge à l’aide d’un en-tête d’autorisation, d’un certificat client ou d’un en-tête cookie.
Il n’y a pas de prise en charge intégrée de l’antifalsification. Toutefois, elle peut être implémentée à l’aide du service IAntiforgery
.
L’attribut [AsParameters]
active la liaison de paramètres pour les listes d’arguments
L’attribut [AsParameters]
active la liaison de paramètres pour les listes d’arguments. Pour plus d’informations, consultez Liaison de paramètres pour les listes d’arguments avec [AsParameters]
.
API minimales et contrôleurs d’API
Nouveau service de détails du problème
Le service de détails du problème implémente l’interface IProblemDetailsService, qui prend en charge la création de Détails du problème pour les API HTTP.
Pour plus d’informations, consultez Service de détails du problème.
Groupes d’itinéraires
La méthode d’extension MapGroup permet d’organiser des groupes de points de terminaison avec un préfixe commun. Cela réduit le code répétitif et permet de personnaliser des groupes entiers de points de terminaison avec un seul appel à des méthodes comme RequireAuthorization et WithMetadata, qui ajoutent des métadonnées de point de terminaison.
Par exemple, le code suivant crée deux groupes de points de terminaison similaires :
app.MapGroup("/public/todos")
.MapTodosApi()
.WithTags("Public");
app.MapGroup("/private/todos")
.MapTodosApi()
.WithTags("Private")
.AddEndpointFilterFactory(QueryPrivateTodos)
.RequireAuthorization();
EndpointFilterDelegate QueryPrivateTodos(EndpointFilterFactoryContext factoryContext, EndpointFilterDelegate next)
{
var dbContextIndex = -1;
foreach (var argument in factoryContext.MethodInfo.GetParameters())
{
if (argument.ParameterType == typeof(TodoDb))
{
dbContextIndex = argument.Position;
break;
}
}
// Skip filter if the method doesn't have a TodoDb parameter.
if (dbContextIndex < 0)
{
return next;
}
return async invocationContext =>
{
var dbContext = invocationContext.GetArgument<TodoDb>(dbContextIndex);
dbContext.IsPrivate = true;
try
{
return await next(invocationContext);
}
finally
{
// This should only be relevant if you're pooling or otherwise reusing the DbContext instance.
dbContext.IsPrivate = false;
}
};
}
public static RouteGroupBuilder MapTodosApi(this RouteGroupBuilder group)
{
group.MapGet("/", GetAllTodos);
group.MapGet("/{id}", GetTodo);
group.MapPost("/", CreateTodo);
group.MapPut("/{id}", UpdateTodo);
group.MapDelete("/{id}", DeleteTodo);
return group;
}
Dans ce scénario, vous pouvez utiliser une adresse relative pour l’en-tête Location
dans le résultat 201 Created
:
public static async Task<Created<Todo>> CreateTodo(Todo todo, TodoDb database)
{
await database.AddAsync(todo);
await database.SaveChangesAsync();
return TypedResults.Created($"{todo.Id}", todo);
}
Le premier groupe de points de terminaison correspond uniquement aux requêtes précédées de /public/todos
, accessibles sans authentification. Le second groupe de points de terminaison correspond uniquement aux requêtes préfixées par /private/todos
, qui nécessitent une authentification.
La QueryPrivateTodos
fabrique de filtre de point de terminaison est une fonction locale qui modifie les paramètres TodoDb
du gestionnaire d’itinéraires pour permettre l’accès et le stockage de données todo privées.
Les groupes de routage prennent également en charge les groupes imbriqués et les modèles de préfixe complexes avec des contraintes et des paramètres de routage. Dans l’exemple suivant, un gestionnaire de routage mappé au groupe user
peut capturer les paramètres de routage {org}
et {group}
définis dans les préfixes de groupe externe.
Le préfixe peut également être vide. Cela peut être utile pour ajouter des métadonnées ou des filtres de point de terminaison à un groupe de points de terminaison sans modifier le modèle de routage.
var all = app.MapGroup("").WithOpenApi();
var org = all.MapGroup("{org}");
var user = org.MapGroup("{user}");
user.MapGet("", (string org, string user) => $"{org}/{user}");
L’ajout de filtres ou de métadonnées à un groupe se comporte de la même façon que si vous les ajoutiez individuellement à chaque point de terminaison avant d’ajouter des filtres ou des métadonnées supplémentaires qui ont pu être ajoutés à un groupe interne ou à un point de terminaison spécifique.
var outer = app.MapGroup("/outer");
var inner = outer.MapGroup("/inner");
inner.AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation("/inner group filter");
return next(context);
});
outer.AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation("/outer group filter");
return next(context);
});
inner.MapGet("/", () => "Hi!").AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation("MapGet filter");
return next(context);
});
Dans l’exemple ci-dessus, le filtre externe enregistre la requête entrante avant le filtre interne, même si elle a été ajoutée en deuxième. Étant donné que les filtres ont été appliqués à différents groupes, l’ordre dans lequel ils ont été ajoutés les uns par rapport aux autres n’a pas d’importance. Les filtres d’ordre ajoutés sont importants s’ils sont appliqués au même groupe ou au même point de terminaison spécifique.
Une requête sur /outer/inner/
journalisera les éléments suivants :
/outer group filter
/inner group filter
MapGet filter
gRPC
Transcodage JSON
Le transcodage JSON gRPC est une extension pour ASP.NET Core qui crée des API RESTful JSON pour les services gRPC. Le transcodage JSON gRPC permet :
- Aux applications d’appeler des services gRPC avec des concepts HTTP familiers.
- Aux applications gRPC ASP.NET Core de prendre en charge à la fois les API gRPC et JSON RESTful sans répliquer de fonctionnalités.
- La prise en charge expérimentale de la génération d’OpenAPI à partir d’API RESTful transcodées grâce à l’intégration à Swashbuckle.
Pour plus d’informations, consultez Transcodage JSON gRPC dans les applications gRPC ASP.NET Core et Utiliser OpenAPI avec les applications transcodées JSON gRPC ASP.NET Core.
Contrôles d’intégrité gRPC dans ASP.NET Core
Le protocole de contrôle d’intégrité gRPC est une norme permettant de signaler l’intégrité des applications serveur gRPC. Une application expose des contrôles d’intégrité en tant que service gRPC. Ils sont généralement utilisés avec un service de supervision externe pour vérifier l’état d’une application.
ASP.NET Core gRPC a ajouté la prise en charge intégrée des vérifications d’intégrité gRPC avec le package Grpc.AspNetCore.HealthChecks
. Les résultats des contrôles d’intégrité .NET sont signalés aux appelants.
Pour plus d’informations, consultez Contrôles d’intégrité gRPC dans ASP.NET Core.
Amélioration de la prise en charge des informations d’identification d’appel
Les informations d’identification d’appel sont la méthode recommandée pour configurer un client gRPC afin d’envoyer un jeton d’authentification au serveur. Les clients gRPC prennent en charge deux nouvelles fonctionnalités pour faciliter l’utilisation des informations d’identification d’appel :
- Prise en charge des informations d’identification d’appel avec les connexions en texte clair. Auparavant, un appel gRPC envoyait uniquement les informations d’identification d’appel si la connexion était sécurisée avec TLS. Un nouveau paramètre sur
GrpcChannelOptions
, appeléUnsafeUseInsecureChannelCallCredentials
, permet de personnaliser ce comportement. Il existe des implications en matière de sécurité si vous ne sécurisez pas une connexion avec TLS. - Une nouvelle méthode appelée
AddCallCredentials
est disponible avec la fabrique de clients gRPC.AddCallCredentials
est un moyen rapide de configurer les informations d’identification d’appel pour un client gRPC, et s’intègre bien à l’injection de dépendances (DI).
Le code suivant configure la fabrique de clients gRPC pour envoyer des métadonnées Authorization
:
builder.Services
.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.AddCallCredentials((context, metadata) =>
{
if (!string.IsNullOrEmpty(_token))
{
metadata.Add("Authorization", $"Bearer {_token}");
}
return Task.CompletedTask;
});
Pour plus d’informations, consultez Configurer un jeton de porteur avec la fabrique de clients gRPC.
SignalR
Résultats du client
Le serveur prend désormais en charge la demande d’un résultat à partir d’un client. Cela nécessite que le serveur utilise ISingleClientProxy.InvokeAsync
et que le client retourne un résultat à partir de son gestionnaire .On
. Les hubs fortement typés peuvent également retourner des valeurs à partir de méthodes d’interface.
Pour plus d’informations, consultez Résultats du client
Injection de dépendances pour les méthodes hub SignalR
Les méthodes de hub SignalR prennent désormais en charge l’injection de services via l’injection de dépendances (DI).
Les constructeurs de hub peuvent accepter les services de DI en tant que paramètres, qui peuvent être stockés dans des propriétés sur la classe pour une utilisation dans une méthode de hub. Pour plus d’informations, consultez Injecter des services dans un hub
Blazor
Gérer les événements de changement d’emplacement et l’état de navigation
Dans .NET 7, Blazor prend en charge les événements de changement d’emplacement et le maintien de l’état de navigation. Cela vous permet d’avertir les utilisateurs concernant le travail non enregistré ou d’effectuer des actions associées lorsque l’utilisateur effectue une navigation sur une page.
Pour plus d’informations, consultez les sections suivantes de l’article Routage et navigation :
Modèles de projet Blazor vides
Blazor propose deux nouveaux modèles de projet pour commencer à partir de zéro. Les nouveaux modèles Application Blazor Server vide et Application Blazor WebAssembly vide sont semblables à leurs équivalents non vides, mais sans exemple de code. Ces modèles vides incluent uniquement une page d’home de base, et nous avons supprimé Bootstrap pour que vous puissiez commencer avec un autre framework CSS.
Pour plus d’informations, consultez les articles suivants :
Éléments personnalisés Blazor
Le package Microsoft.AspNetCore.Components.CustomElements
permet de créer des éléments DOM personnalisés basés sur des normes à l’aide de Blazor.
Pour plus d’informations, consultez Composants ASP.NET Core Razor.
Modificateurs de liaison (@bind:after
, @bind:get
, @bind:set
)
Important
Les fonctionnalités @bind:after
/@bind:get
/@bind:set
reçoivent actuellement d’autres mises à jour. Pour tirer parti des dernières mises à jour, vérifiez que vous avez installé la dernière version du SDK.
L’utilisation d’un paramètre de rappel d’événement ([Parameter] public EventCallback<string> ValueChanged { get; set; }
) n’est pas prise en charge. Au lieu de cela, passez une retournant Action ou Task à @bind:set
/@bind:after
.
Pour plus d’informations, consultez les ressources suivantes :
Dans .NET 7, vous pouvez exécuter une logique asynchrone une fois qu’un événement de liaison est terminé à l’aide du nouveau modificateur @bind:after
. Dans l’exemple suivant, la méthode asynchrone PerformSearch
s’exécute automatiquement après la détection des modifications apportées au texte de recherche :
<input @bind="searchText" @bind:after="PerformSearch" />
@code {
private string searchText;
private async Task PerformSearch()
{
...
}
}
Dans .NET 7, il est également plus facile de configurer la liaison pour les paramètres de composant. Les composants peuvent prendre en charge la liaison de données bidirectionnelle en définissant une paire de paramètres :
@bind:get
: spécifie la valeur à lier.@bind:set
: spécifie un rappel au moment où la valeur change.
Les modificateurs @bind:get
et @bind:set
sont toujours utilisés ensemble.
Exemples :
@* Elements *@
<input type="text" @bind="text" @bind:after="() => { }" />
<input type="text" @bind:get="text" @bind:set="(value) => { }" />
<input type="text" @bind="text" @bind:after="AfterAsync" />
<input type="text" @bind:get="text" @bind:set="SetAsync" />
<input type="text" @bind="text" @bind:after="() => { }" />
<input type="text" @bind:get="text" @bind:set="(value) => { }" />
<input type="text" @bind="text" @bind:after="AfterAsync" />
<input type="text" @bind:get="text" @bind:set="SetAsync" />
@* Components *@
<InputText @bind-Value="text" @bind-Value:after="() => { }" />
<InputText @bind-Value:get="text" @bind-Value:set="(value) => { }" />
<InputText @bind-Value="text" @bind-Value:after="AfterAsync" />
<InputText @bind-Value:get="text" @bind-Value:set="SetAsync" />
<InputText @bind-Value="text" @bind-Value:after="() => { }" />
<InputText @bind-Value:get="text" @bind-Value:set="(value) => { }" />
<InputText @bind-Value="text" @bind-Value:after="AfterAsync" />
<InputText @bind-Value:get="text" @bind-Value:set="SetAsync" />
@code {
private string text = "";
private void After(){}
private void Set() {}
private Task AfterAsync() { return Task.CompletedTask; }
private Task SetAsync(string value) { return Task.CompletedTask; }
}
Pour plus d’informations sur le composant InputText
, consultez Composants d’entrée Blazor ASP.NET Core.
Améliorations du rechargement à chaud
Dans .NET 7, la prise en charge du rechargement à chaud comprend les éléments suivants :
- Les composants réinitialisent leurs paramètres à leurs valeurs par défaut lorsqu’une valeur est supprimée.
- Blazor WebAssembly:
- Ajout de nouveaux types.
- Ajout des classes imbriquées.
- Ajout de méthodes statiques et d’instance aux types existants.
- Ajout de champs et de méthodes statiques aux types existants.
- Ajout de lambdas statiques aux méthodes existantes.
- Ajout de lambdas qui capturent
this
pour les méthodes existantes qui capturaient déjàthis
précédemment.
Demandes d’authentification dynamique avec MSAL dans Blazor WebAssembly
Nouveauté de .NET 7, Blazor WebAssembly prend en charge la création de requêtes d’authentification dynamique au moment de l’exécution avec des paramètres personnalisés pour gérer les scénarios d’authentification avancés.
Pour plus d’informations, consultez les articles suivants :
- Sécuriser ASP.NET Core Blazor WebAssembly
- Autres scénarios de sécurité ASP.NET Core Blazor WebAssembly
Améliorations du débogage de Blazor WebAssembly
Le débogage de Blazor WebAssembly présente les améliorations suivantes :
- Prise en charge du paramètre Uniquement mon code pour afficher ou masquer les membres de type qui ne proviennent pas du code utilisateur.
- Prise en charge de l’inspection des tableaux multidimensionnels.
- La pile d’appels affiche désormais le nom correct pour les méthodes asynchrones.
- Amélioration de l’évaluation des expressions.
- Gestion correcte du mot clé
new
sur les membres dérivés. - Prise en charge des attributs liés au débogueur dans
System.Diagnostics
.
Prise en charge de System.Security.Cryptography
sur WebAssembly
.NET 6 prenait en charge la famille SHA d’algorithmes de hachage lors de l’exécution sur WebAssembly. .NET 7 propose davantage d’algorithmes de chiffrement en tirant parti de SubtleCrypto, lorsque cela est possible, et en revenant à une implémentation .NET quand SubtleCrypto ne peut pas être utilisé. Les algorithmes suivants sont pris en charge sur WebAssembly dans .NET 7 :
- SHA1
- SHA256
- SHA384
- SHA512
- HMACSHA1
- HMACSHA256
- HMACSHA384
- HMACSHA512
- AES-CBC
- PBKDF2
- HKDF
Pour plus d’informations, consultez Les développeurs ciblant browser-wasm peuvent utiliser les API de chiffrement web (dotnet/runtime #40074).
Injection de services dans des attributs de validation personnalisés
Vous pouvez maintenant injecter des services dans des attributs de validation personnalisés. Blazor configure le ValidationContext
afin qu’il puisse être utilisé en tant que fournisseur de services.
Pour plus d’informations, consultez Validation des formulaires Blazor ASP.NET Core.
Composants Input*
en dehors d’un EditContext
/EditForm
Les composants d’entrée intégrés sont désormais pris en charge en dehors d’un formulaire dans le balisage de composant Razor.
Pour obtenir plus d’informations, consultez Composants d’entrée Blazor ASP.NET Core.
Changements au modèle de projet
Lorsque .NET 6 a été publié l’année dernière, le balisage HTML de la page _Host
(Pages/_Host.chstml
) a été fractionné entre la page _Host
et une nouvelle page _Layout
(Pages/_Layout.chstml
) dans le modèle de projet Blazor Server .NET 6.
Dans .NET 7, le balisage HTML a été combiné avec la page _Host
dans les modèles de projet.
Plusieurs modifications supplémentaires ont été apportées aux modèles de projet Blazor. Il n’est pas possible de répertorier chaque modification apportée aux modèles dans la documentation. Pour migrer une application vers .NET 7 afin d’adopter toutes les modifications, consultez Migrer d’ASP.NET Core 6.0 vers 7.0.
Composant QuickGrid
expérimental
Le nouveau composant QuickGrid
fournit un composant de grille de données pratique pour les exigences les plus courantes et en tant qu’architecture de référence et base de référence pour toute personne qui crée des composants de grille de données Blazor.
Pour plus d’informations, consultez Composant QuickGrid ASP.NET Core Blazor.
Démonstration en direct : QuickGrid pour l’exemple d’application Blazor
Améliorations apportées à la virtualisation
Améliorations apportées à la virtualisation dans .NET 7 :
- Le composant
Virtualize
prend en charge l’utilisation du document lui-même comme racine de défilement, comme alternative à l’utilisation d’un autre élément avecoverflow-y: scroll
appliqué. - Si le composant
Virtualize
est placé à l’intérieur d’un élément qui nécessite un nom de balise enfant spécifique,SpacerElement
vous permet d’obtenir ou de définir le nom de la balise d’espaceur de virtualisation.
Pour plus d’informations, consultez les sections suivantes de l’article Virtualisation :
Mises à jour de MouseEventArgs
MovementX
et MovementY
ont été ajoutés à MouseEventArgs
.
Pour plus d’informations, consultez Gestion des événements ASP.NET Core Blazor.
Nouvelle page de chargement Blazor
Le modèle de projet Blazor WebAssembly a une nouvelle interface utilisateur de chargement qui indique la progression du chargement de l’application.
Pour plus d’informations, consultez Démarrage ASP.NET Core Blazor.
Amélioration des diagnostics pour l’authentification dans Blazor WebAssembly
Pour diagnostiquer les problèmes d’authentification dans les applications Blazor WebAssembly, la journalisation détaillée est disponible.
Pour plus d’informations, consultez Journalisation ASP.NET Core Blazor.
Interopérabilité JavaScript sur WebAssembly
L’API d’interopérabilité [JSImport]
/[JSExport]
JavaScript est un nouveau mécanisme de bas niveau permettant d’utiliser .NET dans Blazor WebAssembly et les applications JavaScript. Avec cette nouvelle fonctionnalité d’interopérabilité JavaScript, vous pouvez appeler du code .NET à partir de JavaScript à l’aide du runtime WebAssembly .NET et appeler la fonctionnalité JavaScript à partir de .NET sans dépendance sur le modèle de composant d’interface utilisateur Blazor.
Pour plus d'informations :
- Interopérabilité Javascript JSImport/JSExport avec ASP.NET Core Blazor : concerne uniquement les applications Blazor WebAssembly.
- Interopérabilité JavaScript `[JSImport]`/`[JSImport]` dans WebAssembly .NET : se rapporte uniquement aux applications JavaScript qui ne dépendent pas du modèle de composant de l’interface utilisateur Blazor.
Inscription conditionnelle du fournisseur d’état d’authentification
Avant la publication de .NET 7, AuthenticationStateProvider
était inscrit dans le conteneur de service avec AddScoped
. Cela rendait difficile le débogage d’applications, en imposant un ordre spécifique d’inscriptions de service lors de la fourniture d’une implémentation personnalisée. En raison des changements du framework interne au fil du temps, il n’est plus nécessaire d’inscrire AuthenticationStateProvider
auprès de AddScoped
.
Dans le code du développeur, apportez la modification suivante à l’inscription du service de fournisseur d’état d’authentification :
- builder.Services.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
+ builder.Services.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
Dans l’exemple précédent, ExternalAuthStateProvider
est l’implémentation du service du développeur.
Améliorations apportées aux outils de génération de WebAssembly .NET
Nouvelles fonctionnalités de la charge de travail wasm-tools
pour .NET 7 qui permettent d’améliorer les performances et de gérer les exceptions :
- Prise en charge de Single Instruction, Multiple Data (SIMD) WebAssembly (uniquement avec AOT, non pris en charge par Apple Safari)
- Prise en charge de la gestion des exceptions WebAssembly
Pour plus d’informations, consultez Outils de génération ASP.NET Core Blazor WebAssembly et compilation AOT (ahead-of-time).
Blazor Hybrid
URL externes
Une option a été ajoutée pour permettre l’ouverture de pages web externes dans le navigateur.
Pour plus d’informations, consultez Routage et navigation ASP.NET Core Blazor Hybrid.
Sécurité
De nouvelles instructions sont disponibles pour les scénarios de sécurité Blazor Hybrid. Pour plus d’informations, consultez les articles suivants :
- Authentification et autorisation avec ASP.NET Core Blazor Hybrid
- Considérations relatives à la sécurité avec ASP.NET Core Blazor Hybrid
Performances
Intergiciel de mise en cache de sortie
La mise en cache de sortie est un nouvel intergiciel qui stocke les réponses d’une application web et les sert à partir d’un cache au lieu de les calculer à chaque fois. La mise en cache de sortie diffère de la mise en cache des réponses des manières suivantes :
- Le comportement de mise en cache est configurable sur le serveur.
- Les entrées de cache peuvent être invalidées par programmation.
- Le verrouillage des ressources atténue le risque de tamponnement du cache et de troupeau tonitruant.
- La revalidation du cache signifie que le serveur peut retourner un code d’état HTTP
304 Not Modified
au lieu d’un corps de réponse mis en cache. - Le support de stockage du cache est extensible.
Pour plus d’informations, consultez Vue d’ensemble de la mise en cache et Intergiciel de mise en cache de sortie.
Améliorations de HTTP/3
Cette version :
- Rend HTTP/3 entièrement pris en charge par ASP.NET Core, la prise en charge n’est plus expérimentale.
- Améliore la prise en charge de Kestrel pour HTTP/3. Les deux principaux domaines d’amélioration sont la parité des fonctionnalités avec HTTP/1.1 et HTTP/2 et les performances.
- Fournit une prise en charge complète de UseHttps(ListenOptions, X509Certificate2) avec HTTP/3. Kestrel offre des options avancées pour la configuration des certificats de connexion, comme le raccordement à l’indication du nom du serveur (SNI).
- Ajoute la prise en charge de HTTP/3 sur HTTP.sys et IIS.
L’exemple suivant montre comment utiliser un rappel SNI pour résoudre les options TLS :
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Https;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(options =>
{
options.ListenAnyIP(8080, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
listenOptions.UseHttps(new TlsHandshakeCallbackOptions
{
OnConnection = context =>
{
var options = new SslServerAuthenticationOptions
{
ServerCertificate =
MyResolveCertForHost(context.ClientHelloInfo.ServerName)
};
return new ValueTask<SslServerAuthenticationOptions>(options);
},
});
});
});
Un travail important a été effectué dans .NET 7 pour réduire les allocations HTTP/3. Vous pouvez voir certaines de ces améliorations dans les tirages GitHub suivants :
- HTTP/3 : Éviter les allocations de jeton d’annulation par requête
- HTTP/3 : Éviter les allocations ConnectionAbortedException
- HTTP/3 : Regroupement de ValueTask
Améliorations des performances de HTTP/2
.NET 7 repense la façon dont Kestrel traite les requêtes HTTP/2. Les applications ASP.NET Core avec des connexions HTTP/2 occupées noteront une utilisation réduite du processeur et un débit plus élevé.
Auparavant, l’implémentation du multiplexage HTTP/2 s’appuyait sur un verrou contrôlant la requête pouvant écrire dans la connexion TCP sous-jacente. Une file d’attente thread-safe remplace le verrou d’écriture. Maintenant, plutôt que de se battre pour déterminer quel thread peut utiliser le verrou d’écriture, les requêtes sont maintenant mises en file d’attente, et un consommateur dédié les traite. Les ressources processeur précédemment gaspillées sont disponibles pour le rest de l’application.
L’un des endroits où ces améliorations peuvent être remarquées est dans gRPC, une infrastructure RPC populaire qui utilise HTTP/2. Les benchmarks Kestrel + gRPC montrent une amélioration spectaculaire :
Des modifications ont été apportées au code d’écriture de trame HTTP/2, améliorant les performances lorsque plusieurs flux tentent d’écrire des données sur une seule connexion HTTP/2. Nous répartissons maintenant le travail TLS dans le pool de threads et publions plus rapidement un verrou d’écriture que d’autres flux peuvent acquérir pour écrire leurs données. La réduction des temps d’attente peut entraîner des améliorations significatives des performances dans les cas où il existe une contention pour ce verrou d’écriture. Un benchmark gRPC avec 70 flux sur une seule connexion (avec TLS) a montré une amélioration d’environ 15 % des requêtes par seconde (RPS) avec cette modification.
Prise en charge de WebSockets Http/2
.NET 7 introduit la prise en charge de WebSockets sur HTTP/2 pour Kestrel, le client JavaScript SignalR et SignalR avec Blazor WebAssembly.
L’utilisation de WebSockets sur HTTP/2 tire parti des nouvelles fonctionnalités, dont les suivantes :
- Compression des en-têtes.
- Multiplexage, qui réduit le temps et les ressources nécessaires lors de l’envoi de plusieurs demandes au serveur.
Ces fonctionnalités prises en charge sont disponibles dans Kestrel sur toutes les plateformes prenant en charge HTTP/2. La négociation de version étant automatique dans les navigateurs et Kestrel, aucune nouvelle API n’est nécessaire.
Pour plus d’informations, consultez Prise en charge de WebSockets Http/2.
Améliorations des performances de Kestrel sur les machines à nombreux cœurs
Kestrel utilise ConcurrentQueue<T> à de nombreuses fins. L’un des objectifs est de planifier les opérations d’E/S dans le transport de socket par défaut de Kestrel. Le partitionnement de la ConcurrentQueue
en fonction du socket associé réduit la contention et augmente le débit sur les machines avec de nombreux cœurs de processeur.
Le profilage sur des machines à nombreux cœurs sur .NET 6 a montré une contention significative dans l’une des autres instances ConcurrentQueue
de Kestrel, le PinnedMemoryPool
que Kestrel utilise pour mettre en cache des mémoires tampons d’octets.
Dans .NET 7, le pool de mémoire de Kestrel est partitionné de la même façon que sa file d’attente d’E/S, ce qui entraîne une contention beaucoup plus faible et un débit plus élevé sur les machines à nombreux cœurs. Sur les machines virtuelles ARM64 à 80 cœurs, nous constatons une amélioration de plus de 500 % des réponses par seconde (RPS) dans le benchmark en texte clair TechEmpower. Sur les machines virtuelles AMD à 48 cœurs, l’amélioration est de près de 100 % dans notre benchmark JSON HTTPS.
Événement ServerReady
pour mesurer le temps de démarrage
Les applications utilisant EventSource peuvent mesurer le temps de démarrage pour comprendre et optimiser les performances de démarrage. Le nouvel événement ServerReady
dans Microsoft.AspNetCore.Hosting représente le point où le serveur est prêt à répondre aux requêtes.
Serveur
Nouvel événement ServerReady pour mesurer le temps de démarrage
L’événement ServerReady
a été ajouté pour mesurer le temps de démarrage des applications ASP.NET Core.
IIS
Cliché instantané dans IIS
La prise de clichés instantanés des assemblys d’application dans le module ASP.NET Core (ANCM) pour IIS peut offrir une meilleure expérience utilisateur que l’arrêt de l’application en déployant un fichier App Offline.
Pour plus d’informations, consultez Clichés instantanés dans IIS.
Divers
Améliorations de la chaîne de certificats complète de Kestrel
HttpsConnectionAdapterOptions offre une nouvelle propriété ServerCertificateChain de type X509Certificate2Collection, qui facilite la validation des chaînes de certificats en autorisant la spécification d’une chaîne complète incluant des certificats intermédiaires. Pour plus d’informations, consultez dotnet/aspnetcore#21513.
dotnet watch run
Sortie de console améliorée pour dotnet watch
La sortie de console de dotnet watch a été améliorée pour mieux s’aligner sur la journalisation d’ASP.NET Core et pour se distinguer avec des 😮emojis😍.
Voici un exemple de ce à quoi ressemble la nouvelle sortie :
Pour plus d’informations, consultez cette requête de tirage GitHub.
Configurer dotnet watch pour qu’il redémarre toujours pour les modifications non applicables
Les modifications non applicables sont des modifications qui ne peuvent pas être rechargées à chaud. Pour configurer dotnet watch pour qu’il redémarre toujours sans invite de modifications non applicables, définissez la variable d’environnement DOTNET_WATCH_RESTART_ON_RUDE_EDIT
sur true
.
Mode sombre pour la page d’exceptions du développeur
La prise en charge du mode sombre a été ajoutée à la page d’exceptions du développeur, grâce à une contribution de Patrick Westerhoff. Pour tester le mode sombre dans un navigateur, à partir de la page Outils de développement, définissez le mode sur Sombre. Par exemple, dans Firefox :
Dans Chrome :
Option de modèle de projet permettant d’utiliser la méthode Program.Main au lieu d’instructions de niveau supérieur
Les modèles .NET 7 incluent une option permettant de ne pas utiliser d’instructions de niveau supérieur et de générer un namespace
et une méthode Main
déclarée sur une classe Program
.
À l’aide de l’interface CLI .NET, utilisez l’option --use-program-main
:
dotnet new web --use-program-main
Avec Visual Studio, cochez la nouvelle case Ne pas utiliser d’instructions de niveau supérieur lors de la création du projet :
Modèles Angular et React mis à jour
Le modèle de projet Angular a été mis à jour vers Angular 14. Le modèle de projet React a été mis à jour vers React 18.2.
Gérer les jetons web JSON dans le développement avec dotnet user-jwts
Le nouvel outil en ligne de commande dotnet user-jwts
peut créer et gérer des jetons web JSON (JWT) locaux spécifiques à l’application. Pour plus d’informations, consultez Gérer les jetons web JSON en développement avec dotnet user-jwts.
Prise en charge des en-têtes de requête supplémentaires dans W3CLogger
Vous pouvez maintenant spécifier des en-têtes de requête supplémentaires à consigner lors de l’utilisation de l’enregistreur d’événements W3C en appelant AdditionalRequestHeaders()
sur W3CLoggerOptions :
services.AddW3CLogging(logging =>
{
logging.AdditionalRequestHeaders.Add("x-forwarded-for");
logging.AdditionalRequestHeaders.Add("x-client-ssl-protocol");
});
Pour plus d’informations, consultez Options W3CLogger.
Décompression des requêtes
Nouvel Intergiciel de décompression de requête :
- Permet aux points de terminaison d’API d’accepter les requêtes avec du contenu compressé.
- Utilise l’en-tête HTTP
Content-Encoding
pour identifier et décompresser automatiquement les requêtes qui contiennent du contenu compressé. - Élimine la nécessité d’écrire du code pour gérer les requêtes compressées.
Pour plus d’informations, consultez Intergiciel de décompression de requête.