CacheStorage
The service-worker Cache API from C#: store request/response pairs in named, origin-scoped caches that survive reloads. Fetch-and-store real URLs, or synthesize responses from text and bytes you build client-side.
@inject Bit.Butil.CacheStorage cacheStorageMDN reference
Caches are persisted per origin and outlive the page. Keys lists every cache name the origin owns (including ones created by service workers), and Has checks for a specific cache without opening it.
@inject Bit.Butil.CacheStorage cacheStorage
var supported = await cacheStorage.IsSupported();
var names = await cacheStorage.Keys(); // string[]
var exists = await cacheStorage.Has("app-v1"); // boolNot everything worth caching comes from the network. PutText and PutBytes build a Response from data you already have - generated reports, downloaded blobs, precomputed JSON - and store it against any URL key you choose, with a configurable content type and status.
await cacheStorage.PutText("butil-docs-cache", "/greetings.txt", "Hello from the cache!");
await cacheStorage.PutBytes("butil-docs-cache", "/report.bin",
data: myBytes,
contentType: "application/octet-stream");Add fetches a URL and stores the response in one step - the cache-side equivalent of fetch followed by put. AddAll does the same for many URLs atomically: if any fetch fails, nothing is stored. Cross-origin URLs work but yield opaque responses whose bodies cannot be read back.
await cacheStorage.Add("butil-docs-cache", "css/app.css");
await cacheStorage.AddAll("butil-docs-cache", "css/app.css", "favicon.ico");Match retrieves a cached response snapshot: status, headers and body bytes. Check Found before using the result - a miss is not an exception. EntryKeys lists the request URLs currently stored in a cache, which is handy for building cache inspectors.
var response = await cacheStorage.Match("butil-docs-cache", "/greetings.txt");
if (response.Found)
{
var text = System.Text.Encoding.UTF8.GetString(response.Body);
// response.Status, response.StatusText, response.Url, response.Headers
}
var urls = await cacheStorage.EntryKeys("butil-docs-cache"); // string[]DeleteEntry removes a single request/response pair; Delete drops the whole named cache. Both return true when something was actually removed, so you can distinguish a cleanup from a no-op.
var removedEntry = await cacheStorage.DeleteEntry("butil-docs-cache", "/greetings.txt");
var removedCache = await cacheStorage.Delete("butil-docs-cache");Match reports them
with an empty body and no useful status. The same applies to 204/304 responses, which legitimately
have no body. A secure context (HTTPS or localhost) is required for the whole API.
API reference
ValueTask<bool> IsSupported()ValueTask<string[]> Keys()ValueTask<bool> Has(string cacheName)ValueTask<bool> Delete(string cacheName)ValueTask Add(string cacheName, string url)ValueTask AddAll(string cacheName, params string[] urls)ValueTask PutBytes(string cacheName, string url, byte[] data, string contentType = "application/octet-stream", int status = 200, string statusText = "OK")ValueTask PutText(string cacheName, string url, string text, string contentType = "text/plain;charset=utf-8", int status = 200, string statusText = "OK")ValueTask<CachedResponse> Match(string cacheName, string url)ValueTask<bool> DeleteEntry(string cacheName, string url)ValueTask<string[]> EntryKeys(string cacheName)class CachedResponse { bool Found; int Status; string StatusText; string Url; Dictionary<string, string> Headers; byte[] Body; }ValueTask<CachedResponse> MatchAny(string url)