Gestion de session et d’état dans ASP.NET Core

Par Rick Anderson, Kirk Larkin et Diana LaRose

HTTP est un protocole sans état. Par défaut, les requêtes HTTP sont des messages indépendants qui ne conservent pas les valeurs utilisateur. Cet article décrit plusieurs approches pour conserver les données utilisateur entre les demandes.

Gestion de l'état

L’état peut être stocké à l’aide de plusieurs approches. Chacune d’elles est abordée plus loin dans cet article.

Approche du stockage Mécanisme de stockage
Cookies cookies HTTP. Peuvent inclure des données stockées à l’aide de code d’application côté serveur.
État de session cookies HTTP et code d’application côté serveur
TempData cookies HTTP ou état de session
Chaînes de requête Chaînes de requête HTTP
Champs masqués Champs de formulaires HTTP
HttpContext.Items Code d’application côté serveur
Cache Code d’application côté serveur

SignalR/Blazor Server et gestion de l’état basé sur le contexte HTTP

Les applications SignalR ne doivent pas utiliser l’état de session et d’autres approches de gestion d’état qui s’appuient sur un contexte HTTP stable pour stocker des informations. Les applications SignalR peuvent stocker l’état par connexion dans Context.Items dans le hub. Pour plus d’informations et d’autres approches de gestion de l’état pour les applications Blazor Server, consultez Gestion de l’état ASP.NET Core Blazor.

Cookies

Les Cookies stockent des données entre les demandes. Comme les cookies sont envoyés avec chaque demande, il est essentiel de limiter leur taille au minimum. Dans l’idéal, un cookie doit stocker uniquement un identificateur et les données stockées par l’application. La plupart des navigateurs limitent la taille des cookies à 4096 octets. Seul un nombre limité de cookies est disponible pour chaque domaine.

Pour éviter les risques de falsification, les cookies doivent être validés par l’application. LesCookies peuvent être supprimés par les utilisateurs et ils expirent sur les clients. Toutefois, les cookies constituent généralement la forme la plus durable de persistance des données sur le client.

Les Cookies servent souvent à personnaliser le contenu pour un utilisateur connu. L’utilisateur est uniquement identifié, et pas authentifié dans la plupart des cas. Le cookie peut stocker le nom de l’utilisateur, le nom du compte ou l’ID utilisateur unique, tel qu’un GUID. Le cookie peut être utilisé pour accéder aux paramètres personnalisés de l’utilisateur, telles que sa couleur d’arrière-plan de site web par défaut.

Consultez le Règlement général sur la protection des données (RGPD) de l’Union Européenne lors de l’émission de cookies et de la gestion de la confidentialité. Pour plus d’informations, consultez Prise en charge du règlement général sur la protection des données (RGPD) de l’Union Européenne dans ASP.NET Core.

État de session

L’état de session est un scénario ASP.NET Core pour le stockage des données utilisateur pendant que l’utilisateur parcourt une application web. L’état de session utilise un magasin tenu à jour par l’application afin de conserver les données entre les requêtes d’un client. Les données de session sont sauvegardées par un cache et considérées comme des données éphémères. Le site doit continuer à fonctionner sans les données de session. Les données d’application critiques doivent être stockées dans la base de données utilisateur et mises en cache dans la session uniquement à des fins d’optimisation des performances.

La session n’est pas prise en charge dans les applications SignalR car un hub SignalR peut s’exécuter indépendamment d’un contexte HTTP. Par exemple, cela peut se produire quand une longue requête d’interrogation est ouverte par un hub au-delà de la durée de vie du contexte de la requête HTTP.

ASP.NET Core tient à jour l’état de session en fournissant au client un cookie qui contient un ID de session. L’ID de session du cookie :

  • Est envoyé à l’application avec chaque demande.
  • Est utilisé par l’application pour récupérer les données de session.

L’état de session présente les comportements suivants :

  • Le cookie de session est spécifique au navigateur. Les sessions ne sont pas partagées entre les navigateurs.
  • Les cookies de session sont supprimés quand la session du navigateur se termine.
  • Si un cookie est reçu pour une session qui a expiré, une session qui utilise le même cookie de session est créée.
  • Les sessions vides ne sont pas conservées. La session doit avoir au moins une valeur définie pour pouvoir être conservée entre les demandes. Quand une session n’est pas conservée, un nouvel ID de session est généré pour chaque nouvelle requête.
  • L’application conserve une session pendant une période limitée après la dernière requête. L’application définit le délai d’expiration d’une session ou utilise la valeur par défaut de 20 minutes. L’état de session est idéal pour stocker des données utilisateur :
    • spécifiques à une session particulière ;
    • où les données ne nécessitent pas un stockage permanent entre les sessions.
  • Les données de session sont supprimées quand l’implémentation ISession.Clear est appelée ou quand la session expire.
  • Il n’existe aucun mécanisme par défaut permettant de signaler au code d’application qu’un navigateur client a été fermé ou que le cookie de session a été supprimé ou a expiré sur le client.
  • Les cookies d’état de session ne sont pas marqués comme essentiels par défaut. L’état de session n’est pas fonctionnel, sauf si le suivi est autorisé par le visiteur du site. Pour plus d’informations, consultez Prise en charge du règlement général sur la protection des données (RGPD) de l’Union Européenne dans ASP.NET Core.
  • Remarque : Il n’existe aucun remplacement pour la fonctionnalité de session sans cookie de l’infrastructure ASP.NET, car elle est considérée comme non sécurisée et peut entraîner des attaques de fixation de session.

Avertissement

Ne stockez pas de données sensibles dans l’état de session. L’utilisateur risque de ne pas fermer le navigateur et de ne pas effacer le cookie de session. Certains navigateurs conservent des cookies de session valides entre les fenêtres du navigateur. Une session peut ne pas être limitée à un seul utilisateur. L’utilisateur suivant peut continuer à parcourir l’application avec le même cookie de session.

Le fournisseur de cache en mémoire stocke les données de session dans la mémoire du serveur où réside l’application. Dans un scénario de batterie de serveurs :

Configurer l’état de session

L’intergiciel pour gérer l’état de session est inclus dans l’infrastructure. Pour activer le middleware Session, Program.cs doit contenir les éléments suivants :

Le code suivant montre comment configurer le fournisseur de session en mémoire avec une implémentation en mémoire par défaut de IDistributedCache :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDistributedMemoryCache();

builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromSeconds(10);
    options.Cookie.HttpOnly = true;
    options.Cookie.IsEssential = true;
});

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.UseSession();

app.MapRazorPages();
app.MapDefaultControllerRoute();

app.Run();

Le code précédent définit un court délai d’attente pour simplifier les tests.

L’ordre des middlewares est important. Appelez UseSession après UseRouting et avant MapRazorPages et MapDefaultControllerRoute. Consultez Ordre des intergiciels.

HttpContext.Session est disponible une fois l’état de session configuré.

HttpContext.Session n’est pas accessible avant que UseSession ait été appelée.

Il est impossible de créer une nouvelle session avec un nouveau cookie de session une fois que l’application a commencé à écrire dans le flux de réponse. L’exception est enregistrée dans le journal de serveur web et n’est pas affichée pas dans le navigateur.

Charger l’état de session de façon asynchrone

Le fournisseur de session par défaut dans ASP.NET Core charge des enregistrements de session de façon asynchrone à partir du magasin de stockage sous-jacent IDistributedCache uniquement si la méthode ISession.LoadAsync est appelée explicitement avant les méthodes TryGetValue, Set ou Remove. Si LoadAsync n’est pas appelée en premier, l’enregistrement de session sous-jacent est chargé de façon synchrone, ce qui peut entraîner une baisse des performances à l’échelle.

Pour forcer les applications à appliquer ce modèle, incluez les implémentations DistributedSessionStore et DistributedSession dans un wrapper, avec des versions qui lèvent une exception si la méthode LoadAsync n’est pas appelée avant TryGetValue, Set ou Remove. Inscrivez ensuite les versions incluses dans le wrapper auprès du conteneur de services.

Options de session

Pour substituer les valeurs de session par défaut, utilisez SessionOptions.

Option Description
Cookie Détermine les paramètres utilisés pour créer le cookie. Name a la valeur par défaut SessionDefaults.CookieName (.AspNetCore.Session). Path a la valeur par défaut SessionDefaults.CookiePath (/). SameSite a la valeur par défaut SameSiteMode.Lax (1). HttpOnly a la valeur par défaut true. IsEssential a la valeur par défaut false.
IdleTimeout IdleTimeout indique la durée pendant laquelle la session peut être inactive avant que son contenu soit abandonné. Chaque accès à la session réinitialise le délai d’expiration. Ce paramètre s’applique uniquement au contenu de la session, et non au cookie. La valeur par défaut est 20 minutes.
IOTimeout Durée maximale autorisée pour charger une session à partir du magasin ou pour la valider dans le magasin. Ce paramètre peut s’appliquer uniquement aux opérations asynchrones. Vous pouvez désactiver ce délai d’expiration à l’aide de InfiniteTimeSpan. La valeur par défaut est de 1 minute.

La session utilise un cookie pour suivre et identifier les demandes reçues d’un navigateur. Par défaut, ce cookie se nomme .AspNetCore.Session et utilise le chemin /. Étant donné que le cookie par défaut ne spécifie pas de domaine, il n’est pas mis à disposition du script côté client dans la page (car HttpOnly a la valeur par défaut true).

Pour substituer les valeurs de session de cookie par défaut, utilisez SessionOptions :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDistributedMemoryCache();

builder.Services.AddSession(options =>
{
    options.Cookie.Name = ".AdventureWorks.Session";
    options.IdleTimeout = TimeSpan.FromSeconds(10);
    options.Cookie.IsEssential = true;
});

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.UseSession();

app.MapRazorPages();
app.MapDefaultControllerRoute();

app.Run();

L’application utilise la propriété IdleTimeout pour déterminer la durée pendant laquelle une session peut rester inactive avant que son contenu dans le cache du serveur soit abandonné. Cette propriété est indépendante du délai d’expiration du cookie. Chaque requête qui passe par le middleware Session réinitialise le délai d’expiration.

L’état de session est sans verrouillage. Si deux requêtes tentent simultanément de modifier le contenu d’une session, la dernière requête remplace la première. Session est implémentée comme une session cohérente, ce qui signifie que tout le contenu est stocké au même emplacement. Quand deux requêtes tentent de modifier différentes valeurs de session, la dernière requête peut remplacer les modifications de session effectuées par la première.

Définir et obtenir des valeurs Session

L’état de session est accessible à partir d’une classe RazorPageModel Pages ou d’une classe Controller MVC avec HttpContext.Session. Cette propriété est une implémentation ISession.

L’implémentation de ISession fournit plusieurs méthodes d’extension pour définir et récupérer des valeurs de chaîne et d’entier. Les méthodes d’extension se trouvent dans l’espace de noms Microsoft.AspNetCore.Http.

Méthodes d’extension ISession :

L’exemple suivant récupère la valeur de session pour la clé IndexModel.SessionKeyName (_Name dans l’exemple d’application) dans une page Razor Pages :

@page
@using Microsoft.AspNetCore.Http
@model IndexModel

...

Name: @HttpContext.Session.GetString(IndexModel.SessionKeyName)

L’exemple suivant montre comment définir et obtenir un entier et une chaîne :

public class IndexModel : PageModel
{
    public const string SessionKeyName = "_Name";
    public const string SessionKeyAge = "_Age";

    private readonly ILogger<IndexModel> _logger;

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

    public void OnGet()
    {
        if (string.IsNullOrEmpty(HttpContext.Session.GetString(SessionKeyName)))
        {
            HttpContext.Session.SetString(SessionKeyName, "The Doctor");
            HttpContext.Session.SetInt32(SessionKeyAge, 73);
        }
        var name = HttpContext.Session.GetString(SessionKeyName);
        var age = HttpContext.Session.GetInt32(SessionKeyAge).ToString();

        _logger.LogInformation("Session Name: {Name}", name);
        _logger.LogInformation("Session Age: {Age}", age);
    }
}

Le balisage suivant affiche les valeurs de session sur une page Razor :

@page
@model PrivacyModel
@{
    ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<div class="text-center">
<p><b>Name:</b> @HttpContext.Session.GetString("_Name");<b>Age:

</b> @HttpContext.Session.GetInt32("_Age").ToString()</p>
</div>


Toutes les données de session doivent être sérialisées pour activer un scénario de cache distribué, même si vous utilisez le cache en mémoire. Les sérialiseurs de chaîne et d’entier sont fournis par les méthodes d’extension de ISession. Les types complexes doivent être sérialisés par l’utilisateur à l’aide d’un autre mécanisme, tel que JSON.

Utilisez l’exemple de code suivant pour sérialiser des objets :

public static class SessionExtensions
{
    public static void Set<T>(this ISession session, string key, T value)
    {
        session.SetString(key, JsonSerializer.Serialize(value));
    }

    public static T? Get<T>(this ISession session, string key)
    {
        var value = session.GetString(key);
        return value == null ? default : JsonSerializer.Deserialize<T>(value);
    }
}

L’exemple suivant montre comment définir et obtenir un objet sérialisable avec la classe SessionExtensions :

using Microsoft.AspNetCore.Mvc.RazorPages;
using Web.Extensions;    // SessionExtensions

namespace SessionSample.Pages
{
    public class Index6Model : PageModel
    {
        const string SessionKeyTime = "_Time";
        public string? SessionInfo_SessionTime { get; private set; }
        private readonly ILogger<Index6Model> _logger;

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

        public void OnGet()
        {
            var currentTime = DateTime.Now;

            // Requires SessionExtensions from sample.
            if (HttpContext.Session.Get<DateTime>(SessionKeyTime) == default)
            {
                HttpContext.Session.Set<DateTime>(SessionKeyTime, currentTime);
            }
            _logger.LogInformation("Current Time: {Time}", currentTime);
            _logger.LogInformation("Session Time: {Time}", 
                           HttpContext.Session.Get<DateTime>(SessionKeyTime));

        }
    }
}

Avertissement

Le stockage d’un objet actif dans la session doit être utilisé avec précaution, car de nombreux problèmes peuvent se produire avec des objets sérialisés. Pour plus d’informations, consultez Les sessions doivent être autorisées à stocker des objets (dotnet/aspnetcore #18159).

TempData

ASP.NET Core expose TempData de Razor Pages ou TempData du contrôleur. Cette propriété stocke les données jusqu’à ce qu’elles soient lues dans une autre demande. Les méthodes Keep(String) et Peek(string) peuvent être utilisées pour examiner les données sans suppression à la fin de la demande. Keep marque tous les éléments dans le dictionnaire pour la rétention. TempData est :

  • Utile pour la redirection, quand des données sont nécessaires pour plusieurs demandes.
  • Implémenté par des fournisseurs TempData à l’aide de cookies ou de l’état de session.

Échantillons TempData

Considérez la page suivante qui crée un client :

public class CreateModel : PageModel
{
    private readonly RazorPagesContactsContext _context;

    public CreateModel(RazorPagesContactsContext context)
    {
        _context = context;
    }

    public IActionResult OnGet()
    {
        return Page();
    }

    [TempData]
    public string Message { get; set; }

    [BindProperty]
    public Customer Customer { get; set; }

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        _context.Customer.Add(Customer);
        await _context.SaveChangesAsync();
        Message = $"Customer {Customer.Name} added";

        return RedirectToPage("./IndexPeek");
    }
}

La page suivante affiche TempData["Message"] :

@page
@model IndexModel

<h1>Peek Contacts</h1>

@{
    if (TempData.Peek("Message") != null)
    {
        <h3>Message: @TempData.Peek("Message")</h3>
    }
}

@*Content removed for brevity.*@

Dans le balisage précédent, à la fin de la demande, TempData["Message"]n’est pas supprimé, car Peek est utilisé. L’actualisation de la page affiche le contenu de TempData["Message"].

Le balisage suivant est similaire au code précédent, mais utilise Keep pour conserver les données à la fin de la demande :

@page
@model IndexModel

<h1>Contacts Keep</h1>

@{
    if (TempData["Message"] != null)
    {
        <h3>Message: @TempData["Message"]</h3>
    }
    TempData.Keep("Message");
}

@*Content removed for brevity.*@

La navigation entre les pages IndexPeek et IndexKeep ne supprime pas TempData["Message"].

Le code suivant affiche TempData["Message"], mais à la fin de la demande, TempData["Message"] est supprimé :

@page
@model IndexModel

<h1>Index no Keep or Peek</h1>

@{
    if (TempData["Message"] != null)
    {
        <h3>Message: @TempData["Message"]</h3>
    }
}

@*Content removed for brevity.*@

Fournisseurs TempData

Le fournisseur TempData basé sur les cookies est utilisé par défaut pour stocker TempData dans des cookies.

Les données cookie sont chiffrées à l’aide de IDataProtector, encodées avec Base64UrlTextEncoder, puis segmentées. La taille maximale de cookie est inférieure à 4 096 octets en raison du chiffrement et de la segmentation. Les données de cookie ne sont pas compressées, car la compression de données chiffrées peut entraîner des problèmes de sécurité, notamment les attaques CRIME et BREACH. Pour plus d’informations sur le fournisseur TempData basé sur les cookies, consultez CookieTempDataProvider.

Choisir un fournisseur TempData

Pour choisir un fournisseur TempData, vous devez tenir compte de plusieurs points. Par exemple :

  • L’application utilise-t-elle déjà l’état de session ? Si c’est le cas, l’utilisation du fournisseur TempData d’état de session n’entraîne pas de surcoût pour l’application au-delà de la taille des données.
  • L’application utilise-t-elle TempData seulement de façon ponctuelle, pour des quantités de données relativement petites, jusqu’à 500 octets ? Si c’est le cas, le fournisseur TempData de cookies ajoute un petit coût à chaque demande traitée par TempData. Si ce n’est pas le cas, le fournisseur TempData d’état de session peut être utile pour éviter l’aller-retour d’une grande quantité de données dans chaque requête jusqu’à ce que le TempData soit consommé.
  • L’application s’exécute-t-elle dans une batterie de serveurs sur plusieurs serveurs ? Si c’est le cas, aucune configuration supplémentaire n’est nécessaire pour utiliser le fournisseur TempData de cookies en dehors de la Protection des données. Pour plus d’informations, consultez Vue d’ensemble de la protection des données ASP.NET Core et Fournisseurs de stockage de clés.

La plupart des clients web, tels que les navigateurs web, appliquent des limites pour la taille maximale de chaque cookie et le nombre total de cookies. Quand vous utilisez le fournisseur TempData de cookies, vérifiez que l’application ne dépasse pas ces limites. Prenez en compte la taille totale des données. Pensez aux augmentations de taille de cookie dues au chiffrement et à la segmentation.

Configuration du fournisseur TempData

Le fournisseur TempData basé sur les cookies est activé par défaut.

Pour activer le fournisseur TempData basé sur la session, utilisez la méthode d’extension AddSessionStateTempDataProvider. Un seul appel à AddSessionStateTempDataProvider est requis :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages()
                    .AddSessionStateTempDataProvider();
builder.Services.AddControllersWithViews()
                    .AddSessionStateTempDataProvider();

builder.Services.AddSession();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.UseSession();

app.MapRazorPages();
app.MapDefaultControllerRoute();

app.Run();

Chaînes de requête

Vous pouvez passer une quantité limitée de données d’une requête à une autre en l’ajoutant à la chaîne de la nouvelle requête. Cela est utile pour capturer l’état de manière persistante et permettre ainsi le partage de liens avec état incorporé par e-mail ou sur les réseaux sociaux. Les chaînes de requête URL étant publiques, vous ne devez jamais utiliser de chaînes de requête pour des données sensibles.

En plus du partage involontaire, l’inclusion de données dans des chaînes de requête peut exposer l’application à des attaques de falsification de requête intersites (CSRF, Cross-Site Request Forgery). Chaque état de session conservé doit garantir une protection contre les attaques CSRF. Pour plus d’informations, consultez Prévenir les attaques par falsification de requête intersites (XSRF/CSRF) dans ASP.NET Core.

Champs masqués

Les données peuvent être enregistrées dans des champs de formulaire masqués et être republiées lors de la requête suivante. Cela est courant dans les formulaires de plusieurs pages. Étant donné que le client peut potentiellement falsifier les données, l’application doit toujours revalider les données stockées dans les champs masqués.

HttpContext.Items

La collection HttpContext.Items est utilisée pour stocker les données lors du traitement d’une seule demande. Le contenu de la collection est supprimé une fois la requête traitée. La collection Items est souvent utilisée pour permettre à des composants ou des middlewares de communiquer quand ils opèrent à différents moments de l’exécution d’une requête et qu’ils ne peuvent pas passer les paramètres de façon directe.

Dans l’exemple suivant, l’intergiciel ajoute isVerified à la collection Items :

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

ILogger logger = app.Logger;

app.Use(async (context, next) =>
{
    // context.Items["isVerified"] is null
    logger.LogInformation($"Before setting: Verified: {context.Items["isVerified"]}");
    context.Items["isVerified"] = true;
    await next.Invoke();
});

app.Use(async (context, next) =>
{
    // context.Items["isVerified"] is true
    logger.LogInformation($"Next: Verified: {context.Items["isVerified"]}");
    await next.Invoke();
});

app.MapGet("/", async context =>
{
    await context.Response.WriteAsync($"Verified: {context.Items["isVerified"]}");
});

app.Run();

Pour un intergiciel utilisé dans une seule application, il est peu probable que l’utilisation d’une clé fixe string provoque une collision de clé. Toutefois, pour éviter tout risque de collision de clé, un object peut être utilisé comme clé d’élément. Cette approche est particulièrement utile pour un intergiciel partagé entre les applications et présente également l’avantage d’éliminer l’utilisation de chaînes de clés dans le code. L’exemple suivant montre comment utiliser une clé object définie dans une classe d’intergiciels :

public class HttpContextItemsMiddleware
{
    private readonly RequestDelegate _next;
    public static readonly object HttpContextItemsMiddlewareKey = new();

    public HttpContextItemsMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        httpContext.Items[HttpContextItemsMiddlewareKey] = "K-9";

        await _next(httpContext);
    }
}

public static class HttpContextItemsMiddlewareExtensions
{
    public static IApplicationBuilder 
        UseHttpContextItemsMiddleware(this IApplicationBuilder app)
    {
        return app.UseMiddleware<HttpContextItemsMiddleware>();
    }
}

Tout autre code peut accéder à la valeur stockée dans HttpContext.Items à l’aide de la clé exposée par la classe du middleware :

public class Index2Model : PageModel
{
    private readonly ILogger<Index2Model> _logger;

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

    public void OnGet()
    {
        HttpContext.Items
            .TryGetValue(HttpContextItemsMiddleware.HttpContextItemsMiddlewareKey,
                out var middlewareSetValue);

        _logger.LogInformation("Middleware value {MV}",
            middlewareSetValue?.ToString() ?? "Middleware value not set!");
    }
}

Cache

La mise en cache est un moyen efficace de stocker et récupérer des données. L’application peut contrôler la durée de vie des éléments mis en cache. Pour plus d’informations, consultez Mise en cache des réponses dans ASP.NET Core.

Les données mises en cache ne sont pas associées à une requête, un utilisateur ou une session spécifique. Ne mettez pas en cache des données propres à l’utilisateur susceptibles d’être récupérées par les demandes d’autres utilisateurs.

Pour mettre en cache les données à l’échelle de l’application, consultez Mettre en cache en mémoire dans ASP.NET Core.

Vérification de l’état de session

ISession.IsAvailable est destiné à rechercher des défaillances temporaires. L’appel de IsAvailable avant l’exécution de l’intergiciel de session lève une exception InvalidOperationException.

Les bibliothèques qui doivent tester la disponibilité de session peuvent utiliser HttpContext.Features.Get<ISessionFeature>()?.Session != null.

Erreurs courantes

  • « Impossible de résoudre le service pour le type 'Microsoft.Extensions.Caching.Distributed.IDistributedCache' lors de la tentative d’activation de 'Microsoft.AspNetCore.Session.DistributedSessionStore'. »

    Cette erreur est généralement due à la non-configuration d’au moins une implémentation IDistributedCache. Pour plus d’informations, consultez Mise en cache distribuée dans ASP.NET Core et Mettre en cache en mémoire dans ASP.NET Core.

Si l’intergiciel de session ne parvient pas à rendre persistante une session :

  • L’intergiciel consigne l’exception et la demande continue normalement.
  • Cela entraîne un comportement imprévisible.

L’intergiciel de session peut ne pas parvenir à rendre persistante une session si le magasin de stockage n’est pas disponible. Par exemple, imaginez qu’un utilisateur stocke un panier d’achat dans la session. Il ajoute un élément au panier, mais la validation échoue. L’application n’a pas connaissance de l’échec et signale donc à l’utilisateur que l’élément a été ajouté au panier, ce qui est faux.

L’approche recommandée pour rechercher les erreurs consiste à appeler await feature.Session.CommitAsync quand l’application a terminé d’écrire dans la session. CommitAsync lève une exception si le magasin de stockage n’est pas disponible. Si CommitAsync échoue, l’application peut traiter l’exception. LoadAsync lève une exception dans les mêmes conditions, quand le magasin de données n’est pas disponible.

Ressources supplémentaires

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)

Hôte ASP.NET Core dans une batterie de serveurs web

Par Rick Anderson, Kirk Larkin et Diana LaRose

HTTP est un protocole sans état. Par défaut, les requêtes HTTP sont des messages indépendants qui ne conservent pas les valeurs utilisateur. Cet article décrit plusieurs approches pour conserver les données utilisateur entre les demandes.

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)

Gestion de l'état

L’état peut être stocké à l’aide de plusieurs approches. Chacune d’elles est abordée plus loin dans cet article.

Approche du stockage Mécanisme de stockage
Cookies cookies HTTP. Peuvent inclure des données stockées à l’aide de code d’application côté serveur.
État de session cookies HTTP et code d’application côté serveur
TempData cookies HTTP ou état de session
Chaînes de requête Chaînes de requête HTTP
Champs masqués Champs de formulaires HTTP
HttpContext.Items Code d’application côté serveur
Cache Code d’application côté serveur

SignalR/Blazor Server et gestion de l’état basé sur le contexte HTTP

Les applications SignalR ne doivent pas utiliser l’état de session et d’autres approches de gestion d’état qui s’appuient sur un contexte HTTP stable pour stocker des informations. Les applications SignalR peuvent stocker l’état par connexion dans Context.Items dans le hub. Pour plus d’informations et d’autres approches de gestion de l’état pour les applications Blazor Server, consultez Gestion de l’état ASP.NET Core Blazor.

Cookies

Les Cookies stockent des données entre les demandes. Comme les cookies sont envoyés avec chaque demande, il est essentiel de limiter leur taille au minimum. Dans l’idéal, un cookie doit stocker uniquement un identificateur et les données stockées par l’application. La plupart des navigateurs limitent la taille des cookies à 4096 octets. Seul un nombre limité de cookies est disponible pour chaque domaine.

Pour éviter les risques de falsification, les cookies doivent être validés par l’application. LesCookies peuvent être supprimés par les utilisateurs et ils expirent sur les clients. Toutefois, les cookies constituent généralement la forme la plus durable de persistance des données sur le client.

Les Cookies servent souvent à personnaliser le contenu pour un utilisateur connu. L’utilisateur est uniquement identifié, et pas authentifié dans la plupart des cas. Le cookie peut stocker le nom de l’utilisateur, le nom du compte ou l’ID utilisateur unique, tel qu’un GUID. Le cookie peut être utilisé pour accéder aux paramètres personnalisés de l’utilisateur, telles que sa couleur d’arrière-plan de site web par défaut.

Consultez le Règlement général sur la protection des données (RGPD) de l’Union Européenne lors de l’émission de cookies et de la gestion de la confidentialité. Pour plus d’informations, consultez Prise en charge du règlement général sur la protection des données (RGPD) de l’Union Européenne dans ASP.NET Core.

État de session

L’état de session est un scénario ASP.NET Core pour le stockage des données utilisateur pendant que l’utilisateur parcourt une application web. L’état de session utilise un magasin tenu à jour par l’application afin de conserver les données entre les requêtes d’un client. Les données de session sont sauvegardées par un cache et considérées comme des données éphémères. Le site doit continuer à fonctionner sans les données de session. Les données d’application critiques doivent être stockées dans la base de données utilisateur et mises en cache dans la session uniquement à des fins d’optimisation des performances.

La session n’est pas prise en charge dans les applications SignalR car un hub SignalR peut s’exécuter indépendamment d’un contexte HTTP. Par exemple, cela peut se produire quand une longue requête d’interrogation est ouverte par un hub au-delà de la durée de vie du contexte de la requête HTTP.

ASP.NET Core tient à jour l’état de session en fournissant au client un cookie qui contient un ID de session. L’ID de session du cookie :

  • Est envoyé à l’application avec chaque demande.
  • Est utilisé par l’application pour récupérer les données de session.

L’état de session présente les comportements suivants :

  • Le cookie de session est spécifique au navigateur. Les sessions ne sont pas partagées entre les navigateurs.
  • Les cookies de session sont supprimés quand la session du navigateur se termine.
  • Si un cookie est reçu pour une session qui a expiré, une session qui utilise le même cookie de session est créée.
  • Les sessions vides ne sont pas conservées. La session doit avoir au moins une valeur définie pour pouvoir être conservée entre les demandes. Quand une session n’est pas conservée, un nouvel ID de session est généré pour chaque nouvelle requête.
  • L’application conserve une session pendant une période limitée après la dernière requête. L’application définit le délai d’expiration d’une session ou utilise la valeur par défaut de 20 minutes. L’état de session est idéal pour stocker des données utilisateur :
    • spécifiques à une session particulière ;
    • où les données ne nécessitent pas un stockage permanent entre les sessions.
  • Les données de session sont supprimées quand l’implémentation ISession.Clear est appelée ou quand la session expire.
  • Il n’existe aucun mécanisme par défaut permettant de signaler au code d’application qu’un navigateur client a été fermé ou que le cookie de session a été supprimé ou a expiré sur le client.
  • Les cookies d’état de session ne sont pas marqués comme essentiels par défaut. L’état de session n’est pas fonctionnel, sauf si le suivi est autorisé par le visiteur du site. Pour plus d’informations, consultez Prise en charge du règlement général sur la protection des données (RGPD) de l’Union Européenne dans ASP.NET Core.

Avertissement

Ne stockez pas de données sensibles dans l’état de session. L’utilisateur risque de ne pas fermer le navigateur et de ne pas effacer le cookie de session. Certains navigateurs conservent des cookies de session valides entre les fenêtres du navigateur. Une session peut ne pas être limitée à un seul utilisateur. L’utilisateur suivant peut continuer à parcourir l’application avec le même cookie de session.

Le fournisseur de cache en mémoire stocke les données de session dans la mémoire du serveur où réside l’application. Dans un scénario de batterie de serveurs :

Configurer l’état de session

Le package Microsoft.AspNetCore.Session :

  • Est inclus implicitement par l’infrastructure.
  • Fournit un intergiciel pour gérer l’état de session.

Pour activer le middleware Session, Startup doit contenir les éléments suivants :

Le code suivant montre comment configurer le fournisseur de session en mémoire avec une implémentation en mémoire par défaut de IDistributedCache :

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDistributedMemoryCache();

        services.AddSession(options =>
        {
            options.IdleTimeout = TimeSpan.FromSeconds(10);
            options.Cookie.HttpOnly = true;
            options.Cookie.IsEssential = true;
        });

        services.AddControllersWithViews();
        services.AddRazorPages();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseSession();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapDefaultControllerRoute();
            endpoints.MapRazorPages();
        });
    }
}

Le code précédent définit un court délai d’attente pour simplifier les tests.

L’ordre des middlewares est important. Appelez UseSession après UseRouting et avant UseEndpoints. Consultez Ordre des intergiciels.

HttpContext.Session est disponible une fois l’état de session configuré.

HttpContext.Session n’est pas accessible avant que UseSession ait été appelée.

Il est impossible de créer une nouvelle session avec un nouveau cookie de session une fois que l’application a commencé à écrire dans le flux de réponse. L’exception est enregistrée dans le journal de serveur web et n’est pas affichée pas dans le navigateur.

Charger l’état de session de façon asynchrone

Le fournisseur de session par défaut dans ASP.NET Core charge des enregistrements de session de façon asynchrone à partir du magasin de stockage sous-jacent IDistributedCache uniquement si la méthode ISession.LoadAsync est appelée explicitement avant les méthodes TryGetValue, Set ou Remove. Si LoadAsync n’est pas appelée en premier, l’enregistrement de session sous-jacent est chargé de façon synchrone, ce qui peut entraîner une baisse des performances à l’échelle.

Pour forcer les applications à appliquer ce modèle, incluez les implémentations DistributedSessionStore et DistributedSession dans un wrapper, avec des versions qui lèvent une exception si la méthode LoadAsync n’est pas appelée avant TryGetValue, Set ou Remove. Inscrivez ensuite les versions incluses dans le wrapper auprès du conteneur de services.

Options de session

Pour substituer les valeurs de session par défaut, utilisez SessionOptions.

Option Description
Cookie Détermine les paramètres utilisés pour créer le cookie. Name a la valeur par défaut SessionDefaults.CookieName (.AspNetCore.Session). Path a la valeur par défaut SessionDefaults.CookiePath (/). SameSite a la valeur par défaut SameSiteMode.Lax (1). HttpOnly a la valeur par défaut true. IsEssential a la valeur par défaut false.
IdleTimeout IdleTimeout indique la durée pendant laquelle la session peut être inactive avant que son contenu soit abandonné. Chaque accès à la session réinitialise le délai d’expiration. Ce paramètre s’applique uniquement au contenu de la session, et non au cookie. La valeur par défaut est 20 minutes.
IOTimeout Durée maximale autorisée pour charger une session à partir du magasin ou pour la valider dans le magasin. Ce paramètre peut s’appliquer uniquement aux opérations asynchrones. Vous pouvez désactiver ce délai d’expiration à l’aide de InfiniteTimeSpan. La valeur par défaut est de 1 minute.

La session utilise un cookie pour suivre et identifier les demandes reçues d’un navigateur. Par défaut, ce cookie se nomme .AspNetCore.Session et utilise le chemin /. Étant donné que le cookie par défaut ne spécifie pas de domaine, il n’est pas mis à disposition du script côté client dans la page (car HttpOnly a la valeur par défaut true).

Pour substituer les valeurs de session de cookie par défaut, utilisez SessionOptions :

public void ConfigureServices(IServiceCollection services)
{
    services.AddDistributedMemoryCache();

    services.AddSession(options =>
    {
        options.Cookie.Name = ".AdventureWorks.Session";
        options.IdleTimeout = TimeSpan.FromSeconds(10);
        options.Cookie.IsEssential = true;
    });

    services.AddControllersWithViews();
    services.AddRazorPages();
}

L’application utilise la propriété IdleTimeout pour déterminer la durée pendant laquelle une session peut rester inactive avant que son contenu dans le cache du serveur soit abandonné. Cette propriété est indépendante du délai d’expiration du cookie. Chaque requête qui passe par le middleware Session réinitialise le délai d’expiration.

L’état de session est sans verrouillage. Si deux requêtes tentent simultanément de modifier le contenu d’une session, la dernière requête remplace la première. Session est implémentée comme une session cohérente, ce qui signifie que tout le contenu est stocké au même emplacement. Quand deux requêtes tentent de modifier différentes valeurs de session, la dernière requête peut remplacer les modifications de session effectuées par la première.

Définir et obtenir des valeurs Session

L’état de session est accessible à partir d’une classe RazorPageModel Pages ou d’une classe Controller MVC avec HttpContext.Session. Cette propriété est une implémentation ISession.

L’implémentation de ISession fournit plusieurs méthodes d’extension pour définir et récupérer des valeurs de chaîne et d’entier. Les méthodes d’extension se trouvent dans l’espace de noms Microsoft.AspNetCore.Http.

Méthodes d’extension ISession :

L’exemple suivant récupère la valeur de session pour la clé IndexModel.SessionKeyName (_Name dans l’exemple d’application) dans une page Razor Pages :

@page
@using Microsoft.AspNetCore.Http
@model IndexModel

...

Name: @HttpContext.Session.GetString(IndexModel.SessionKeyName)

L’exemple suivant montre comment définir et obtenir un entier et une chaîne :

public class IndexModel : PageModel
{
    public const string SessionKeyName = "_Name";
    public const string SessionKeyAge = "_Age";
    const string SessionKeyTime = "_Time";

    public string SessionInfo_Name { get; private set; }
    public string SessionInfo_Age { get; private set; }
    public string SessionInfo_CurrentTime { get; private set; }
    public string SessionInfo_SessionTime { get; private set; }
    public string SessionInfo_MiddlewareValue { get; private set; }

    public void OnGet()
    {
        // Requires: using Microsoft.AspNetCore.Http;
        if (string.IsNullOrEmpty(HttpContext.Session.GetString(SessionKeyName)))
        {
            HttpContext.Session.SetString(SessionKeyName, "The Doctor");
            HttpContext.Session.SetInt32(SessionKeyAge, 773);
        }

        var name = HttpContext.Session.GetString(SessionKeyName);
        var age = HttpContext.Session.GetInt32(SessionKeyAge);

Toutes les données de session doivent être sérialisées pour activer un scénario de cache distribué, même si vous utilisez le cache en mémoire. Les sérialiseurs de chaîne et d’entier sont fournis par les méthodes d’extension de ISession. Les types complexes doivent être sérialisés par l’utilisateur à l’aide d’un autre mécanisme, tel que JSON.

Utilisez l’exemple de code suivant pour sérialiser des objets :

public static class SessionExtensions
{
    public static void Set<T>(this ISession session, string key, T value)
    {
        session.SetString(key, JsonSerializer.Serialize(value));
    }

    public static T Get<T>(this ISession session, string key)
    {
        var value = session.GetString(key);
        return value == null ? default : JsonSerializer.Deserialize<T>(value);
    }
}

L’exemple suivant montre comment définir et obtenir un objet sérialisable avec la classe SessionExtensions :

// Requires SessionExtensions from sample download.
if (HttpContext.Session.Get<DateTime>(SessionKeyTime) == default)
{
    HttpContext.Session.Set<DateTime>(SessionKeyTime, currentTime);
}

TempData

ASP.NET Core expose TempData de Razor Pages ou TempData du contrôleur. Cette propriété stocke les données jusqu’à ce qu’elles soient lues dans une autre demande. Les méthodes Keep(String) et Peek(string) peuvent être utilisées pour examiner les données sans suppression à la fin de la demande. Keep marque tous les éléments dans le dictionnaire pour la rétention. TempData est :

  • Utile pour la redirection, quand des données sont nécessaires pour plusieurs demandes.
  • Implémenté par des fournisseurs TempData à l’aide de cookies ou de l’état de session.

Échantillons TempData

Considérez la page suivante qui crée un client :

public class CreateModel : PageModel
{
    private readonly RazorPagesContactsContext _context;

    public CreateModel(RazorPagesContactsContext context)
    {
        _context = context;
    }

    public IActionResult OnGet()
    {
        return Page();
    }

    [TempData]
    public string Message { get; set; }

    [BindProperty]
    public Customer Customer { get; set; }

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        _context.Customer.Add(Customer);
        await _context.SaveChangesAsync();
        Message = $"Customer {Customer.Name} added";

        return RedirectToPage("./IndexPeek");
    }
}

La page suivante affiche TempData["Message"] :

@page
@model IndexModel

<h1>Peek Contacts</h1>

@{
    if (TempData.Peek("Message") != null)
    {
        <h3>Message: @TempData.Peek("Message")</h3>
    }
}

@*Content removed for brevity.*@

Dans le balisage précédent, à la fin de la demande, TempData["Message"]n’est pas supprimé, car Peek est utilisé. L’actualisation de la page affiche le contenu de TempData["Message"].

Le balisage suivant est similaire au code précédent, mais utilise Keep pour conserver les données à la fin de la demande :

@page
@model IndexModel

<h1>Contacts Keep</h1>

@{
    if (TempData["Message"] != null)
    {
        <h3>Message: @TempData["Message"]</h3>
    }
    TempData.Keep("Message");
}

@*Content removed for brevity.*@

La navigation entre les pages IndexPeek et IndexKeep ne supprime pas TempData["Message"].

Le code suivant affiche TempData["Message"], mais à la fin de la demande, TempData["Message"] est supprimé :

@page
@model IndexModel

<h1>Index no Keep or Peek</h1>

@{
    if (TempData["Message"] != null)
    {
        <h3>Message: @TempData["Message"]</h3>
    }
}

@*Content removed for brevity.*@

Fournisseurs TempData

Le fournisseur TempData basé sur les cookies est utilisé par défaut pour stocker TempData dans des cookies.

Les données cookie sont chiffrées à l’aide de IDataProtector, encodées avec Base64UrlTextEncoder, puis segmentées. La taille maximale de cookie est inférieure à 4 096 octets en raison du chiffrement et de la segmentation. Les données de cookie ne sont pas compressées, car la compression de données chiffrées peut entraîner des problèmes de sécurité, notamment les attaques CRIME et BREACH. Pour plus d’informations sur le fournisseur TempData basé sur les cookies, consultez CookieTempDataProvider.

Choisir un fournisseur TempData

Pour choisir un fournisseur TempData, vous devez tenir compte de plusieurs points. Par exemple :

  • L’application utilise-t-elle déjà l’état de session ? Si c’est le cas, l’utilisation du fournisseur TempData d’état de session n’entraîne pas de surcoût pour l’application au-delà de la taille des données.
  • L’application utilise-t-elle TempData seulement de façon ponctuelle, pour des quantités de données relativement petites, jusqu’à 500 octets ? Si c’est le cas, le fournisseur TempData de cookies ajoute un petit coût à chaque demande traitée par TempData. Si ce n’est pas le cas, le fournisseur TempData d’état de session peut être utile pour éviter l’aller-retour d’une grande quantité de données dans chaque requête jusqu’à ce que le TempData soit consommé.
  • L’application s’exécute-t-elle dans une batterie de serveurs sur plusieurs serveurs ? Si c’est le cas, aucune configuration supplémentaire n’est requise pour utiliser le fournisseur TempData de cookies en dehors de la Protection des données (consultez Vue d’ensemble de la protection des données ASP.NET Core et Fournisseurs de stockage de clés).

La plupart des clients web, tels que les navigateurs web, appliquent des limites pour la taille maximale de chaque cookie et le nombre total de cookies. Quand vous utilisez le fournisseur TempData de cookies, vérifiez que l’application ne dépasse pas ces limites. Prenez en compte la taille totale des données. Pensez aux augmentations de taille de cookie dues au chiffrement et à la segmentation.

Configuration du fournisseur TempData

Le fournisseur TempData basé sur les cookies est activé par défaut.

Pour activer le fournisseur TempData basé sur la session, utilisez la méthode d’extension AddSessionStateTempDataProvider. Un seul appel à AddSessionStateTempDataProvider est requis :

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews()
        .AddSessionStateTempDataProvider();
    services.AddRazorPages()
        .AddSessionStateTempDataProvider();

    services.AddSession();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }
    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseSession();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
        endpoints.MapRazorPages();
    });
}

Chaînes de requête

Vous pouvez passer une quantité limitée de données d’une requête à une autre en l’ajoutant à la chaîne de la nouvelle requête. Cela est utile pour capturer l’état de manière persistante et permettre ainsi le partage de liens avec état incorporé par e-mail ou sur les réseaux sociaux. Les chaînes de requête URL étant publiques, vous ne devez jamais utiliser de chaînes de requête pour des données sensibles.

En plus du partage involontaire, l’inclusion de données dans des chaînes de requête peut exposer l’application à des attaques de falsification de requête intersites (CSRF, Cross-Site Request Forgery). Chaque état de session conservé doit garantir une protection contre les attaques CSRF. Pour plus d’informations, consultez Prévenir les attaques par falsification de requête intersites (XSRF/CSRF) dans ASP.NET Core.

Champs masqués

Les données peuvent être enregistrées dans des champs de formulaire masqués et être republiées lors de la requête suivante. Cela est courant dans les formulaires de plusieurs pages. Étant donné que le client peut potentiellement falsifier les données, l’application doit toujours revalider les données stockées dans les champs masqués.

HttpContext.Items

La collection HttpContext.Items est utilisée pour stocker les données lors du traitement d’une seule demande. Le contenu de la collection est supprimé une fois la requête traitée. La collection Items est souvent utilisée pour permettre à des composants ou des middlewares de communiquer quand ils opèrent à différents moments de l’exécution d’une requête et qu’ils ne peuvent pas passer les paramètres de façon directe.

Dans l’exemple suivant, l’intergiciel ajoute isVerified à la collection Items :

public void Configure(IApplicationBuilder app, ILogger<Startup> logger)
{
    app.UseRouting();

    app.Use(async (context, next) =>
    {
        logger.LogInformation($"Before setting: Verified: {context.Items["isVerified"]}");
        context.Items["isVerified"] = true;
        await next.Invoke();
    });

    app.Use(async (context, next) =>
    {
        logger.LogInformation($"Next: Verified: {context.Items["isVerified"]}");
        await next.Invoke();
    });

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGet("/", async context =>
        {
            await context.Response.WriteAsync($"Verified: {context.Items["isVerified"]}");
        });
    });
}

Pour un intergiciel utilisé dans une seule application, les clés string fixes sont acceptables. L’intergiciel partagé entre des applications doit utiliser des clés d’objets uniques afin d’éviter les conflits de clés. L’exemple suivant montre comment utiliser une clé d’objet unique définie dans une classe de middleware :

public class HttpContextItemsMiddleware
{
    private readonly RequestDelegate _next;
    public static readonly object HttpContextItemsMiddlewareKey = new Object();

    public HttpContextItemsMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        httpContext.Items[HttpContextItemsMiddlewareKey] = "K-9";

        await _next(httpContext);
    }
}

public static class HttpContextItemsMiddlewareExtensions
{
    public static IApplicationBuilder 
        UseHttpContextItemsMiddleware(this IApplicationBuilder app)
    {
        return app.UseMiddleware<HttpContextItemsMiddleware>();
    }
}

Tout autre code peut accéder à la valeur stockée dans HttpContext.Items à l’aide de la clé exposée par la classe du middleware :

HttpContext.Items
    .TryGetValue(HttpContextItemsMiddleware.HttpContextItemsMiddlewareKey, 
        out var middlewareSetValue);
SessionInfo_MiddlewareValue = 
    middlewareSetValue?.ToString() ?? "Middleware value not set!";

Cette approche a également l’avantage d’éliminer l’utilisation des chaînes de clés dans le code.

Cache

La mise en cache est un moyen efficace de stocker et récupérer des données. L’application peut contrôler la durée de vie des éléments mis en cache. Pour plus d’informations, consultez Mise en cache des réponses dans ASP.NET Core.

Les données mises en cache ne sont pas associées à une requête, un utilisateur ou une session spécifique. Ne mettez pas en cache des données propres à l’utilisateur susceptibles d’être récupérées par les demandes d’autres utilisateurs.

Pour mettre en cache les données à l’échelle de l’application, consultez Mettre en cache en mémoire dans ASP.NET Core.

Erreurs courantes

  • « Impossible de résoudre le service pour le type 'Microsoft.Extensions.Caching.Distributed.IDistributedCache' lors de la tentative d’activation de 'Microsoft.AspNetCore.Session.DistributedSessionStore'. »

    Cette erreur est généralement due à la non-configuration d’au moins une implémentation IDistributedCache. Pour plus d’informations, consultez Mise en cache distribuée dans ASP.NET Core et Mettre en cache en mémoire dans ASP.NET Core.

Si l’intergiciel de session ne parvient pas à rendre persistante une session :

  • L’intergiciel consigne l’exception et la demande continue normalement.
  • Cela entraîne un comportement imprévisible.

L’intergiciel de session peut ne pas parvenir à rendre persistante une session si le magasin de stockage n’est pas disponible. Par exemple, imaginez qu’un utilisateur stocke un panier d’achat dans la session. Il ajoute un élément au panier, mais la validation échoue. L’application n’a pas connaissance de l’échec et signale donc à l’utilisateur que l’élément a été ajouté au panier, ce qui est faux.

L’approche recommandée pour rechercher les erreurs consiste à appeler await feature.Session.CommitAsync quand l’application a terminé d’écrire dans la session. CommitAsync lève une exception si le magasin de stockage n’est pas disponible. Si CommitAsync échoue, l’application peut traiter l’exception. LoadAsync lève une exception dans les mêmes conditions, quand le magasin de données n’est pas disponible.

Ressources supplémentaires

Hôte ASP.NET Core dans une batterie de serveurs web