HybridCache-Bibliothek in ASP.NET Core
Wichtig
HybridCache
ist derzeit noch in der Vorschau, wird aber vollständig nach .NET 9.0 in einer zukünftigen Nebenversion von .NET-Erweiterungen veröffentlicht.
In diesem Artikel wird erläutert, wie Sie die HybridCache
-Bibliothek in einer ASP.NET Core-App konfigurieren und verwenden. Eine Einführung in die Bibliothek finden Sie im HybridCache
-Abschnitt zur Übersicht über das Zwischenspeichern.
Abrufen der Bibliothek
Installieren Sie das Microsoft.Extensions.Caching.Hybrid
-Paket.
dotnet add package Microsoft.Extensions.Caching.Hybrid --version "9.0.0-preview.7.24406.2"
Registrieren des Diensts
Fügen Sie den HybridCache
-Dienst zum Container Abhängigkeitsinjektion (DI) hinzu, indem Sie AddHybridCache
aufrufen:
// Add services to the container.
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddAuthorization();
builder.Services.AddHybridCache();
Der voranstehende Code registriert den HybridCache
-Dienst mit Standardoptionen. Die Registrierungs-API kann auch Optionen und Serialisierung konfigurieren.
Abrufen und Speichern von Cacheeinträgen
Der HybridCache
-Dienst stellt eine GetOrCreateAsync
-Methode mit zwei Überladungen bereit, wobei ein Schlüssel verwendet wird und:
- Eine Factory-Methode.
- Zustand und eine Factorymethode.
Die Methode verwendet den Schlüssel, um das Objekt aus dem primären Cache abzurufen. Wenn das Element nicht im primären Cache gefunden wird (ein Cachefehler), überprüft es den sekundären Cache, falls einer konfiguriert ist. Wenn die Daten dort nicht gefunden werden (ein anderer Cachefehler), ruft es die Factorymethode auf, um das Objekt aus der Datenquelle abzurufen. Anschließend wird das Objekt sowohl im primären als auch im sekundären Cache gespeichert. Die Factorymethode wird nie aufgerufen, wenn das Objekt im primären oder sekundären Cache gefunden wird (ein Cachetreffer).
Der HybridCache
-Dienst stellt sicher, dass nur ein gleichzeitiger Aufrufer für einen bestimmten Schlüssel die Factorymethode aufruft, und alle anderen Aufrufer warten auf das Ergebnis dieses Aufrufs. Der Wert CancellationToken
übergeben an GetOrCreateAsync
stellt den kombinierten Abbruch aller gleichzeitigen Anrufer dar.
Die Hauptüberladung GetOrCreateAsync
Die zustandslose Überladung GetOrCreateAsync
wird für die meisten Szenarien empfohlen. Der Code zum Aufrufen ist relativ einfach. Ein Beispiel:
public class SomeService(HybridCache cache)
{
private HybridCache _cache = cache;
public async Task<string> GetSomeInfoAsync(string name, int id, CancellationToken token = default)
{
return await _cache.GetOrCreateAsync(
$"{name}-{id}", // Unique key to the cache entry
async cancel => await GetDataFromTheSourceAsync(name, id, cancel),
cancellationToken: token
);
}
public async Task<string> GetDataFromTheSourceAsync(string name, int id, CancellationToken token)
{
string someInfo = $"someinfo-{name}-{id}";
return someInfo;
}
}
Die alternative GetOrCreateAsync
-Überladung
Die alternative Überladung kann den Mehraufwand von erfassten Variablen und Rückrufen pro Instanz verringern, aber auf Kosten von komplexerem Code. In den meisten Szenarien überwiegt die Leistungssteigerung nicht die Codekomplexität. Hier ist ein Beispiel, das die alternative Überladung verwendet:
public class SomeService(HybridCache cache)
{
private HybridCache _cache = cache;
public async Task<string> GetSomeInfoAsync(string name, int id, CancellationToken token = default)
{
return await _cache.GetOrCreateAsync(
$"{name}-{id}", // Unique key to the cache entry
(name, id, obj: this),
static async (state, token) =>
await state.obj.GetDataFromTheSourceAsync(state.name, state.id, token),
cancellationToken: token
);
}
public async Task<string> GetDataFromTheSourceAsync(string name, int id, CancellationToken token)
{
string someInfo = $"someinfo-{name}-{id}";
return someInfo;
}
}
Die SetAsync
-Methode
In vielen Szenarien ist GetOrCreateAsync
die einzige erforderliche API. Aber HybridCache
hat auch SetAsync
, um ein Objekt im Cache zu speichern, ohne es zuerst abzurufen.
Entfernen von Cacheeinträgen nach Schlüssel
Wenn die zugrunde liegenden Daten für einen Cacheeintrag vor ablaufen, entfernen Sie den Eintrag explizit, indem Sie RemoveAsync
mit dem Schlüssel zum Eintrag aufrufen. Mit einer Überladung können Sie eine Sammlung von Schlüsselwerten angeben.
Wenn ein Eintrag entfernt wird, wird er aus den primären und sekundären Caches entfernt.
Entfernen von Cacheeinträgen nach Tag
Tags können verwendet werden, um Cacheeinträge zu gruppieren und zusammen ungültig zu machen.
Legen Sie Tags beim Aufrufen von GetOrCreateAsync
fest, wie im folgenden Beispiel gezeigt:
public class SomeService(HybridCache cache)
{
private HybridCache _cache = cache;
public async Task<string> GetSomeInfoAsync(string name, int id, CancellationToken token = default)
{
var tags = new List<string> { "tag1", "tag2", "tag3" };
var entryOptions = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromMinutes(1),
LocalCacheExpiration = TimeSpan.FromMinutes(1)
};
return await _cache.GetOrCreateAsync(
$"{name}-{id}", // Unique key to the cache entry
async cancel => await GetDataFromTheSourceAsync(name, id, cancel),
entryOptions,
tags,
cancellationToken: token
);
}
public async Task<string> GetDataFromTheSourceAsync(string name, int id, CancellationToken token)
{
string someInfo = $"someinfo-{name}-{id}";
return someInfo;
}
}
Entfernen Sie alle Einträge für ein angegebenes Tag, indem Sie RemoveByTagAsync
mit dem Tagwert aufrufen. Mit einer Überladung können Sie eine Sammlung von Tagwerten angeben.
Wenn ein Eintrag entfernt wird, wird er aus den primären und sekundären Caches entfernt.
Optionen
Die AddHybridCache
-Methode kann verwendet werden, um globale Standardwerte zu konfigurieren. Das folgende Beispiel zeigt, wie Sie einige der verfügbaren Optionen konfigurieren:
// Add services to the container.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthorization();
builder.Services.AddHybridCache(options =>
{
options.MaximumPayloadBytes = 1024 * 1024;
options.MaximumKeyLength = 1024;
options.DefaultEntryOptions = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromMinutes(5),
LocalCacheExpiration = TimeSpan.FromMinutes(5)
};
});
Die GetOrCreateAsync
-Methode kann auch ein HybridCacheEntryOptions
-Objekt verwenden, um die globalen Standardwerte für einen bestimmten Cacheeintrag außer Kraft zu setzen. Ein Beispiel:
public class SomeService(HybridCache cache)
{
private HybridCache _cache = cache;
public async Task<string> GetSomeInfoAsync(string name, int id, CancellationToken token = default)
{
var tags = new List<string> { "tag1", "tag2", "tag3" };
var entryOptions = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromMinutes(1),
LocalCacheExpiration = TimeSpan.FromMinutes(1)
};
return await _cache.GetOrCreateAsync(
$"{name}-{id}", // Unique key to the cache entry
async cancel => await GetDataFromTheSourceAsync(name, id, cancel),
entryOptions,
tags,
cancellationToken: token
);
}
public async Task<string> GetDataFromTheSourceAsync(string name, int id, CancellationToken token)
{
string someInfo = $"someinfo-{name}-{id}";
return someInfo;
}
}
Weitere Informationen zu den Optionen finden Sie im Quellcode:
- HybridCacheOptions-Klasse.
- HybridCacheEntryOptions-Klasse.
Grenzwerte
Mit den folgenden Eigenschaften von HybridCacheOptions
können Sie Grenzwerte konfigurieren, die für alle Cacheeinträge gelten:
- MaximumPayloadBytes – Maximale Größe eines Cacheeintrags. Der Standardwert ist 1 MB. Versuche, Werte über dieser Größe zu speichern, werden protokolliert, und der Wert wird nicht im Cache gespeichert.
- MaximumKeyLength – Maximale Länge eines Cacheschlüssels. Der Standardwert ist 1024 Zeichen. Versuche, Werte über dieser Größe zu speichern, werden protokolliert, und der Wert wird nicht im Cache gespeichert.
Serialisierung
Die Verwendung eines sekundären Out-of-Process-Caches erfordert eine Serialisierung. Die Serialisierung wird im Rahmen der Registrierung des HybridCache
-Diensts konfiguriert. Typspezifische und allgemeine Serialisierer können über die Methoden AddSerializer
und AddSerializerFactory
konfiguriert werden, die vom AddHybridCache
-Aufruf verkettet werden. Standardmäßig verarbeitet die Bibliothek string
und byte[]
intern und verwendet System.Text.Json
für alles andere. HybridCache
kann auch andere Serialisierer verwenden, z. B. Protobuf oder XML.
Im folgenden Beispiel wird der Dienst so konfiguriert, dass ein typspezifischer Protobuf-Serialisierer verwendet wird:
// Add services to the container.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthorization();
builder.Services.AddHybridCache(options =>
{
options.DefaultEntryOptions = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromSeconds(10),
LocalCacheExpiration = TimeSpan.FromSeconds(5)
};
}).AddSerializer<SomeProtobufMessage,
GoogleProtobufSerializer<SomeProtobufMessage>>();
Im folgenden Beispiel wird der Dienst so konfiguriert, dass ein allgemeiner Protobuf-Serialisierer verwendet wird, der viele Protobuf-Typen verarbeiten kann:
// Add services to the container.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthorization();
builder.Services.AddHybridCache(options =>
{
options.DefaultEntryOptions = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromSeconds(10),
LocalCacheExpiration = TimeSpan.FromSeconds(5)
};
}).AddSerializerFactory<GoogleProtobufSerializerFactory>();
Der sekundäre Cache erfordert einen Datenspeicher, z. B. Redis oder SqlServer. So verwenden Sie beispielsweise Azure Cache for Redis:
Installieren Sie das
Microsoft.Extensions.Caching.StackExchangeRedis
-Paket.Erstellen Sie eine Instanz von Azure Cache for Redis.
Rufen Sie eine Verbindungszeichenfolge ab, die eine Verbindung mit der Redis-Instanz herstellt. Suchen Sie die Verbindungszeichenfolge, indem Sie Zugriffsschlüssel anzeigen auf der Seite Übersicht im Azure-Portal auswählen.
Speichern Sie die Verbindungszeichenfolge in der App-Konfiguration. Verwenden Sie z. B. eine Datei mit Benutzergeheimnissen, die wie die folgende JSON aussieht, mit der Verbindungszeichenfolge im Abschnitt
ConnectionStrings
. Ersetzen Sie<the connection string>
durch die tatsächliche Verbindungszeichenfolge:{ "ConnectionStrings": { "RedisConnectionString": "<the connection string>" } }
Registrieren Sie in DI die
IDistributedCache
-Implementierung, die durch das Redis-Paket bereitstellt wird. Rufen Sie dazuAddStackExchangeRedisCache
auf, und übergeben Sie die Verbindungszeichenfolge. Zum Beispiel:builder.Services.AddStackExchangeRedisCache(options => { options.Configuration = builder.Configuration.GetConnectionString("RedisConnectionString"); });
Die Redis-Implementierung
IDistributedCache
ist jetzt im DI-Container der App verfügbar.HybridCache
verwendet sie als sekundären Cache und verwendet den dafür konfigurierten Serialisierer.
Weitere Informationen finden Sie in der Beispiel-App für die HybridCache-Serialisierung.
Cachespeicher
Standardmäßig verwendet HybridCache
MemoryCache für den primären Cachespeicher. Zwischengespeicherte Einträge werden „In-Process“ gespeichert, sodass jeder Server über einen separaten Cache verfügt, der bei jedem Neustart des Serverprozesses verloren geht. Für sekundären Out-of-Process-Speicher, z. B. Redis oder SQL Server, verwendet HybridCache
ggf. die konfigurierte IDistributedCache
-Implementierung. Aber auch ohne IDistributedCache
Implementierung bietet der HybridCache
-Dienst weiterhin In-Process-Cache- und Stampede-Schutz.
Optimieren der Leistung
Um die Leistung zu optimieren, konfigurieren Sie die Wiederverwendung von HybridCache
-Objekten und vermeiden Sie byte[]
-Zuordnungen.
Wiederverwenden von Objekten
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.
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. Objekte sind jedoch inhärent threadsicher, wenn:
- Sie unveränderliche Typen sind.
- 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üsselwortsealed
in C# bedeutet, dass die Klasse nicht geerbt werden kann. - Anwenden des
[ImmutableObject(true)]
-Attributs auf den Typ. Das Attribut[ImmutableObject(true)]
gibt an, dass der Status des Objekts nach der Erstellung nicht mehr geändert werden kann.
Vermeiden von byte[]
-Zuordnungen
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. Weitere Informationen finden Sie unter IBufferDistributedCache Hier finden Sie die .NET CLI-Befehle zum Installieren der Pakete:
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis --prerelease
dotnet add package Microsoft.Extensions.Caching.SqlServer --prerelease
Benutzerdefinierte HybridCache-Implementierungen
Eine konkrete Implementierung der abstrakten Klasse HybridCache
ist im freigegebenen Framework enthalten und wird über Abhängigkeitsinjektion bereitgestellt. Entwickler können jedoch benutzerdefinierte Implementierungen der API bereitstellen.
Kompatibilität
Die HybridCache
-Bibliothek unterstützt ältere .NET-Runtimes bis zu .NET Framework 4.7.2 und .NET Standard 2.0.
Zusätzliche Ressourcen
Weitere Informationen zu HybridCache
finden Sie in den folgenden Ressourcen:
- GitHub-Problem dotnet/aspnetcore 54647.
HybridCache
-Quellcode
ASP.NET Core