| File: Storage.cs | Web Access |
| Project: Microsoft.AspNetCore.Components.Platform.csproj (Microsoft.AspNetCore.Components.Platform) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.JSInterop; namespace Microsoft.AspNetCore.Components.Platform; /// <summary> /// Represents a browser Web Storage object. /// </summary> public sealed class Storage : IInternalAsyncDisposal { private readonly IJSRuntime _jsRuntime; private readonly string _propertyName; private Task<IJSObjectReference>? _referenceTask; private bool _disposed; internal Storage(IJSRuntime jsRuntime, string propertyName) { _jsRuntime = jsRuntime; _propertyName = propertyName; } /// <summary> /// Gets the number of stored items. /// </summary> /// <returns>The number of stored items.</returns> public async ValueTask<uint> GetLengthAsync() { var storage = await GetReferenceAsync().ConfigureAwait(false); return await storage.GetValueAsync<uint>("length").ConfigureAwait(false); } /// <summary> /// Gets the key at the specified index. /// </summary> /// <param name="index">The zero-based index of the key to retrieve.</param> /// <returns>The key at <paramref name="index"/>, or <see langword="null"/> if no key exists at that index.</returns> public async ValueTask<string?> KeyAsync(uint index) { var storage = await GetReferenceAsync().ConfigureAwait(false); return await storage.InvokeAsync<string?>("key", [index]).ConfigureAwait(false); } /// <summary> /// Gets the value associated with the specified key. /// </summary> /// <param name="key">The key of the value to retrieve.</param> /// <returns>The value associated with <paramref name="key"/>, or <see langword="null"/> if the key does not exist.</returns> /// <exception cref="ArgumentNullException"><paramref name="key"/> is <see langword="null"/>.</exception> public async ValueTask<string?> GetItemAsync(string key) { ArgumentNullException.ThrowIfNull(key); var storage = await GetReferenceAsync().ConfigureAwait(false); return await storage.InvokeAsync<string?>("getItem", [key]).ConfigureAwait(false); } /// <summary> /// Sets the value associated with the specified key, replacing any existing value. /// </summary> /// <param name="key">The key of the value to set.</param> /// <param name="value">The value to store.</param> /// <returns>A <see cref="ValueTask"/> representing the completion of the operation.</returns> /// <exception cref="ArgumentNullException"><paramref name="key"/> or <paramref name="value"/> is <see langword="null"/>.</exception> public async ValueTask SetItemAsync(string key, string value) { ArgumentNullException.ThrowIfNull(key); ArgumentNullException.ThrowIfNull(value); var storage = await GetReferenceAsync().ConfigureAwait(false); await storage.InvokeVoidAsync("setItem", key, value).ConfigureAwait(false); } /// <summary> /// Removes the value associated with the specified key, if it exists. /// </summary> /// <param name="key">The key of the value to remove.</param> /// <returns>A <see cref="ValueTask"/> representing the completion of the operation.</returns> /// <exception cref="ArgumentNullException"><paramref name="key"/> is <see langword="null"/>.</exception> public async ValueTask RemoveItemAsync(string key) { ArgumentNullException.ThrowIfNull(key); var storage = await GetReferenceAsync().ConfigureAwait(false); await storage.InvokeVoidAsync("removeItem", key).ConfigureAwait(false); } /// <summary> /// Removes all stored values. /// </summary> /// <returns>A <see cref="ValueTask"/> representing the completion of the operation.</returns> public async ValueTask ClearAsync() { var storage = await GetReferenceAsync().ConfigureAwait(false); await storage.InvokeVoidAsync("clear").ConfigureAwait(false); } async ValueTask IInternalAsyncDisposal.InternalDisposeAsync() { if (_disposed) { return; } _disposed = true; // Don't wait for a pending acquisition. It could hold up scope disposal until the JS interop timeout. if (_referenceTask is { IsCompletedSuccessfully: true } referenceTask) { await referenceTask.Result.DisposeAsync().ConfigureAwait(false); } } private Task<IJSObjectReference> GetReferenceAsync() { ObjectDisposedException.ThrowIf(_disposed, this); if (_referenceTask is null || _referenceTask.IsFaulted || _referenceTask.IsCanceled) { _referenceTask = _jsRuntime.GetValueAsync<IJSObjectReference>(_propertyName).AsTask(); } return _referenceTask; } }