To speed up the loading process, the browser stores the responses in cache. The most common scenario is caching JavaScript files. You, as a developer, the requests made by the browser and has no control over this process. However, with the Cache storage, you can store any request and response that you initiated and use them to reduce the call to the server or to provide offline support. This tutorial will give you a basic setup to interact with the Cache storage, you may need to add more features. In this tutorial, you will learn:
You can download the example code used in this topic on GitHub.
The Cache storage is a great choice for caching URL-addressable resources. You should use the Cache storage when your website deals with lots of data, or you want the users to be able to use your website when they don't have the connection. The Cache storage is a new technology, you might need to check if the browser supports the Cache storage before using it. The Cache storage only accepts Request
and Response
as key and value, respectively.
Request
and Response
?Request
and Response
are the JavaScript classes. Request
, as its name suggested, represents a request to an API. Response
, as its name suggested, represents a response from the API.
You can access the Cache storage in the browser by opening the Developer Tools (F12 for most browsers).
For Firefox, the Cache storage is located at the Storage tab as the following image:
For Chrome and Edge, the Cache storage is located at the Application tab as the following images:
To use the Cache storage, you first need to create a JavaScript module, then you will use C# code to call the exported functions of this module.
async function openCacheStorage() { return await window.caches.open("Blazor School"); } function createRequest(url, method, body = "") { let requestInit = { method: method }; if (body != "") { requestInit.body = body; } let request = new Request(url, requestInit); return request; }
public class CacheStorageAccessor : IAsyncDisposable { private Lazy<IJSObjectReference> _accessorJsRef = new(); private readonly IJSRuntime _jsRuntime; public CacheStorageAccessor(IJSRuntime jsRuntime) { _jsRuntime = jsRuntime; } private async Task WaitForReference() { if (_accessorJsRef.IsValueCreated is false) { _accessorJsRef = new(await _jsRuntime.InvokeAsync<IJSObjectReference>("import", "/js/CacheStorageAccessor.js")); } } public async ValueTask DisposeAsync() { if (_accessorJsRef.IsValueCreated) { await _accessorJsRef.Value.DisposeAsync(); } } }
Always remember to dispose the JavaScript module.
Program.cs
builder.Services.AddScoped<CacheStorageAccessor>();
In this section, we will demonstrate how to add some basic operations with the Cache storage. You can also add your own operations with this method too.
export async function store(url, method, body = "", responseString) { let blazorSchoolCache = await openCacheStorage(); let request = createRequest(url, method, body); let response = new Response(responseString); await blazorSchoolCache.put(request, response); } export async function get(url, method, body = "") { let blazorSchoolCache = await openCacheStorage(); let request = createRequest(url, method, body); let response = await blazorSchoolCache.match(request); if (response == undefined) { return ""; } let result = await response.text(); return result; } export async function remove(url, method, body = "") { let blazorSchoolCache = await openCacheStorage(); let request = createRequest(url, method, body); await blazorSchoolCache.delete(request); } export async function removeAll() { let blazorSchoolCache = await openCacheStorage(); let requests = await blazorSchoolCache.keys(); for (let i = 0; i < requests.length; i++) { await blazorSchoolCache.delete(requests[i]); } }
WaitForReference()
in all methods.public class CacheStorageAccessor : IAsyncDisposable { ... public async Task StoreAsync(HttpRequestMessage requestMessage, HttpResponseMessage responseMessage) { await WaitForReference(); string requestMethod = requestMessage.Method.Method; string requestBody = await GetRequestBodyAsync(requestMessage); string responseBody = await responseMessage.Content.ReadAsStringAsync(); await _accessorJsRef.Value.InvokeVoidAsync("store", requestMessage.RequestUri, requestMethod, requestBody, responseBody); } public async Task<string> GetAsync(HttpRequestMessage requestMessage) { await WaitForReference(); string requestMethod = requestMessage.Method.Method; string requestBody = await GetRequestBodyAsync(requestMessage); string result = await _accessorJsRef.Value.InvokeAsync<string>("get", requestMessage.RequestUri, requestMethod, requestBody); return result; } public async Task RemoveAsync(HttpRequestMessage requestMessage) { await WaitForReference(); string requestMethod = requestMessage.Method.Method; string requestBody = await GetRequestBodyAsync(requestMessage); await _accessorJsRef.Value.InvokeVoidAsync("remove", requestMessage.RequestUri, requestMethod, requestBody); } public async Task RemoveAllAsync() { await WaitForReference(); await _accessorJsRef.Value.InvokeVoidAsync("removeAll"); } private static async Task<string> GetRequestBodyAsync(HttpRequestMessage requestMessage) { string requestBody = ""; if (requestMessage.Content is not null) { requestBody = await requestMessage.Content.ReadAsStringAsync() ?? ""; } return requestBody; } }
Once you have the complete all the previous steps, you can use it as follows:
@inject CacheStorageAccessor CacheStorageAccessor @inject HttpClient HttpClient <button class="btn btn-primary" type="button" @onclick="SetValueAsync">Set Value</button> <div>Stored Value: @StoredValue</div> <button class="btn btn-primary" type="button" @onclick="GetValueAsync">Get Value</button> <button class="btn btn-primary" type="button" @onclick="RemoveAsync">Remove Value</button> <button class="btn btn-primary" type="button" @onclick="ClearAllAsync">Clear All</button> @code { public string StoredValue { get; set; } = ""; public async Task SetValueAsync() { var message = CreateMessage(); var response = await HttpClient.SendAsync(message); await CacheStorageAccessor.StoreAsync(message, response); } public async Task GetValueAsync() { StoredValue = await CacheStorageAccessor.GetAsync(CreateMessage()); } public async Task RemoveAsync() { await CacheStorageAccessor.RemoveAsync(CreateMessage()); } public async Task ClearAllAsync() { await CacheStorageAccessor.RemoveAllAsync(); } public HttpRequestMessage CreateMessage() => new HttpRequestMessage(HttpMethod.Get, "/sample-data/books.json"); }
You need to create a new HttpRequestMessage
everytime to store the request.