HybridCache-bibliotek i ASP.NET Core
Viktig
HybridCache
är för närvarande fortfarande i förhandsversion men kommer att släppas helt efter .NET 9.0 i en framtida mindre version av .NET-tillägg.
Den här artikeln beskriver hur du konfigurerar och använder HybridCache
-biblioteket i en ASP.NET Core-app. En introduktion till biblioteket finns i avsnittet HybridCache
i översikten över cachelagring.
Hämta biblioteket
Installera Microsoft.Extensions.Caching.Hybrid
-paketet.
dotnet add package Microsoft.Extensions.Caching.Hybrid --version "9.0.0-preview.7.24406.2"
Registrera tjänsten
Lägg till HybridCache
-tjänsten i beroendeinmatning (DI) container genom att anropa AddHybridCache
:
// Add services to the container.
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddAuthorization();
builder.Services.AddHybridCache();
Föregående kod registrerar HybridCache
-tjänsten med standardalternativ. Registrerings-API:et kan också konfigurera alternativ och serialisering.
Hämta och lagra cache-objekt
Tjänsten HybridCache
tillhandahåller en GetOrCreateAsync
-metod med två överlagringar, där en tar en nyckel och:
- En fabriksmetod.
- Tillstånd och en fabriksmetod.
Metoden använder nyckeln för att försöka hämta objektet från den primära cachen. Om objektet inte hittas i den primära cachen (en cachemiss) kontrollerar det sedan den sekundära cachen om en har konfigurerats. Om den inte hittar data där (en annan cachemiss) anropas fabriksmetoden för att hämta objektet från datakällan. Objektet lagras sedan i både primära och sekundära cacheminnen. Fabriksmetoden anropas aldrig om objektet hittas i den primära eller sekundära cachen (en cacheträff).
Tjänsten HybridCache
ser till att endast en samtidig anropare för en viss nyckel anropar fabriksmetoden och alla andra anropare väntar på resultatet av det anropet. Den CancellationToken
som skickas till GetOrCreateAsync
representerar den kombinerade annulleringen av alla samtidiga anropare.
Den huvudsakliga GetOrCreateAsync
-överbelastningen
Tillståndslös överbelastning av GetOrCreateAsync
rekommenderas för de flesta scenarier. Koden som ska anropas är relativt enkel. Här är ett exempel:
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;
}
}
Vägledning för cachenyckel
Den key
som skickas till GetOrCreateAsync
måste unikt identifiera de data som cachelagras:
- När det gäller de identifierarvärden som används för att hämta dessa data från källan.
- När det gäller andra data som cachelagras i programmet.
Båda typerna av unikhet säkerställs vanligtvis med hjälp av strängsammanfogning för att göra en enda nyckelsträng bestående av olika delar sammanfogade i en sträng. Till exempel:
cache.GetOrCreateAsync($"/orders/{region}/{orderId}", ...);
eller
cache.GetOrCreateAsync($"user_prefs_{userId}", ...);
Det är anroparens ansvar att se till att ett nyckelschema är giltigt och inte kan orsaka att data blir förvirrade.
Vi rekommenderar att du inte använder extern användarinmatning i cache-nyckeln. Använd till exempel inte råa string
värden från ett användargränssnitt som en del av en cachenyckel. Sådana nycklar kan tillåta försök till skadlig åtkomst eller användas i en överbelastningsattack genom att mätta cachen med data som har meningslösa nycklar som genereras från slumpmässiga strängar. I de föregående giltiga exemplen är beställning-data och användarpreferens-data tydligt åtskilda.
-
orderid
ochuserId
är internt genererade identifierare. -
region
kan vara en uppräkning eller sträng från en fördefinierad lista över kända regioner.
Det finns ingen betydelse för token som /
eller _
. Hela nyckelvärdet behandlas som en ogenomskinlig identifieringssträng. I det här fallet kan du utelämna /
och _
utan att ändra hur cachen fungerar, men en avgränsare används vanligtvis för att undvika tvetydighet , till exempel $"order{customerId}{orderId}"
kan orsaka förvirring mellan:
-
customerId
42 medorderId
123 -
customerId
421 medorderId
23
(som båda skulle generera cachenyckeln order42123
)
Den här vägledningen gäller även för alla string
-baserade cache-API:et, till exempel HybridCache
, IDistributedCache
och IMemoryCache
.
Observera att den infogade interpolerade strängsyntaxen ($"..."
i föregående exempel på giltiga nycklar) finns direkt i GetOrCreateAsync
-anropet. Den här syntaxen rekommenderas när du använder HybridCache
eftersom den möjliggör planerade framtida förbättringar som kringgår behovet av att allokera en string
för nyckeln i många scenarier.
Ytterligare viktiga överväganden
- Nycklar kan begränsas till giltiga maximala längder. Standardimplementeringen för
HybridCache
(viaAddHybridCache(...)
) begränsar till exempel nycklar till 1 024 tecken som standard. Det talet kan konfigureras viaHybridCacheOptions.MaximumKeyLength
, med längre nycklar som kringgår cachemekanismerna för att förhindra mättnad. - Nycklarna måste vara giltiga Unicode-sekvenser. Om ogiltiga Unicode-sekvenser skickas är beteendet odefinierat.
- När du använder en sekundär cache som inte är bearbetad, till exempel
IDistributedCache
, kan den specifika serverdelsimplementeringen införa ytterligare begränsningar. Som ett hypotetiskt exempel kan en viss backend använda skiftlägesokänslig nyckellogik. Standard-HybridCache
(viaAddHybridCache(...)
) identifierar det här scenariot för att förhindra förvirringsattacker, men det kan fortfarande leda till att motstridiga nycklar skrivs över eller avlägsnas tidigare än förväntat.
Alternativ GetOrCreateAsync
överbelastning
Den alternativa överlagringen kan minska vissa kostnader från insamlade variabler och återanrop per instans, men på bekostnad av mer komplex kod. I de flesta scenarier uppväger prestandaökningen inte kodkomplexiteten. Här är ett exempel som använder alternativ överlagring:
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;
}
}
Metoden SetAsync
I många scenarier är GetOrCreateAsync
det enda API som behövs. Men HybridCache
har också SetAsync
för att lagra ett objekt i cacheminnet utan att försöka hämta det först.
Ta bort cacheposter med hjälp av nyckel
När underliggande data för en cachepost ändras innan den upphör att gälla tar du bort posten explicit genom att anropa RemoveAsync
med nyckeln till posten. Med en överbelastning kan du ange en samling nyckelvärden.
När en post tas bort tas den bort från både de primära och sekundära cacheminnena.
Ta bort cacheposter efter tagg
Viktig
Den här funktionen är fortfarande under utveckling. Om du försöker ta bort poster efter tagg ser du att det inte har någon effekt.
Taggar kan användas för att gruppera cacheposter och ogiltigförklara dem tillsammans.
Ange taggar när du anropar GetOrCreateAsync
, enligt följande exempel:
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;
}
}
Ta bort alla poster för en angiven tagg genom att anropa RemoveByTagAsync
med taggvärdet. Med en överlagring kan du ange en samling taggvärden.
När en post tas bort tas den bort från både de primära och sekundära cacheminnena.
Alternativ
Metoden AddHybridCache
kan användas för att konfigurera globala standardvärden. I följande exempel visas hur du konfigurerar några av de tillgängliga alternativen:
// 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)
};
});
Metoden GetOrCreateAsync
kan också ta ett HybridCacheEntryOptions
objekt för att åsidosätta de globala standardvärdena för en specifik cachepost. Här är ett exempel:
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;
}
}
Mer information om alternativen finns i källkoden:
- HybridCacheOptions-klass.
- HybridCacheEntryOptions-klass.
Gränser
Med följande egenskaper för HybridCacheOptions
kan du konfigurera gränser som gäller för alla cacheposter:
- MaximumPayloadBytes – Maximal storlek på en cachepost. Standardvärdet är 1 MB. Försök att lagra värden över den här storleken loggas och värdet lagras inte i cacheminnet.
- MaximumKeyLength – Maximal längd på en cachenyckel. Standardvärdet är 1 024 tecken. Försök att lagra värden över den här storleken loggas och värdet lagras inte i cacheminnet.
Serialisering
Användning av ett sekundärt cacheminne utan process kräver serialisering. Serialisering konfigureras som en del av registreringen av HybridCache
-tjänsten. Typspecifika och allmänna serialiserare kan konfigureras via metoderna AddSerializer
och AddSerializerFactory
, länkade från AddHybridCache
-anropet. Som standard hanterar biblioteket string
och byte[]
internt och använder System.Text.Json
för allt annat.
HybridCache
kan också använda andra serialiserare, till exempel protobuf eller XML.
I följande exempel konfigureras tjänsten för att använda en typspecifik protobuf-serialiserare:
// 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>>();
I följande exempel konfigureras tjänsten för att använda en protobuf-serialiserare för generell användning som kan hantera många protobuf-typer:
// 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>();
Den sekundära cachen kräver ett datalager, till exempel Redis eller SqlServer. Så här använder du Azure Cache for Redis, till exempel:
Installera
Microsoft.Extensions.Caching.StackExchangeRedis
-paketet.Skapa en instans av Azure Cache for Redis.
Hämta en anslutningssträng som ansluter till Redis-instansen. Leta upp anslutningssträngen genom att välja Visa åtkomstnycklar på sidan Översikt i Azure-portalen.
Lagra anslutningssträngen i appens konfiguration. Använd till exempel en fil med användarhemligheter som ser ut som följande JSON, med anslutningssträngen i avsnittet
ConnectionStrings
. Ersätt<the connection string>
med den faktiska anslutningssträngen:{ "ConnectionStrings": { "RedisConnectionString": "<the connection string>" } }
Registrera i DI den
IDistributedCache
implementering som Redis-paketet tillhandahåller. Det gör du genom att anropaAddStackExchangeRedisCache
och skicka anslutningssträngen. Till exempel:builder.Services.AddStackExchangeRedisCache(options => { options.Configuration = builder.Configuration.GetConnectionString("RedisConnectionString"); });
Redis-
IDistributedCache
-implementeringen är nu tillgänglig från appens DI-container.HybridCache
använder den som sekundär cache och använder serialiseraren som konfigurerats för den.
Mer information finns i appen HybridCache serialiseringsexempel.
Cachelagring
Som standard använder HybridCache
MemoryCache för sin primära cachelagring. Cacheposter lagras i processen, så varje server har en separat cache som går förlorad när serverprocessen startas om. För sekundär out-of-process-lagring, till exempel Redis eller SQL Server, använder HybridCache
den konfigurerade IDistributedCache
implementeringen, om sådan finns. Men även utan en IDistributedCache
implementering tillhandahåller HybridCache
-tjänsten fortfarande processbaserad cachelagring och stampede-skydd.
Not
När cacheposter ogiltigförklaras genom nyckel eller taggar, ogiltigförklaras de både på den aktuella servern och i den sekundära utomprocesslagringen. Minnesintern cache på andra servrar påverkas dock inte.
Optimera prestanda
Du kan optimera prestanda genom att konfigurera HybridCache
att återanvända objekt och undvika byte[]
allokeringar.
Återanvända objekt
Genom att återanvända instanser kan HybridCache
minska kostnaderna för PROCESSOR- och objektallokeringar som är associerade med deserialisering per anrop. Detta kan leda till prestandaförbättringar i scenarier där cachelagrade objekt är stora eller används ofta.
I vanlig befintlig kod som använder IDistributedCache
resulterar varje hämtning av ett objekt från cachen i deserialisering. Det här beteendet innebär att varje samtidig anropare får en separat instans av objektet, som inte kan interagera med andra instanser. Resultatet är trådsäkerhet eftersom det inte finns någon risk för samtidiga ändringar av samma objektinstans.
Eftersom mycket HybridCache
användning kommer att anpassas från befintlig IDistributedCache
kod, bevarar HybridCache
det här beteendet som standard för att undvika samtidighetsbuggar. Objekt är dock i sig trådsäkra om:
- De är oföränderliga typer.
- Koden ändrar dem inte.
I sådana fall, informera HybridCache
om att det är säkert att återanvända exemplar genom att:
- Markera typen som
sealed
. Nyckelordetsealed
i C# innebär att klassen inte kan ärvas. - Tillämpa attributet
[ImmutableObject(true)]
på typen. Attributet[ImmutableObject(true)]
anger att objektets tillstånd inte kan ändras när det har skapats.
Undvik byte[]
allokeringar
HybridCache
tillhandahåller även valfria API:er för IDistributedCache
implementeringar för att undvika byte[]
allokeringar. Den här funktionen implementeras av förhandsversionerna av paketen Microsoft.Extensions.Caching.StackExchangeRedis
och Microsoft.Extensions.Caching.SqlServer
. Mer information finns i IBufferDistributedCache Här är .NET CLI-kommandona för att installera paketen:
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis
dotnet add package Microsoft.Extensions.Caching.SqlServer
Anpassade HybridCache-implementeringar
En konkret implementering av den HybridCache
abstrakta klassen ingår i det delade ramverket och tillhandahålls via beroendeinmatning. Men utvecklare är välkomna att tillhandahålla anpassade implementeringar av API:et.
Kompatibilitet
HybridCache
-biblioteket stöder äldre .NET-körningar, ned till .NET Framework 4.7.2 och .NET Standard 2.0.
Ytterligare resurser
Mer information om HybridCache
finns i följande resurser:
- GitHub-problem dotnet/aspnetcore #54647.
-
HybridCache
källkod
ASP.NET Core