Bibliothèque HybridCache dans ASP.NET Core
Important
HybridCache
est toujours en préversion, mais sera entièrement publié après .NET 9.0 dans une prochaine version mineure des extensions .NET.
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 --version "9.0.0-preview.7.24406.2"
Enregistrer le service
Ajoutez le service HybridCache
au conteneur d’injection de dépendances 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, qui acceptent une clé et :
- Une méthode de fabrique.
- Un état et une méthode de fabrique.
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é. Si les données sont introuvables également à cet emplacement (autre non-correspondance dans le cache), elle 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 de fabrique n’est jamais appelée si l’objet est trouvé dans le cache principal ou secondaire (correspondance dans le 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.
Surcharge principale de GetOrCreateAsync
La surcharge sans état de GetOrCreateAsync
est recommandée pour la plupart des scénarios. 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;
}
}
Surcharge alternative de 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. Dans la plupart des scénarios, l’augmentation des performances ne l’emporte pas sur la complexité du code. Voici un exemple d’utilisation de 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 de clé.
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 d’étiquette.
Lorsqu’une entrée est supprimée, elle est supprimée des caches principaux et secondaires.
Options
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 ainsi que les sérialiseurs à usage général peuvent être configurés via les méthodes AddSerializer
et AddSerializerFactory
, chaînées à partir de l’appel de 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, par exemple Redis ou SqlServer. 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 l’implémentation de
IDistributedCache
fournie par le package Redis dans le conteneur d’injection de dépendances. Pour ce faire, appelezAddStackExchangeRedisCache
, et passez la chaîne de connexion. Par exemple :builder.Services.AddStackExchangeRedisCache(options => { options.Configuration = builder.Configuration.GetConnectionString("RedisConnectionString"); });
L’implémentation Redis de
IDistributedCache
est désormais disponible dans le conteneur d’injection de dépendances de l’application.HybridCache
s’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, par exemple Redis ou SQL Server, HybridCache
utilise l’implémentation configurée de IDistributedCache
, le cas échéant. Toutefois, même sans l’implémentation de IDistributedCache
, le service HybridCache
fournit toujours une mise en cache in-process et une protection contre les requêtes simultanées en grand nombre.
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 cohérence de thread, car il n’existe aucun risque de modifications simultanées sur la même instance d’objet.
Étant donné que beaucoup d’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 d’accès concurrentiel. Toutefois, les objets sont intrinsèquement thread-safe si :
- Leurs types sont immuables.
- Le code ne les modifie pas.
Dans ce genre de situation, indiquez à HybridCache
que les instances peuvent être réutilisées de manière sécurisée en :
- Marquant le type en tant que
sealed
. Le mot clésealed
en 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 de 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 préversions des packages Microsoft.Extensions.Caching.StackExchangeRedis
et Microsoft.Extensions.Caching.SqlServer
. Pour plus d’informations, consultez IBufferDistributedCache. Voici les commandes CLI .NET pour installer les packages :
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis --prerelease
dotnet add package Microsoft.Extensions.Caching.SqlServer --prerelease
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. Toutefois, les développeurs sont invités à fournir des implémentations personnalisées de l’API.
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 sur HybridCache
, consultez les ressources suivantes :
- Problème GitHub dotnet/aspnetcore #54647.
- Code source de
HybridCache