Your own APIs
Tag responses from your site's own controllers, record changes to their data, and purge by hand.
Your site’s own API endpoints can carry cache keys too, so a frontend can cache their responses and the package purges them. The repository’s sample does this for an endpoint that serves Umbraco’s dictionary items.
Tag the responses
Put [CacheTagged] on a controller or action, and name what each response covers with the scoped ICacheTagsResponse:
[ApiController]
[Route("api/dictionary")]
[CacheTagged]
public sealed class DictionaryController(ILanguageService languages, ICacheTagsResponse cacheTags) : ControllerBase
{
[HttpGet]
public async Task<IActionResult> Get([FromQuery] string locale)
{
ILanguage? language = await languages.GetAsync(locale);
if (language is null)
{
return NotFound();
}
cacheTags.Add($"x-dictionary-{language.IsoCode.ToLowerInvariant()}");
// ... read the dictionary items in that language
return Ok(items);
}
}
Like a Delivery API response, the response carries umbraco and the keys of what it shows: the keys you name, and the keys of the Delivery API items in its result, which the package finds by itself.
- Custom keys start with
x-and use lowercase letters, digits and hyphens, at most 200 characters. An item’scontent-ormedia-key works too. - Only a 200 is tagged. The package tags a response before its result runs, so it reads the status from the result: return an
ObjectResult(Ok(...)), aJsonResult, aContentResult, a status code result, a file, anEmptyResult, or a typed result (TypedResults.Ok(...),Results<...>) with a status code. Anything else, such as a redirect, a challenge or a result type the package does not know, getsno-storeand no key.
Record changes
When the data behind those responses changes, record a change with ICacheTagsChanges:
public sealed class DictionaryCacheTags(ICacheTagsChanges changes, ILanguageService languages)
: INotificationAsyncHandler<DictionaryItemSavedNotification>,
INotificationAsyncHandler<DictionaryItemDeletedNotification>,
INotificationHandler<DictionaryCacheRefresherNotification>
{
public Task HandleAsync(DictionaryItemSavedNotification notification, CancellationToken cancellationToken)
=> RecordAsync("dictionary items saved");
public Task HandleAsync(DictionaryItemDeletedNotification notification, CancellationToken cancellationToken)
=> RecordAsync("dictionary items deleted");
// Raised on every server, once its dictionary cache has the change.
public void Handle(DictionaryCacheRefresherNotification notification) => changes.Applied("dictionary");
// A dictionary item has text in every language, so a change reaches every language's response.
private async Task RecordAsync(string reason)
=> changes.Record(
(await languages.GetAllAsync()).Select(language => $"x-dictionary-{language.IsoCode.ToLowerInvariant()}"),
waitFor: "dictionary",
reason: reason);
}
Register it in a composer:
builder.AddNotificationAsyncHandler<DictionaryItemSavedNotification, DictionaryCacheTags>();
builder.AddNotificationAsyncHandler<DictionaryItemDeletedNotification, DictionaryCacheTags>();
builder.AddNotificationHandler<DictionaryCacheRefresherNotification, DictionaryCacheTags>();
waitFornames a signal. The package sends the purge once every server has reported the signal withApplied(signal). Call it wherever a server refreshes its copy of the data, usually in a cache refresher’s notification handler. Signals use lowercase letters, digits, dots and hyphens.- Without
waitFor, the package sends the purge at once. Use that for data that every server reads straight from the database. reasonis shown with the change in the backoffice.
Purge by hand
Administrators can purge keys under Settings > Advanced > Cache tags > Purge, or through the Management API:
| Request | Does |
|---|---|
POST /umbraco/management/api/v1/cache-tags/purge |
Purges the keys in the JSON array body at once: x- keys, items’ content- and media- keys, or ["umbraco"] for everything. |
GET .../cache-tags/purges?state=Dead |
Lists purges in a state: Pending, Sent, Dead or Discarded. |
POST .../cache-tags/purges/{id}/retry |
Sends a failed or set-aside purge again. |
POST .../cache-tags/purges/{id}/discard |
Sets a pending or failed purge aside. |