Libreria HybridCache in ASP.NET Core
Importante
HybridCache
è attualmente ancora in anteprima, ma verrà completamente rilasciato dopo .NET 9.0 in una versione secondaria futura delle estensioni .NET.
Questo articolo illustra come configurare e usare la HybridCache
libreria in un'app ASP.NET Core. Per un'introduzione alla libreria, vedere la HybridCache
sezione della panoramica della memorizzazione nella cache.
Ottenere la libreria
Installare il pacchetto Microsoft.Extensions.Caching.Hybrid
.
dotnet add package Microsoft.Extensions.Caching.Hybrid --version "9.0.0-preview.7.24406.2"
Registrare il servizio
Aggiungere il HybridCache
servizio al contenitore di inserimento delle dipendenze chiamando AddHybridCache
:
// Add services to the container.
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddAuthorization();
builder.Services.AddHybridCache();
Il codice precedente registra il HybridCache
servizio con le opzioni predefinite. L'API di registrazione può anche configurare opzioni e serializzazione.
Ottenere e archiviare le voci della cache
Il HybridCache
servizio fornisce un GetOrCreateAsync
metodo con due overload, prendendo una chiave e:
- Metodo factory.
- Stato e metodo factory.
Il metodo usa la chiave per tentare di recuperare l'oggetto dalla cache primaria. Se l'elemento non viene trovato nella cache primaria (un mancato riscontro nella cache), controlla la cache secondaria se ne è configurata una. Se non trova i dati (un altro mancato riscontro nella cache), chiama il metodo factory per ottenere l'oggetto dall'origine dati. Archivia quindi l'oggetto nelle cache primarie e secondarie. Il metodo factory non viene mai chiamato se l'oggetto viene trovato nella cache primaria o secondaria (un riscontro nella cache).
Il HybridCache
servizio garantisce che un solo chiamante simultaneo per una determinata chiave chiami il metodo factory e tutti gli altri chiamanti attendino il risultato di tale chiamata. Oggetto CancellationToken
passato a GetOrCreateAsync
rappresenta l'annullamento combinato di tutti i chiamanti simultanei.
Overload principale GetOrCreateAsync
L'overload senza stato di GetOrCreateAsync
è consigliato per la maggior parte degli scenari. Il codice da chiamare è relativamente semplice. Ecco un esempio:
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;
}
}
Overload alternativo GetOrCreateAsync
L'overload alternativo potrebbe ridurre il sovraccarico delle variabili acquisite e dei callback per istanza, ma a scapito di codice più complesso. Per la maggior parte degli scenari, l'aumento delle prestazioni non supera la complessità del codice. Ecco un esempio che usa l'overload alternativo:
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;
}
}
Metodo SetAsync
In molti scenari, GetOrCreateAsync
è l'unica API necessaria. Ma HybridCache
deve SetAsync
anche archiviare un oggetto nella cache senza tentare di recuperarlo per primo.
Rimuovere le voci della cache per chiave
Quando i dati sottostanti per una voce della cache vengono modificati prima della scadenza, rimuovere la voce in modo esplicito chiamando RemoveAsync
con la chiave alla voce. Un overload consente di specificare una raccolta di valori chiave.
Quando una voce viene rimossa, viene rimossa dalle cache primarie e secondarie.
Rimuovere le voci della cache in base al tag
I tag possono essere usati per raggruppare le voci della cache e invalidarle insieme.
Impostare i tag quando si chiama GetOrCreateAsync
, come illustrato nell'esempio seguente:
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;
}
}
Rimuovere tutte le voci per un tag specificato chiamando RemoveByTagAsync
con il valore del tag. Un overload consente di specificare una raccolta di valori di tag.
Quando una voce viene rimossa, viene rimossa dalle cache primarie e secondarie.
Opzioni
Il AddHybridCache
metodo può essere usato per configurare le impostazioni predefinite globali. L'esempio seguente illustra come configurare alcune delle opzioni disponibili:
// 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)
};
});
Il GetOrCreateAsync
metodo può anche accettare un HybridCacheEntryOptions
oggetto per eseguire l'override delle impostazioni predefinite globali per una voce di cache specifica. Ecco un esempio:
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;
}
}
Per altre informazioni sulle opzioni, vedere il codice sorgente:
Limiti
Le proprietà seguenti di consentono di configurare i limiti applicabili a tutte le voci della HybridCacheOptions
cache:
- MaximumPayloadBytes: dimensione massima di una voce della cache. Il valore predefinito è 1 MB. I tentativi di archiviare i valori di questa dimensione vengono registrati e il valore non viene archiviato nella cache.
- MaximumKeyLength: lunghezza massima di una chiave della cache. Il valore predefinito è 1024 caratteri. I tentativi di archiviare i valori di questa dimensione vengono registrati e il valore non viene archiviato nella cache.
Serializzazione
L'uso di una cache secondaria out-of-process richiede la serializzazione. La serializzazione viene configurata come parte della registrazione del HybridCache
servizio. I serializzatori specifici del tipo e per utilizzo generico possono essere configurati tramite i AddSerializer
metodi e AddSerializerFactory
, concatenati dalla AddHybridCache
chiamata. Per impostazione predefinita, la libreria gestisce string
e byte[]
internamente e usa System.Text.Json
per tutto il resto. HybridCache
può anche usare altri serializzatori, ad esempio protobuf o XML.
L'esempio seguente configura il servizio per l'uso di un serializzatore protobuf specifico del tipo:
// 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'esempio seguente configura il servizio per l'uso di un serializzatore protobuf per utilizzo generico in grado di gestire molti tipi 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>();
La cache secondaria richiede un archivio dati, ad esempio Redis o SqlServer. Per usare cache di Azure per Redis, ad esempio:
Installare il pacchetto
Microsoft.Extensions.Caching.StackExchangeRedis
.Creare un'istanza di cache di Azure per Redis.
Ottenere un stringa di connessione che si connette all'istanza di Redis. Trovare il stringa di connessione selezionando Mostra chiavi di accesso nella pagina Panoramica del portale di Azure.
Archiviare il stringa di connessione nella configurazione dell'app. Ad esempio, usare un file di segreti utente simile al codice JSON seguente, con il stringa di connessione nella
ConnectionStrings
sezione . Sostituire<the connection string>
con il stringa di connessione effettivo:{ "ConnectionStrings": { "RedisConnectionString": "<the connection string>" } }
Registrare nell'implementazione di inserimento delle dipendenze
IDistributedCache
fornita dal pacchetto Redis. A tale scopo, chiamareAddStackExchangeRedisCache
e passare il stringa di connessione. Ad esempio:builder.Services.AddStackExchangeRedisCache(options => { options.Configuration = builder.Configuration.GetConnectionString("RedisConnectionString"); });
L'implementazione di Redis
IDistributedCache
è ora disponibile dal contenitore di inserimento delle dipendenze dell'app.HybridCache
lo usa come cache secondaria e usa il serializzatore configurato per tale cache.
Per altre informazioni, vedere l'app di esempio di serializzazione HybridCache.
Archiviazione cache
Per impostazione predefinita HybridCache
, MemoryCache usa per l'archiviazione della cache primaria. Le voci della cache vengono archiviate in-process, quindi ogni server dispone di una cache separata che viene persa ogni volta che viene riavviato il processo del server. Per l'archiviazione out-of-process secondaria, ad esempio Redis o SQL Server, HybridCache
usa l'implementazione configurataIDistributedCache
, se presente. Ma anche senza un'implementazione IDistributedCache
, il HybridCache
servizio fornisce comunque la protezione in-process caching e stampede.
Ottimizzare le prestazioni
Per ottimizzare le prestazioni, configurare per riutilizzare HybridCache
gli oggetti ed evitare byte[]
allocazioni.
Riutilizzare gli oggetti
Riutilizzando istanze, HybridCache
è possibile ridurre il sovraccarico delle allocazioni di CPU e oggetti associate alla deserializzazione per chiamata. Ciò può comportare miglioramenti delle prestazioni negli scenari in cui gli oggetti memorizzati nella cache sono di grandi dimensioni o a cui si accede di frequente.
Nel codice esistente tipico che usa IDistributedCache
, ogni recupero di un oggetto dalla cache comporta la deserializzazione. Questo comportamento significa che ogni chiamante simultaneo ottiene un'istanza separata dell'oggetto, che non può interagire con altre istanze. Il risultato è thread safety, poiché non esiste alcun rischio di modifiche simultanee alla stessa istanza dell'oggetto.
Poiché gran parte HybridCache
dell'utilizzo verrà adattato dal codice esistente IDistributedCache
, HybridCache
mantiene questo comportamento per impostazione predefinita per evitare di introdurre bug di concorrenza. Tuttavia, gli oggetti sono intrinsecamente thread-safe se:
- Sono tipi non modificabili.
- Il codice non li modifica.
In questi casi, informare HybridCache
che è sicuro riutilizzare le istanze in base a:
- Contrassegnare il tipo come
sealed
. Lasealed
parola chiave in C# indica che la classe non può essere ereditata. - Applicazione dell'attributo
[ImmutableObject(true)]
al tipo. L'attributo[ImmutableObject(true)]
indica che lo stato dell'oggetto non può essere modificato dopo la creazione.
Evitare byte[]
allocazioni
HybridCache
fornisce anche API facoltative per IDistributedCache
le implementazioni, per evitare byte[]
allocazioni. Questa funzionalità viene implementata dalle versioni di anteprima dei Microsoft.Extensions.Caching.StackExchangeRedis
pacchetti e Microsoft.Extensions.Caching.SqlServer
. Per altre informazioni, vedere IBufferDistributedCache Ecco i comandi dell'interfaccia della riga di comando di .NET per installare i pacchetti:
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis --prerelease
dotnet add package Microsoft.Extensions.Caching.SqlServer --prerelease
Implementazioni di HybridCache personalizzate
Un'implementazione concreta della HybridCache
classe astratta è inclusa nel framework condiviso e viene fornita tramite inserimento delle dipendenze. Gli sviluppatori sono tuttavia invitati a fornire implementazioni personalizzate dell'API.
Compatibilità
La HybridCache
libreria supporta runtime .NET meno recenti, fino a .NET Framework 4.7.2 e .NET Standard 2.0.
Risorse aggiuntive
Per altre informazioni su HybridCache
, vedere le risorse seguenti: