Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Door Rick Anderson, John Luo en Steve Smith
Caching kan de prestaties en schaalbaarheid van een app aanzienlijk verbeteren door het werk te verminderen dat nodig is om inhoud te genereren. Caching werkt het beste met gegevens die niet vaak worden gewijzigd en die duur zijn om te genereren. Caching maakt een kopie van gegevens die veel sneller kunnen worden geretourneerd dan van de bron. Apps moeten worden geschreven en getest om nooit afhankelijk te zijn van gegevens in de cache.
ASP.NET Core ondersteunt verschillende caches. De eenvoudigste cache is gebaseerd op de IMemoryCache.
IMemoryCache
vertegenwoordigt een cache die is opgeslagen in het geheugen van de webserver. Apps die worden uitgevoerd op een serverfarm (meerdere servers) moeten ervoor zorgen dat sessies plakkerig zijn wanneer de cache in het geheugen wordt gebruikt. Plaksessies zorgen ervoor dat aanvragen van een client allemaal naar dezelfde server gaan. Azure-web-apps maken bijvoorbeeld gebruik van ARR (Application Request Routing ) om alle aanvragen naar dezelfde server te routeren.
Voor niet-klevende sessies in een webfarm is een gedistribueerde cache vereist om consistentieproblemen met de cache te voorkomen. Voor sommige apps kan een gedistribueerde cache een hogere uitschaling ondersteunen dan een cache in het geheugen. Met behulp van een gedistribueerde cache wordt het cachegeheugen naar een extern proces verplaatst.
In de cache in het geheugen kan elk object worden opgeslagen. De interface voor gedistribueerde cache is beperkt tot byte[]
. Cacheitems in de in-memorycache en gedistribueerde cache slaan cache-items op als sleutel-waardeparen.
System.Runtime.Caching/MemoryCache
System.Runtime.Caching / MemoryCache (NuGet-pakket) kan worden gebruikt met:
- .NET Standard 2.0 of hoger.
- Een .NET-implementatie die is gericht op .NET Standard 2.0 of hoger. Bijvoorbeeld ASP.NET Core 3.1 of hoger.
- .NET Framework 4.5 of hoger.
Microsoft.Extensions.Caching.Memory/IMemoryCache
(beschreven in dit artikel) wordt aanbevolen boven System.Runtime.Caching
/MemoryCache
omdat deze beter is geïntegreerd in ASP.NET Core. Werkt bijvoorbeeld IMemoryCache
systeemeigen met ASP.NET Core-afhankelijkheidsinjectie.
Als compatibiliteitsbrug gebruiken System.Runtime.Caching
/MemoryCache
bij het overzetten van code van ASP.NET 4.x naar ASP.NET Core.
Cache guidelines
- Code moet altijd een terugvaloptie hebben om gegevens op te halen en niet afhankelijk te zijn van een waarde in de cache die beschikbaar is.
- De cache maakt gebruik van een schaarse resource, geheugen. De groei van de cache beperken:
- Voeg geen externe invoer in de cache in. Als voorbeeld wordt het gebruik van willekeurige door de gebruiker verstrekte invoer als een cachesleutel niet aanbevolen, omdat de invoer mogelijk een onvoorspelbare hoeveelheid geheugen verbruikt.
- Gebruik vervaldatums om de groei van de cache te beperken.
- Gebruik SetSize, Grootte en SizeLimit om de cachegrootte te beperken. De ASP.NET Core-runtime beperkt de cachegrootte niet op basis van geheugendruk. Het is aan de ontwikkelaar om de cachegrootte te beperken.
Use IMemoryCache
Warning
Als u een gedeelde geheugencache gebruikt van afhankelijkheidsinjectie en aanroepen SetSize
, Size
of SizeLimit
om de cachegrootte te beperken, kan de app mislukken. Wanneer een groottelimiet is ingesteld voor een cache, moeten alle vermeldingen een grootte opgeven wanneer ze worden toegevoegd. Dit kan leiden tot problemen omdat ontwikkelaars mogelijk geen volledige controle hebben over wat gebruikmaakt van de gedeelde cache.
Wanneer u SetSize
, Size
, of SizeLimit
gebruikt om de cache te beperken, maakt u een cache-singleton voor caching. Zie SetSize, Grootte en SizeLimit gebruiken om de cachegrootte te beperken voor meer informatie en een voorbeeld.
Een gedeelde cache wordt gedeeld door andere frameworks of bibliotheken.
In-memory caching is een service waarnaar wordt verwezen vanuit een app met behulp van afhankelijkheidsinjectie. Vraag het IMemoryCache
exemplaar aan in de constructor:
public class IndexModel : PageModel
{
private readonly IMemoryCache _memoryCache;
public IndexModel(IMemoryCache memoryCache) =>
_memoryCache = memoryCache;
// ...
De volgende code gebruikt TryGetValue om te controleren of een tijd zich in de cache bevindt. Als er geen tijd in de cache is opgeslagen, wordt er een nieuwe vermelding gemaakt en aan de cache toegevoegd met Set:
public void OnGet()
{
CurrentDateTime = DateTime.Now;
if (!_memoryCache.TryGetValue(CacheKeys.Entry, out DateTime cacheValue))
{
cacheValue = CurrentDateTime;
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(3));
_memoryCache.Set(CacheKeys.Entry, cacheValue, cacheEntryOptions);
}
CacheCurrentDateTime = cacheValue;
}
In de voorgaande code wordt het cache-item geconfigureerd met een vervaltermijn van drie seconden. Als de cachevermelding langer dan drie seconden niet wordt geopend, wordt deze verwijderd uit de cache. Telkens wanneer de cachevermelding wordt geopend, blijft deze gedurende 3 seconden in de cache. De CacheKeys
klasse maakt deel uit van het downloadvoorbeeld.
De huidige tijd en de tijd in de cache worden weergegeven:
<ul>
<li>Current Time: @Model.CurrentDateTime</li>
<li>Cached Time: @Model.CacheCurrentDateTime</li>
</ul>
De volgende code gebruikt de extensiemethode om gegevens gedurende een relatieve tijd in de Set
cache op te cachen zonder MemoryCacheEntryOptions
:
_memoryCache.Set(CacheKeys.Entry, DateTime.Now, TimeSpan.FromDays(1));
In de voorgaande code wordt de cachevermelding geconfigureerd met een relatieve vervaldatum van één dag. De cachevermelding wordt na één dag verwijderd uit de cache, zelfs als deze binnen deze time-outperiode wordt geopend.
De volgende code maakt gebruik van GetOrCreate en GetOrCreateAsync om gegevens in de cache op te slaan.
public void OnGetCacheGetOrCreate()
{
var cachedValue = _memoryCache.GetOrCreate(
CacheKeys.Entry,
cacheEntry =>
{
cacheEntry.SlidingExpiration = TimeSpan.FromSeconds(3);
return DateTime.Now;
});
// ...
}
public async Task OnGetCacheGetOrCreateAsync()
{
var cachedValue = await _memoryCache.GetOrCreateAsync(
CacheKeys.Entry,
cacheEntry =>
{
cacheEntry.SlidingExpiration = TimeSpan.FromSeconds(3);
return Task.FromResult(DateTime.Now);
});
// ...
}
De volgende code aanroepen Get om de tijd in de cache op te halen:
var cacheEntry = _memoryCache.Get<DateTime?>(CacheKeys.Entry);
Met de volgende code wordt een item in de cache opgehaald of gemaakt met een absolute vervaldatum:
var cachedValue = _memoryCache.GetOrCreate(
CacheKeys.Entry,
cacheEntry =>
{
cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(20);
return DateTime.Now;
});
Een itemset in de cache met alleen een glijdende vervaldatum loopt het risico dat het nooit verloopt. Als het item in de cache herhaaldelijk wordt benaderd binnen het glijdende verloopinterval, verloopt het item niet. Combineer een vervaltijd op basis van inactiviteit met een absolute vervaldatum om te garanderen dat het item vervalt. Met de absolute vervaldatum wordt een bovengrens ingesteld voor hoe lang een item in de cache kan worden opgeslagen. Het item kan echter eerder vervallen als het niet binnen het verloopinterval van de glijdende vervaldatum wordt opgevraagd. Als ofwel de sliding expiration interval of de absolute vervaltijd is verstreken, wordt het item uit de cache verwijderd.
Met de volgende code wordt een item in de cache opgehaald of gemaakt met zowel een glijdende als absolute vervaldatum:
var cachedValue = _memoryCache.GetOrCreate(
CacheKeys.CallbackEntry,
cacheEntry =>
{
cacheEntry.SlidingExpiration = TimeSpan.FromSeconds(3);
cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(20);
return DateTime.Now;
});
De voorgaande code garandeert dat de gegevens niet langer in de cache worden opgeslagen dan de absolute tijd.
GetOrCreate, GetOrCreateAsyncen Get zijn uitbreidingsmethoden in de CacheExtensions klasse. Deze methoden breiden de capaciteit van IMemoryCache uit.
MemoryCacheEntryOptions
Het volgende voorbeeld:
- Hiermee stelt u de prioriteit van de cache in op CacheItemPriority.NeverRemove.
- Stel een PostEvictionDelegate in die wordt aangeroepen nadat het item uit de cache is verwijderd. De callback wordt uitgevoerd op een andere thread dan de code waarmee het item uit de cache wordt verwijderd.
public void OnGetCacheRegisterPostEvictionCallback()
{
var memoryCacheEntryOptions = new MemoryCacheEntryOptions()
.SetPriority(CacheItemPriority.NeverRemove)
.RegisterPostEvictionCallback(PostEvictionCallback, _memoryCache);
_memoryCache.Set(CacheKeys.CallbackEntry, DateTime.Now, memoryCacheEntryOptions);
}
private static void PostEvictionCallback(
object cacheKey, object cacheValue, EvictionReason evictionReason, object state)
{
var memoryCache = (IMemoryCache)state;
memoryCache.Set(
CacheKeys.CallbackMessage,
$"Entry {cacheKey} was evicted: {evictionReason}.");
}
Gebruik SetSize, Grootte en SizeLimit om de grootte van de cache te beperken
Een MemoryCache
exemplaar kan eventueel een groottelimiet opgeven en afdwingen. De limiet voor de cachegrootte heeft geen gedefinieerde maateenheid omdat de cache geen mechanisme heeft om de grootte van vermeldingen te meten. Als de limiet voor de cachegrootte is ingesteld, moeten alle vermeldingen de grootte opgeven. De ASP.NET Core-runtime beperkt de cachegrootte niet op basis van geheugendruk. Het is aan de ontwikkelaar om de cachegrootte te beperken. De opgegeven grootte is in eenheden die de ontwikkelaar kiest.
For example:
- Als de web-app voornamelijk tekenreeksen in de cache op zou slaan, kan de grootte van elke cachevermelding de tekenreekslengte zijn.
- De app kan de grootte van alle vermeldingen opgeven als 1 en de limiet voor de grootte is het aantal vermeldingen.
Als SizeLimit niet is ingesteld, groeit de cache onbeheerst. De ASP.NET Core-runtime trimt de cache niet wanneer het systeemgeheugen laag is. Apps moeten worden ontworpen voor:
De volgende code creëert een vaste grootte zonder eenheid die toegankelijk is via MemoryCache:
public class MyMemoryCache
{
public MemoryCache Cache { get; } = new MemoryCache(
new MemoryCacheOptions
{
SizeLimit = 1024
});
}
SizeLimit
heeft geen eenheden. Cache-items moeten, indien de limiet voor de cachegrootte is ingesteld, de omvang specificeren in de meest geschikte eenheden. Alle gebruikers van een cache-exemplaar moeten hetzelfde eenheidssysteem gebruiken. Een vermelding wordt niet in de cache opgeslagen als de som van de invoergrootten in de cache groter is dan de waarde die is opgegeven door SizeLimit
. Als er geen limiet voor de cachegrootte is ingesteld, wordt de cachegrootte die is ingesteld voor de vermelding genegeerd.
De volgende code registreert MyMemoryCache
bij de container voor afhankelijkheidsinjectie :
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddSingleton<MyMemoryCache>();
MyMemoryCache
wordt gemaakt als een onafhankelijke geheugencache voor onderdelen die zich bewust zijn van deze grootte beperkte cache en weten hoe de cachevermeldingsgrootte op de juiste manier moet worden ingesteld.
De grootte van de cachevermelding kan worden ingesteld met behulp van de SetSize extensiemethode of de Size eigenschap:
if (!_myMemoryCache.Cache.TryGetValue(CacheKeys.Entry, out DateTime cacheValue))
{
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetSize(1);
// cacheEntryOptions.Size = 1;
_myMemoryCache.Cache.Set(CacheKeys.Entry, cacheValue, cacheEntryOptions);
}
In de voorgaande code bereiken de twee gemarkeerde regels hetzelfde resultaat van het instellen van de grootte van de cachevermelding.
SetSize
wordt voor het gemak geboden bij het koppelen van aanroepen naar new MemoryCacheOptions()
.
MemoryCache.Compact
MemoryCache.Compact
probeert het opgegeven percentage van de cache in de volgende volgorde te verwijderen:
- Alle vervallen items.
- Items naar prioriteit. Items met de laagste prioriteit worden eerst verwijderd.
- Minst recent gebruikte objecten.
- Items met de vroegste absolute vervaldatum.
- Items met de vroegste glijdende verlooptijd.
Vastgemaakte items met prioriteit NeverRemove worden nooit verwijderd. Met de volgende code verwijdert u een cache-item en roept u Compact
aan om 25% met vermeldingen in de cache te verwijderen:
_myMemoryCache.Cache.Remove(CacheKeys.Entry);
_myMemoryCache.Cache.Compact(.25);
Zie de compacte bron op GitHub voor meer informatie.
Cache dependencies
In het volgende voorbeeld ziet u hoe u een cachevermelding kunt laten verlopen als een afhankelijke vermelding verloopt. Er wordt een CancellationChangeToken toegevoegd aan het item in de cache. Wanneer Cancel
wordt aangeroepen op de CancellationTokenSource
cache, worden beide cachevermeldingen verwijderd:
public void OnGetCacheCreateDependent()
{
var cancellationTokenSource = new CancellationTokenSource();
_memoryCache.Set(
CacheKeys.DependentCancellationTokenSource,
cancellationTokenSource);
using var parentCacheEntry = _memoryCache.CreateEntry(CacheKeys.Parent);
parentCacheEntry.Value = DateTime.Now;
_memoryCache.Set(
CacheKeys.Child,
DateTime.Now,
new CancellationChangeToken(cancellationTokenSource.Token));
}
public void OnGetCacheRemoveDependent()
{
var cancellationTokenSource = _memoryCache.Get<CancellationTokenSource>(
CacheKeys.DependentCancellationTokenSource);
cancellationTokenSource.Cancel();
}
Door een CancellationTokenSource te gebruiken, kunnen meerdere cachevermeldingen als groep worden verwijderd. Met het using
patroon in de bovenstaande code nemen cachevermeldingen die zijn gemaakt in het using
bereik triggers en verloopinstellingen over.
Additional notes
Verval vindt niet plaats op de achtergrond. Er is geen timer die de cache actief scant op verlopen items. Elke activiteit in de cache (
Get
,TryGetValue
,Set
, )Remove
kan een achtergrondscan voor verlopen items activeren. Een timer op deCancellationTokenSource
(CancelAfter) verwijdert ook de vermelding en activeert een scan voor verlopen items. In het volgende voorbeeld wordt het geregistreerde token gebruikt CancellationTokenSource(TimeSpan) . Wanneer dit token wordt geactiveerd, wordt de vermelding onmiddellijk verwijderd en worden de callbacks voor verwijdering geactiveerd:if (!_memoryCache.TryGetValue(CacheKeys.Entry, out DateTime cacheValue)) { cacheValue = DateTime.Now; var cancellationTokenSource = new CancellationTokenSource( TimeSpan.FromSeconds(10)); var cacheEntryOptions = new MemoryCacheEntryOptions() .AddExpirationToken( new CancellationChangeToken(cancellationTokenSource.Token)) .RegisterPostEvictionCallback((key, value, reason, state) => { ((CancellationTokenSource)state).Dispose(); }, cancellationTokenSource); _memoryCache.Set(CacheKeys.Entry, cacheValue, cacheEntryOptions); }
Wanneer u een callback gebruikt om een cache-item opnieuw in te vullen:
- Meerdere aanvragen kunnen de sleutelwaarde in de cache leeg vinden omdat de callback niet is voltooid.
- Dit kan ertoe leiden dat meerdere threads het gecachte item opnieuw laden.
Wanneer een cachevermelding wordt gebruikt om een andere te maken, kopieert de kindvermelding de vervaltokens en tijdbepaalde verloopinstellingen van de bovenliggende vermelding. Het kind is niet verwijderd door handmatig verwijderen of bijwerken van de oudervermelding.
Gebruik PostEvictionCallbacks om de callbacks in te stellen die worden geactiveerd nadat de cachevermelding uit de cache is verwijderd.
Voor de meeste apps
IMemoryCache
is ingeschakeld. Bijvoorbeeld, het aanroepen vanAddMvc
,AddControllersWithViews
,AddRazorPages
,AddMvcCore().AddRazorViewEngine
en vele andereAdd{Service}
-methoden inProgram.cs
, maaktIMemoryCache
mogelijk. Voor apps die geen van de voorgaandeAdd{Service}
methoden aanroepen, kan het nodig zijn om AddMemoryCache inProgram.cs
aan te roepen.
Update van achtergrondcache
Gebruik een achtergrondservice zoals IHostedService om de cache bij te werken. De achtergrondservice kan de vermeldingen opnieuw compileren en deze vervolgens alleen toewijzen aan de cache wanneer ze klaar zijn.
Additional resources
- Voorbeeldcode bekijken of downloaden (hoe download je)
- Gedistribueerde caching in ASP.NET Core
- Wijzigingen detecteren met wijzigingstokens in ASP.NET Core
- Responsecaching in ASP.NET Core
- Response caching middleware in ASP.NET kern
- Cache Tag Helper in ASP.NET Core MVC
- Helper voor gedistribueerde cachetags in ASP.NET Core
Voorbeeldcode bekijken of downloaden (hoe download je)
Caching basics
Caching kan de prestaties en schaalbaarheid van een app aanzienlijk verbeteren door het werk te verminderen dat nodig is om inhoud te genereren. Caching werkt het beste met gegevens die niet vaak worden gewijzigd en die duur zijn om te genereren. Caching maakt een kopie van gegevens die veel sneller kunnen worden geretourneerd dan van de bron. Apps moeten worden geschreven en getest om nooit afhankelijk te zijn van gegevens in de cache.
ASP.NET Core ondersteunt verschillende caches. De eenvoudigste cache is gebaseerd op de IMemoryCache.
IMemoryCache
vertegenwoordigt een cache die is opgeslagen in het geheugen van de webserver. Apps die worden uitgevoerd op een serverfarm (meerdere servers) moeten ervoor zorgen dat sessies plakkerig zijn wanneer de cache in het geheugen wordt gebruikt. Sticky sessions zorgen ervoor dat opeenvolgende aanvragen van een cliënt allemaal naar dezelfde server gaan. Azure-web-apps maken bijvoorbeeld gebruik van ARR (Application Request Routing ) om alle volgende aanvragen naar dezelfde server te routeren.
Voor niet-klevende sessies in een webfarm is een gedistribueerde cache vereist om consistentieproblemen met de cache te voorkomen. Voor sommige apps kan een gedistribueerde cache een hogere uitschaling ondersteunen dan een cache in het geheugen. Met behulp van een gedistribueerde cache wordt het cachegeheugen naar een extern proces verplaatst.
In de cache in het geheugen kan elk object worden opgeslagen. De interface voor gedistribueerde cache is beperkt tot byte[]
. Cacheitems in de in-memorycache en gedistribueerde cache slaan cache-items op als sleutel-waardeparen.
System.Runtime.Caching/MemoryCache
System.Runtime.Caching / MemoryCache (NuGet-pakket) kan worden gebruikt met:
- .NET Standard 2.0 of hoger.
- Een .NET-implementatie die is gericht op .NET Standard 2.0 of hoger. Bijvoorbeeld ASP.NET Core 3.1 of hoger.
- .NET Framework 4.5 of hoger.
Microsoft.Extensions.Caching.Memory/IMemoryCache
(beschreven in dit artikel) wordt aanbevolen boven System.Runtime.Caching
/MemoryCache
omdat deze beter is geïntegreerd in ASP.NET Core. Werkt bijvoorbeeld IMemoryCache
systeemeigen met ASP.NET Core-afhankelijkheidsinjectie.
Als compatibiliteitsbrug gebruiken System.Runtime.Caching
/MemoryCache
bij het overzetten van code van ASP.NET 4.x naar ASP.NET Core.
Cache guidelines
- Code moet altijd een terugvaloptie hebben om gegevens op te halen en niet afhankelijk te zijn van een waarde in de cache die beschikbaar is.
- De cache maakt gebruik van een schaarse resource, geheugen. De groei van de cache beperken:
- Gebruik geen externe invoer als cachesleutels.
- Gebruik vervaldatums om de groei van de cache te beperken.
- Gebruik SetSize, Grootte en SizeLimit om de cachegrootte te beperken. De ASP.NET Core-runtime beperkt de cachegrootte niet op basis van geheugendruk. Het is aan de ontwikkelaar om de cachegrootte te beperken.
Use IMemoryCache
Warning
Als u een gedeelde geheugencache gebruikt van afhankelijkheidsinjectie en aanroepen SetSize
, Size
of SizeLimit
om de cachegrootte te beperken, kan de app mislukken. Wanneer een groottelimiet is ingesteld voor een cache, moeten alle vermeldingen een grootte opgeven wanneer ze worden toegevoegd. Dit kan leiden tot problemen omdat ontwikkelaars mogelijk geen volledige controle hebben over wat gebruikmaakt van de gedeelde cache.
Wanneer u SetSize
, Size
, of SizeLimit
gebruikt om de cache te beperken, maakt u een cache-singleton voor caching. Zie SetSize, Grootte en SizeLimit gebruiken om de cachegrootte te beperken voor meer informatie en een voorbeeld.
Een gedeelde cache wordt gedeeld door andere frameworks of bibliotheken.
In-memory caching is een service waarnaar wordt verwezen vanuit een app met behulp van afhankelijkheidsinjectie. Vraag het IMemoryCache
exemplaar aan in de constructor:
public class HomeController : Controller
{
private IMemoryCache _cache;
public HomeController(IMemoryCache memoryCache)
{
_cache = memoryCache;
}
De volgende code gebruikt TryGetValue om te controleren of een tijd zich in de cache bevindt. Als een tijd niet in de cache wordt opgeslagen, wordt er een nieuwe vermelding gemaakt en toegevoegd aan de cache met Set. De CacheKeys
klasse maakt deel uit van het downloadvoorbeeld.
public static class CacheKeys
{
public static string Entry => "_Entry";
public static string CallbackEntry => "_Callback";
public static string CallbackMessage => "_CallbackMessage";
public static string Parent => "_Parent";
public static string Child => "_Child";
public static string DependentMessage => "_DependentMessage";
public static string DependentCTS => "_DependentCTS";
public static string Ticks => "_Ticks";
public static string CancelMsg => "_CancelMsg";
public static string CancelTokenSource => "_CancelTokenSource";
}
public IActionResult CacheTryGetValueSet()
{
DateTime cacheEntry;
// Look for cache key.
if (!_cache.TryGetValue(CacheKeys.Entry, out cacheEntry))
{
// Key not in cache, so get data.
cacheEntry = DateTime.Now;
// Set cache options.
var cacheEntryOptions = new MemoryCacheEntryOptions()
// Keep in cache for this time, reset time if accessed.
.SetSlidingExpiration(TimeSpan.FromSeconds(3));
// Save data in cache.
_cache.Set(CacheKeys.Entry, cacheEntry, cacheEntryOptions);
}
return View("Cache", cacheEntry);
}
De huidige tijd en de tijd in de cache worden weergegeven:
@model DateTime?
<div>
<h2>Actions</h2>
<ul>
<li><a asp-controller="Home" asp-action="CacheTryGetValueSet">TryGetValue and Set</a></li>
<li><a asp-controller="Home" asp-action="CacheGet">Get</a></li>
<li><a asp-controller="Home" asp-action="CacheGetOrCreate">GetOrCreate</a></li>
<li><a asp-controller="Home" asp-action="CacheGetOrCreateAsynchronous">CacheGetOrCreateAsynchronous</a></li>
<li><a asp-controller="Home" asp-action="CacheRemove">Remove</a></li>
<li><a asp-controller="Home" asp-action="CacheGetOrCreateAbs">CacheGetOrCreateAbs</a></li>
<li><a asp-controller="Home" asp-action="CacheGetOrCreateAbsSliding">CacheGetOrCreateAbsSliding</a></li>
</ul>
</div>
<h3>Current Time: @DateTime.Now.TimeOfDay.ToString()</h3>
<h3>Cached Time: @(Model == null ? "No cached entry found" : Model.Value.TimeOfDay.ToString())</h3>
In de volgende code wordt de extensiemethode gebruikt om gegevens gedurende een relatieve tijd in de Set
cache op te cachen zonder het MemoryCacheEntryOptions
object te maken:
public IActionResult SetCacheRelativeExpiration()
{
DateTime cacheEntry;
// Look for cache key.
if (!_cache.TryGetValue(CacheKeys.Entry, out cacheEntry))
{
// Key not in cache, so get data.
cacheEntry = DateTime.Now;
// Save data in cache and set the relative expiration time to one day
_cache.Set(CacheKeys.Entry, cacheEntry, TimeSpan.FromDays(1));
}
return View("Cache", cacheEntry);
}
De waarde in de cache DateTime
blijft in de cache terwijl er aanvragen zijn binnen de time-outperiode.
De volgende code maakt gebruik van GetOrCreate en GetOrCreateAsync om gegevens in de cache op te slaan.
public IActionResult CacheGetOrCreate()
{
var cacheEntry = _cache.GetOrCreate(CacheKeys.Entry, entry =>
{
entry.SlidingExpiration = TimeSpan.FromSeconds(3);
return DateTime.Now;
});
return View("Cache", cacheEntry);
}
public async Task<IActionResult> CacheGetOrCreateAsynchronous()
{
var cacheEntry = await
_cache.GetOrCreateAsync(CacheKeys.Entry, entry =>
{
entry.SlidingExpiration = TimeSpan.FromSeconds(3);
return Task.FromResult(DateTime.Now);
});
return View("Cache", cacheEntry);
}
De volgende code aanroepen Get om de tijd in de cache op te halen:
public IActionResult CacheGet()
{
var cacheEntry = _cache.Get<DateTime?>(CacheKeys.Entry);
return View("Cache", cacheEntry);
}
Met de volgende code wordt een item in de cache opgehaald of gemaakt met een absolute vervaldatum:
public IActionResult CacheGetOrCreateAbs()
{
var cacheEntry = _cache.GetOrCreate(CacheKeys.Entry, entry =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(10);
return DateTime.Now;
});
return View("Cache", cacheEntry);
}
Een itemset in de cache met alleen een glijdende vervaldatum loopt het risico dat het nooit verloopt. Als het item in de cache herhaaldelijk wordt benaderd binnen het glijdende verloopinterval, verloopt het item niet. Combineer een vervaltijd op basis van inactiviteit met een absolute vervaldatum om te garanderen dat het item vervalt. Met de absolute vervaldatum wordt een bovengrens ingesteld voor hoe lang een item in de cache kan worden opgeslagen. Het item kan echter eerder vervallen als het niet binnen het verloopinterval van de glijdende vervaldatum wordt opgevraagd. Als ofwel de sliding expiration interval of de absolute vervaltijd is verstreken, wordt het item uit de cache verwijderd.
Met de volgende code wordt een item in de cache opgehaald of gemaakt met zowel een glijdende als absolute vervaldatum:
public IActionResult CacheGetOrCreateAbsSliding()
{
var cacheEntry = _cache.GetOrCreate(CacheKeys.Entry, entry =>
{
entry.SetSlidingExpiration(TimeSpan.FromSeconds(3));
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(20);
return DateTime.Now;
});
return View("Cache", cacheEntry);
}
De voorgaande code garandeert dat de gegevens niet langer in de cache worden opgeslagen dan de absolute tijd.
GetOrCreate, GetOrCreateAsyncen Get zijn uitbreidingsmethoden in de CacheExtensions klasse. Deze methoden breiden de capaciteit van IMemoryCache uit.
MemoryCacheEntryOptions
Het volgende voorbeeld:
- Hiermee stelt u een glijdende verlooptijd in. Aanvragen die toegang hebben tot dit item in de cache, stellen de schuifverloopklok opnieuw in.
- Hiermee stelt u de prioriteit van de cache in op CacheItemPriority.NeverRemove.
- Hiermee stelt u een PostEvictionDelegate in die wordt aangeroepen nadat de vermelding is verwijderd uit de cache. De callback wordt uitgevoerd op een andere thread dan de code waarmee het item uit de cache wordt verwijderd.
public IActionResult CreateCallbackEntry()
{
var cacheEntryOptions = new MemoryCacheEntryOptions()
// Pin to cache.
.SetPriority(CacheItemPriority.NeverRemove)
// Add eviction callback
.RegisterPostEvictionCallback(callback: EvictionCallback, state: this);
_cache.Set(CacheKeys.CallbackEntry, DateTime.Now, cacheEntryOptions);
return RedirectToAction("GetCallbackEntry");
}
public IActionResult GetCallbackEntry()
{
return View("Callback", new CallbackViewModel
{
CachedTime = _cache.Get<DateTime?>(CacheKeys.CallbackEntry),
Message = _cache.Get<string>(CacheKeys.CallbackMessage)
});
}
public IActionResult RemoveCallbackEntry()
{
_cache.Remove(CacheKeys.CallbackEntry);
return RedirectToAction("GetCallbackEntry");
}
private static void EvictionCallback(object key, object value,
EvictionReason reason, object state)
{
var message = $"Entry was evicted. Reason: {reason}.";
((HomeController)state)._cache.Set(CacheKeys.CallbackMessage, message);
}
Gebruik SetSize, Grootte en SizeLimit om de grootte van de cache te beperken
Een MemoryCache
exemplaar kan eventueel een groottelimiet opgeven en afdwingen. De limiet voor de cachegrootte heeft geen gedefinieerde maateenheid omdat de cache geen mechanisme heeft om de grootte van vermeldingen te meten. Als de limiet voor de cachegrootte is ingesteld, moeten alle vermeldingen de grootte opgeven. De ASP.NET Core-runtime beperkt de cachegrootte niet op basis van geheugenbelasting. Het is aan de ontwikkelaar om de cachegrootte te beperken. De opgegeven grootte is in eenheden die de ontwikkelaar kiest.
For example:
- Als de web-app voornamelijk tekenreeksen in de cache op zou slaan, kan de grootte van elke cachevermelding de tekenreekslengte zijn.
- De app kan de grootte van alle vermeldingen opgeven als 1 en de limiet voor de grootte is het aantal vermeldingen.
Als SizeLimit niet is ingesteld, groeit de cache onbeheerst. De ASP.NET Core-runtime trimt de cache niet wanneer het systeemgeheugen laag is. Apps moeten worden ontworpen voor:
De volgende code creëert een vaste grootte zonder eenheid die toegankelijk is via MemoryCache:
// using Microsoft.Extensions.Caching.Memory;
public class MyMemoryCache
{
public MemoryCache Cache { get; private set; }
public MyMemoryCache()
{
Cache = new MemoryCache(new MemoryCacheOptions
{
SizeLimit = 1024
});
}
}
SizeLimit
heeft geen eenheden. Vermeldingen in de cache moeten de grootte opgeven in de eenheden die ze het meest geschikt achten als de limiet voor de cachegrootte is ingesteld. Alle gebruikers van een cache-exemplaar moeten hetzelfde eenheidssysteem gebruiken. Een vermelding wordt niet in de cache opgeslagen als de som van de invoergrootten in de cache groter is dan de waarde die is opgegeven door SizeLimit
. Als er geen limiet voor de cachegrootte is ingesteld, wordt de cachegrootte die voor de vermelding is ingesteld, genegeerd.
De volgende code registreert MyMemoryCache
in de container voor afhankelijkheidsinjectie.
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddSingleton<MyMemoryCache>();
}
MyMemoryCache
wordt gemaakt als een onafhankelijke geheugencache voor onderdelen die zich bewust zijn van deze grootte beperkte cache en weten hoe de cachevermeldingsgrootte op de juiste manier moet worden ingesteld.
De volgende code maakt gebruik van MyMemoryCache
:
public class SetSize : PageModel
{
private MemoryCache _cache;
public static readonly string MyKey = "_MyKey";
public SetSize(MyMemoryCache memoryCache)
{
_cache = memoryCache.Cache;
}
[TempData]
public string DateTime_Now { get; set; }
public IActionResult OnGet()
{
if (!_cache.TryGetValue(MyKey, out string cacheEntry))
{
// Key not in cache, so get data.
cacheEntry = DateTime.Now.TimeOfDay.ToString();
var cacheEntryOptions = new MemoryCacheEntryOptions()
// Set cache entry size by extension method.
.SetSize(1)
// Keep in cache for this time, reset time if accessed.
.SetSlidingExpiration(TimeSpan.FromSeconds(3));
// Set cache entry size via property.
// cacheEntryOptions.Size = 1;
// Save data in cache.
_cache.Set(MyKey, cacheEntry, cacheEntryOptions);
}
DateTime_Now = cacheEntry;
return RedirectToPage("./Index");
}
}
De grootte van de cachevermelding kan worden ingesteld door Size of de SetSize extensiemethoden:
public IActionResult OnGet()
{
if (!_cache.TryGetValue(MyKey, out string cacheEntry))
{
// Key not in cache, so get data.
cacheEntry = DateTime.Now.TimeOfDay.ToString();
var cacheEntryOptions = new MemoryCacheEntryOptions()
// Set cache entry size by extension method.
.SetSize(1)
// Keep in cache for this time, reset time if accessed.
.SetSlidingExpiration(TimeSpan.FromSeconds(3));
// Set cache entry size via property.
// cacheEntryOptions.Size = 1;
// Save data in cache.
_cache.Set(MyKey, cacheEntry, cacheEntryOptions);
}
DateTime_Now = cacheEntry;
return RedirectToPage("./Index");
}
MemoryCache.Compact
MemoryCache.Compact
probeert het opgegeven percentage van de cache in de volgende volgorde te verwijderen:
- Alle vervallen items.
- Items naar prioriteit. Items met de laagste prioriteit worden eerst verwijderd.
- Minst recent gebruikte objecten.
- Items met de vroegste absolute vervaldatum.
- Items met de vroegste glijdende verlooptijd.
Vastgemaakte items met prioriteit NeverRemove worden nooit verwijderd. Met de volgende code wordt een cache-item verwijderd en Compact
aangeroepen.
_cache.Remove(MyKey);
// Remove 33% of cached items.
_cache.Compact(.33);
cache_size = _cache.Count;
Zie de compacte bron op GitHub voor meer informatie.
Cache dependencies
In het volgende voorbeeld ziet u hoe u een cachevermelding kunt laten verlopen als een afhankelijke vermelding verloopt. Er wordt een CancellationChangeToken toegevoegd aan het item in de cache. Wanneer Cancel
wordt aangeroepen op CancellationTokenSource
, worden beide cachevermeldingen verwijderd.
public IActionResult CreateDependentEntries()
{
var cts = new CancellationTokenSource();
_cache.Set(CacheKeys.DependentCTS, cts);
using (var entry = _cache.CreateEntry(CacheKeys.Parent))
{
// expire this entry if the dependant entry expires.
entry.Value = DateTime.Now;
entry.RegisterPostEvictionCallback(DependentEvictionCallback, this);
_cache.Set(CacheKeys.Child,
DateTime.Now,
new CancellationChangeToken(cts.Token));
}
return RedirectToAction("GetDependentEntries");
}
public IActionResult GetDependentEntries()
{
return View("Dependent", new DependentViewModel
{
ParentCachedTime = _cache.Get<DateTime?>(CacheKeys.Parent),
ChildCachedTime = _cache.Get<DateTime?>(CacheKeys.Child),
Message = _cache.Get<string>(CacheKeys.DependentMessage)
});
}
public IActionResult RemoveChildEntry()
{
_cache.Get<CancellationTokenSource>(CacheKeys.DependentCTS).Cancel();
return RedirectToAction("GetDependentEntries");
}
private static void DependentEvictionCallback(object key, object value,
EvictionReason reason, object state)
{
var message = $"Parent entry was evicted. Reason: {reason}.";
((HomeController)state)._cache.Set(CacheKeys.DependentMessage, message);
}
Door een CancellationTokenSource te gebruiken, kunnen meerdere cachevermeldingen als groep worden verwijderd. Met het using
patroon in de bovenstaande code nemen cachevermeldingen die in het using
blok zijn gemaakt triggers en verloopinstellingen over.
Additional notes
Verval vindt niet plaats op de achtergrond. Er is geen timer die de cache actief scant op verlopen items. Elke activiteit in de cache (
Get
,Set
,Remove
) kan een achtergrondscan voor verlopen items activeren. Een timer op deCancellationTokenSource
(CancelAfter) verwijdert ook de vermelding en activeert een scan voor verlopen items. In het volgende voorbeeld wordt het geregistreerde token gebruikt CancellationTokenSource(TimeSpan) . Wanneer dit token wordt geactiveerd, wordt het item onmiddellijk verwijderd en worden de verwijderingscallbacks geactiveerd.public IActionResult CacheAutoExpiringTryGetValueSet() { DateTime cacheEntry; if (!_cache.TryGetValue(CacheKeys.Entry, out cacheEntry)) { cacheEntry = DateTime.Now; var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); var cacheEntryOptions = new MemoryCacheEntryOptions() .AddExpirationToken(new CancellationChangeToken(cts.Token)); _cache.Set(CacheKeys.Entry, cacheEntry, cacheEntryOptions); } return View("Cache", cacheEntry); }
Wanneer u een callback gebruikt om een cache-item opnieuw in te vullen:
- Meerdere aanvragen kunnen de sleutelwaarde in de cache leeg vinden omdat de callback niet is voltooid.
- Dit kan ertoe leiden dat meerdere threads het gecachte item opnieuw laden.
Wanneer een cachevermelding wordt gebruikt om een andere te maken, kopieert de kindvermelding de vervaltokens en tijdbepaalde verloopinstellingen van de bovenliggende vermelding. Het kind is niet verwijderd door handmatig verwijderen of bijwerken van de oudervermelding.
Gebruik PostEvictionCallbacks om de callbacks in te stellen die worden geactiveerd nadat de cachevermelding uit de cache is verwijderd. In de voorbeeldcode wordt CancellationTokenSource.Dispose() aangeroepen om de onbeheerde resources die worden gebruikt door de
CancellationTokenSource
vrij te geven. HetCancellationTokenSource
wordt echter niet onmiddellijk verwijderd omdat deze nog steeds wordt gebruikt door de cachevermelding. HetCancellationToken
wordt aanMemoryCacheEntryOptions
doorgegeven om een cache-item aan te maken dat na een bepaalde tijd verloopt. DusDispose
moet niet worden aangeroepen totdat de cachevermelding is verwijderd of verlopen. Met de voorbeeldcode wordt de RegisterPostEvictionCallback methode aangeroepen om een callback te registreren die wordt aangeroepen wanneer de cachevermelding wordt verwijderd en wordt deCancellationTokenSource
in die callback verwijderd.Voor de meeste apps
IMemoryCache
is ingeschakeld. Bijvoorbeeld, het aanroepen vanAddMvc
,AddControllersWithViews
,AddRazorPages
,AddMvcCore().AddRazorViewEngine
en vele andereAdd{Service}
-methoden inConfigureServices
, maaktIMemoryCache
mogelijk. Voor apps die geen van de voorgaandeAdd{Service}
methoden aanroepen, kan het nodig zijn om AddMemoryCache inConfigureServices
aan te roepen.
Update van achtergrondcache
Gebruik een achtergrondservice zoals IHostedService om de cache bij te werken. De achtergrondservice kan de vermeldingen opnieuw compileren en deze vervolgens alleen toewijzen aan de cache wanneer ze klaar zijn.