Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Par Rick Anderson, John Luo et Steve Smith
La mise en cache peut améliorer considérablement les performances et l’évolutivité d’une application en réduisant le travail nécessaire à la génération de contenu. La mise en cache fonctionne mieux avec des données qui changent rarement et qui sont coûteuses à générer. La mise en cache effectue une copie des données qui peut être renvoyée beaucoup plus rapidement qu’à partir de la source. Les applications doivent être écrites et testées pour ne jamais dépendre des données mises en cache.
ASP.NET Core prend en charge plusieurs caches différents. Le cache le plus simple est basé sur le IMemoryCache.
IMemoryCache
Représente un cache stocké dans la mémoire du serveur web. Les applications exécutées sur une batterie de serveurs (plusieurs serveurs) doivent garantir que les sessions sont persistantes lors de l’utilisation du cache en mémoire. Les sessions persistantes garantissent que les requêtes d’un client sont toutes transmises au même serveur. Par exemple, Azure Web Apps utilise le routage des demandes d’application (ARR) pour acheminer toutes les demandes vers le même serveur.
Les sessions non persistantes dans une batterie de serveurs Web nécessitent un cache distribué pour éviter les problèmes de cohérence du cache. Pour certaines applications, un cache distribué peut prendre en charge un scale-out plus élevé qu’un cache en mémoire. L’utilisation d’un cache distribué décharge la mémoire cache vers un processus externe.
Le cache en mémoire peut stocker n’importe quel objet. L’interface de cache distribué est limitée à byte[]
. Le cache en mémoire et le cache distribué stockent les éléments de cache sous forme de paires clé-valeur.
System.Runtime.Caching/MemoryCache
System.Runtime.Caching / MemoryCache (Package NuGet) peut être utilisé avec :
- .NET Standard 2.0 ou version ultérieure.
- Toute implémentation .NET qui cible .NET Standard 2.0 ou version ultérieure. Par exemple, ASP.NET Core 3.1 ou version ultérieure.
- .NET Framework 4.5 ou version ultérieure.
Microsoft.Extensions.Caching.Memory/IMemoryCache
(décrit dans cet article) est recommandé carMemoryCache
System.Runtime.Caching
/il est mieux intégré dans ASP.NET Core. Par exemple, IMemoryCache
fonctionne nativement avec ASP.NET injection de dépendances Core.
À utiliser System.Runtime.Caching
/MemoryCache
comme pont de compatibilité lors du portage de code de ASP.NET 4.x vers ASP.NET Core.
Directives relatives au cache
- Le code doit toujours avoir une option de secours pour récupérer les données et ne pas dépendre de la disponibilité d’une valeur mise en cache.
- Le cache utilise une ressource rare, la mémoire. Limiter la croissance du cache :
- N’insérez pas d’entrée externe dans le cache. Par exemple, il n’est pas recommandé d’utiliser une entrée arbitraire fournie par l’utilisateur comme clé de cache, car l’entrée peut consommer une quantité imprévisible de mémoire.
- Utilisez des expirations pour limiter la croissance du cache.
- Utilisez SetSize, Size et SizeLimit pour limiter la taille du cache. Le runtime ASP.NET Core ne limite pas la taille du cache en fonction de la sollicitation de la mémoire. C’est au développeur de limiter la taille du cache.
Utiliser IMemoryCache
Avertissement
L’utilisation d’un cache de mémoire partagée à partir de l’injection de dépendances et l’appel SetSize
de , Size
ou SizeLimit
pour limiter la taille du cache peuvent entraîner l’échec de l’application. Lorsqu’une limite de taille est définie sur un cache, toutes les entrées doivent spécifier une taille lors de l’ajout. Cela peut entraîner des problèmes, car les développeurs peuvent ne pas avoir un contrôle total sur ce qui utilise le cache partagé.
Lorsque vous utilisez SetSize
, Size
ou SizeLimit
pour limiter le cache, créez un singleton de cache pour la mise en cache. Pour plus d’informations et un exemple, consultez Utiliser SetSize, Size et SizeLimit pour limiter la taille du cache.
Un cache partagé est un cache partagé par d’autres frameworks ou bibliothèques.
La mise en cache en mémoire est un service référencé à partir d’une application à l’aide de l’injection de dépendances. Demandez l’instance IMemoryCache
dans le constructeur :
public class IndexModel : PageModel
{
private readonly IMemoryCache _memoryCache;
public IndexModel(IMemoryCache memoryCache) =>
_memoryCache = memoryCache;
// ...
Le code suivant permet TryGetValue de vérifier si une heure se trouve dans le cache. Si une heure n’est pas mise en cache, une nouvelle entrée est créée et ajoutée au cache avec Set:
public void OnGet()
{
CurrentDateTime = DateTime.Now;
if (!_memoryCache.TryGetValue(CacheKeys.Entry, out DateTime cacheValue))
{
cacheValue = CurrentDateTime;
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(3));
_memoryCache.Set(CacheKeys.Entry, cacheValue, cacheEntryOptions);
}
CacheCurrentDateTime = cacheValue;
}
Dans le code précédent, l’entrée de cache est configurée avec une expiration glissante de trois secondes. Si l’entrée du cache n’est pas consultée pendant plus de trois secondes, elle est supprimée du cache. Chaque fois que l’entrée du cache est accédée, elle reste dans le cache pendant 3 secondes supplémentaires. La CacheKeys
classe fait partie de l’exemple de téléchargement.
L’heure actuelle et l’heure mise en cache sont affichées :
<ul>
<li>Current Time: @Model.CurrentDateTime</li>
<li>Cached Time: @Model.CacheCurrentDateTime</li>
</ul>
Le code suivant utilise la méthode d’extension pour mettre en cache les Set
données pendant une durée relative sans MemoryCacheEntryOptions
:
_memoryCache.Set(CacheKeys.Entry, DateTime.Now, TimeSpan.FromDays(1));
Dans le code précédent, l’entrée de cache est configurée avec une expiration relative d’un jour. L’entrée du cache est supprimée du cache au bout d’un jour, même si elle est accessible pendant ce délai d’expiration.
Le code suivant utilise GetOrCreate et GetOrCreateAsync pour mettre en cache les données.
public void OnGetCacheGetOrCreate()
{
var cachedValue = _memoryCache.GetOrCreate(
CacheKeys.Entry,
cacheEntry =>
{
cacheEntry.SlidingExpiration = TimeSpan.FromSeconds(3);
return DateTime.Now;
});
// ...
}
public async Task OnGetCacheGetOrCreateAsync()
{
var cachedValue = await _memoryCache.GetOrCreateAsync(
CacheKeys.Entry,
cacheEntry =>
{
cacheEntry.SlidingExpiration = TimeSpan.FromSeconds(3);
return Task.FromResult(DateTime.Now);
});
// ...
}
Les appels Get de code suivants pour récupérer l’heure mise en cache :
var cacheEntry = _memoryCache.Get<DateTime?>(CacheKeys.Entry);
Le code suivant obtient ou crée un élément mis en cache avec une expiration absolue :
var cachedValue = _memoryCache.GetOrCreate(
CacheKeys.Entry,
cacheEntry =>
{
cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(20);
return DateTime.Now;
});
Un ensemble d’éléments mis en cache avec une expiration glissante uniquement risque de ne jamais expirer. Si l’élément mis en cache est consulté à plusieurs reprises dans l’intervalle d’expiration glissant, l’élément n’expire jamais. Combinez une date d’expiration glissante avec une date d’expiration absolue pour garantir l’expiration de l’article. L’expiration absolue définit une limite supérieure sur la durée de mise en cache de l’élément, tout en permettant à l’élément d’expirer plus tôt s’il n’est pas demandé dans l’intervalle d’expiration glissant. Si l’intervalle d’expiration glissant ou le délai d’expiration absolu est dépassé, l’élément est supprimé du cache.
Le code suivant obtient ou crée un élément mis en cache avec une expiration glissante et absolue :
var cachedValue = _memoryCache.GetOrCreate(
CacheKeys.CallbackEntry,
cacheEntry =>
{
cacheEntry.SlidingExpiration = TimeSpan.FromSeconds(3);
cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(20);
return DateTime.Now;
});
Le code précédent garantit que les données ne seront pas mises en cache plus longtemps que la durée absolue.
GetOrCreate, GetOrCreateAsyncet sont Get des méthodes d’extension dans la CacheExtensions classe. Ces méthodes étendent la capacité de IMemoryCache.
MemoryCacheEntryOptions
L’exemple suivant :
- Définit la priorité du cache sur CacheItemPriority.NeverRemove.
- Définit a PostEvictionDelegate qui est appelé après l’expulsion de l’entrée du cache. Le rappel est exécuté sur un thread différent du code qui supprime l’élément du cache.
public void OnGetCacheRegisterPostEvictionCallback()
{
var memoryCacheEntryOptions = new MemoryCacheEntryOptions()
.SetPriority(CacheItemPriority.NeverRemove)
.RegisterPostEvictionCallback(PostEvictionCallback, _memoryCache);
_memoryCache.Set(CacheKeys.CallbackEntry, DateTime.Now, memoryCacheEntryOptions);
}
private static void PostEvictionCallback(
object cacheKey, object cacheValue, EvictionReason evictionReason, object state)
{
var memoryCache = (IMemoryCache)state;
memoryCache.Set(
CacheKeys.CallbackMessage,
$"Entry {cacheKey} was evicted: {evictionReason}.");
}
Utilisez SetSize, Size et SizeLimit pour limiter la taille du cache
Une MemoryCache
instance peut éventuellement spécifier et appliquer une limite de taille. La limite de taille du cache n’a pas d’unité de mesure définie, car le cache ne dispose d’aucun mécanisme pour mesurer la taille des entrées. Si la limite de taille du cache est définie, toutes les entrées doivent spécifier la taille. Le runtime ASP.NET Core ne limite pas la taille du cache en fonction de la sollicitation de la mémoire. C’est au développeur de limiter la taille du cache. La taille spécifiée est exprimée en unités choisies par le développeur.
Par exemple:
- Si l’application web mettait principalement en cache des chaînes, la taille de chaque entrée de cache pouvait correspondre à la longueur de la chaîne.
- L’application peut spécifier la taille de toutes les entrées sur 1, et la limite de taille est le nombre d’entrées.
Si SizeLimit n’est pas défini, le cache augmente sans limite. Le runtime ASP.NET Core ne réduit pas le cache lorsque la mémoire système est faible. L’architecture des applications doit être conforme aux critères suivants :
- Limitez la croissance du cache.
- Appelez Compact ou Remove lorsque la mémoire disponible est limitée.
Le code suivant crée une taille MemoryCache fixe sans unité accessible par injection de dépendances :
public class MyMemoryCache
{
public MemoryCache Cache { get; } = new MemoryCache(
new MemoryCacheOptions
{
SizeLimit = 1024
});
}
SizeLimit
n’a pas d’unités. Les entrées mises en cache doivent spécifier la taille dans les unités qu’elles jugent les plus appropriées si la limite de taille du cache a été définie. Tous les utilisateurs d’une instance de cache doivent utiliser le même système d’unités. Une entrée n’est pas mise en cache si la somme des tailles d’entrée mises en cache dépasse la valeur spécifiée par SizeLimit
. Si aucune limite de taille de cache n’est définie, la taille de cache définie sur l’entrée est ignorée.
Le code suivant s’enregistre MyMemoryCache
avec le conteneur d’injection de dépendances :
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddSingleton<MyMemoryCache>();
MyMemoryCache
est créé en tant que cache mémoire indépendant pour les composants qui sont conscients de cette taille de cache limitée et qui savent comment définir correctement la taille d’entrée de cache.
La taille de l’entrée de cache peut être définie à l’aide de la SetSize méthode extension ou de la Size propriété :
if (!_myMemoryCache.Cache.TryGetValue(CacheKeys.Entry, out DateTime cacheValue))
{
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetSize(1);
// cacheEntryOptions.Size = 1;
_myMemoryCache.Cache.Set(CacheKeys.Entry, cacheValue, cacheEntryOptions);
}
Dans le code précédent, les deux lignes en surbrillance obtiennent le même résultat en définissant la taille de l’entrée de cache.
SetSize
est fourni pour plus de commodité lors du chaînage des appels sur new MemoryCacheOptions()
.
MemoryCache.Compact
MemoryCache.Compact
tente de supprimer le pourcentage spécifié du cache dans l’ordre suivant :
- Tous les articles expirés.
- Éléments par priorité. Les éléments les moins prioritaires sont supprimés en premier.
- Objets les moins récemment utilisés.
- Articles dont l’expiration absolue est la plus proche.
- Articles dont l’expiration glissante est la plus proche.
Les éléments épinglés avec la priorité NeverRemovene sont jamais supprimés. Le code suivant supprime un élément de cache et appelle Compact
à supprimer 25% des entrées mises en cache :
_myMemoryCache.Cache.Remove(CacheKeys.Entry);
_myMemoryCache.Cache.Compact(.25);
Pour plus d’informations, consultez la source Compact sur GitHub.
Dépendances de cache
L’exemple suivant montre comment faire expirer une entrée de cache si une entrée dépendante expire. A CancellationChangeToken est ajouté à l’élément mis en cache. Lorsque Cancel
est appelé sur le CancellationTokenSource
, les deux entrées du cache sont supprimées :
public void OnGetCacheCreateDependent()
{
var cancellationTokenSource = new CancellationTokenSource();
_memoryCache.Set(
CacheKeys.DependentCancellationTokenSource,
cancellationTokenSource);
using var parentCacheEntry = _memoryCache.CreateEntry(CacheKeys.Parent);
parentCacheEntry.Value = DateTime.Now;
_memoryCache.Set(
CacheKeys.Child,
DateTime.Now,
new CancellationChangeToken(cancellationTokenSource.Token));
}
public void OnGetCacheRemoveDependent()
{
var cancellationTokenSource = _memoryCache.Get<CancellationTokenSource>(
CacheKeys.DependentCancellationTokenSource);
cancellationTokenSource.Cancel();
}
L’utilisation de a CancellationTokenSource permet de supprimer plusieurs entrées de cache en tant que groupe. Avec le using
modèle dans le code ci-dessus, les entrées de cache créées à l’intérieur de l’étendue using
héritent des déclencheurs et des paramètres d’expiration.
Remarques supplémentaires
L’expiration ne se produit pas en arrière-plan. Il n’y a pas de minuterie qui analyse activement le cache à la recherche d’éléments expirés. Toute activité sur le cache (
Get
,TryGetValue
,Set
Remove
, ) peut déclencher une analyse en arrière-plan des éléments expirés. Une minuterie sur leCancellationTokenSource
(CancelAfter) supprime également l’entrée et déclenche une recherche d’articles expirés. L’exemple suivant utilise CancellationTokenSource(TimeSpan) pour le jeton enregistré. Lorsque ce jeton se déclenche, il supprime immédiatement l’entrée et déclenche les rappels d’éviction :if (!_memoryCache.TryGetValue(CacheKeys.Entry, out DateTime cacheValue)) { cacheValue = DateTime.Now; var cancellationTokenSource = new CancellationTokenSource( TimeSpan.FromSeconds(10)); var cacheEntryOptions = new MemoryCacheEntryOptions() .AddExpirationToken( new CancellationChangeToken(cancellationTokenSource.Token)) .RegisterPostEvictionCallback((key, value, reason, state) => { ((CancellationTokenSource)state).Dispose(); }, cancellationTokenSource); _memoryCache.Set(CacheKeys.Entry, cacheValue, cacheEntryOptions); }
Lors de l’utilisation d’un callback pour remplir à nouveau un élément de cache :
- Plusieurs requêtes peuvent trouver la valeur de clé mise en cache vide car le rappel n’est pas terminé.
- Cela peut entraîner le remplissage de l’élément mis en cache par plusieurs threads.
Lorsqu’une entrée de cache est utilisée pour en créer une autre, l’enfant copie les jetons d’expiration et les paramètres d’expiration basés sur le temps de l’entrée parente. L’enfant n’a pas expiré en raison de la suppression ou de la mise à jour manuelle de l’entrée parente.
Permet PostEvictionCallbacks de définir les rappels qui seront déclenchés après l’élimination de l’entrée de cache du cache.
Pour la plupart des applications,
IMemoryCache
est activé. Par exemple, l’appel de , ,AddRazorPages
, et de nombreuses autres méthodes dansProgram.cs
, permet d’activerIMemoryCache
Add{Service}
.AddMvcCore().AddRazorViewEngine
AddControllersWithViews
AddMvc
Pour les applications qui n’appellent pas l’une des méthodes précédentesAdd{Service}
, il peut être nécessaire d’appeler AddMemoryCacheProgram.cs
.
Mise à jour du cache d’arrière-plan
Utilisez un service d’arrière-plan pour IHostedService mettre à jour le cache. Le service d’arrière-plan peut recalculer les entrées, puis les affecter au cache uniquement lorsqu’elles sont prêtes.
Ressources supplémentaires
- Afficher ou télécharger un exemple de code (comment télécharger)
- Mise en cache distribuée dans ASP.NET Core
- Détecter les modifications avec des jetons de modification dans ASP.NET Core
- Mise en cache des réponses dans ASP.NET Core
- Intergiciel de mise en cache des réponses dans ASP.NET Core
- Tag Helper Cache dans ASP.NET Core MVC
- Tag Helper Cache distribué dans ASP.NET Core
Afficher ou télécharger un exemple de code (comment télécharger)
Principes de base de la mise en cache
La mise en cache peut améliorer considérablement les performances et l’évolutivité d’une application en réduisant le travail nécessaire à la génération de contenu. La mise en cache fonctionne mieux avec des données qui changent rarement et qui sont coûteuses à générer. La mise en cache effectue une copie des données qui peut être renvoyée beaucoup plus rapidement qu’à partir de la source. Les applications doivent être écrites et testées pour ne jamais dépendre des données mises en cache.
ASP.NET Core prend en charge plusieurs caches différents. Le cache le plus simple est basé sur le IMemoryCache.
IMemoryCache
Représente un cache stocké dans la mémoire du serveur web. Les applications exécutées sur une batterie de serveurs (plusieurs serveurs) doivent garantir que les sessions sont persistantes lors de l’utilisation du cache en mémoire. Les sessions persistantes garantissent que les requêtes ultérieures d’un client sont toutes transmises au même serveur. Par exemple, Azure Web Apps utilise le routage des demandes d’application (ARR) pour acheminer toutes les demandes suivantes vers le même serveur.
Les sessions non persistantes dans une batterie de serveurs Web nécessitent un cache distribué pour éviter les problèmes de cohérence du cache. Pour certaines applications, un cache distribué peut prendre en charge un scale-out plus élevé qu’un cache en mémoire. L’utilisation d’un cache distribué décharge la mémoire cache vers un processus externe.
Le cache en mémoire peut stocker n’importe quel objet. L’interface de cache distribué est limitée à byte[]
. Le cache en mémoire et le cache distribué stockent les éléments de cache sous forme de paires clé-valeur.
System.Runtime.Caching/MemoryCache
System.Runtime.Caching / MemoryCache (Package NuGet) peut être utilisé avec :
- .NET Standard 2.0 ou version ultérieure.
- Toute implémentation .NET qui cible .NET Standard 2.0 ou version ultérieure. Par exemple, ASP.NET Core 3.1 ou version ultérieure.
- .NET Framework 4.5 ou version ultérieure.
Microsoft.Extensions.Caching.Memory/IMemoryCache
(décrit dans cet article) est recommandé carMemoryCache
System.Runtime.Caching
/il est mieux intégré dans ASP.NET Core. Par exemple, IMemoryCache
fonctionne nativement avec ASP.NET injection de dépendances Core.
À utiliser System.Runtime.Caching
/MemoryCache
comme pont de compatibilité lors du portage de code de ASP.NET 4.x vers ASP.NET Core.
Directives relatives au cache
- Le code doit toujours avoir une option de secours pour récupérer les données et ne pas dépendre de la disponibilité d’une valeur mise en cache.
- Le cache utilise une ressource rare, la mémoire. Limiter la croissance du cache :
- N’utilisez pas d’entrée externe comme clé de cache.
- Utilisez des expirations pour limiter la croissance du cache.
- Utilisez SetSize, Size et SizeLimit pour limiter la taille du cache. Le runtime ASP.NET Core ne limite pas la taille du cache en fonction de la sollicitation de la mémoire. C’est au développeur de limiter la taille du cache.
Utiliser IMemoryCache
Avertissement
L’utilisation d’un cache de mémoire partagée à partir de l’injection de dépendances et l’appel SetSize
de , Size
ou SizeLimit
pour limiter la taille du cache peuvent entraîner l’échec de l’application. Lorsqu’une limite de taille est définie sur un cache, toutes les entrées doivent spécifier une taille lors de l’ajout. Cela peut entraîner des problèmes, car les développeurs peuvent ne pas avoir un contrôle total sur ce qui utilise le cache partagé.
Lorsque vous utilisez SetSize
, Size
ou SizeLimit
pour limiter le cache, créez un singleton de cache pour la mise en cache. Pour plus d’informations et un exemple, consultez Utiliser SetSize, Size et SizeLimit pour limiter la taille du cache.
Un cache partagé est un cache partagé par d’autres frameworks ou bibliothèques.
La mise en cache en mémoire est un service référencé à partir d’une application à l’aide de l’injection de dépendances. Demandez l’instance IMemoryCache
dans le constructeur :
public class HomeController : Controller
{
private IMemoryCache _cache;
public HomeController(IMemoryCache memoryCache)
{
_cache = memoryCache;
}
Le code suivant permet TryGetValue de vérifier si une heure se trouve dans le cache. Si une heure n’est pas mise en cache, une nouvelle entrée est créée et ajoutée au cache avec Set. La CacheKeys
classe fait partie de l’exemple de téléchargement.
public static class CacheKeys
{
public static string Entry => "_Entry";
public static string CallbackEntry => "_Callback";
public static string CallbackMessage => "_CallbackMessage";
public static string Parent => "_Parent";
public static string Child => "_Child";
public static string DependentMessage => "_DependentMessage";
public static string DependentCTS => "_DependentCTS";
public static string Ticks => "_Ticks";
public static string CancelMsg => "_CancelMsg";
public static string CancelTokenSource => "_CancelTokenSource";
}
public IActionResult CacheTryGetValueSet()
{
DateTime cacheEntry;
// Look for cache key.
if (!_cache.TryGetValue(CacheKeys.Entry, out cacheEntry))
{
// Key not in cache, so get data.
cacheEntry = DateTime.Now;
// Set cache options.
var cacheEntryOptions = new MemoryCacheEntryOptions()
// Keep in cache for this time, reset time if accessed.
.SetSlidingExpiration(TimeSpan.FromSeconds(3));
// Save data in cache.
_cache.Set(CacheKeys.Entry, cacheEntry, cacheEntryOptions);
}
return View("Cache", cacheEntry);
}
L’heure actuelle et l’heure mise en cache sont affichées :
@model DateTime?
<div>
<h2>Actions</h2>
<ul>
<li><a asp-controller="Home" asp-action="CacheTryGetValueSet">TryGetValue and Set</a></li>
<li><a asp-controller="Home" asp-action="CacheGet">Get</a></li>
<li><a asp-controller="Home" asp-action="CacheGetOrCreate">GetOrCreate</a></li>
<li><a asp-controller="Home" asp-action="CacheGetOrCreateAsynchronous">CacheGetOrCreateAsynchronous</a></li>
<li><a asp-controller="Home" asp-action="CacheRemove">Remove</a></li>
<li><a asp-controller="Home" asp-action="CacheGetOrCreateAbs">CacheGetOrCreateAbs</a></li>
<li><a asp-controller="Home" asp-action="CacheGetOrCreateAbsSliding">CacheGetOrCreateAbsSliding</a></li>
</ul>
</div>
<h3>Current Time: @DateTime.Now.TimeOfDay.ToString()</h3>
<h3>Cached Time: @(Model == null ? "No cached entry found" : Model.Value.TimeOfDay.ToString())</h3>
Le code suivant utilise la méthode d’extension pour mettre en cache les Set
données pendant une durée relative sans créer l’objet MemoryCacheEntryOptions
:
public IActionResult SetCacheRelativeExpiration()
{
DateTime cacheEntry;
// Look for cache key.
if (!_cache.TryGetValue(CacheKeys.Entry, out cacheEntry))
{
// Key not in cache, so get data.
cacheEntry = DateTime.Now;
// Save data in cache and set the relative expiration time to one day
_cache.Set(CacheKeys.Entry, cacheEntry, TimeSpan.FromDays(1));
}
return View("Cache", cacheEntry);
}
La valeur mise DateTime
en cache reste dans le cache tant qu’il y a des demandes pendant la période d’expiration.
Le code suivant utilise GetOrCreate et GetOrCreateAsync pour mettre en cache les données.
public IActionResult CacheGetOrCreate()
{
var cacheEntry = _cache.GetOrCreate(CacheKeys.Entry, entry =>
{
entry.SlidingExpiration = TimeSpan.FromSeconds(3);
return DateTime.Now;
});
return View("Cache", cacheEntry);
}
public async Task<IActionResult> CacheGetOrCreateAsynchronous()
{
var cacheEntry = await
_cache.GetOrCreateAsync(CacheKeys.Entry, entry =>
{
entry.SlidingExpiration = TimeSpan.FromSeconds(3);
return Task.FromResult(DateTime.Now);
});
return View("Cache", cacheEntry);
}
Les appels Get de code suivants pour récupérer l’heure mise en cache :
public IActionResult CacheGet()
{
var cacheEntry = _cache.Get<DateTime?>(CacheKeys.Entry);
return View("Cache", cacheEntry);
}
Le code suivant obtient ou crée un élément mis en cache avec une expiration absolue :
public IActionResult CacheGetOrCreateAbs()
{
var cacheEntry = _cache.GetOrCreate(CacheKeys.Entry, entry =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(10);
return DateTime.Now;
});
return View("Cache", cacheEntry);
}
Un ensemble d’éléments mis en cache avec une expiration glissante uniquement risque de ne jamais expirer. Si l’élément mis en cache est consulté à plusieurs reprises dans l’intervalle d’expiration glissant, l’élément n’expire jamais. Combinez une date d’expiration glissante avec une date d’expiration absolue pour garantir l’expiration de l’article. L’expiration absolue définit une limite supérieure sur la durée de mise en cache de l’élément, tout en permettant à l’élément d’expirer plus tôt s’il n’est pas demandé dans l’intervalle d’expiration glissant. Si l’intervalle d’expiration glissant ou le délai d’expiration absolu est dépassé, l’élément est supprimé du cache.
Le code suivant obtient ou crée un élément mis en cache avec une expiration glissante et absolue :
public IActionResult CacheGetOrCreateAbsSliding()
{
var cacheEntry = _cache.GetOrCreate(CacheKeys.Entry, entry =>
{
entry.SetSlidingExpiration(TimeSpan.FromSeconds(3));
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(20);
return DateTime.Now;
});
return View("Cache", cacheEntry);
}
Le code précédent garantit que les données ne seront pas mises en cache plus longtemps que la durée absolue.
GetOrCreate, GetOrCreateAsyncet sont Get des méthodes d’extension dans la CacheExtensions classe. Ces méthodes étendent la capacité de IMemoryCache.
MemoryCacheEntryOptions
L’exemple suivant :
- Définit un délai d’expiration glissant. Les demandes qui accèdent à cet élément mis en cache réinitialisent l’horloge d’expiration glissante.
- Définit la priorité du cache sur CacheItemPriority.NeverRemove.
- Définit a PostEvictionDelegate qui sera appelé après l’élimination de l’entrée du cache. Le rappel est exécuté sur un thread différent du code qui supprime l’élément du cache.
public IActionResult CreateCallbackEntry()
{
var cacheEntryOptions = new MemoryCacheEntryOptions()
// Pin to cache.
.SetPriority(CacheItemPriority.NeverRemove)
// Add eviction callback
.RegisterPostEvictionCallback(callback: EvictionCallback, state: this);
_cache.Set(CacheKeys.CallbackEntry, DateTime.Now, cacheEntryOptions);
return RedirectToAction("GetCallbackEntry");
}
public IActionResult GetCallbackEntry()
{
return View("Callback", new CallbackViewModel
{
CachedTime = _cache.Get<DateTime?>(CacheKeys.CallbackEntry),
Message = _cache.Get<string>(CacheKeys.CallbackMessage)
});
}
public IActionResult RemoveCallbackEntry()
{
_cache.Remove(CacheKeys.CallbackEntry);
return RedirectToAction("GetCallbackEntry");
}
private static void EvictionCallback(object key, object value,
EvictionReason reason, object state)
{
var message = $"Entry was evicted. Reason: {reason}.";
((HomeController)state)._cache.Set(CacheKeys.CallbackMessage, message);
}
Utilisez SetSize, Size et SizeLimit pour limiter la taille du cache
Une MemoryCache
instance peut éventuellement spécifier et appliquer une limite de taille. La limite de taille du cache n’a pas d’unité de mesure définie, car le cache ne dispose d’aucun mécanisme pour mesurer la taille des entrées. Si la limite de taille du cache est définie, toutes les entrées doivent spécifier la taille. Le runtime ASP.NET Core ne limite pas la taille du cache en fonction de la sollicitation de la mémoire. C’est au développeur de limiter la taille du cache. La taille spécifiée est exprimée en unités choisies par le développeur.
Par exemple:
- Si l’application web mettait principalement en cache des chaînes, la taille de chaque entrée de cache pouvait correspondre à la longueur de la chaîne.
- L’application peut spécifier la taille de toutes les entrées sur 1, et la limite de taille est le nombre d’entrées.
Si SizeLimit n’est pas défini, le cache augmente sans limite. Le runtime ASP.NET Core ne réduit pas le cache lorsque la mémoire système est faible. L’architecture des applications doit être conforme aux critères suivants :
- Limitez la croissance du cache.
- Appelez Compact ou Remove lorsque la mémoire disponible est limitée :
Le code suivant crée une taille MemoryCache fixe sans unité accessible par injection de dépendances :
// using Microsoft.Extensions.Caching.Memory;
public class MyMemoryCache
{
public MemoryCache Cache { get; private set; }
public MyMemoryCache()
{
Cache = new MemoryCache(new MemoryCacheOptions
{
SizeLimit = 1024
});
}
}
SizeLimit
n’a pas d’unités. Les entrées mises en cache doivent spécifier la taille dans les unités qu’elles jugent les plus appropriées si la limite de taille du cache a été définie. Tous les utilisateurs d’une instance de cache doivent utiliser le même système d’unités. Une entrée n’est pas mise en cache si la somme des tailles d’entrée mises en cache dépasse la valeur spécifiée par SizeLimit
. Si aucune limite de taille de cache n’est définie, la taille de cache définie sur l’entrée sera ignorée.
Le code suivant s’enregistre MyMemoryCache
avec le conteneur d’injection de dépendances .
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddSingleton<MyMemoryCache>();
}
MyMemoryCache
est créé en tant que cache mémoire indépendant pour les composants qui sont conscients de cette taille de cache limitée et qui savent comment définir correctement la taille d’entrée de cache.
Le code suivant utilise MyMemoryCache
:
public class SetSize : PageModel
{
private MemoryCache _cache;
public static readonly string MyKey = "_MyKey";
public SetSize(MyMemoryCache memoryCache)
{
_cache = memoryCache.Cache;
}
[TempData]
public string DateTime_Now { get; set; }
public IActionResult OnGet()
{
if (!_cache.TryGetValue(MyKey, out string cacheEntry))
{
// Key not in cache, so get data.
cacheEntry = DateTime.Now.TimeOfDay.ToString();
var cacheEntryOptions = new MemoryCacheEntryOptions()
// Set cache entry size by extension method.
.SetSize(1)
// Keep in cache for this time, reset time if accessed.
.SetSlidingExpiration(TimeSpan.FromSeconds(3));
// Set cache entry size via property.
// cacheEntryOptions.Size = 1;
// Save data in cache.
_cache.Set(MyKey, cacheEntry, cacheEntryOptions);
}
DateTime_Now = cacheEntry;
return RedirectToPage("./Index");
}
}
La taille de l’entrée du cache peut être définie par Size les méthodes d’extension SetSize :
public IActionResult OnGet()
{
if (!_cache.TryGetValue(MyKey, out string cacheEntry))
{
// Key not in cache, so get data.
cacheEntry = DateTime.Now.TimeOfDay.ToString();
var cacheEntryOptions = new MemoryCacheEntryOptions()
// Set cache entry size by extension method.
.SetSize(1)
// Keep in cache for this time, reset time if accessed.
.SetSlidingExpiration(TimeSpan.FromSeconds(3));
// Set cache entry size via property.
// cacheEntryOptions.Size = 1;
// Save data in cache.
_cache.Set(MyKey, cacheEntry, cacheEntryOptions);
}
DateTime_Now = cacheEntry;
return RedirectToPage("./Index");
}
MemoryCache.Compact
MemoryCache.Compact
tente de supprimer le pourcentage spécifié du cache dans l’ordre suivant :
- Tous les articles expirés.
- Éléments par priorité. Les éléments les moins prioritaires sont supprimés en premier.
- Objets les moins récemment utilisés.
- Articles dont l’expiration absolue est la plus proche.
- Articles dont l’expiration glissante est la plus proche.
Les éléments épinglés avec la priorité NeverRemove ne sont jamais supprimés. Le code suivant supprime un élément de cache et appelle Compact
:
_cache.Remove(MyKey);
// Remove 33% of cached items.
_cache.Compact(.33);
cache_size = _cache.Count;
Pour plus d’informations, consultez la source Compact sur GitHub.
Dépendances de cache
L’exemple suivant montre comment faire expirer une entrée de cache si une entrée dépendante expire. A CancellationChangeToken est ajouté à l’élément mis en cache. Lorsque Cancel
est appelé sur le , les deux entrées du CancellationTokenSource
cache sont supprimées.
public IActionResult CreateDependentEntries()
{
var cts = new CancellationTokenSource();
_cache.Set(CacheKeys.DependentCTS, cts);
using (var entry = _cache.CreateEntry(CacheKeys.Parent))
{
// expire this entry if the dependant entry expires.
entry.Value = DateTime.Now;
entry.RegisterPostEvictionCallback(DependentEvictionCallback, this);
_cache.Set(CacheKeys.Child,
DateTime.Now,
new CancellationChangeToken(cts.Token));
}
return RedirectToAction("GetDependentEntries");
}
public IActionResult GetDependentEntries()
{
return View("Dependent", new DependentViewModel
{
ParentCachedTime = _cache.Get<DateTime?>(CacheKeys.Parent),
ChildCachedTime = _cache.Get<DateTime?>(CacheKeys.Child),
Message = _cache.Get<string>(CacheKeys.DependentMessage)
});
}
public IActionResult RemoveChildEntry()
{
_cache.Get<CancellationTokenSource>(CacheKeys.DependentCTS).Cancel();
return RedirectToAction("GetDependentEntries");
}
private static void DependentEvictionCallback(object key, object value,
EvictionReason reason, object state)
{
var message = $"Parent entry was evicted. Reason: {reason}.";
((HomeController)state)._cache.Set(CacheKeys.DependentMessage, message);
}
L’utilisation de a CancellationTokenSource permet de supprimer plusieurs entrées de cache en tant que groupe. Avec le using
modèle dans le code ci-dessus, les entrées de cache créées à l’intérieur du using
bloc hériteront des déclencheurs et des paramètres d’expiration.
Remarques supplémentaires
L’expiration ne se produit pas en arrière-plan. Il n’y a pas de minuterie qui analyse activement le cache à la recherche d’éléments expirés. Toute activité sur le cache (
Get
,Set
,Remove
) peut déclencher une analyse en arrière-plan des éléments expirés. Une minuterie sur leCancellationTokenSource
(CancelAfter) supprime également l’entrée et déclenche une recherche d’articles expirés. L’exemple suivant utilise CancellationTokenSource(TimeSpan) pour le jeton enregistré. Lorsque ce jeton se déclenche, il supprime immédiatement l’entrée et déclenche les rappels d’éviction :public IActionResult CacheAutoExpiringTryGetValueSet() { DateTime cacheEntry; if (!_cache.TryGetValue(CacheKeys.Entry, out cacheEntry)) { cacheEntry = DateTime.Now; var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); var cacheEntryOptions = new MemoryCacheEntryOptions() .AddExpirationToken(new CancellationChangeToken(cts.Token)); _cache.Set(CacheKeys.Entry, cacheEntry, cacheEntryOptions); } return View("Cache", cacheEntry); }
Lors de l’utilisation d’un callback pour remplir à nouveau un élément de cache :
- Plusieurs requêtes peuvent trouver la valeur de clé mise en cache vide car le rappel n’est pas terminé.
- Cela peut entraîner le remplissage de l’élément mis en cache par plusieurs threads.
Lorsqu’une entrée de cache est utilisée pour en créer une autre, l’enfant copie les jetons d’expiration et les paramètres d’expiration basés sur le temps de l’entrée parente. L’enfant n’a pas expiré en raison de la suppression ou de la mise à jour manuelle de l’entrée parente.
Permet PostEvictionCallbacks de définir les rappels qui seront déclenchés après l’élimination de l’entrée de cache du cache. Dans l’exemple de code, CancellationTokenSource.Dispose() est appelé pour libérer les ressources non gérées utilisées par le
CancellationTokenSource
. Cependant, le n’estCancellationTokenSource
pas supprimé immédiatement, car il est toujours utilisé par l’entrée de cache. LeCancellationToken
est passé àMemoryCacheEntryOptions
pour créer une entrée de cache qui expire après un certain temps. Il ne doit doncDispose
pas être appelé tant que l’entrée de cache n’est pas supprimée ou n’a pas expiré. L’exemple de code appelle la RegisterPostEvictionCallback méthode pour enregistrer un rappel qui sera appelé lorsque l’entrée de cache est supprimée, et il supprime leCancellationTokenSource
dans ce rappel.Pour la plupart des applications,
IMemoryCache
est activé. Par exemple, l’appel de , ,AddRazorPages
, et de nombreuses autres méthodes dansConfigureServices
, permet d’activerIMemoryCache
Add{Service}
.AddMvcCore().AddRazorViewEngine
AddControllersWithViews
AddMvc
Pour les applications qui n’appellent pas l’une des méthodes précédentesAdd{Service}
, il peut être nécessaire d’appeler AddMemoryCacheConfigureServices
.
Mise à jour du cache d’arrière-plan
Utilisez un service d’arrière-plan pour IHostedService mettre à jour le cache. Le service d’arrière-plan peut recalculer les entrées, puis les affecter au cache uniquement lorsqu’elles sont prêtes.
Ressources supplémentaires
- Mise en cache distribuée dans ASP.NET Core
- Détecter les modifications avec des jetons de modification dans ASP.NET Core
- Mise en cache des réponses dans ASP.NET Core
- Intergiciel de mise en cache des réponses dans ASP.NET Core
- Tag Helper Cache dans ASP.NET Core MVC
- Tag Helper Cache distribué dans ASP.NET Core