Skip to content
Cache Tags
Esc
↑↓navigate↵open⌘Jpreview
On this page

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’s content- or media- 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(...)), a JsonResult, a ContentResult, a status code result, a file, an EmptyResult, 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, gets no-store and 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>();
  • waitFor names a signal. The package sends the purge once every server has reported the signal with Applied(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.
  • reason is 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.

Was this page helpful?