Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Questo articolo illustra come configurare e usare la HybridCache libreria in un'app ASP.NET Core. Per un'introduzione alla libreria, vedere HybridCache.
Scarica la libreria
Installare il pacchetto Microsoft.Extensions.Caching.Hybrid.
dotnet add package Microsoft.Extensions.Caching.Hybrid
Registrare il servizio
Aggiungere il servizio HybridCache al contenitore di iniezione di dipendenze (DI) 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.
Recuperare e archiviare le voci della cache
Il HybridCache servizio fornisce un GetOrCreateAsync metodo con due sovraccarichi, accettando una chiave e:
- Metodo fabbrica.
- Stato e metodo fabbrica.
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.
CancellationToken passato a GetOrCreateAsync rappresenta l'annullamento combinato di tutti i chiamanti simultanei.
L'overload principale GetOrCreateAsync
Il sovraccarico senza stato di GetOrCreateAsync è consigliato per la maggior parte degli scenari. Il codice per chiamarlo è 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;
}
}
Linee guida per la chiave della cache
Il key passato a GetOrCreateAsync deve identificare in modo univoco i dati memorizzati nella cache:
- In termini di valori di identificatore usati per recuperare i dati dall'origine.
- In termini di altri dati memorizzati nella cache nell'applicazione.
Entrambi i tipi di univocità vengono in genere assicurati usando la concatenazione di stringhe per creare una singola stringa chiave composta da parti diverse concatenate in una sola stringa. Ad esempio:
cache.GetOrCreateAsync($"/orders/{region}/{orderId}", ...);
oppure
cache.GetOrCreateAsync($"user_prefs_{userId}", ...);
È responsabilità del chiamante assicurarsi che uno schema chiave sia valido e non possa causare confusione nei dati.
Evitare di usare l'input dell'utente esterno direttamente nelle chiavi della cache. Ad esempio, non usare stringhe non elaborate dalle interfacce utente come chiavi della cache. In questo modo si può esporre l'app a rischi per la sicurezza, come accessi non autorizzati o attacchi di denial-of-service causati dall'inondazione della cache con chiavi casuali o prive di significato. Negli esempi validi precedenti i dati relativi all'ordine e alle preferenze utente sono chiaramente separati e usano identificatori attendibili:
-
orderideuserIdsono identificatori generati internamente. -
regionpotrebbe essere un'enumerazione o una stringa da un elenco predefinito di aree note.
Nessun significato viene inserito nei token, / ad esempio o _. L'intero valore della chiave viene considerato come una stringa di identificazione opaca. In questo caso, è possibile omettere il / e _ senza alcuna modifica al modo in cui le funzioni della cache, ma un delimitatore viene in genere usato per evitare ambiguità, ad esempio $"order{customerId}{orderId}" potrebbe causare confusione tra:
-
customerId42 conorderId123 -
customerId421 conorderId23
Entrambi gli esempi precedenti generano la chiave order42123della cache .
Queste linee guida si applicano allo stesso modo a qualsiasi API cache basata su string, ad esempio HybridCache, IDistributedCachee IMemoryCache.
Si noti che la sintassi di stringa interpolata inline ($"..." negli esempi precedenti di chiavi valide) si trova direttamente all'interno della chiamata GetOrCreateAsync. Questa sintassi è consigliata quando si usa HybridCache, perché consente miglioramenti futuri pianificati che ignorano la necessità di allocare un string per la chiave in molti scenari.
Considerazioni chiave aggiuntive
- Le chiavi possono essere limitate a lunghezze massime valide. Ad esempio, l'implementazione
HybridCachepredefinita (tramiteAddHybridCache(...)) limita le chiavi a 1024 caratteri per impostazione predefinita. Tale numero è configurabile tramiteHybridCacheOptions.MaximumKeyLength, con chiavi più lunghe ignorando i meccanismi della cache per evitare la saturazione. - Le chiavi devono essere sequenze Unicode valide. Se vengono passate sequenze Unicode non valide, il comportamento non è definito.
- Quando si utilizza una cache secondaria fuori processo come
IDistributedCache, l'implementazione del back-end potrebbe imporre restrizioni aggiuntive. Come esempio ipotetico, un particolare back-end potrebbe utilizzare una logica delle chiavi insensibile alle maiuscole. L'impostazione predefinitaHybridCache(tramiteAddHybridCache(...)) rileva questo scenario per evitare attacchi di confusione o attacchi alias (usando l'uguaglianza di stringhe bit per bit). Tuttavia, in questo scenario potrebbe comunque verificarsi una sovrascrittura o una rimozione anticipata delle chiavi in conflitto rispetto al previsto.
L'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 il sovraccarico 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 in base alla chiave
Quando i dati sottostanti per una voce della cache vengono modificati prima della scadenza, rimuovere la voce in modo esplicito chiamando RemoveAsync utilizzando la chiave della voce. Un overload consente di specificare una raccolta di valori chiave.
Quando una voce viene rimossa, essa viene eliminata sia dalla cache primaria che da quella secondaria.
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 sovraccarico consente di specificare una raccolta di valori di tag.
Né IMemoryCache né IDistributedCache ha supporto diretto per il concetto di tag, quindi l'invalidazione basata su tag è solo un'operazione logica . Non rimuove attivamente i valori dalla cache locale o distribuita. Garantisce invece che quando si ricevono dati con tali tag, i dati vengono considerati come mancati riscontri nella cache sia dalla cache locale che dalla cache remota. I valori scadono da IMemoryCache e IDistributedCache nel modo consueto in base alla durata configurata.
Rimozione di tutte le voci della cache
Il tag asterisco (*) è riservato come jolly e non è consentito per singoli valori. La chiamata RemoveByTagAsync("*") ha l'effetto di invalidare tutti iHybridCache dati, anche i dati che non hanno tag. Come per i singoli tag, si tratta di un'operazione logica e i singoli valori continuano a esistere fino alla scadenza naturale. Le corrispondenze in stile GLOB non sono supportate. Ad esempio, non è possibile usare RemoveByTagAsync("foo*") per rimuovere tutti gli elementi che iniziano con foo.
Considerazioni aggiuntive sul tag
- Il sistema non limita il numero di tag che è possibile usare, ma grandi set di tag potrebbero influire negativamente sulle prestazioni.
- I tag non possono essere vuoti, solo spazi vuoti o il valore
*riservato .
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:
- classe HybridCacheOptions.
- classe HybridCacheEntryOptions.
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 per tipo e quelli di uso generale possono essere configurati tramite i metodi AddSerializer e AddSerializerFactory, concatenati alla chiamata AddHybridCache. 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 utilizzare un serializzatore protobuf specifico per 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, SQL Server o Postgres. 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.
Ottieni una 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.
Archivia la stringa di connessione nella configurazione dell'app. Ad esempio, usare un file di segreti utente simile al codice JSON seguente, con la stringa di connessione nella sezione
ConnectionStrings. Sostituire<the connection string>con la stringa di connessione effettiva.{ "ConnectionStrings": { "RedisConnectionString": "<the connection string>" } }Registrare nell'Injection delle Dipendenze l'implementazione
IDistributedCachefornita dal pacchetto Redis. Per farlo, chiamareAddStackExchangeRedisCachee passare la 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 dell'app.HybridCachelo 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 utilizza MemoryCache 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, SQL Server o Postgres, HybridCache usa l'implementazione configurataIDistributedCache, se presente. Ma anche senza un'implementazione IDistributedCache, il servizio HybridCache fornisce comunque la memorizzazione nella cache in-process e protezione contro il caos .
Nota
Quando invalidano le voci della cache in base alla chiave o ai tag, vengono invalidate nel server corrente e nell'archiviazione out-of-process secondaria. Tuttavia, la cache in memoria in altri server non è interessata.
Ottimizzare le prestazioni
Per ottimizzare le prestazioni, configurare HybridCache per riutilizzare gli oggetti ed evitare allocazioni byte[].
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 è la sicurezza del thread, poiché non esiste alcun rischio di modifiche simultanee alla stessa istanza dell'oggetto.
Poiché gran parte dell'utilizzo di HybridCache 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 apportando entrambe le modifiche seguenti:
- Contrassegnare il tipo come
sealed. Lasealedparola 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.
Eviti le allocazioni byte[]
HybridCache fornisce anche API facoltative per IDistributedCache implementazioni, per evitare byte[] allocazioni. Questa funzionalità viene implementata dalle versioni di anteprima dei Microsoft.Extensions.Caching.StackExchangeRedispacchetti , Microsoft.Extensions.Caching.SqlServere Microsoft.Extensions.Caching.Postgres . 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
dotnet add package Microsoft.Extensions.Caching.SqlServer
dotnet add package Microsoft.Extensions.Caching.Postgres
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 o usare implementazioni personalizzate dell'API, ad esempio FusionCache.
Usare la cache ibrida con AOT nativo
Le seguenti considerazioni specifiche di Native AOT si applicano a HybridCache:
serializzazione
Il AOT nativo non supporta la serializzazione basata sulla reflection al momento dell'esecuzione. Se si memorizzano nella cache tipi personalizzati, è necessario usare generatori di origine o configurare in modo esplicito serializzatori compatibili con AOT, ad esempio
System.Text.Jsonla generazione di origine.HybridCacheè ancora in fase di sviluppo e semplificare il modo di usarlo con AOT è una priorità alta per tale sviluppo. Per altre informazioni, vedere pull request dotnet/extensions#6475Taglio
Assicurati che tutti i tipi che metti in cache siano referenziati in modo tale da impedirne l'eliminazione da parte del compilatore AOT. L'uso dei generatori di origine per la serializzazione è utile per questo requisito. Per altre informazioni, vedere supporto di ASP.NET Core per AOT nativo.
Se si configura correttamente la serializzazione e il taglio, HybridCache si comporta allo stesso modo in AOT nativo come nelle normali app ASP.NET Core.
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, vedere il HybridCache codice sorgente