Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Artikel erfahren Sie mehr über verschiedene Zwischenspeicherungsmechanismen. Zwischenspeichern ist das Speichern von Daten in einer Zwischenschicht, wodurch nachfolgende Datenabrufe schneller erfolgen. Konzeptuell ist Caching eine Strategie zur Leistungsoptimierung und Designüberlegung. Das Zwischenspeichern kann die App-Leistung erheblich verbessern, indem selten geänderte (oder teure) Daten leichter verfügbar sind. In diesem Artikel werden die beiden primären Cachetypen vorgestellt, und es werden Beispielquellcode für beides bereitgestellt:
Von Bedeutung
Es gibt zwei MemoryCache
Klassen in .NET, eine im System.Runtime.Caching
Namespace und die andere im Microsoft.Extensions.Caching
Namespace:
Dieser Artikel konzentriert sich zwar auf das Zwischenspeichern, enthält aber nicht das System.Runtime.Caching
NuGet-Paket. Alle Verweise zu MemoryCache
befinden sich im Microsoft.Extensions.Caching
Namensraum.
Alle Microsoft.Extensions.*
Pakete sind für die Abhängigkeitsinjektion (DI) bereit, sowohl die IMemoryCache als auch die IDistributedCache Schnittstellen können als Dienste genutzt werden.
In-Memory-Caching
In diesem Abschnitt erfahren Sie mehr über das Microsoft.Extensions.Caching.Memory-Paket . Die aktuelle Implementierung von IMemoryCache ist ein Wrapper um das ConcurrentDictionary<TKey,TValue>, wobei eine funktionsreiche API verfügbar gemacht wird. Einträge innerhalb des Caches werden durch das ICacheEntry dargestellt und können beliebig object
sein. Die In-Memory-Cachelösung eignet sich hervorragend für Apps, die auf einem einzelnen Server ausgeführt werden, auf dem alle zwischengespeicherten Daten Arbeitsspeicher im Prozess der App belegen.
Tipp
Berücksichtigen Sie bei Szenarien mit multiserverbasiertem Zwischenspeichern den Ansatz für die verteilte Zwischenspeicherung als Alternative zur Zwischenspeicherung im Arbeitsspeicher.
Zwischenspeicherungs-API im RAM
Der Verbraucher des Caches hat Kontrolle über sowohl gleitende als auch absolute Ablaufzeiten.
- ICacheEntry.AbsoluteExpiration
- ICacheEntry.AbsoluteExpirationRelativeToNow
- ICacheEntry.SlidingExpiration
Das Festlegen eines Ablaufs führt dazu, dass Einträge im Cache entfernt werden, wenn nicht innerhalb der zugewiesenen Ablaufzeit auf sie zugegriffen wird. Verbraucher haben zusätzliche Optionen zum Verwalten von Cacheeinträgen durch die MemoryCacheEntryOptions. Jeder ICacheEntry ist mit MemoryCacheEntryOptions gekoppelt, wodurch die Funktionalität zum Entfernen von Ablaufzeit mit IChangeToken, Prioritätseinstellungen mit CacheItemPriority und das Steuern des ICacheEntry.Size verfügbar gemacht werden. Berücksichtigen Sie die folgenden Erweiterungsmethoden:
- MemoryCacheEntryExtensions.AddExpirationToken
- MemoryCacheEntryExtensions.RegisterPostEvictionCallback
- MemoryCacheEntryExtensions.SetSize
- MemoryCacheEntryExtensions.SetPriority
Beispiel für in-Memory-Cache
Um die Standardimplementierung IMemoryCache zu verwenden, rufen Sie die AddMemoryCache Erweiterungsmethode auf, um alle erforderlichen Dienste bei DI zu registrieren. Im folgenden Codebeispiel wird der generische Host verwendet, um DI-Funktionen verfügbar zu machen:
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddMemoryCache();
using IHost host = builder.Build();
Abhängig von Ihrer .NET-Workload können Sie anders auf den IMemoryCache
zugreifen, z. B. als Konstruktorinjektion. In diesem Beispiel verwenden Sie die IServiceProvider
Instanz auf der host
und rufen die generische GetRequiredService<T>(IServiceProvider) Erweiterungsmethode auf.
IMemoryCache cache =
host.Services.GetRequiredService<IMemoryCache>();
Mit registrierten In-Memory-Cachediensten und aufgelöst über DI – Sie können mit dem Zwischenspeichern beginnen. Im Beispiel werden im englischen Alphabet die Buchstaben „A“ bis „Z“ durchlaufen. Der record AlphabetLetter
Typ enthält den Verweis auf den Brief und generiert eine Nachricht.
file record AlphabetLetter(char Letter)
{
internal string Message =>
$"The '{Letter}' character is the {Letter - 64} letter in the English alphabet.";
}
Tipp
Der file
Zugriffsmodifizierer wird für den AlphabetLetter
Typ verwendet, da er innerhalb definiert ist und nur über die Program.cs Datei darauf zugegriffen wird. Weitere Informationen finden Sie in der Datei (C#-Referenz). Informationen zum vollständigen Quellcode finden Sie im Abschnitt Program.cs .
Das Beispiel enthält eine Hilfsfunktion, die durch die Buchstaben des Alphabets iteriert.
static async ValueTask IterateAlphabetAsync(
Func<char, Task> asyncFunc)
{
for (char letter = 'A'; letter <= 'Z'; ++letter)
{
await asyncFunc(letter);
}
Console.WriteLine();
}
Im oben stehenden C#-Code ist Folgendes passiert:
- Die
Func<char, Task> asyncFunc
wird bei jeder Iteration erwartet, wobei der aktuelleletter
übergeben wird. - Nachdem alle Buchstaben verarbeitet wurden, wird eine leere Zeile in die Konsole geschrieben.
So fügen Sie Elemente dem Cache hinzu, indem Sie eines der Create
APIs oder Set
APIs aufrufen.
var addLettersToCacheTask = IterateAlphabetAsync(letter =>
{
MemoryCacheEntryOptions options = new()
{
AbsoluteExpirationRelativeToNow =
TimeSpan.FromMilliseconds(MillisecondsAbsoluteExpiration)
};
_ = options.RegisterPostEvictionCallback(OnPostEviction);
AlphabetLetter alphabetLetter =
cache.Set(
letter, new AlphabetLetter(letter), options);
Console.WriteLine($"{alphabetLetter.Letter} was cached.");
return Task.Delay(
TimeSpan.FromMilliseconds(MillisecondsDelayAfterAdd));
});
await addLettersToCacheTask;
Im oben stehenden C#-Code ist Folgendes passiert:
- Die Variable
addLettersToCacheTask
delegiert anIterateAlphabetAsync
und wird benötigt. -
Func<char, Task> asyncFunc
ist durch eine Lambda-Funktion vertreten. -
MemoryCacheEntryOptions
wird mit einem zum aktuellen Zeitpunkt relativen absoluten Ablauf instanziiert. - Ein Rückruf nach dem Entfernen wird registriert.
- Ein
AlphabetLetter
Objekt wird instanziiert und zusammen mit Set undletter
inoptions
übergeben. - Der Buchstabe wird als zwischengespeichert in die Konsole geschrieben.
- Schließlich wird ein Task.Delay Wert zurückgegeben.
Für jeden Buchstaben im Alphabet wird ein Cacheeintrag mit einem Ablauf und Rückruf nach dem Entfernen geschrieben.
Der Rückruf nach dem Entfernen schreibt die Details des entfernten Werts in die Konsole:
static void OnPostEviction(
object key, object? letter, EvictionReason reason, object? state)
{
if (letter is AlphabetLetter alphabetLetter)
{
Console.WriteLine($"{alphabetLetter.Letter} was evicted for {reason}.");
}
};
Nach dem Auffüllen des Caches wird ein weiterer Aufruf von IterateAlphabetAsync
erwartet, aber dieses Mal rufen Sie IMemoryCache.TryGetValue auf:
var readLettersFromCacheTask = IterateAlphabetAsync(letter =>
{
if (cache.TryGetValue(letter, out object? value) &&
value is AlphabetLetter alphabetLetter)
{
Console.WriteLine($"{letter} is still in cache. {alphabetLetter.Message}");
}
return Task.CompletedTask;
});
await readLettersFromCacheTask;
Wenn der cache
den letter
Schlüssel enthält und value
eine Instanz eines AlphabetLetter
ist, wird diese in die Konsole geschrieben. Wenn sich der letter
-Schlüssel nicht im Cache befindet, wurde er entfernt, und der Rückruf nach dem Entfernen wurde aufgerufen.
Zusätzliche Erweiterungsmethoden
Das IMemoryCache
kommt mit vielen komfortbasierten Erweiterungsmethoden, einschließlich einer asynchronen GetOrCreateAsync
:
- CacheExtensions.Get
- CacheExtensions.GetOrCreate
- CacheExtensions.GetOrCreateAsync
- CacheExtensions.Set
- CacheExtensions.TryGetValue
Alles zusammenfügen
Der gesamte Beispiel-App-Quellcode ist ein Programm der obersten Ebene und erfordert zwei NuGet-Pakete:
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddMemoryCache();
using IHost host = builder.Build();
IMemoryCache cache =
host.Services.GetRequiredService<IMemoryCache>();
const int MillisecondsDelayAfterAdd = 50;
const int MillisecondsAbsoluteExpiration = 750;
static void OnPostEviction(
object key, object? letter, EvictionReason reason, object? state)
{
if (letter is AlphabetLetter alphabetLetter)
{
Console.WriteLine($"{alphabetLetter.Letter} was evicted for {reason}.");
}
};
static async ValueTask IterateAlphabetAsync(
Func<char, Task> asyncFunc)
{
for (char letter = 'A'; letter <= 'Z'; ++letter)
{
await asyncFunc(letter);
}
Console.WriteLine();
}
var addLettersToCacheTask = IterateAlphabetAsync(letter =>
{
MemoryCacheEntryOptions options = new()
{
AbsoluteExpirationRelativeToNow =
TimeSpan.FromMilliseconds(MillisecondsAbsoluteExpiration)
};
_ = options.RegisterPostEvictionCallback(OnPostEviction);
AlphabetLetter alphabetLetter =
cache.Set(
letter, new AlphabetLetter(letter), options);
Console.WriteLine($"{alphabetLetter.Letter} was cached.");
return Task.Delay(
TimeSpan.FromMilliseconds(MillisecondsDelayAfterAdd));
});
await addLettersToCacheTask;
var readLettersFromCacheTask = IterateAlphabetAsync(letter =>
{
if (cache.TryGetValue(letter, out object? value) &&
value is AlphabetLetter alphabetLetter)
{
Console.WriteLine($"{letter} is still in cache. {alphabetLetter.Message}");
}
return Task.CompletedTask;
});
await readLettersFromCacheTask;
await host.RunAsync();
file record AlphabetLetter(char Letter)
{
internal string Message =>
$"The '{Letter}' character is the {Letter - 64} letter in the English alphabet.";
}
Sie können die Werte MillisecondsDelayAfterAdd
und MillisecondsAbsoluteExpiration
anpassen, um die Verhaltensänderungen beim Ablauf und beim Entfernen von zwischengespeicherten Einträgen zu beobachten. Im Folgenden sehen Sie eine Beispielausgabe aus der Ausführung dieses Codes. Aufgrund der nicht deterministischen Natur von .NET-Ereignissen kann ihre Ausgabe unterschiedlich sein.
A was cached.
B was cached.
C was cached.
D was cached.
E was cached.
F was cached.
G was cached.
H was cached.
I was cached.
J was cached.
K was cached.
L was cached.
M was cached.
N was cached.
O was cached.
P was cached.
Q was cached.
R was cached.
S was cached.
T was cached.
U was cached.
V was cached.
W was cached.
X was cached.
Y was cached.
Z was cached.
A was evicted for Expired.
C was evicted for Expired.
B was evicted for Expired.
E was evicted for Expired.
D was evicted for Expired.
F was evicted for Expired.
H was evicted for Expired.
K was evicted for Expired.
L was evicted for Expired.
J was evicted for Expired.
G was evicted for Expired.
M was evicted for Expired.
N was evicted for Expired.
I was evicted for Expired.
P was evicted for Expired.
R was evicted for Expired.
O was evicted for Expired.
Q was evicted for Expired.
S is still in cache. The 'S' character is the 19 letter in the English alphabet.
T is still in cache. The 'T' character is the 20 letter in the English alphabet.
U is still in cache. The 'U' character is the 21 letter in the English alphabet.
V is still in cache. The 'V' character is the 22 letter in the English alphabet.
W is still in cache. The 'W' character is the 23 letter in the English alphabet.
X is still in cache. The 'X' character is the 24 letter in the English alphabet.
Y is still in cache. The 'Y' character is the 25 letter in the English alphabet.
Z is still in cache. The 'Z' character is the 26 letter in the English alphabet.
Da das absolute Ablaufdatum (MemoryCacheEntryOptions.AbsoluteExpirationRelativeToNow) festgelegt ist, werden alle zwischengespeicherten Elemente letztendlich entfernt.
Zwischenspeichern des Workerdiensts
Eine gängige Strategie zum Zwischenspeichern von Daten ist das Aktualisieren des Caches unabhängig von den verbrauchenden Datendiensten. Die Workerdienst-Vorlage ist ein gutes Beispiel, da der BackgroundService unabhängig vom übrigen Anwendungscode (d. h. im Hintergrund) ausgeführt wird. Wenn eine Anwendung gestartet wird, die eine Implementierung von IHostedService hostet, wird die entsprechende Implementierung (in diesem Fall BackgroundService
oder Worker) innerhalb desselben Prozesses ausgeführt. Diese gehosteten Dienste werden über die AddHostedService<THostedService>(IServiceCollection) Erweiterungsmethode als Singletons bei DI registriert. Andere Dienste können bei DI mit jeder Dienstlebensdauer registriert werden.
Von Bedeutung
Es ist sehr wichtig, mit der Lebensdauer des Diensts vertraut zu sein. Wenn AddMemoryCache aufgerufen wird, um alle In-Memory-Caching-Dienste zu registrieren, werden die Dienste als Singletons registriert.
Fotodienstszenario
Stellen Sie sich vor, Sie entwickeln einen Fotodienst, der auf eine Drittanbieter-API angewiesen ist und über HTTP zugänglich ist. Diese Fotodaten ändern sich nicht sehr oft, aber es gibt viele davon. Jedes Foto wird durch ein einfaches record
Dargestellt:
namespace CachingExamples.Memory;
public readonly record struct Photo(
int AlbumId,
int Id,
string Title,
string Url,
string ThumbnailUrl);
Im folgenden Beispiel werden mehrere Dienste angezeigt, die bei DI registriert werden. Jeder Dienst hat eine einzige Verantwortung.
using CachingExamples.Memory;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddMemoryCache();
builder.Services.AddHttpClient<CacheWorker>();
builder.Services.AddHostedService<CacheWorker>();
builder.Services.AddScoped<PhotoService>();
builder.Services.AddSingleton(typeof(CacheSignal<>));
using IHost host = builder.Build();
await host.StartAsync();
Im oben stehenden C#-Code ist Folgendes passiert:
- Der generische Host wird mit Standardeinstellungen erstellt.
- In-Memory-Caching-Dienste werden bei AddMemoryCache registriert.
- Eine
HttpClient
Instanz wird für dieCacheWorker
Klasse registriert mit AddHttpClient<TClient>(IServiceCollection). - Die
CacheWorker
Klasse ist registriert bei AddHostedService<THostedService>(IServiceCollection). - Die
PhotoService
Klasse ist registriert bei AddScoped<TService>(IServiceCollection). - Die
CacheSignal<T>
Klasse ist registriert bei AddSingleton. - Der
host
wird vom Generator instanziiert und asynchron gestartet.
Dies PhotoService
ist für das Abrufen von Fotos verantwortlich, die bestimmten Kriterien entsprechen (oder filter
):
using Microsoft.Extensions.Caching.Memory;
namespace CachingExamples.Memory;
public sealed class PhotoService(
IMemoryCache cache,
CacheSignal<Photo> cacheSignal,
ILogger<PhotoService> logger)
{
public async IAsyncEnumerable<Photo> GetPhotosAsync(Func<Photo, bool>? filter = default)
{
try
{
await cacheSignal.WaitAsync();
Photo[] photos =
(await cache.GetOrCreateAsync(
"Photos", _ =>
{
logger.LogWarning("This should never happen!");
return Task.FromResult(Array.Empty<Photo>());
}))!;
// If no filter is provided, use a pass-thru.
filter ??= _ => true;
foreach (Photo photo in photos)
{
if (!default(Photo).Equals(photo) && filter(photo))
{
yield return photo;
}
}
}
finally
{
cacheSignal.Release();
}
}
}
Im oben stehenden C#-Code ist Folgendes passiert:
- Der Konstruktor erfordert ein
IMemoryCache
,CacheSignal<Photo>
undILogger
. - Die
GetPhotosAsync
Methode:- Definiert einen
Func<Photo, bool> filter
-Parameter und gibt einIAsyncEnumerable<Photo>
zurück. - Ruft an und wartet darauf, dass
_cacheSignal.WaitAsync()
freigegeben wird, damit sichergestellt ist, dass der Cache aufgefüllt wird, bevor darauf zugegriffen wird. - Ruft
_cache.GetOrCreateAsync()
auf, und ruft asynchron alle Fotos im Cache ab. - Das
factory
Argument protokolliert eine Warnung und gibt ein leeres Fotoarray zurück – dies sollte nie geschehen. - Jedes Foto im Cache wird durchlaufen, gefiltert und mit
yield return
angezeigt. - Schließlich wird das Cachesignal zurückgesetzt.
- Definiert einen
Nutzer dieses Dienstes können die GetPhotosAsync
-Methode aufrufen und Fotos entsprechend bearbeiten. Nein HttpClient
ist erforderlich, da der Cache die Fotos enthält.
Das asynchrone Signal basiert auf einer gekapselten SemaphoreSlim Instanz innerhalb eines generisch eingeschränkten Singletons. Dies CacheSignal<T>
basiert auf einer Instanz von SemaphoreSlim
:
namespace CachingExamples.Memory;
public sealed class CacheSignal<T>
{
private readonly SemaphoreSlim _semaphore = new(1, 1);
/// <summary>
/// Exposes a <see cref="Task"/> that represents the asynchronous wait operation.
/// When signaled (consumer calls <see cref="Release"/>), the
/// <see cref="Task.Status"/> is set as <see cref="TaskStatus.RanToCompletion"/>.
/// </summary>
public Task WaitAsync() => _semaphore.WaitAsync();
/// <summary>
/// Exposes the ability to signal the release of the <see cref="WaitAsync"/>'s operation.
/// Callers who were waiting, will be able to continue.
/// </summary>
public void Release() => _semaphore.Release();
}
Im vorhergehenden C#-Code wird das Dekorator-Muster verwendet, um eine Instanz von SemaphoreSlim
einzuwickeln. Da CacheSignal<T>
als Singleton registriert ist, kann es in allen Dienstlebensdauern mit jedem generischen Typ verwendet werden, in diesem Fall mit Photo
. Es ist für das Signalisieren des Seedings des Caches verantwortlich.
Dies CacheWorker
ist eine Unterklasse von BackgroundService:
using System.Net.Http.Json;
using Microsoft.Extensions.Caching.Memory;
namespace CachingExamples.Memory;
public sealed class CacheWorker(
ILogger<CacheWorker> logger,
HttpClient httpClient,
CacheSignal<Photo> cacheSignal,
IMemoryCache cache) : BackgroundService
{
private readonly TimeSpan _updateInterval = TimeSpan.FromHours(3);
private bool _isCacheInitialized = false;
private const string Url = "https://jsonplaceholder.typicode.com/photos";
public override async Task StartAsync(CancellationToken cancellationToken)
{
await cacheSignal.WaitAsync();
await base.StartAsync(cancellationToken);
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
logger.LogInformation("Updating cache.");
try
{
Photo[]? photos =
await httpClient.GetFromJsonAsync<Photo[]>(
Url, stoppingToken);
if (photos is { Length: > 0 })
{
cache.Set("Photos", photos);
logger.LogInformation(
"Cache updated with {Count:#,#} photos.", photos.Length);
}
else
{
logger.LogWarning(
"Unable to fetch photos to update cache.");
}
}
finally
{
if (!_isCacheInitialized)
{
cacheSignal.Release();
_isCacheInitialized = true;
}
}
try
{
logger.LogInformation(
"Will attempt to update the cache in {Hours} hours from now.",
_updateInterval.Hours);
await Task.Delay(_updateInterval, stoppingToken);
}
catch (OperationCanceledException)
{
logger.LogWarning("Cancellation acknowledged: shutting down.");
break;
}
}
}
}
Im oben stehenden C#-Code ist Folgendes passiert:
- Der Konstruktor erfordert ein
ILogger
,HttpClient
undIMemoryCache
. - Dies
_updateInterval
ist für drei Stunden definiert. - Die
ExecuteAsync
Methode:- Führt während der Ausführung der App Schleifendurchläufe durch.
- Stellt eine HTTP-Anforderung an
"https://jsonplaceholder.typicode.com/photos"
und ordnet die Antwort als Array vonPhoto
Objekten zu. - Das Array von Fotos wird im
IMemoryCache
unter dem"Photos"
-Schlüssel platziert. -
_cacheSignal.Release()
wird aufgerufen und gibt alle Nutzer frei, die auf das Signal gewartet haben. - Der Aufruf von Task.Delay wird erwartet, wenn das Aktualisierungsintervall angegeben ist.
- Nach einer Verzögerung von drei Stunden wird der Cache erneut aktualisiert.
Consumer im selben Prozess können IMemoryCache
nach den Fotos fragen, aber der CacheWorker
ist für die Aktualisierung des Caches verantwortlich.
Verteiltes Zwischenspeichern
In einigen Szenarien ist ein verteilter Cache erforderlich , z. B. bei mehreren App-Servern. Ein verteilter Cache unterstützt eine höhere Skalierung als der In-Memory-Cache-Ansatz. Durch die Verwendung eines verteilten Caches wird der Cachespeicher in einen externen Prozess entladen, erfordert jedoch zusätzliche Netzwerk-E/A und führt etwas mehr Latenz ein (auch wenn nominal).
Die verteilten Zwischenspeicherungsabstraktionen sind Teil des Microsoft.Extensions.Caching.Memory
NuGet-Pakets, und es gibt sogar eine AddDistributedMemoryCache
Erweiterungsmethode.
Vorsicht
Dies AddDistributedMemoryCache sollte nur in Entwicklungs- und/oder Testszenarien verwendet werden und ist keine praktikable Produktionsimplementierung.
Betrachten Sie eine der verfügbaren Implementierungen des IDistributedCache
aus den folgenden Paketen:
Microsoft.Extensions.Caching.SqlServer
Microsoft.Extensions.Caching.StackExchangeRedis
NCache.Microsoft.Extensions.Caching.OpenSource
Api für verteilte Zwischenspeicherung
Die verteilten Cache-APIs sind etwas primitiver als ihre In-Memory-Cache-API-Entsprechungen. Die Schlüsselwertpaare sind etwas einfacher. Im Arbeitsspeicher basieren Zwischenspeicher-Schlüssel auf einem object
, während verteilter Schlüssel ein string
sind. Bei der Zwischenspeicherung im Arbeitsspeicher kann der Wert ein beliebiger stark typisierter generischer Typ sein, während die Werte in verteilten Zwischenspeicherungen als byte[]
gespeichert werden. Das heißt nicht, dass verschiedene Implementierungen keine stark typierten generischen Werte verfügbar machen, dies wäre jedoch ein Implementierungsdetail.
Erstellen von Werten
Rufen Sie zum Erstellen von Werten im verteilten Cache eine der festgelegten APIs auf:
Mit dem AlphabetLetter
Eintrag aus dem Beispiel des Speichercaches können Sie das Objekt in JSON serialisieren und dann string
als byte[]
codieren.
DistributedCacheEntryOptions options = new()
{
AbsoluteExpirationRelativeToNow =
TimeSpan.FromMilliseconds(MillisecondsAbsoluteExpiration)
};
AlphabetLetter alphabetLetter = new(letter);
string json = JsonSerializer.Serialize(alphabetLetter);
byte[] bytes = Encoding.UTF8.GetBytes(json);
await cache.SetAsync(letter.ToString(), bytes, options);
Ähnlich wie beim Zwischenspeichern im Arbeitsspeicher können Cacheeinträge Optionen haben, um das Vorhandensein im Cache zu optimieren – in diesem Fall die DistributedCacheEntryOptions.
Erstellen von Erweiterungsmethoden
Es gibt mehrere Erweiterungsmethoden zur bequemen Erstellung von Werten, die helfen, die Codierung von Darstellungen string
von Objekten in eine byte[]
zu vermeiden.
Werte lesen
Rufen Sie eine der get-APIs auf, um Werte aus dem verteilten Cache zu lesen:
AlphabetLetter? alphabetLetter = null;
byte[]? bytes = await cache.GetAsync(letter.ToString());
if (bytes is { Length: > 0 })
{
string json = Encoding.UTF8.GetString(bytes);
alphabetLetter = JsonSerializer.Deserialize<AlphabetLetter>(json);
}
Sobald ein Cacheeintrag aus dem Cache gelesen wurde, können Sie die UTF-8-codierte string
Darstellung aus der byte[]
erhalten.
Lesen von Erweiterungsmethoden
Es gibt mehrere benutzerfreundliche Erweiterungsmethoden zum Lesen von Werten, die dazu beitragen, die Decodierung byte[]
in string
Darstellungen von Objekten zu vermeiden:
Aktualisieren von Werten
Es gibt keine Möglichkeit, die Werte im verteilten Cache mit einem einzelnen API-Aufruf zu aktualisieren. Stattdessen können Werte ihre gleitenden Ablaufvorgänge mit einer der Aktualisierungs-APIs zurücksetzen lassen:
Wenn der tatsächliche Wert aktualisiert werden muss, müssen Sie den Wert löschen und dann erneut hinzufügen.
Löschen von Werten
Rufen Sie zum Löschen von Werten im verteilten Cache eine der entfernten APIs auf:
Tipp
Obwohl es synchrone Versionen der oben genannten APIs gibt, berücksichtigen Sie bitte die Tatsache, dass Implementierungen von verteilten Caches auf Netzwerk-E/A angewiesen sind. Aus diesem Grund werden häufiger als nicht die asynchronen APIs bevorzugt.