Sitzungs- und Zustandsverwaltung in ASP.NET Core

Von Rick Anderson, Kirk Larkin und Diana LaRose

Bei HTTP handelt es sich um ein zustandsloses Protokoll. HTTP-Anforderungen sind standardmäßig unabhängige Nachrichten, die keine Benutzerwerte beibehalten. In diesem Artikel werden mehrere Ansätze zum Beibehalten von Benutzerdaten zwischen Anforderungen beschrieben.

Zustandsverwaltung

Zustände können mithilfe mehrerer Ansätze gespeichert werden. Die einzelnen Ansätze werden im weiteren Verlauf dieses Artikels beschrieben.

Speicheransatz Speichermechanismus
Cookies HTTP-cookies. Schließt möglicherweise Daten ein, die mit serverseitigem App-Code gespeichert wurden.
Sitzungszustand HTTP-cookies und serverseitiger App-Code
TempData HTTP-cookies oder Sitzungszustand
Abfragezeichenfolgen HTTP-Abfragezeichenfolgen
Verborgene Felder HTTP-Formularfelder
HttpContext.Items Serverseitiger App-Code
Cache Serverseitiger App-Code

SignalR/Blazor Server und kontextbasierte HTTP-Zustandsverwaltung

SignalR-Apps sollten nicht den Sitzungszustand und andere Ansätze zur Zustandsverwaltung verwenden, die auf einem stabilen HTTP-Kontext zum Speichern von Informationen basieren. SignalR-Apps können den Zustand pro Verbindung in Context.Items im Hub speichern. Weitere Informationen und alternative Ansätze zur Zustandsverwaltung für Blazor Server-Apps finden Sie unter Blazor-Zustandsverwaltung in ASP.NET Core.

Cookie

Cookies speichern Daten anforderungsübergreifend. Da mit jeder Anforderung cookies gesendet werden, sollte deren Größe auf ein Minimum begrenzt sein. Idealerweise sollte nur ein Bezeichner in einem cookie gespeichert werden, während die Daten von der App gespeichert werden sollten. Die meisten Browser beschränken die Größe von cookies auf 4096 Byte. Nur eine begrenzte Anzahl von cookies ist für jede Domäne verfügbar.

Da cookies manipuliert werden können, müssen sie von der App überprüft werden. Cookies können von Benutzern gelöscht werden und können auf Clients ablaufen. cookies sind für gewöhnlich die dauerhafteste Form der Datenpersistenz auf dem Client.

Cookies werden häufig aus Personalisierungsgründen verwendet, wenn Inhalt für einen bekannten Benutzer angepasst wird. In den meisten Fällen wird der Benutzer nur identifiziert und nicht authentifiziert. Das cookie kann den Benutzernamen, Kontonamen oder eine eindeutige Benutzer-ID wie die GUID speichern. Dann können Sie mit dem cookie auf die persönlichen Einstellungen (z. B. die bevorzugte Farbe des Websitehintergrunds) des Benutzers zugreifen.

Beachten Sie die Europäische Datenschutz-Grundverordnung (DSGVO) beim Ausstellen von cookies und beim Umgang mit Aspekten des Datenschutzes. Weitere In finden Sie unter General Data Protection Regulation (GDPR) support in ASP.NET Core (DSGVO-Unterstützung in ASP.NET Core).

Sitzungszustand

Der Sitzungszustand ist ein Szenario in ASP.NET Core zum Speichern von Benutzerdaten, wenn der Benutzer eine Web-App verwendet. Der Sitzungszustand verwendet einen von der App verwalteten Speicher, um Daten für mehrere Anforderungen eines Clients beizubehalten. Die Sitzungsdaten werden durch einen Cache gesichert und als kurzlebige Daten betrachtet. Die Website sollte auch ohne die Sitzungsdaten weiterhin funktionieren. Kritische Anwendungsdaten sollten in der Benutzerdatenbank gespeichert und nur zur Leistungsoptimierung in der Sitzung zwischengespeichert werden.

Sitzungen werden in SignalRSignalR-Apps nicht unterstützt, da ein -Hub unabhängig vom HTTP-Kontext ausgeführt werden kann. Das kann z.B. passieren, wenn eine lange Abrufanforderung von einem Hub länger als die Lebensdauer des HTTP-Kontexts einer Anforderung offen gehalten wird.

ASP.NET Core verwaltet den Sitzungszustand, indem ein cookie an den Client übergeben wird, das die Sitzungs-ID enthält. Die Sitzungscookie-ID:

  • Sie wird mit jeder Anforderung an die App gesendet.
  • Sie wird von der App zum Abrufen der Sitzungsdaten verwendet.

Der Sitzungszustand verhält sich wie folgt:

  • Das Sitzungscookie ist für den Browser spezifisch. Die Sitzungen werden nicht browserübergreifend geteilt.
  • Sitzungscookies werden gelöscht, wenn die Browsersitzung abläuft.
  • Wenn für eine abgelaufene Sitzung ein cookie empfangen wird, wird eine neue Sitzung erstellt, die dasselbe cookie verwendet.
  • Leere Sitzungen werden nicht beibehalten. Für die Sitzung muss mindestens ein Wert festgelegt sein, damit die Sitzung anforderungsübergreifend beibehalten wird. Wenn eine Sitzung nicht beibehalten wird, wird eine neue Sitzungs-ID für jede neue Anforderung erzeugt.
  • Die App speichert Sitzungen für einen beschränkten Zeitraum nach der letzten Anforderung. Die App legt entweder ein Zeitlimit für die Sitzungen fest oder verwendet den Standardwert von 20 Minuten. Der Sitzungszustand ist ideal zum Speichern von Benutzerdaten:
    • Das ist spezifisch für eine bestimmte Sitzung.
    • Wo die Daten keine permanente und sitzungsübergreifende Speicherung erfordern.
  • Sitzungsdaten werden gelöscht, wenn die Implementierung von ISession.Clear aufgerufen wird oder wenn die Sitzung abläuft.
  • Es gibt kein Standardverfahren, wie App-Code darüber informiert wird, dass ein Clientbrowser geschlossen wurde oder dass ein Sitzungscookie gelöscht wurde oder auf dem Client abgelaufen ist.
  • Sitzungszustandscookies sind standardmäßig nicht als grundlegend gekennzeichnet. Der Sitzungszustand ist nicht praktisch, es sei denn, der Besucher der Website gestattet die Nachverfolgung. Weitere In finden Sie unter General Data Protection Regulation (GDPR) support in ASP.NET Core (DSGVO-Unterstützung in ASP.NET Core).
  • Hinweis:Es gibt keinen Ersatz für das Feature für Sitzungen ohne cookie von ASP.NET Framework, da es als unsicher angesehen wird und zu Session-Fixation-Angriffen führen kann.

Warnung

Speichern Sie keine vertraulichen Daten im Sitzungszustand. Es besteht die Möglichkeit, dass der Benutzer seinen Browser nicht schließt oder die Sitzungscookies nicht löscht. Einige Browser behalten gültige Sitzungscookies browserfensterübergreifend bei. Eine Sitzung ist möglicherweise nicht auf einen einzelnen Benutzer beschränkt. Der nächste Benutzer kann die App mit demselben Sitzungscookie weiter durchsuchen.

Der Cacheanbieter im Arbeitsspeicher speichert Sitzungsdaten im Arbeitsspeicher des Servers, auf dem sich die App befindet. Beachten Sie in einem Szenario mit einer Serverfarm Folgendes:

Konfigurieren des Sitzungszustands

Middleware zum Verwalten des Sitzungszustands ist im Framework enthalten. Program.cs muss folgende Elemente enthalten, um die Sitzungsmiddleware zu aktivieren:

Der folgende Code zeigt, wie Sie den speicherinternen Sitzungsanbieter mit einer Standardimplementierung von IDistributedCache im Arbeitsspeicher einrichten:

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();

Der vorangegangene Code setzt ein kurzes Zeitlimit, um das Testen zu vereinfachen.

Die Reihenfolge der Middleware ist wichtig. Rufen Sie UseSession nach UseRouting und vor MapRazorPages und MapDefaultControllerRoute auf. Informationen finden Sie unter Festlegen einer Reihenfolge für Middleware.

HttpContext.Session ist verfügbar, nachdem der Sitzungszustand konfiguriert wurde.

Auf HttpContext.Session kann vor einem Aufruf von UseSession nicht zugegriffen werden.

Nachdem die App mit dem Schreiben in den Antwortdatenstrom begonnen hat, kann keine neue Sitzung mit einem neuen Sitzungscookie erstellt werden. Die Ausnahme wird im Webserverprotokoll erfasst und nicht im Browser angezeigt.

Asynchrones Laden des Sitzungszustands

Der Standardsitzungsanbieter in ASP.NET Core lädt Sitzungsaufzeichnungen aus dem zugrunde liegenden IDistributedCache-Speicher nur dann asynchron, wenn die ISession.LoadAsync-Methode explizit vor den Methoden TryGetValue, Set oder Remove aufgerufen wird. Wenn LoadAsync nicht zuerst aufgerufen wird, werden die zugrunde liegenden Sitzungsaufzeichnungen synchron geladen, was entsprechende Auswirkungen auf die Leistung haben kann.

Damit Apps dieses Muster erzwingen, umschließen Sie die Implementierungen DistributedSessionStore und DistributedSession mit Versionen, die eine Ausnahme auslösen, wenn die LoadAsync-Methode nicht vor TryGetValue, Set oder Remove aufgerufen wird. Registrieren Sie die umschlossenen Versionen in den Dienstcontainern.

Sitzungsoptionen

Verwenden Sie SessionOptions, um Standardwerte für Sitzungen zu überschreiben.

Option Beschreibung
Cookie Bestimmt die Einstellungen, die zum Erstellen des cookies verwendet wurden. Der Standardwert von Name ist SessionDefaults.CookieName (.AspNetCore.Session). Der Standardwert von Path ist SessionDefaults.CookiePath (/). Der Standardwert von SameSite ist SameSiteMode.Lax (1). Der Standardwert von HttpOnly ist true. Der Standardwert von IsEssential ist false.
IdleTimeout IdleTimeout gibt an, wie lang die Sitzung sich im Leerlauf befinden darf, bevor die Inhalte verworfen werden. Jeder Zugriff auf eine Sitzung setzt das Zeitlimit zurück. Diese Einstellung gilt nur für den Inhalt der Sitzung und nicht für das cookie. Der Standardwert beträgt 20 Minuten.
IOTimeout Der maximale Zeitraum, in dem eine Sitzung aus dem Speicher geladen oder mithilfe eines Commits erneut in diesem hinterlegt werden kann. Diese Einstellung gilt möglicherweise nur für asynchrone Vorgänge. Dieses Zeitlimit kann mit InfiniteTimeSpan deaktiviert werden. Der Standardwert beträgt 1 Minute.

Die Sitzung verwendet ein cookie, um Anforderungen eines Browsers nachzuverfolgen und zu identifizieren. Standardmäßig wird das cookie.AspNetCore.Session genannt und verwendet den Pfad von /. Da die Standardeinstellungen des cookies keine Domäne festlegen, wird es dem clientseitigen Skript auf der Seite nicht zur Verfügung gestellt (da HttpOnly standardmäßig auf true festgelegt ist).

Verwenden Sie SessionOptions, um Standardwerte für cookiesitzungen zu überschreiben.

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();

Die App verwendet die IdleTimeout-Eigenschaft, um zu bestimmen, wie lange sich eine Sitzung im Leerlauf befinden darf, bevor ihre Inhalte im Cache des Servers verworfen werden. Diese Eigenschaft ist unabhängig vom Ablauf der cookies. Jede Anforderung, die über die Sitzungsmiddleware übergeben wird, setzt das Zeitlimit zurück.

Der Sitzungszustand ist nicht sperrend. Die letzte Anforderung überschreibt die erste, wenn zwei Anforderungen gleichzeitig versuchen, die Inhalte einer Sitzung zu bearbeiten. Session wird als kohärente Sitzung implementiert, d.h., dass alle Inhalte zusammen gespeichert werden. Wenn zwei Anforderungen unterschiedliche Sitzungswerte bearbeiten möchten, überschreibt die letzte Anforderung möglicherweise Anforderungen der ersten.

Festlegen und Abrufen von Sitzungswerten

Auf den Sitzungszustand wird von der Razor Pages-Klasse PageModel oder der MVC-Klasse Controller mit HttpContext.Session zugegriffen. Diese Eigenschaft ist eine Implementierung von ISession.

Die ISession-Implementierung bietet mehrere Erweiterungsmethoden zum Festlegen und Abrufen von Integerwerten und Zeichenfolgenwerten. Die Erweiterungsmethoden befinden sich im Namespace Microsoft.AspNetCore.Http.

ISession-Erweiterungsmethoden:

Mit dem folgenden Codebeispiel wird der Sitzungswert für denIndexModel.SessionKeyName-Schlüssel (_Name in der Beispiel-App) auf einer Razor Pages-Seite abgerufen:

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

...

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

Im folgenden Codebeispiel wird veranschaulicht, wie Sie eine ganze Zahl und eine Zeichenfolge abrufen und festlegen können:

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);
    }
}

Das folgende Markup zeigt die Sitzungswerte auf einer Razor Page an:

@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>


Alle Sitzungsdaten müssen serialisiert werden, um ein Szenario mit einem verteilten Cache zu ermöglichen, auch wenn Sie den speicherinternen Cache verwenden. Serialisierer für Zeichenfolgen und ganze Zahlen werden durch die Erweiterungsmethoden von ISession bereitgestellt. Komplexe Typen müssen vom Benutzer mit einem anderen Verfahren wie etwa JSON serialisiert werden.

Verwenden Sie den folgenden Beispielcode, um Objekte zu serialisieren:

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);
    }
}

Im folgenden Beispiel wird dargestellt, wie ein serialisierbares Objekt mit der Klasse SessionExtensions festgelegt und abgerufen werden kann:

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));

        }
    }
}

Warnung

Das Speichern eines Liveobjekts in der Sitzung sollte mit Vorsicht verwendet werden, da bei serialisierten Objekten viele Probleme auftreten können. Weitere Informationen finden Sie unter Sitzungen sollten Objekte speichern dürfen (dotnet/aspnetcore #18159).

TempData

ASP.NET Core macht die Razor Pages-TempData oder Controller-TempData verfügbar. Diese Eigenschaft speichert Daten, bis sie in einer anderen Anforderung gelesen werden. Mit den Methoden Keep(String) und Peek(String) können die Daten untersucht werden, ohne am Ende der Anforderung gelöscht zu werden. Keep markiert alle Elemente im Wörterbuch für die Aufbewahrung. TempData ist:

  • Nützlich für die Umleitung, wenn Daten für mehr als eine einzelne Anforderung erforderlich sind.
  • Wird von TempData-Anbietern durch Verwendung von cookies oder des Sitzungszustands implementiert.

TempData-Beispiele

Beachten Sie die folgende Seite, die einen Kunden erstellt:

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");
    }
}

Die folgende Seite zeigt TempData["Message"] an:

@page
@model IndexModel

<h1>Peek Contacts</h1>

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

@*Content removed for brevity.*@

Im vorangehenden Markup wird TempData["Message"] am Ende der Anforderung nicht gelöscht, da Peek verwendet wird. Beim Aktualisieren der Seite wird der Inhalt von TempData["Message"] angezeigt.

Das folgende Markup ähnelt dem vorangehenden Code, verwendet jedoch Keep, um die Daten am Ende der Anforderung beizubehalten:

@page
@model IndexModel

<h1>Contacts Keep</h1>

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

@*Content removed for brevity.*@

Die Navigation zwischen den Seiten IndexPeek und IndexKeep löscht TempData["Message"] nicht.

Der folgende Code zeigt TempData["Message"] an, aber am Ende der Anforderung wird TempData["Message"] gelöscht:

@page
@model IndexModel

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

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

@*Content removed for brevity.*@

TempData-Anbieter

Der cookiebasierte TempData-Anbieter wird standardmäßig verwendet, um TempData in cookies zu speichern.

Die cookiedaten werden mit IDataProtector verschlüsselt, mit Base64UrlTextEncoder codiert und dann segmentiert. Die maximale cookiegröße beträgt aufgrund von Verschlüsselung und Segmentierung weniger als 4096 Bytes. Die cookiedaten werden nicht komprimiert, da es zu Sicherheitsproblemen kommen kann, wenn Daten verschlüsselt werden, z. B. durch CRIME- und BREACH-Angriffe. Weitere Informationen zum cookiebasierten TempData-Anbieter finden Sie unter CookieTempDataProvider.

Auswählen eines TempData-Anbieters

Bevor Sie einen TempData-Anbieter auswählen, müssen Sie folgende Überlegungen anstellen:

  • Verwendet die App bereits den Sitzungszustand? Falls dies der Fall ist, hat die Verwendung des TempData-Anbieters für den Sitzungszustand abgesehen von der Größe der Daten keine zusätzlichen Auswirkungen auf die App.
  • Verwendet die App TempData nur selten für verhältnismäßig kleine Datenmengen bis zu 500 Bytes? Falls dies der Fall ist, entsteht durch das cookie des TempData-Anbieters nur ein kleiner zusätzlicher Aufwand für jede Anforderung, die TempData enthält. Falls dies nicht der Fall ist, kann der Sitzungszustand des TempData-Anbieters nützlich sein, um Roundtrips für große Datenmengen für jede Anforderung durchzuführen, bis TempData verarbeitet wird.
  • Wird die App in einer Serverfarm auf mehreren Servern ausgeführt? In diesem Fall ist keine weitere Konfiguration erforderlich, um den cookie-TempData-Anbieter außerhalb des Schutzes von Daten zu verwenden. Weitere Informationen finden Sie unter Schutz von Daten in ASP.NET Core: Übersicht und Schlüsselspeicheranbieter.

Die meisten Webclients (z. B. Webbrowser) erzwingen Einschränkungen für die maximale Größe der cookies und für die Gesamtzahl der cookies. Wenn Sie das cookie des TempData-Anbieters verwenden, sollten Sie überprüfen, ob die App diese Einschränkungen überschreitet. Beachten Sie die Gesamtgröße der Daten. Rechnen Sie mit erhöhter cookiegröße aufgrund von Verschlüsselung und Segmentierung.

Konfigurieren des TempData-Anbieters

Der cookiebasierte TempData-Anbieter ist standardmäßig aktiviert.

Verwenden Sie die Erweiterungsmethode AddSessionStateTempDataProvider, um den sitzungsbasierten TempData-Anbieter zu aktivieren. Es ist nur ein Aufruf von AddSessionStateTempDataProvider erforderlich:

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();

Abfragezeichenfolgen

Eine begrenzte Menge an Daten kann von einer Anforderung an eine andere übergeben werden, indem Sie diese zu der Abfragezeichenfolge einer neuen Anforderung hinzufügen. Dies ist nützlich, um den Zustand dauerhaft zu erfassen und Links mit einem eingebetteten Zustand zuzulassen, die über E-Mail oder soziale Netzwerke geteilt werden sollen. Verwenden Sie keine Abfragezeichenfolgen für vertrauliche Daten, da URL-Abfragezeichenfolgen öffentlich sind.

Zusätzlich zur unbeabsichtigten Freigabe können auch Daten in Abfragezeichenfolgen die App entsprechenden CSRF-Angriffen (websiteübergreifende Anforderungsfälschung) aussetzen. Jeder gespeicherte Sitzungszustand muss vor solchen Anforderungsfälschungen geschützt sein. Weitere Informationen finden Sie unter Prevent Cross-Site Request Forgery (XSRF/CSRF) Attacks in ASP.NET Core (Verhindern von websiteübergreifenden Anforderungsfälschungen (XSRF/CSRF) in ASP.NET Core).

Verborgene Felder

Daten können in ausgeblendeten Formularfeldern gespeichert und an die nächste Anforderung zurückgesendet werden. Dies ist häufig in mehrseitigen Formularen der Fall. Die App muss die in verborgenen Feldern gespeicherten Daten immer wieder überprüfen, da der Client die Daten manipulieren könnte.

HttpContext.Items

Die Auflistung HttpContext.Items wird verwendet, um Daten zu speichern, während eine einzelne Anforderung verarbeitet wird. Die Inhalte der Auflistung werden nach der Verarbeitung jeder Anforderung verworfen. Die Items-Auflistung wird häufig von Komponenten oder Middleware zur Kommunikation verwendet, wenn sie zu unterschiedlichen Zeitpunkten während einer Anforderung ausgeführt werden und es keinen direkten Weg gibt, Parameter zu übergeben.

Im folgenden Beispiel fügt MiddlewareisVerified zur Auflistung Items hinzu:

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();

Bei Middleware, die nur in einer einzelnen App verwendet wird, ist es unwahrscheinlich, dass die Verwendung eines festen string-Schlüssels einen Schlüsselkonflikt verursacht. Um jedoch die Möglichkeit eines Schlüsselkonflikts ganz zu vermeiden, kann object als Elementschlüssel verwendet werden. Dieser Ansatz ist besonders nützlich für Middleware, die von Apps gemeinsam genutzt wird. Er bietet auch den Vorteil, dass im Code keine Schlüsselzeichenfolgen mehr verwendet werden. Das folgenden Beispiel zeigt, wie Sie einen object-Schlüssel verwenden, der in einer Middlewareklasse definiert wurde:

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>();
    }
}

Anderer Code kann auf den Wert zugreifen, der in HttpContext.Items gespeichert ist, indem er den Schlüssel verwendet, der von der Middlewareklasse zur Verfügung gestellt wird:

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

Das Caching stellt eine effiziente Möglichkeit zum Speichern und Abrufen von Daten dar. Die App kann die Lebensdauer zwischengespeicherter Elemente bestimmen. Weitere Informationen finden Sie unter Zwischenspeichern von Antworten in ASP.NET Core.

Zwischengespeicherte Daten sind nicht mit einer spezifischen Anforderung, einem spezifischen Benutzer oder einer spezifischen Sitzung verknüpft. Speichern Sie keine benutzerspezifischen Daten zwischen, die von anderen Benutzeranforderungen abgerufen werden können.

Informationen zum Zwischenspeichern anwendungsweiter Daten finden Sie unter Zwischenspeichern im Arbeitsspeicher in ASP.NET Core.

Überprüfen des Sitzungszustands

ISession.IsAvailable dient zur Überprüfung auf vorübergehende Fehler. Durch Aufrufen von IsAvailable vor der Ausführung der Sitzungsmiddleware wird eine InvalidOperationException ausgelöst.

Bibliotheken, für die die Sitzungsverfügbarkeit getestet werden muss, können HttpContext.Features.Get<ISessionFeature>()?.Session != null verwenden.

Häufige Fehler

  • „Unable to resolve service for type 'Microsoft.Extensions.Caching.Distributed.IDistributedCache' while attempting to activate 'Microsoft.AspNetCore.Session.DistributedSessionStore'. (Dienst kann nicht für den Typ „Microsoft.Extensions.Caching.Distributed.IDistributedCache“ aufgelöst werden, während versucht wird, auf „Microsoft.AspNetCore.Session.DistributedSessionStore“ zuzugreifen.)

    Dieser Fehler entsteht in der Regel, wenn nicht alle IDistributedCache-Implementierungen konfiguriert werden. Weitere Informationen finden Sie unter Verteiltes Zwischenspeichern in ASP.NET Core und Zwischenspeichern im Arbeitsspeicher in ASP.NET Core.

Wenn die Middleware für Sitzungen eine Sitzung nicht aufrechterhalten kann:

  • Die Middleware protokolliert die Ausnahme, und die Anforderung wird normal fortgesetzt.
  • Das führt zu unvorhersehbarem Verhalten.

Die Middleware für Sitzungen kann eine Sitzung nicht aufrechterhalten, wenn der Sicherungsspeicher nicht verfügbar ist. Nehmen wir an, dass ein Benutzer seinen Einkaufswagen in einer Sitzung speichert. Der Benutzer fügt ein Element zum Einkaufswagen hinzu, aber der Commit schlägt fehl. Die App wird nicht über den Fehler informiert und meldet dem Benutzer, dass das Element zum Einkaufswagen hinzugefügt wurde. Dies stimmt jedoch nicht.

Es wird empfohlen, nach Fehlern zu suchen, indem Sie await feature.Session.CommitAsync aufrufen, wenn die App mit dem Schreiben in die Sitzung fertig ist. CommitAsync löst eine Ausnahme aus, wenn der Sicherungsspeicher nicht verfügbar ist. Wenn CommitAsync fehlschlägt, kann die App die Ausnahme verarbeiten. LoadAsync wird unter den gleichen Bedingungen ausgelöst, wenn der Sicherungsspeicher nicht verfügbar ist.

Zusätzliche Ressourcen

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Hosten von ASP.NET Core in einer Webfarm

Von Rick Anderson, Kirk Larkin und Diana LaRose

Bei HTTP handelt es sich um ein zustandsloses Protokoll. HTTP-Anforderungen sind standardmäßig unabhängige Nachrichten, die keine Benutzerwerte beibehalten. In diesem Artikel werden mehrere Ansätze zum Beibehalten von Benutzerdaten zwischen Anforderungen beschrieben.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Zustandsverwaltung

Zustände können mithilfe mehrerer Ansätze gespeichert werden. Die einzelnen Ansätze werden im weiteren Verlauf dieses Artikels beschrieben.

Speicheransatz Speichermechanismus
Cookies HTTP-cookies. Schließt möglicherweise Daten ein, die mit serverseitigem App-Code gespeichert wurden.
Sitzungszustand HTTP-cookies und serverseitiger App-Code
TempData HTTP-cookies oder Sitzungszustand
Abfragezeichenfolgen HTTP-Abfragezeichenfolgen
Verborgene Felder HTTP-Formularfelder
HttpContext.Items Serverseitiger App-Code
Cache Serverseitiger App-Code

SignalR/Blazor Server und kontextbasierte HTTP-Zustandsverwaltung

SignalR-Apps sollten nicht den Sitzungszustand und andere Ansätze zur Zustandsverwaltung verwenden, die auf einem stabilen HTTP-Kontext zum Speichern von Informationen basieren. SignalR-Apps können den Zustand pro Verbindung in Context.Items im Hub speichern. Weitere Informationen und alternative Ansätze zur Zustandsverwaltung für Blazor Server-Apps finden Sie unter Blazor-Zustandsverwaltung in ASP.NET Core.

Cookie

Cookies speichern Daten anforderungsübergreifend. Da mit jeder Anforderung cookies gesendet werden, sollte deren Größe auf ein Minimum begrenzt sein. Idealerweise sollte nur ein Bezeichner in einem cookie gespeichert werden, während die Daten von der App gespeichert werden sollten. Die meisten Browser beschränken die Größe von cookies auf 4096 Byte. Nur eine begrenzte Anzahl von cookies ist für jede Domäne verfügbar.

Da cookies manipuliert werden können, müssen sie von der App überprüft werden. Cookies können von Benutzern gelöscht werden und können auf Clients ablaufen. cookies sind für gewöhnlich die dauerhafteste Form der Datenpersistenz auf dem Client.

Cookies werden häufig aus Personalisierungsgründen verwendet, wenn Inhalt für einen bekannten Benutzer angepasst wird. In den meisten Fällen wird der Benutzer nur identifiziert und nicht authentifiziert. Das cookie kann den Benutzernamen, Kontonamen oder eine eindeutige Benutzer-ID wie die GUID speichern. Dann können Sie mit dem cookie auf die persönlichen Einstellungen (z. B. die bevorzugte Farbe des Websitehintergrunds) des Benutzers zugreifen.

Beachten Sie die Europäische Datenschutz-Grundverordnung (DSGVO) beim Ausstellen von cookies und beim Umgang mit Aspekten des Datenschutzes. Weitere In finden Sie unter General Data Protection Regulation (GDPR) support in ASP.NET Core (DSGVO-Unterstützung in ASP.NET Core).

Sitzungszustand

Der Sitzungszustand ist ein Szenario in ASP.NET Core zum Speichern von Benutzerdaten, wenn der Benutzer eine Web-App verwendet. Der Sitzungszustand verwendet einen von der App verwalteten Speicher, um Daten für mehrere Anforderungen eines Clients beizubehalten. Die Sitzungsdaten werden durch einen Cache gesichert und als kurzlebige Daten betrachtet. Die Website sollte auch ohne die Sitzungsdaten weiterhin funktionieren. Kritische Anwendungsdaten sollten in der Benutzerdatenbank gespeichert und nur zur Leistungsoptimierung in der Sitzung zwischengespeichert werden.

Sitzungen werden in SignalRSignalR-Apps nicht unterstützt, da ein -Hub unabhängig vom HTTP-Kontext ausgeführt werden kann. Das kann z.B. passieren, wenn eine lange Abrufanforderung von einem Hub länger als die Lebensdauer des HTTP-Kontexts einer Anforderung offen gehalten wird.

ASP.NET Core verwaltet den Sitzungszustand, indem ein cookie an den Client übergeben wird, das die Sitzungs-ID enthält. Die Sitzungscookie-ID:

  • Sie wird mit jeder Anforderung an die App gesendet.
  • Sie wird von der App zum Abrufen der Sitzungsdaten verwendet.

Der Sitzungszustand verhält sich wie folgt:

  • Das Sitzungscookie ist für den Browser spezifisch. Die Sitzungen werden nicht browserübergreifend geteilt.
  • Sitzungscookies werden gelöscht, wenn die Browsersitzung abläuft.
  • Wenn für eine abgelaufene Sitzung ein cookie empfangen wird, wird eine neue Sitzung erstellt, die dasselbe cookie verwendet.
  • Leere Sitzungen werden nicht beibehalten. Für die Sitzung muss mindestens ein Wert festgelegt sein, damit die Sitzung anforderungsübergreifend beibehalten wird. Wenn eine Sitzung nicht beibehalten wird, wird eine neue Sitzungs-ID für jede neue Anforderung erzeugt.
  • Die App speichert Sitzungen für einen beschränkten Zeitraum nach der letzten Anforderung. Die App legt entweder ein Zeitlimit für die Sitzungen fest oder verwendet den Standardwert von 20 Minuten. Der Sitzungszustand ist ideal zum Speichern von Benutzerdaten:
    • Das ist spezifisch für eine bestimmte Sitzung.
    • Wo die Daten keine permanente und sitzungsübergreifende Speicherung erfordern.
  • Sitzungsdaten werden gelöscht, wenn die Implementierung von ISession.Clear aufgerufen wird oder wenn die Sitzung abläuft.
  • Es gibt kein Standardverfahren, wie App-Code darüber informiert wird, dass ein Clientbrowser geschlossen wurde oder dass ein Sitzungscookie gelöscht wurde oder auf dem Client abgelaufen ist.
  • Sitzungszustandscookies sind standardmäßig nicht als grundlegend gekennzeichnet. Der Sitzungszustand ist nicht praktisch, es sei denn, der Besucher der Website gestattet die Nachverfolgung. Weitere In finden Sie unter General Data Protection Regulation (GDPR) support in ASP.NET Core (DSGVO-Unterstützung in ASP.NET Core).

Warnung

Speichern Sie keine vertraulichen Daten im Sitzungszustand. Es besteht die Möglichkeit, dass der Benutzer seinen Browser nicht schließt oder die Sitzungscookies nicht löscht. Einige Browser behalten gültige Sitzungscookies browserfensterübergreifend bei. Eine Sitzung ist möglicherweise nicht auf einen einzelnen Benutzer beschränkt. Der nächste Benutzer kann die App mit demselben Sitzungscookie weiter durchsuchen.

Der Cacheanbieter im Arbeitsspeicher speichert Sitzungsdaten im Arbeitsspeicher des Servers, auf dem sich die App befindet. Beachten Sie in einem Szenario mit einer Serverfarm Folgendes:

Konfigurieren des Sitzungszustands

Das Microsoft.AspNetCore.Session-Paket:

  • Wird durch das Framework implizit einbezogen.
  • Stellt Middleware zum Verwalten eines Sitzungszustands zur Verfügung.

Startup muss folgende Elemente enthalten, um die Sitzungsmiddleware zu aktivieren:

Der folgende Code zeigt, wie Sie den speicherinternen Sitzungsanbieter mit einer Standardimplementierung von IDistributedCache im Arbeitsspeicher einrichten:

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();
        });
    }
}

Der vorangegangene Code setzt ein kurzes Zeitlimit, um das Testen zu vereinfachen.

Die Reihenfolge der Middleware ist wichtig. Rufen Sie UseSession nach UseRouting und vor UseEndpoints auf. Informationen finden Sie unter Festlegen einer Reihenfolge für Middleware.

HttpContext.Session ist verfügbar, nachdem der Sitzungszustand konfiguriert wurde.

Auf HttpContext.Session kann vor einem Aufruf von UseSession nicht zugegriffen werden.

Nachdem die App mit dem Schreiben in den Antwortdatenstrom begonnen hat, kann keine neue Sitzung mit einem neuen Sitzungscookie erstellt werden. Die Ausnahme wird im Webserverprotokoll erfasst und nicht im Browser angezeigt.

Asynchrones Laden des Sitzungszustands

Der Standardsitzungsanbieter in ASP.NET Core lädt Sitzungsaufzeichnungen aus dem zugrunde liegenden IDistributedCache-Speicher nur dann asynchron, wenn die ISession.LoadAsync-Methode explizit vor den Methoden TryGetValue, Set oder Remove aufgerufen wird. Wenn LoadAsync nicht zuerst aufgerufen wird, werden die zugrunde liegenden Sitzungsaufzeichnungen synchron geladen, was entsprechende Auswirkungen auf die Leistung haben kann.

Damit Apps dieses Muster erzwingen, umschließen Sie die Implementierungen DistributedSessionStore und DistributedSession mit Versionen, die eine Ausnahme auslösen, wenn die LoadAsync-Methode nicht vor TryGetValue, Set oder Remove aufgerufen wird. Registrieren Sie die umschlossenen Versionen in den Dienstcontainern.

Sitzungsoptionen

Verwenden Sie SessionOptions, um Standardwerte für Sitzungen zu überschreiben.

Option Beschreibung
Cookie Bestimmt die Einstellungen, die zum Erstellen des cookies verwendet wurden. Der Standardwert von Name ist SessionDefaults.CookieName (.AspNetCore.Session). Der Standardwert von Path ist SessionDefaults.CookiePath (/). Der Standardwert von SameSite ist SameSiteMode.Lax (1). Der Standardwert von HttpOnly ist true. Der Standardwert von IsEssential ist false.
IdleTimeout IdleTimeout gibt an, wie lang die Sitzung sich im Leerlauf befinden darf, bevor die Inhalte verworfen werden. Jeder Zugriff auf eine Sitzung setzt das Zeitlimit zurück. Diese Einstellung gilt nur für den Inhalt der Sitzung und nicht für das cookie. Der Standardwert beträgt 20 Minuten.
IOTimeout Der maximale Zeitraum, in dem eine Sitzung aus dem Speicher geladen oder mithilfe eines Commits erneut in diesem hinterlegt werden kann. Diese Einstellung gilt möglicherweise nur für asynchrone Vorgänge. Dieses Zeitlimit kann mit InfiniteTimeSpan deaktiviert werden. Der Standardwert beträgt 1 Minute.

Die Sitzung verwendet ein cookie, um Anforderungen eines Browsers nachzuverfolgen und zu identifizieren. Standardmäßig wird das cookie.AspNetCore.Session genannt und verwendet den Pfad von /. Da die Standardeinstellungen des cookies keine Domäne festlegen, wird es dem clientseitigen Skript auf der Seite nicht zur Verfügung gestellt (da HttpOnly standardmäßig auf true festgelegt ist).

Verwenden Sie SessionOptions, um Standardwerte für cookiesitzungen zu überschreiben.

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();
}

Die App verwendet die IdleTimeout-Eigenschaft, um zu bestimmen, wie lange sich eine Sitzung im Leerlauf befinden darf, bevor ihre Inhalte im Cache des Servers verworfen werden. Diese Eigenschaft ist unabhängig vom Ablauf der cookies. Jede Anforderung, die über die Sitzungsmiddleware übergeben wird, setzt das Zeitlimit zurück.

Der Sitzungszustand ist nicht sperrend. Die letzte Anforderung überschreibt die erste, wenn zwei Anforderungen gleichzeitig versuchen, die Inhalte einer Sitzung zu bearbeiten. Session wird als kohärente Sitzung implementiert, d.h., dass alle Inhalte zusammen gespeichert werden. Wenn zwei Anforderungen unterschiedliche Sitzungswerte bearbeiten möchten, überschreibt die letzte Anforderung möglicherweise Anforderungen der ersten.

Festlegen und Abrufen von Sitzungswerten

Auf den Sitzungszustand wird von der Razor Pages-Klasse PageModel oder der MVC-Klasse Controller mit HttpContext.Session zugegriffen. Diese Eigenschaft ist eine Implementierung von ISession.

Die ISession-Implementierung bietet mehrere Erweiterungsmethoden zum Festlegen und Abrufen von Integerwerten und Zeichenfolgenwerten. Die Erweiterungsmethoden befinden sich im Namespace Microsoft.AspNetCore.Http.

ISession-Erweiterungsmethoden:

Mit dem folgenden Codebeispiel wird der Sitzungswert für denIndexModel.SessionKeyName-Schlüssel (_Name in der Beispiel-App) auf einer Razor Pages-Seite abgerufen:

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

...

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

Im folgenden Codebeispiel wird veranschaulicht, wie Sie eine ganze Zahl und eine Zeichenfolge abrufen und festlegen können:

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);

Alle Sitzungsdaten müssen serialisiert werden, um ein Szenario mit einem verteilten Cache zu ermöglichen, auch wenn Sie den speicherinternen Cache verwenden. Serialisierer für Zeichenfolgen und ganze Zahlen werden durch die Erweiterungsmethoden von ISession bereitgestellt. Komplexe Typen müssen vom Benutzer mit einem anderen Verfahren wie etwa JSON serialisiert werden.

Verwenden Sie den folgenden Beispielcode, um Objekte zu serialisieren:

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);
    }
}

Im folgenden Beispiel wird dargestellt, wie ein serialisierbares Objekt mit der Klasse SessionExtensions festgelegt und abgerufen werden kann:

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

TempData

ASP.NET Core macht die Razor Pages-TempData oder Controller-TempData verfügbar. Diese Eigenschaft speichert Daten, bis sie in einer anderen Anforderung gelesen werden. Mit den Methoden Keep(String) und Peek(String) können die Daten untersucht werden, ohne am Ende der Anforderung gelöscht zu werden. Keep markiert alle Elemente im Wörterbuch für die Aufbewahrung. TempData ist:

  • Nützlich für die Umleitung, wenn Daten für mehr als eine einzelne Anforderung erforderlich sind.
  • Wird von TempData-Anbietern durch Verwendung von cookies oder des Sitzungszustands implementiert.

TempData-Beispiele

Beachten Sie die folgende Seite, die einen Kunden erstellt:

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");
    }
}

Die folgende Seite zeigt TempData["Message"] an:

@page
@model IndexModel

<h1>Peek Contacts</h1>

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

@*Content removed for brevity.*@

Im vorangehenden Markup wird TempData["Message"] am Ende der Anforderung nicht gelöscht, da Peek verwendet wird. Beim Aktualisieren der Seite wird der Inhalt von TempData["Message"] angezeigt.

Das folgende Markup ähnelt dem vorangehenden Code, verwendet jedoch Keep, um die Daten am Ende der Anforderung beizubehalten:

@page
@model IndexModel

<h1>Contacts Keep</h1>

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

@*Content removed for brevity.*@

Die Navigation zwischen den Seiten IndexPeek und IndexKeep löscht TempData["Message"] nicht.

Der folgende Code zeigt TempData["Message"] an, aber am Ende der Anforderung wird TempData["Message"] gelöscht:

@page
@model IndexModel

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

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

@*Content removed for brevity.*@

TempData-Anbieter

Der cookiebasierte TempData-Anbieter wird standardmäßig verwendet, um TempData in cookies zu speichern.

Die cookiedaten werden mit IDataProtector verschlüsselt, mit Base64UrlTextEncoder codiert und dann segmentiert. Die maximale cookiegröße beträgt aufgrund von Verschlüsselung und Segmentierung weniger als 4096 Bytes. Die cookiedaten werden nicht komprimiert, da es zu Sicherheitsproblemen kommen kann, wenn Daten verschlüsselt werden, z. B. durch CRIME- und BREACH-Angriffe. Weitere Informationen zum cookiebasierten TempData-Anbieter finden Sie unter CookieTempDataProvider.

Auswählen eines TempData-Anbieters

Bevor Sie einen TempData-Anbieter auswählen, müssen Sie folgende Überlegungen anstellen:

  • Verwendet die App bereits den Sitzungszustand? Falls dies der Fall ist, hat die Verwendung des TempData-Anbieters für den Sitzungszustand abgesehen von der Größe der Daten keine zusätzlichen Auswirkungen auf die App.
  • Verwendet die App TempData nur selten für verhältnismäßig kleine Datenmengen bis zu 500 Bytes? Falls dies der Fall ist, entsteht durch das cookie des TempData-Anbieters nur ein kleiner zusätzlicher Aufwand für jede Anforderung, die TempData enthält. Falls dies nicht der Fall ist, kann der Sitzungszustand des TempData-Anbieters nützlich sein, um Roundtrips für große Datenmengen für jede Anforderung durchzuführen, bis TempData verarbeitet wird.
  • Wird die App in einer Serverfarm auf mehreren Servern ausgeführt? In diesem Fall ist keine weitere Konfiguration erforderlich, um den cookie-TempData-Anbieter außerhalb des Schutzes von Daten zu verwenden (siehe Schutz von Daten in ASP.NET Core: Übersicht und Schlüsselspeicheranbieter).

Die meisten Webclients (z. B. Webbrowser) erzwingen Einschränkungen für die maximale Größe der cookies und für die Gesamtzahl der cookies. Wenn Sie das cookie des TempData-Anbieters verwenden, sollten Sie überprüfen, ob die App diese Einschränkungen überschreitet. Beachten Sie die Gesamtgröße der Daten. Rechnen Sie mit erhöhter cookiegröße aufgrund von Verschlüsselung und Segmentierung.

Konfigurieren des TempData-Anbieters

Der cookiebasierte TempData-Anbieter ist standardmäßig aktiviert.

Verwenden Sie die Erweiterungsmethode AddSessionStateTempDataProvider, um den sitzungsbasierten TempData-Anbieter zu aktivieren. Es ist nur ein Aufruf von AddSessionStateTempDataProvider erforderlich:

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();
    });
}

Abfragezeichenfolgen

Eine begrenzte Menge an Daten kann von einer Anforderung an eine andere übergeben werden, indem Sie diese zu der Abfragezeichenfolge einer neuen Anforderung hinzufügen. Dies ist nützlich, um den Zustand dauerhaft zu erfassen und Links mit einem eingebetteten Zustand zuzulassen, die über E-Mail oder soziale Netzwerke geteilt werden sollen. Verwenden Sie keine Abfragezeichenfolgen für vertrauliche Daten, da URL-Abfragezeichenfolgen öffentlich sind.

Zusätzlich zur unbeabsichtigten Freigabe können auch Daten in Abfragezeichenfolgen die App entsprechenden CSRF-Angriffen (websiteübergreifende Anforderungsfälschung) aussetzen. Jeder gespeicherte Sitzungszustand muss vor solchen Anforderungsfälschungen geschützt sein. Weitere Informationen finden Sie unter Prevent Cross-Site Request Forgery (XSRF/CSRF) Attacks in ASP.NET Core (Verhindern von websiteübergreifenden Anforderungsfälschungen (XSRF/CSRF) in ASP.NET Core).

Verborgene Felder

Daten können in ausgeblendeten Formularfeldern gespeichert und an die nächste Anforderung zurückgesendet werden. Dies ist häufig in mehrseitigen Formularen der Fall. Die App muss die in verborgenen Feldern gespeicherten Daten immer wieder überprüfen, da der Client die Daten manipulieren könnte.

HttpContext.Items

Die Auflistung HttpContext.Items wird verwendet, um Daten zu speichern, während eine einzelne Anforderung verarbeitet wird. Die Inhalte der Auflistung werden nach der Verarbeitung jeder Anforderung verworfen. Die Items-Auflistung wird häufig von Komponenten oder Middleware zur Kommunikation verwendet, wenn sie zu unterschiedlichen Zeitpunkten während einer Anforderung ausgeführt werden und es keinen direkten Weg gibt, Parameter zu übergeben.

Im folgenden Beispiel fügt MiddlewareisVerified zur Auflistung Items hinzu:

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"]}");
        });
    });
}

Für Middleware, die nur in einer einzelnen App verwendet wird, werden string-Schlüssel akzeptiert. Middleware, die von mehreren Apps verwendet wird, sollte eindeutige Objektschlüssel verwenden, um Schlüsselkonflikte zu vermeiden. Das folgenden Beispiel zeigt, wie Sie einen eindeutigen Objektschlüssel verwenden, der in einer Middlewareklasse definiert wurde:

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>();
    }
}

Anderer Code kann auf den Wert zugreifen, der in HttpContext.Items gespeichert ist, indem er den Schlüssel verwendet, der von der Middlewareklasse zur Verfügung gestellt wird:

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

Dieser Ansatz hat außerdem den Vorteil, dass das Verwenden von Schlüsselzeichenfolgen im Code vermieden wird.

cache

Das Caching stellt eine effiziente Möglichkeit zum Speichern und Abrufen von Daten dar. Die App kann die Lebensdauer zwischengespeicherter Elemente bestimmen. Weitere Informationen finden Sie unter Zwischenspeichern von Antworten in ASP.NET Core.

Zwischengespeicherte Daten sind nicht mit einer spezifischen Anforderung, einem spezifischen Benutzer oder einer spezifischen Sitzung verknüpft. Speichern Sie keine benutzerspezifischen Daten zwischen, die von anderen Benutzeranforderungen abgerufen werden können.

Informationen zum Zwischenspeichern anwendungsweiter Daten finden Sie unter Zwischenspeichern im Arbeitsspeicher in ASP.NET Core.

Häufige Fehler

  • „Unable to resolve service for type 'Microsoft.Extensions.Caching.Distributed.IDistributedCache' while attempting to activate 'Microsoft.AspNetCore.Session.DistributedSessionStore'. (Dienst kann nicht für den Typ „Microsoft.Extensions.Caching.Distributed.IDistributedCache“ aufgelöst werden, während versucht wird, auf „Microsoft.AspNetCore.Session.DistributedSessionStore“ zuzugreifen.)

    Dieser Fehler entsteht in der Regel, wenn nicht alle IDistributedCache-Implementierungen konfiguriert werden. Weitere Informationen finden Sie unter Verteiltes Zwischenspeichern in ASP.NET Core und Zwischenspeichern im Arbeitsspeicher in ASP.NET Core.

Wenn die Middleware für Sitzungen eine Sitzung nicht aufrechterhalten kann:

  • Die Middleware protokolliert die Ausnahme, und die Anforderung wird normal fortgesetzt.
  • Das führt zu unvorhersehbarem Verhalten.

Die Middleware für Sitzungen kann eine Sitzung nicht aufrechterhalten, wenn der Sicherungsspeicher nicht verfügbar ist. Nehmen wir an, dass ein Benutzer seinen Einkaufswagen in einer Sitzung speichert. Der Benutzer fügt ein Element zum Einkaufswagen hinzu, aber der Commit schlägt fehl. Die App wird nicht über den Fehler informiert und meldet dem Benutzer, dass das Element zum Einkaufswagen hinzugefügt wurde. Dies stimmt jedoch nicht.

Es wird empfohlen, nach Fehlern zu suchen, indem Sie await feature.Session.CommitAsync aufrufen, wenn die App mit dem Schreiben in die Sitzung fertig ist. CommitAsync löst eine Ausnahme aus, wenn der Sicherungsspeicher nicht verfügbar ist. Wenn CommitAsync fehlschlägt, kann die App die Ausnahme verarbeiten. LoadAsync wird unter den gleichen Bedingungen ausgelöst, wenn der Sicherungsspeicher nicht verfügbar ist.

Zusätzliche Ressourcen

Hosten von ASP.NET Core in einer Webfarm