Teilen über


Neuerungen in ASP.NET Core 9.0

In diesem Artikel werden die wichtigsten Änderungen in ASP.NET Core 9.0 aufgezeigt und Links zur relevanten Dokumentation bereitgestellt.

Dieser Artikel wurde für .NET 9 Preview 5 aktualisiert.

Blazor

In diesem Abschnitt werden neue Features für Blazor beschrieben.

.NET MAUIBlazor Hybrid und Web App-Lösungsvorlage

Eine neue Lösungsvorlage erleichtert die Erstellung von .NET MAUI-nativen und Blazor-Web-Client-Apps, die dieselbe Benutzeroberfläche verwenden. Diese Vorlage zeigt, wie Sie Client-Apps erstellen, welche die Wiederverwendung von Code maximieren und Android, iOS, Mac, Windows und Web verwenden.

Zu den wichtigsten Funktionen dieser Vorlage gehören:

  • Die Möglichkeit, einen interaktiven Blazor-Rendering-Modus für die Web-App zu wählen.
  • Automatische Erstellung der entsprechenden Projekte, einschließlich einer Blazor-Web App (globales interaktives Autorendering) und einer .NET MAUIBlazor Hybrid-App.
  • Die erstellten Projekte verwenden eine freigegebene Razor Klassenbibliothek (RCL), um die Komponenten der Benutzeroberfläche Razor zu verwalten.
  • Beispielcode ist enthalten, der veranschaulicht, wie Abhängigkeitsinjektion verwendet wird, um verschiedene Schnittstellenimplementierungen für die Blazor Hybrid-App und die Blazor-Web App bereitzustellen.

Um loszulegen, installieren Sie das .NET 9 SDK und installieren Sie den Workload .NET MAUI, der die Vorlage enthält:

dotnet workload install maui

Erstellen Sie eine Projektmappe aus der Projektvorlage in einer Befehlsshell mithilfe des folgenden Befehls:

dotnet new maui-blazor-web

Die Vorlage ist auch in Visual Studio verfügbar.

Hinweis

Derzeit tritt eine Ausnahme auf, wenn Blazor-Rendermodi auf Seiten-/Komponentenebene definiert sind. Weitere Informationen finden Sie unter BlazorWebView benötigt eine Möglichkeit, ResolveComponentForRenderMode (dotnet/aspnetcore #51235) zu aktivieren.

Weitere Informationen finden Sie unter Erstellen einer .NET MAUIBlazor Hybrid-App mit einer Blazor-Web App.

Optimierung der Übermittlung statischer Ressourcen

MapStaticAssets ist eine neue Middleware, welche die Bereitstellung statischer Ressourcen in jeder ASP.NET Core-App, einschließlich Blazor-Apps, optimiert.

Weitere Informationen finden Sie in den folgenden Ressourcen:

Erkennen des Renderorts, der Interaktivität und des zugewiesenen Rendermodus zur Laufzeit

Wir haben eine neue API eingeführt, die das Abfragen von Komponentenzuständen zur Laufzeit vereinfacht. Diese API bietet die folgenden Funktionen:

  • Ermitteln Sie den aktuellen Ausführungsort der Komponente: Dies kann besonders hilfreich beim Debuggen und Optimieren der Komponentenleistung sein.
  • Überprüfen Sie, ob die Komponente in einer interaktiven Umgebung ausgeführt wird: Dies kann für Komponenten hilfreich sein, die je nach Interaktivität ihrer Umgebung unterschiedliche Verhaltensweisen aufweisen.
  • Abrufen des zugewiesenen Rendermodus für die Komponente: Das Verständnis des Rendermodus kann dabei helfen, den Renderingprozess zu optimieren und die Gesamtleistung einer Komponente zu verbessern.

Verbesserte serverseitige erneute Verbindung:

Die folgenden Verbesserungen wurden an der serverseitigen Standardverbindungsumgebung vorgenommen:

  • Wenn der Benutzer zurück zu einer App mit einer getrennten Verbindung navigiert, wird die erneute Verbindung sofort versucht, anstatt auf die Dauer des nächsten erneuten Verbindungsintervalls zu warten. Dies verbessert die Benutzererfahrung, wenn Sie in einer Browser-Registerkarte, die in den Ruhezustand übergegangen ist, zu einer App navigieren.

  • Wenn ein erneuter Verbindungsversuch den Server erreicht, der Server aber bereits den Schaltkreis freigegeben hat, tritt automatisch eine Seitenaktualisierung auf. Dadurch wird verhindert, dass der Benutzer die Seite manuell aktualisieren muss, wenn dies wahrscheinlich zu einer erfolgreichen erneuten Verbindung führt.

  • Die Zeitdauer für die erneute Verbindung verwendet eine berechnete Backoffstrategie. Standardmäßig treten die ersten Wiederholungsversuche in schneller Folge ohne Wiederholungsintervall auf, bevor berechnete Verzögerungen zwischen Versuchen eingeführt werden. Sie können das Wiederholungsintervallverhalten anpassen, indem Sie eine Funktion zum Berechnen des Wiederholungsintervalls angeben, wie das folgende exponentielle Backoff-Beispiel veranschaulicht:

    Blazor.start({
      circuit: {
        reconnectionOptions: {
          retryIntervalMilliseconds: (previousAttempts, maxRetries) => 
            previousAttempts >= maxRetries ? null : previousAttempts * 1000
        },
      },
    });
    
  • Das Design der Standard-Benutzeroberfläche für die Wiederverbindung wurde modernisiert.

Weitere Informationen finden Sie in den Anleitungen zu ASP.NET Core BlazorSignalR.

Vereinfachte Serialisierung des Authentifizierungsstatus für Blazor-Web-Apps

Neue APIs erleichtern das Hinzufügen der Authentifizierung zu einer bestehenden Blazor-Web-App. Wenn Sie eine neue Blazor-Web-App mit Authentifizierung über Einzelkonten erstellen und die WebAssembly-basierte Interaktivität aktivieren, enthält das Projekt sowohl im Server- als auch im Client-Projekt einen benutzerdefinierten Wert AuthenticationStateProvider.

Diese Anbieter geben den Authentifizierungsstatus des Benutzers an den Browser weiter. Die Authentifizierung auf dem Server statt auf dem Client ermöglicht der Anwendung den Zugriff auf den Authentifizierungsstatus während des Prerenderings und vor der Initialisierung der Blazor WebAssembly-Laufzeit.

Die benutzerdefinierten AuthenticationStateProvider-Implementierungen verwenden den Dienst Persistent Component State (PersistentComponentState), um den Authentifizierungsstatus in HTML-Kommentare zu serialisieren und ihn von WebAssembly zurückzulesen, um eine neue AuthenticationState-Instanz zu erstellen.

Das funktioniert gut, wenn Sie von der Blazor-Web-App-Projektvorlage ausgegangen sind und die Option Individuelle Konten gewählt haben, aber es ist eine Menge Code, den Sie selbst implementieren oder kopieren müssen, wenn Sie versuchen, die Authentifizierung zu einem bestehenden Projekt hinzuzufügen. Es gibt jetzt APIs, die jetzt Teil der Blazor-Web App-Projektvorlage sind, die in Server- und Clientprojekten aufgerufen werden können, um diese Funktionalität hinzuzufügen:

  • AddAuthenticationStateSerialization: Fügt die erforderlichen Dienste hinzu, um den Authentifizierungsstatus auf dem Server zu serialisieren.
  • AddAuthenticationStateDeserialization: Fügt die erforderlichen Dienste hinzu, um den Authentifizierungsstatus im Browser zu deserialisieren.

Diese API serialisiert standardmäßig nur die serverseitigen Namens- und Rollenansprüche für den Zugriff im Browser. Eine Option kann an AddAuthenticationStateSerialization übergeben werden, um alle Ansprüche einzuschließen.

Weitere Informationen finden Sie in den folgenden Abschnitten des ** Artikels:

Hinzufügen statischer serverseitiger Renderingseiten (SSR) zu einer global interaktiven Blazor Web-App

Mit der Veröffentlichung von .NET 9 ist es jetzt einfacher, statische SSR-Seiten zu Apps hinzuzufügen, die globale Interaktivität übernehmen.

Dieser Ansatz ist nur hilfreich, wenn bestimmte Seiten der App nicht mit interaktivem Server- oder WebAssembly-Rendering funktionieren. Dieser Ansatz eignet sich z. B. für Seiten, die vom Lesen/Schreiben von HTTP-cookies abhängig sind und nur in einem Anforderungs-/Antwortzyklus funktionieren können, nicht mit interaktivem Rendering. Für Seiten, die mit interaktivem Rendering funktionieren, sollten Sie kein statisches SSR-Rendering erzwingen, da es weniger reaktionsfähig und weniger effizient für den Endbenutzer ist.

Markieren Sie eine beliebige Razor-Komponentenseite mit dem neuen [ExcludeFromInteractiveRouting]-Attribut, das mit der @attributeRazor-Direktive zugewiesen wurde:

@attribute [ExcludeFromInteractiveRouting]

Durch das Anwenden des Attributs wird die Navigation zu der Seite über das interaktive Routing beendet. Die eingehende Navigation wird gezwungen, die Seite vollständig neu zu laden, anstatt die Seite über das interaktive Routing aufzulösen. Das vollständige Neuladen zwingt die Stammkomponente der obersten Ebene, in der Regel die App-Komponente (App.razor), vom Server erneut zu rendern, sodass die App zu einem anderen Rendermodus auf oberster Ebene wechseln kann.

Mit der HttpContext.AcceptsInteractiveRouting-Erweiterungsmethode kann die Komponente erkennen, ob [ExcludeFromInteractiveRouting] auf die aktuelle Seite angewendet wird.

Verwenden Sie in der App-Komponente das Muster im folgenden Beispiel:

  • Seiten, die nicht mit [ExcludeFromInteractiveRouting]-Standard für den InteractiveServer Rendermodus mit globaler Interaktivität versehen sind. Sie können InteractiveServer durch InteractiveWebAssembly oder InteractiveAuto ersetzen, um einen anderen standardmäßigen globalen Rendermodus anzugeben.
  • Seiten, die mit [ExcludeFromInteractiveRouting] versehen sind, übernehmen statischen SSR (PageRenderMode wird null zugewiesen).
<!DOCTYPE html>
<html>
<head>
    ...
    <HeadOutlet @rendermode="@PageRenderMode" />
</head>
<body>
    <Routes @rendermode="@PageRenderMode" />
    ...
</body>
</html>

@code {
    [CascadingParameter]
    private HttpContext HttpContext { get; set; } = default!;

    private IComponentRenderMode? PageRenderMode
        => HttpContext.AcceptsInteractiveRouting() ? InteractiveServer : null;
}

Eine Alternative zur Verwendung der HttpContext.AcceptsInteractiveRouting-Erweiterungsmethode besteht darin, Endpunktmetadaten manuell mithilfe von HttpContext.GetEndpoint()?.Metadata zu lesen.

Dieses Feature wird in der Referenzdokumentation in ASP.NET Core Blazor Rendermodi behandelt.

Constructor Injection

Razor Komponenten unterstützen die Konstruktoreinfügung.

Im folgenden Beispiel fügt die partielle (CodeBehind)-Klasse den NavigationManager Dienst mithilfe eines primären Konstruktors ein:

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

Weitere Informationen finden Sie unter Abhängigkeitsinjektion in ASP.NET Core Blazor.

Websocket-Komprimierung für interaktive Serverkomponenten

Standardmäßig aktivieren Interaktive Server-Komponenten die Komprimierung für WebSocket-Verbindungen und legen eineframe-ancestors CSP-Direktive (Content Security Policy) fest, die 'self'nur das Einbetten der App in einen <iframe> Ursprung ermöglicht, von dem die App bei aktivierter Komprimierung bereitgestellt wird oder wenn eine Konfiguration für den WebSocket-Kontext bereitgestellt wird.

Komprimierung kann durch Festlegen ConfigureWebSocketOptions auf null, wodurch die Sicherheitsanfälligkeit der App zum Angriff reduziert wird, dies kann jedoch zu einer verringerten Leistung führen:

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

Konfigurieren Sie einen strikteren frame-ancestors CSP mit einem Wert von 'none' (einfache Anführungszeichen erforderlich), was die WebSocket-Komprimierung zulässt, aber verhindert, dass Browser die App in eine der <iframe>folgenden Werte einbetten:

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

Weitere Informationen finden Sie in den folgenden Ressourcen:

Behandeln von Tastaturkompositionsereignissen in Blazor

Die neue KeyboardEventArgs.IsComposing-Eigenschaft gibt an, ob das Tastaturereignis Teil einer Kompositionssitzung ist. Das Nachverfolgen des Kompositionszustands von Tastaturereignissen ist entscheidend für die Behandlung internationaler Zeicheneingabemethoden.

Parameter OverscanCount zu QuickGrid hinzugefügt

Die QuickGrid-Komponente macht jetzt eine OverscanCount-Eigenschaft verfügbar, die angibt, wie viele zusätzliche Zeilen vor und nach dem sichtbaren Bereich gerendert werden, wenn die Virtualisierung aktiviert ist.

Der Standard OverscanCount ist „3“. Das folgende Beispiel erhöht OverscanCount um 4:

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

SignalR

In diesem Abschnitt werden neue Features für SignalR beschrieben.

Polymorphe Typunterstützung in SignalR-Hubs

Hubmethoden können nun eine Basisklasse anstelle der abgeleiteten Klasse akzeptieren, um polymorphe Szenarien zu ermöglichen. Der Basistyp muss annotiert werden, um Polymorphismus zu ermöglichen.

public class MyHub : Hub
{
    public void Method(JsonPerson person)
    {
        if (person is JsonPersonExtended)
        {
        }
        else if (person is JsonPersonExtended2)
        {
        }
        else
        {
        }
    }
}

[JsonPolymorphic]
[JsonDerivedType(typeof(JsonPersonExtended), nameof(JsonPersonExtended))]
[JsonDerivedType(typeof(JsonPersonExtended2), nameof(JsonPersonExtended2))]
private class JsonPerson
{
    public string Name { get; set; }
    public Person Child { get; set; }
    public Person Parent { get; set; }
}

private class JsonPersonExtended : JsonPerson
{
    public int Age { get; set; }
}

private class JsonPersonExtended2 : JsonPerson
{
    public string Location { get; set; }
}

Minimale APIs

In diesem Abschnitt werden neue Features für minimale APIs beschrieben.

InternalServerError und InternalServerError<TValue> wurden zu TypedResults hinzugefügt.

Die Klasse TypedResults ist ein hilfreiches Mittel für die Rückgabe von stark typisierten HTTP-Statuscode-basierten Antworten aus einer minimalen API. TypedResults enthält jetzt Factorymethoden und Typen für die Rückgabe von „500 Interner Serverfehler“-Antworten von Endpunkten. Hier ist ein Beispiel, das eine 500-Antwort zurückgibt:

var app = WebApplication.Create();

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

app.Run();

OpenAPI

Integrierte Unterstützung für die OpenAPI-Dokumentgenerierung

Die OpenAPI-Spezifikation ist ein Standard zur Beschreibung von HTTP-APIs. Mit dem Standard können Entwickler die Form der APIs definieren, die an Clientgeneratoren, Servergeneratoren, Testtools, Dokumentationen und vieles mehr angeschlossen werden können. In .NET 9 Preview bietet ASP.NET Core integrierte Unterstützung für das Generieren von OpenAPI-Dokumenten, die controllerbasierte oder minimale APIs über das Microsoft.AspNetCore.OpenApi-Paket darstellen.

Der folgende hervorgehobene Code ruft Folgendes auf:

  • AddOpenApi zum Registrieren der erforderlichen Abhängigkeiten im DI-Container der App.
  • MapOpenApi zum Registrieren der erforderlichen OpenAPI-Endpunkte in den Routen der App.
var builder = WebApplication.CreateBuilder();

builder.Services.AddOpenApi();

var app = builder.Build();

app.MapOpenApi();

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

app.Run();

Installieren Sie das Microsoft.AspNetCore.OpenApi-Paket im Projekt mithilfe des folgenden Befehls:

dotnet add package Microsoft.AspNetCore.OpenApi --prerelease

Führen Sie die App aus, und navigieren Sie zu openapi/v1.json, um das generierte OpenAPI-Dokument anzuzeigen:

OpenAPI-Dokument

OpenAPI-Dokumente können auch zur Buildzeit generiert werden, indem Sie das Microsoft.Extensions.ApiDescription.Server-Paket hinzufügen:

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

Fügen Sie in der Projektdatei der App Folgendes hinzu:

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

Führen Sie dotnet build aus, und prüfen Sie die generierte JSON-Datei im Projektverzeichnis.

OpenAPI-Dokumentgenerierung zur Erstellungszeit

In ASP.NET Core integrierte OpenAPI-Dokumentgenerierung bietet Unterstützung für verschiedene Anpassungen und Optionen. Sie bietet Dokument- und Operationstransformatoren und die Möglichkeit, mehrere OpenAPI-Dokumente für dieselbe Anwendung zu verwalten.

Weitere Informationen zu ASP.NET den neuen OpenAPI-Dokumentfunktionen von Core finden Sie in den neuen Microsoft.AspNetCore.OpenApi-Dokumenten.

Authentifizierung und Autorisierung

In diesem Abschnitt werden neue Features für Authentifizierung und Autorisierung beschrieben.

Anpassung der OIDC- und OAuth-Parameter

Die OAuth- und OIDC-Authentifizierungs-Handler verfügen jetzt über eine AdditionalAuthorizationParameters Option, mit der Sie die Parameter der Autorisierungsnachricht, die normalerweise Teil des Redirect-Query-Strings sind, einfacher anpassen können. In .NET 8 und früher erfordert dies einen benutzerdefinierten OnRedirectToIdentityProvider Callback oder eine überschriebene BuildChallengeUrl Methode in einem benutzerdefinierten Handler. Hier ist ein Beispiel für .NET 8 Code:

builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
    options.Events.OnRedirectToIdentityProvider = context =>
    {
        context.ProtocolMessage.SetParameter("prompt", "login");
        context.ProtocolMessage.SetParameter("audience", "https://api.example.com");
        return Task.CompletedTask;
    };
});

Das vorangegangene Beispiel kann nun zu folgendem Code vereinfacht werden:

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

Konfigurieren Sie die erweiterten Authentifizierungs-Flags von HTTP.sys

Sie können nun die HTTP_AUTH_EX_FLAG_ENABLE_KERBEROS_CREDENTIAL_CACHING und HTTP_AUTH_EX_FLAG_CAPTURE_CREDENTIAL HTTP.sys-Flags konfigurieren, indem Sie die neuen EnableKerberosCredentialCaching und CaptureCredentials Eigenschaften der HTTP.sys AuthenticationManager verwenden, um die Handhabung der Windows-Authentifizierung zu optimieren. Zum Beispiel:

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

Verschiedenes

In den folgenden Abschnitten werden verschiedene neue Features beschrieben.

Neue HybridCache-Bibliothek

Die HybridCache-API überbrückt einige Lücken in den IDistributedCache- und IMemoryCache-APIs. Außerdem werden neue Funktionen hinzugefügt, z. B.:

  • "Stampede"-Schutz, um parallele Abrufe derselben Arbeit zu verhindern.
  • Konfigurierbare Serialisierung.

HybridCache ist als Drop-In-Ersatz für vorhandene IDistributedCache- und IMemoryCache-Nutzung konzipiert und bietet eine einfache API zum Hinzufügen von neuem Zwischenspeicherungscode. Es bietet eine einheitliche API für die In-Process- und Out-of-Process-Zwischenspeicherung.

Um zu sehen, wie die HybridCache-API vereinfacht wird, vergleichen Sie sie mit Code, der IDistributedCache verwendet. Hier sehen Sie ein Beispiel dafür, wie die Verwendung von IDistributedCache aussieht:

public class SomeService(IDistributedCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        var key = $"someinfo:{name}:{id}"; // Unique key for this combination.
        var bytes = await cache.GetAsync(key, token); // Try to get from cache.
        SomeInformation info;
        if (bytes is null)
        {
            // Cache miss; get the data from the real source.
            info = await SomeExpensiveOperationAsync(name, id, token);

            // Serialize and cache it.
            bytes = SomeSerializer.Serialize(info);
            await cache.SetAsync(key, bytes, token);
        }
        else
        {
            // Cache hit; deserialize it.
            info = SomeSerializer.Deserialize<SomeInformation>(bytes);
        }
        return info;
    }

    // This is the work we're trying to cache.
    private async Task<SomeInformation> SomeExpensiveOperationAsync(string name, int id,
        CancellationToken token = default)
    { /* ... */ }
}

Das ist viel Arbeit, um jedes Mal richtig zu liegen, einschließlich Dinge wie Serialisierung. Und im Szenario „Cachefehler“ könnten Sie mit mehreren gleichzeitigen Threads enden, die alle einen Cachefehler erhalten, alle zugrunde liegenden Daten abrufen, serialisieren und alle diese Daten an den Cache senden.

Um diesen Code mit HybridCache zu vereinfachen und zu verbessern, müssen wir zuerst die neue Bibliothek Microsoft.Extensions.Caching.Hybrid hinzufügen:

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

Registrieren Sie den HybridCache-Dienst, wie Sie eine IDistributedCache-Implementierung registrieren würden:

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

Jetzt können die meisten Zwischenspeicherungsbedenken auf HybridCache entladen werden:

public class SomeService(HybridCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        return await cache.GetOrCreateAsync(
            $"someinfo:{name}:{id}", // Unique key for this combination.
            async cancel => await SomeExpensiveOperationAsync(name, id, cancel),
            token: token
        );
    }
}

Wir stellen eine konkrete Implementierung der abstrakten Klasse HybridCache über Abhängigkeitsinjektion bereit, aber es ist beabsichtigt, dass Entwickler benutzerdefinierte Implementierungen der API bereitstellen können. Die HybridCache-Implementierung befasst sich mit allem, was mit dem Caching zusammenhängt, einschließlich der Handhabung gleichzeitiger Operationen. Das cancel-Token steht hier für die kombinierte Annullierung aller gleichzeitigen Anrufer –- nicht nur für die Annullierung des Anrufers, den wir sehen können (d. h. token).

Szenarien mit hohem Durchsatz können mithilfe des TState-Musters weiter optimiert werden, um den Aufwand von erfassten Variablen und Rückrufen pro Instanz zu vermeiden:

public class SomeService(HybridCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync(string name, int id, CancellationToken token = default)
    {
        return await cache.GetOrCreateAsync(
            $"someinfo:{name}:{id}", // unique key for this combination
            (name, id), // all of the state we need for the final call, if needed
            static async (state, token) =>
                await SomeExpensiveOperationAsync(state.name, state.id, token),
            token: token
        );
    }
}

HybridCache verwendet ggf. die konfigurierte IDistributedCache-Implementierung für sekundäre Out-of-Process-Speicherung, z. B. mithilfe von Redis. Aber auch ohne IDistributedCache bietet der HybridCache-Dienst weiterhin In-Process-Cache- und Stampede-Schutz.

Ein Hinweis zur Wiederverwendung von Objekten

Im typischen vorhandenen Code, der IDistributedCache verwendet, führt jeder Abruf eines Objekts aus dem Cache zur Deserialisierung. Dieses Verhalten bedeutet, dass jeder gleichzeitige Aufrufer eine separate Instanz des Objekts erhält, die nicht mit anderen Instanzen interagieren kann. Das Ergebnis ist Threadsicherheit, da es kein Risiko für gleichzeitige Änderungen an derselben Objektinstanz gibt.

Da viele HybridCache-Verwendungen von vorhandenem IDistributedCache-Code angepasst werden, behält HybridCache dieses Verhalten standardmäßig bei, um die Einführung von Parallelitätsfehlern zu vermeiden. Ein bestimmter Anwendungsfall ist jedoch inhärent threadsicher:

  • Wenn die zwischengespeicherten Typen unveränderlich sind.
  • Wenn der Code sie nicht ändert.

Informieren Sie in solchen Fällen HybridCache, dass es sicher ist, Instanzen wiederzuverwenden, indem Sie:

  • Den Typ als sealed markieren. Das Schlüsselwort sealed in C# bedeutet, dass die Klasse nicht geerbt werden kann.
  • Anwenden des [ImmutableObject(true)]-Attributs. Das Attribut [ImmutableObject(true)] gibt an, dass der Status des Objekts nach der Erstellung nicht mehr geändert werden kann.

Durch die erneute Verwendung von Instanzen kann HybridCache den Mehraufwand der CPU- und Objektzuordnungen verringern, die mit der Deserialisierung pro Aufruf verbunden sind. Dies kann zu Leistungsverbesserungen in Szenarien führen, in denen die zwischengespeicherten Objekte groß sind oder häufig aufgerufen werden.

Weitere HybridCache-Funktionen

Wie IDistributedCache unterstützt HybridCache das Entfernen von Schlüsseln mit einer RemoveKeyAsync-Methode.

HybridCache stellt auch optionale APIs für IDistributedCache-Implementierungen bereit, um byte[]-Zuordnungen zu vermeiden. Dieses Feature wird von den Vorschauversionen der Microsoft.Extensions.Caching.StackExchangeRedis- und Microsoft.Extensions.Caching.SqlServer-Pakete implementiert.

Die Serialisierung wird als Teil der Registrierung des Diensts konfiguriert, wobei typspezifische und generalisierte Serialisierer über die WithSerializer- und .WithSerializerFactory-Methoden, verkettet vom AddHybridCache-Aufruf, unterstützt werden. Standardmäßig behandelt die Bibliothek string und byte[] intern und verwendet System.Text.Json für alles weitere, aber Sie können protobuf, xml oder etwas anderes verwenden.

HybridCache unterstützt ältere .NET-Runtimes bis zu .NET Framework 4.7.2 und .NET Standard 2.0.

Weitere Informationen zu HybridCache finden Sie unter HybridCache-Bibliothek in ASP.NET Core

Verbesserungen der Seite mit Ausnahmen für Entwickler

Die ASP.NET Core-Seite mit Ausnahmen für Entwickler wird angezeigt, wenn eine App während der Entwicklung eine unbehandelte Ausnahme auslöst. Die Seite mit Ausnahmen für Entwickler bietet ausführliche Informationen zur Ausnahme und zur Anforderung.

In Preview 3 wurden Endpunktmetadaten auf der Entwicklerausnahmeseite hinzugefügt. ASP.NET Core verwendet Endpunkt-Metadaten, um das Verhalten von Endpunkten zu steuern, z. B. Routing, Antwort-Caching, Ratenbegrenzung, OpenAPI-Generierung und mehr. Die folgende Abbildung zeigt die neuen Metadaten-Informationen im Abschnitt Routing auf der Entwicklerausnahmeseite:

Die neuen Metadaten-Informationen auf der Entwicklerausnahmeseite.

Beim Testen der Ausnahmeseite für Entwickler wurden kleine Verbesserungen der Lebensqualität identifiziert. Sie wurden in Preview 4 ausgeliefert:

  • Besserer Textumbruch. Lange cookies, Abfragezeichenfolgenwerte und Methodennamen fügen keine horizontalen Browser-Bildlaufleisten mehr hinzu.
  • Größerer Text, der in modernen Designs zu finden ist.
  • Konsistentere Tabellengrößen.

Die folgende animierte Abbildung zeigt die neue Seite mit Ausnahmen für Entwickler:

Die neue Seite mit Ausnahmen für Entwickler

Verbesserungen beim Debuggen von Wörterbuchen

Die Debuganzeige von Wörterbüchern und anderen Schlüsselwertsammlungen verfügt über ein verbessertes Layout. Der Schlüssel wird in der Schlüsselspalte des Debuggers angezeigt, anstatt mit dem Wert verkettet zu werden. Die folgenden Bilder stellen die alte und die neue Anzeige eines Wörterbuchs im Debugger dar.

Vorher:

Die bisherige Debugger-Oberfläche

Nachher:

Die neue Debugger-Oberfläche

ASP.NET Core verfügt über viele Schlüsselwertauflistungen. Diese verbesserte Debugerfahrung gilt für:

  • HTTP-Kopfzeilen
  • Abfragezeichenfolgen
  • Formulare
  • Cookie
  • Anzeigen von Daten
  • Routendaten
  • Features

Fix für 503-Apps während der Wiederverwendung von Apps in IIS

Standardmäßig gibt es jetzt eine Verzögerung von einer Sekunde, wenn IIS über eine Wiederverwendung oder ein Herunterfahren benachrichtigt wird und wenn ANCM den verwalteten Server anweist, das Herunterfahren zu initiieren. Die Verzögerung kann über die Umgebungsvariable ANCM_shutdownDelay oder durch Festlegen der Handlereinstellung shutdownDelay konfiguriert werden. Beide Werte sind in Millisekunden. Die Verzögerung soll in erster Linie die Wahrscheinlichkeit eines Wettrennens verringern, bei dem:

  • IIS keine Warteschlangenanforderungen gestartet hat, um zur neuen App zu wechseln.
  • ANCM mit der Ablehnung neuer Anforderungen beginnt, die in die alte App gelangen.

Für langsamere Computer oder Computer mit höherer CPU-Auslastung muss dieser Wert möglicherweise angepasst werden, um die Wahrscheinlichkeit 503 zu verringern.

Beispiel der Einstellung shutdownDelay:

<aspNetCore processPath="dotnet" arguments="myapp.dll" stdoutLogEnabled="false" stdoutLogFile=".logsstdout">
  <handlerSettings>
    <!-- Milliseconds to delay shutdown by.
    this doesn't mean incoming requests will be delayed by this amount,
    but the old app instance will start shutting down after this timeout occurs -->
    <handlerSetting name="shutdownDelay" value="5000" />
  </handlerSettings>
</aspNetCore>

Der Fix befindet sich im global installierten ANCM-Modul, das aus dem Hostingbundle stammt.

Optimieren der Bereitstellung statischer Webobjekte

Das Erstellen von leistungsfähigen Web-Apps umfasst die Optimierung der Ressourcenübermittlung an den Browser. Dies umfasst viele Aspekte wie:

MapStaticAssets ist eine neue Middleware, die die Übermittlung statischer Objekte in einer App optimiert. Sie ist für alle UI-Frameworks geeignet, einschließlich Blazor, Razor Pages und MVC. Sie ist in der Regel ein Drop-In-Ersatz für UseStaticFiles.

Der Vorgang von MapStaticAssets besteht in der Kombination von Build- und Veröffentlichungsprozessen, um Informationen über alle statischen Ressourcen in einer Anwendung zu sammeln. Diese Informationen werden dann von der Laufzeitbibliothek verwendet, um diese Dateien effizient an den Browser zu liefern.

MapStaticAssets kann UseStaticFiles in den meisten Situationen ersetzen, ist aber für die Bereitstellung der Ressourcen optimiert, die der App zum Zeitpunkt der Erstellung und Veröffentlichung bekannt sind. Wenn die App Ressourcen von anderen Speicherorten bereitstellt, z. B. von der Festplatte oder von eingebetteten Ressourcen, sollte UseStaticFiles verwendet werden.

MapStaticAssets bietet die folgenden Vorteile, die UseStaticFiles nicht hat:

  • Buildzeitkomprimierung für alle Ressourcen in der App:
    • gzip während der Entwicklung und gzip + brotli während der Veröffentlichung.
    • Alle Ressourcen werden mit dem Ziel komprimiert, die Größe der Ressourcen auf ein Minimum zu reduzieren.
  • Inhaltsbasierte ETags: Die Etags für jede Ressource sind die Base64-codierte Zeichenfolge des SHA-256-Hashs des Inhalts. Dadurch wird sichergestellt, dass der Browser eine Datei nur dann erneut lädt, wenn sich der Inhalt geändert hat.

In der folgenden Tabelle sind die ursprünglichen und komprimierten Größen der CSS- und JS-Dateien in der Razor Pages-Standardvorlage aufgeführt:

Datei Ursprünglich Compressed % Reduzierung
bootstrap.min.css 163 17,5 89,26 %
jquery.js 89,6 28 68,75 %
bootstrap.min.js 78,5 20 74,52 %
Gesamt 331,1 65,5 80,20 %

Die folgende Tabelle zeigt die ursprünglichen und komprimierten Größen mithilfe der Fluent UI Blazor Komponentenbibliothek:

Datei Ursprünglich Compressed % Reduzierung
fluent.js 384 73 80,99 %
fluent.css 94 11 88,30 %
Gesamt 478 84 82,43 %

Ergebnis: 478 KB unkomprimiert zu 84 KB komprimiert.

Die folgende Tabelle zeigt die originalen und komprimierten Größen mithilfe der MudBlazorBlazor-Komponentenbibliothek:

Datei Ursprünglich Compressed Reduzierung
MudBlazor.min.css 541 37,5 93,07 %
MudBlazor.min.js 47,4 9.2 80,59 %
Gesamt 588,4 46,7 92,07 %

Optimierung erfolgt automatisch bei Verwendung von MapStaticAssets. Wenn eine Bibliothek hinzugefügt oder aktualisiert wird, z. B. mit neuem JavaScript oder CSS, werden die Ressourcen als Teil des Builds optimiert. Die Optimierung ist besonders für mobile Umgebungen von Vorteil, die eine geringere Bandbreite oder unzuverlässige Verbindungen haben können.

Aktivieren der dynamischen Komprimierung auf dem Server gegenüber der Verwendung von MapStaticAssets

MapStaticAssets hat die folgenden Vorteile gegenüber der dynamischen Komprimierung auf dem Server:

  • Es ist einfacher, da keine serverspezifische Konfiguration vorhanden ist.
  • Es ist leistungsfähiger, da die Ressourcen zur Erstellungszeit komprimiert werden.
  • Es ermöglicht der Entwicklerin oder dem Entwickler, während des Buildprozesses zusätzliche Zeit damit zu verbringen, sicherzustellen, dass die Ressourcen die Mindestgröße aufweisen.

Betrachten Sie die folgende Tabelle, in der die MudBlazor-Komprimierung mit der dynamischen IIS-Komprimierung und MapStaticAssets verglichen wird:

IIS gzip MapStaticAssets MapStaticAssets-Reduzierung
≅ 90 37,5 59 %