Note
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier les répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de changer de répertoire.
Cet article explique comment configurer et utiliser la bibliothèque HybridCache dans une application ASP.NET Core. Pour accéder à une présentation de la bibliothèque, consultez la section HybridCache de la vue d’ensemble de la mise en cache.
Obtenir la bibliothèque
Installez le package Microsoft.Extensions.Caching.Hybrid.
dotnet add package Microsoft.Extensions.Caching.Hybrid
Enregistrer le service
Ajoutez le service HybridCache au conteneur d'injection de dépendances (DI) en appelant AddHybridCache :
// Add services to the container.
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddAuthorization();
builder.Services.AddHybridCache();
Le code précédent inscrit le service HybridCache avec les options par défaut. L’API d’inscription peut également configurer les options et la sérialisation.
Obtenir et stocker des entrées de cache
Le service HybridCache fournit une méthode GetOrCreateAsync avec deux surcharges, prenant une clé et :
- Une méthode de fabrique.
- État, et une méthode d'usine.
La méthode utilise la clé pour tenter de récupérer l’objet dans le cache principal. Si l’élément n’est pas trouvé dans le cache principal (un cache manque), il vérifie le cache secondaire s’il est configuré. S'il ne trouve pas les données là-bas (un autre échec de cache), il appelle la méthode de fabrique pour obtenir l’objet à partir de la source de données. Elle stocke ensuite l’objet dans les caches principal et secondaire. La méthode factice n’est jamais appelée si l’objet est trouvé dans le cache principal ou secondaire (en cas de succès de mise en cache).
Le service HybridCache garantit qu’un seul appelant simultané pour une clé donnée appelle la méthode d’usine, et tous les autres appelants attendent le résultat de cet appel. Le CancellationToken passé à GetOrCreateAsync représente l’annulation combinée de tous les appelants simultanés.
La surcharge principale GetOrCreateAsync
La surcharge sans état de GetOrCreateAsync est recommandée dans la plupart des cas. Le code permettant de l’appeler est relativement simple. Voici un exemple :
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;
}
}
Conseils sur les clés de cache
Le key passé à GetOrCreateAsync doit identifier de manière unique les données mises en cache :
- En termes de valeurs d’identificateur utilisées pour récupérer ces données à partir de sa source.
- En termes d’autres données mises en cache dans l’application.
Les deux types d’unicité sont généralement assurés à l’aide de la concaténation de chaînes pour créer une seule chaîne de clé composée de différentes parties concaténées en une seule chaîne. Par exemple :
cache.GetOrCreateAsync($"/orders/{region}/{orderId}", ...);
ou
cache.GetOrCreateAsync($"user_prefs_{userId}", ...);
Il incombe à l’appelant de s’assurer qu’un schéma de clé est valide et ne peut pas provoquer la confusion des données.
Évitez d’utiliser l’entrée utilisateur externe directement dans les clés de cache. Par exemple, n’utilisez pas de chaînes brutes à partir d’interfaces utilisateur comme clés de cache. Cela peut exposer votre application aux risques de sécurité, tels que l’accès non autorisé ou les attaques par déni de service causées par l’inondation du cache avec des clés aléatoires ou sans signification. Dans les exemples valides précédents, les données de commande et de préférence utilisateur sont clairement séparées et utilisent des identificateurs fiables :
-
orderidetuserIdsont des identificateurs générés en interne. -
regionpeut être une énumération ou une chaîne à partir d’une liste prédéfinie de régions connues.
Aucune importance n’est placée sur des jetons tels que / ou _. La valeur de clé entière est traitée comme une chaîne d’identification opaque. Dans ce cas, vous pouvez omettre les / et _ sans modification de la façon dont les fonctions de cache sont utilisées, mais un délimiteur est généralement utilisé pour éviter l’ambiguïté , par exemple $"order{customerId}{orderId}" peut entraîner une confusion entre :
-
customerId42 avecorderId123 -
customerId421 avecorderId23
Les deux exemples précédents génèrent la clé order42123de cache.
Cette aide s’applique également à toute API de cache basée sur string, telle que HybridCache, IDistributedCacheet IMemoryCache.
Notez que la syntaxe de chaîne interpolée inline ($"..." dans les exemples précédents de clés valides) se trouve directement à l’intérieur de l’appel GetOrCreateAsync. Cette syntaxe est recommandée lors de l’utilisation de HybridCache, car elle permet des améliorations futures planifiées qui contournent la nécessité d’allouer une string pour la clé dans de nombreux scénarios.
Considérations clés supplémentaires
- Les clés peuvent être limitées à des longueurs maximales valides. Par exemple, l’implémentation
HybridCachepar défaut (viaAddHybridCache(...)) limite les clés à 1 024 caractères par défaut. Ce nombre est configurable viaHybridCacheOptions.MaximumKeyLength, avec des clés plus longues contournant les mécanismes de cache pour empêcher la saturation. - Les clés doivent être des séquences Unicode valides. Si des séquences Unicode non valides sont passées, le comportement n’est pas défini.
- Lors de l’utilisation d’un cache secondaire hors processus, par
IDistributedCacheexemple, l’implémentation du back-end peut imposer des restrictions supplémentaires. Par exemple, un backend particulier peut utiliser une logique de clé insensible à la casse. La valeur par défautHybridCache(viaAddHybridCache(...)) détecte ce scénario pour empêcher les attaques de confusion ou les attaques d’alias (à l’aide de l’égalité de chaîne au niveau du bit). Toutefois, ce scénario peut encore entraîner un remplacement ou une suppression des clés en conflit plus tôt que prévu.
La surcharge alternative GetOrCreateAsync
La surcharge alternative peut réduire la charge de traitement liée aux variables capturées et aux rappels par instance, mais au prix d’un code plus complexe. Pour la plupart des scénarios, l’augmentation des performances ne dépasse pas la complexité du code. Voici un exemple qui utilise la surcharge alternative :
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;
}
}
Méthode SetAsync
Dans de nombreux scénarios, GetOrCreateAsync est la seule API nécessaire. Toutefois, HybridCache dispose également de SetAsync pour stocker un objet dans le cache sans essayer de le récupérer au préalable.
Supprimer les entrées de cache par clé
Lorsque les données sous-jacentes d’une entrée de cache changent avant son expiration, supprimez explicitement l’entrée en appelant RemoveAsync avec la clé à l’entrée. Une surcharge vous permet de spécifier une collection de valeurs clés.
Lorsqu’une entrée est supprimée, elle est supprimée des caches principaux et secondaires.
Supprimer les entrées du cache par balise
Les balises peuvent être utilisées pour regrouper les entrées de cache et les invalider ensemble.
Définissez des balises lors de l’appel de GetOrCreateAsync, comme illustré dans l’exemple suivant :
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;
}
}
Supprimez toutes les entrées d’une balise spécifiée en appelant RemoveByTagAsync avec la valeur de la balise. Une surcharge vous permet de spécifier une collection de valeurs de balise.
Ni IMemoryCache ni IDistributedCache n'ont de prise en charge directe du concept de balises, par conséquent, l'invalidation basée sur les balises est uniquement une opération logique. Elle ne supprime pas activement les valeurs du cache local ou distribué. Au lieu de cela, il garantit que lors de la réception de données avec de telles balises, les données sont traitées comme un défaut de cache à la fois dans le cache local et distant. Les valeurs expirent de IMemoryCache de manière habituelle IDistributedCache en fonction de la durée de vie configurée.
Suppression de toutes les entrées de cache
La balise astérisque (*) est réservée en tant que caractère générique et est interdite par rapport aux valeurs individuelles. L’appel RemoveByTagAsync("*") a pour effet d’invalider toutes les données, même les HybridCache données qui n’ont pas de balises. Comme pour les balises individuelles, il s’agit d’une opération logique , et les valeurs individuelles continuent d’exister jusqu’à ce qu’elles expirent naturellement. Les correspondances de style Glob ne sont pas prises en charge. Par exemple, vous ne pouvez pas utiliser RemoveByTagAsync("foo*") pour supprimer tout à partir foode .
Considérations supplémentaires relatives aux étiquettes
- Le système ne limite pas le nombre de balises que vous pouvez utiliser, mais de grands ensembles d’étiquettes peuvent avoir un impact négatif sur les performances.
- Les balises ne peuvent pas être vides, simplement des espaces blancs ou la valeur
*réservée.
Paramètres
La méthode AddHybridCache peut être utilisée pour la configuration globale par défaut. L’exemple suivant montre comment configurer certaines des options disponibles :
// 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)
};
});
La méthode GetOrCreateAsync peut également accepter un objet HybridCacheEntryOptions pour remplacer les valeurs par défaut globales d’une entrée de cache spécifique. Voici un exemple :
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;
}
}
Pour plus d’informations sur les options, consultez le code source :
- HybridCacheOptions classe.
- HybridCacheEntryOptions classe.
Limites
Les propriétés suivantes de HybridCacheOptions vous permettent de configurer des limites qui s’appliquent à toutes les entrées de cache :
- MaximumPayloadBytes : taille maximale d’une entrée de cache. La valeur par défaut est de 1 Mo. Les tentatives de stockage des valeurs sur cette taille sont journalisées et la valeur n’est pas stockée dans le cache.
- MaximumKeyLength : longueur maximale d’une clé de cache. La valeur par défaut est de 1 024 caractères. Les tentatives de stockage des valeurs sur cette taille sont journalisées et la valeur n’est pas stockée dans le cache.
Sérialisation
L’utilisation d’un cache secondaire hors processus nécessite une sérialisation. La sérialisation est configurée dans le cadre de l’inscription du service HybridCache. Les sérialiseurs spécifiques à un type ou à usage général peuvent être configurés via les méthodes AddSerializer et AddSerializerFactory, enchaînées à partir de l'appel AddHybridCache. Par défaut, la bibliothèque gère string et byte[] de manière interne, et utilise System.Text.Json pour tout le reste.
HybridCache peut également utiliser d’autres sérialiseurs, par exemple protobuf ou XML.
L’exemple suivant configure le service pour qu’il utilise un sérialiseur Protobuf spécifique au type :
// 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>>();
L’exemple suivant configure le service pour qu’il utilise un sérialiseur protobuf à usage général, capable de gérer de nombreux types protobuf :
// 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>();
Le cache secondaire nécessite un magasin de données, tel que Redis, SQL Server ou Postgres. Pour utiliser Azure Cache pour Redis, par exemple :
Installez le package
Microsoft.Extensions.Caching.StackExchangeRedis.Créez une instance d’Azure Cache pour Redis.
Obtenez une chaîne de connexion qui se connecte à l’instance de Redis. Recherchez la chaîne de connexion en sélectionnant Afficher les clés d’accès dans la page Vue d’ensemble du portail Azure.
Stockez la chaîne de connexion dans la configuration de l’application. Par exemple, utilisez un fichier de secrets utilisateur qui ressemble au code JSON suivant, et spécifiez la chaîne de connexion dans la section
ConnectionStrings. Remplacez<the connection string>par la chaîne de connexion réelle :{ "ConnectionStrings": { "RedisConnectionString": "<the connection string>" } }Inscrivez dans le DI l'implémentation de
IDistributedCachefournie par le package Redis. Pour ce faire, appelezAddStackExchangeRedisCache, et transmettez la chaîne de connexion. Par exemple :builder.Services.AddStackExchangeRedisCache(options => { options.Configuration = builder.Configuration.GetConnectionString("RedisConnectionString"); });L'implémentation de Redis
IDistributedCacheest maintenant disponible depuis le conteneur DI de l'application.HybridCaches’en sert en tant que cache secondaire, et utilise pour cela le sérialiseur configuré.
Pour plus d’informations, consultez l’exemple d’application de sérialisation HybridCache.
Stockage du cache
Par défaut, HybridCache utilise MemoryCache pour le stockage dans le cache principal. Les entrées de cache sont stockées in-process. Ainsi, chaque serveur dispose d’un cache distinct, qui est perdu à chaque redémarrage du processus serveur. Pour le stockage hors processus secondaire, tel que Redis, SQL Server ou Postgres, HybridCache utilise l’implémentation configuréeIDistributedCache, le cas échéant. Mais même en l'absence d'une IDistributedCacheimplémentation, le HybridCache service fournit toujours une mise en cache en cours de processus et une protection anti-emballement .
Remarque
Lors de l’invalidation des entrées de cache par clé ou par étiquettes, elles sont invalidées dans le serveur actuel et dans le stockage hors processus secondaire. Cependant, le cache en mémoire des autres serveurs n'est pas affecté.
Optimiser les performances
Pour optimiser les performances, configurez HybridCache afin de réutiliser les objets et d’éviter les allocations de byte[].
Réutiliser des objets
En réutilisant des instances, HybridCache peut réduire la charge de traitement des allocations de processeur et d’objets associées à la désérialisation par appel. Cela peut entraîner une amélioration des performances dans les scénarios où les objets mis en cache sont volumineux ou utilisés fréquemment.
Dans le code existant classique qui utilise IDistributedCache, chaque récupération d’un objet à partir du cache entraîne une désérialisation. Ce comportement signifie que chaque appelant simultané obtient une instance distincte de l’objet, qui ne peut pas interagir avec d’autres instances. Il en résulte une sécurité des threads, car il n’existe aucun risque de modifications simultanées sur la même instance d’objet.
Étant donné qu'une grande partie de l'utilisation de HybridCache sera adaptée à partir du code IDistributedCache existant, HybridCache préserve ce comportement par défaut pour éviter d'introduire des bogues de concurrence. Cependant, les objets sont intrinsèquement thread-safe si :
- Ils sont des types immuables.
- Le code ne les modifie pas.
Dans ce cas, informez-vous HybridCache qu’il est sûr de réutiliser des instances en apportant les deux modifications suivantes :
- Marquer le type comme
sealed. Le mot clésealeden C# signifie que la classe ne peut pas être héritée. - Appliquant l’attribut
[ImmutableObject(true)]au type. L’attribut[ImmutableObject(true)]indique que l’état de l’objet ne peut pas être modifié après sa création.
Éviter les allocations byte[]
HybridCache fournit également des API facultatives pour les implémentations de IDistributedCache, afin d’éviter les allocations de byte[]. Cette fonctionnalité est implémentée par les versions préliminaires des packages Microsoft.Extensions.Caching.StackExchangeRedis, Microsoft.Extensions.Caching.SqlServer et Microsoft.Extensions.Caching.Postgres. Pour plus d’informations, consultez IBufferDistributedCache.
Voici les commandes CLI .NET pour installer les packages :
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis
dotnet add package Microsoft.Extensions.Caching.SqlServer
dotnet add package Microsoft.Extensions.Caching.Postgres
Implémentations personnalisées de HybridCache
Une implémentation concrète de la classe abstraite HybridCache est incluse dans l’infrastructure partagée, et est fournie via une injection de dépendances. Mais les développeurs sont invités à fournir ou à consommer des implémentations personnalisées de l’API, par exemple FusionCache.
Utiliser le cache hybride avec AOT natif
Les considérations spécifiques à AOT en mode natif suivantes s’appliquent à HybridCache:
Sérialisation
L’AOT natif ne prend pas en charge la sérialisation basée sur la réflexion du runtime. Si vous mettez en cache des types personnalisés, vous devez utiliser des générateurs de code source ou configurer explicitement des sérialiseurs compatibles avec AOT, comme
System.Text.Jsonla génération de code source.HybridCacheest toujours en cours de développement, et simplifier la façon de l’utiliser avec AOT est une priorité élevée pour ce développement. Pour plus d’informations, voir pull request dotnet/extensions#6475Élagage
Vérifiez que tous les types que vous mettez en cache sont référencés de manière à les empêcher d’être supprimés par le compilateur AOT. L’utilisation de générateurs sources pour la sérialisation aide à cette exigence. Pour plus d’informations, consultez prise en charge de ASP.NET Core pour Native AOT.
Si vous configurez la sérialisation et le découpage correctement, HybridCache se comporte de la même façon que dans les applications AOT natives comme dans les applications standard ASP.NET Core.
Compatibilité
La bibliothèque HybridCache prend en charge les runtimes .NET plus anciens, jusqu’à .NET Framework 4.7.2 et .NET Standard 2.0.
Ressources supplémentaires
Pour plus d’informations, consultez le HybridCache code source