Skip to content

Commit

Permalink
Add CancellationToken support to Async methods (#146)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kim-SSi committed Jun 13, 2021
1 parent 050cb65 commit 5b9947f
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 87 deletions.
31 changes: 16 additions & 15 deletions src/Blazored.LocalStorage/BrowserStorageProvider.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.JSInterop;
using Microsoft.JSInterop;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Blazored.LocalStorage
Expand All @@ -15,26 +16,26 @@ public BrowserStorageProvider(IJSRuntime jSRuntime)
_jSInProcessRuntime = jSRuntime as IJSInProcessRuntime;
}

public ValueTask ClearAsync()
=> _jSRuntime.InvokeVoidAsync("localStorage.clear");
public ValueTask ClearAsync(CancellationToken? cancellationToken = null)
=> _jSRuntime.InvokeVoidAsync("localStorage.clear", cancellationToken ?? CancellationToken.None);

public ValueTask<string> GetItemAsync(string key)
=> _jSRuntime.InvokeAsync<string>("localStorage.getItem", key);
public ValueTask<string> GetItemAsync(string key, CancellationToken? cancellationToken = null)
=> _jSRuntime.InvokeAsync<string>("localStorage.getItem", cancellationToken ?? CancellationToken.None, key);

public ValueTask<string> KeyAsync(int index)
=> _jSRuntime.InvokeAsync<string>("localStorage.key", index);
public ValueTask<string> KeyAsync(int index, CancellationToken? cancellationToken = null)
=> _jSRuntime.InvokeAsync<string>("localStorage.key", cancellationToken ?? CancellationToken.None, index);

public ValueTask<bool> ContainKeyAsync(string key)
=> _jSRuntime.InvokeAsync<bool>("localStorage.hasOwnProperty", key);
public ValueTask<bool> ContainKeyAsync(string key, CancellationToken? cancellationToken = null)
=> _jSRuntime.InvokeAsync<bool>("localStorage.hasOwnProperty", cancellationToken ?? CancellationToken.None, key);

public ValueTask<int> LengthAsync()
=> _jSRuntime.InvokeAsync<int>("eval", "localStorage.length");
public ValueTask<int> LengthAsync(CancellationToken? cancellationToken = null)
=> _jSRuntime.InvokeAsync<int>("eval", cancellationToken ?? CancellationToken.None, "localStorage.length");

public ValueTask RemoveItemAsync(string key)
=> _jSRuntime.InvokeVoidAsync("localStorage.removeItem", key);
public ValueTask RemoveItemAsync(string key, CancellationToken? cancellationToken = null)
=> _jSRuntime.InvokeVoidAsync("localStorage.removeItem", cancellationToken ?? CancellationToken.None, key);

public ValueTask SetItemAsync(string key, string data)
=> _jSRuntime.InvokeVoidAsync("localStorage.setItem", key, data);
public ValueTask SetItemAsync(string key, string data, CancellationToken? cancellationToken = null)
=> _jSRuntime.InvokeVoidAsync("localStorage.setItem", cancellationToken ?? CancellationToken.None, key, data);

public void Clear()
{
Expand Down
101 changes: 65 additions & 36 deletions src/Blazored.LocalStorage/ILocalStorageService.cs
Original file line number Diff line number Diff line change
@@ -1,73 +1,102 @@
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Blazored.LocalStorage
{
public interface ILocalStorageService
{
/// <summary>
/// Clears all data from local storage.
/// <summary>
/// Clears all data from local storage.
/// </summary>
/// <returns>A <see cref="ValueTask"/> representing the completion of the operation.</returns>
ValueTask ClearAsync();
ValueTask ClearAsync(CancellationToken? cancellationToken = null);

/// <summary>
/// Retrieve the specified data from local storage and deseralise it to the specfied type.
/// </summary>
/// <param name="key">A <see cref="string"/> value specifying the name of the local storage slot to use</param>
/// <summary>
/// Retrieve the specified data from local storage and deseralise it to the specfied type.
/// </summary>
/// <param name="key">A <see cref="string"/> value specifying the name of the local storage slot to use</param>
/// <param name="cancellationToken">
/// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts
/// (<see cref="JSRuntime.DefaultAsyncTimeout"/>) from being applied.
/// </param>
/// <returns>A <see cref="ValueTask"/> representing the completion of the operation.</returns>
ValueTask<T> GetItemAsync<T>(string key);
ValueTask<T> GetItemAsync<T>(string key, CancellationToken? cancellationToken = null);

/// <summary>
/// Retrieve the specified data from local storage as a <see cref="string"/>.
/// </summary>
/// <param name="key">A <see cref="string"/> value specifying the name of the storage slot to use</param>
/// <summary>
/// Retrieve the specified data from local storage as a <see cref="string"/>.
/// </summary>
/// <param name="key">A <see cref="string"/> value specifying the name of the storage slot to use</param>
/// <param name="cancellationToken">
/// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts
/// (<see cref="JSRuntime.DefaultAsyncTimeout"/>) from being applied.
/// </param>
/// <returns>A <see cref="ValueTask"/> representing the completion of the operation.</returns>
ValueTask<string> GetItemAsStringAsync(string key);
ValueTask<string> GetItemAsStringAsync(string key, CancellationToken? cancellationToken = null);

/// <summary>
/// Return the name of the key at the specified <paramref name="index"/>.
/// </summary>
/// <param name="index"></param>
/// <summary>
/// Return the name of the key at the specified <paramref name="index"/>.
/// </summary>
/// <param name="index"></param>
/// <param name="cancellationToken">
/// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts
/// (<see cref="JSRuntime.DefaultAsyncTimeout"/>) from being applied.
/// </param>
/// <returns>A <see cref="ValueTask"/> representing the completion of the operation.</returns>
ValueTask<string> KeyAsync(int index);
ValueTask<string> KeyAsync(int index, CancellationToken? cancellationToken = null);

/// <summary>
/// Checks if the <paramref name="key"/> exists in local storage, but does not check its value.
/// </summary>
/// <param name="key">A <see cref="string"/> value specifying the name of the storage slot to use</param>
/// <param name="cancellationToken">
/// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts
/// (<see cref="JSRuntime.DefaultAsyncTimeout"/>) from being applied.
/// </param>
/// <returns>A <see cref="ValueTask"/> representing the completion of the operation.</returns>
ValueTask<bool> ContainKeyAsync(string key);
ValueTask<bool> ContainKeyAsync(string key, CancellationToken? cancellationToken = null);

/// <summary>
/// The number of items stored in local storage.
/// </summary>
/// <summary>
/// The number of items stored in local storage.
/// </summary>
/// <returns>A <see cref="ValueTask"/> representing the completion of the operation.</returns>
ValueTask<int> LengthAsync();
ValueTask<int> LengthAsync(CancellationToken? cancellationToken = null);

/// <summary>
/// Remove the data with the specified <paramref name="key"/>.
/// </summary>
/// <param name="key">A <see cref="string"/> value specifying the name of the storage slot to use</param>
/// <summary>
/// Remove the data with the specified <paramref name="key"/>.
/// </summary>
/// <param name="key">A <see cref="string"/> value specifying the name of the storage slot to use</param>
/// <param name="cancellationToken">
/// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts
/// (<see cref="JSRuntime.DefaultAsyncTimeout"/>) from being applied.
/// </param>
/// <returns>A <see cref="ValueTask"/> representing the completion of the operation.</returns>
ValueTask RemoveItemAsync(string key);
ValueTask RemoveItemAsync(string key, CancellationToken? cancellationToken = null);

/// <summary>
/// Sets or updates the <paramref name="data"/> in local storage with the specified <paramref name="key"/>.
/// </summary>
/// <param name="key">A <see cref="string"/> value specifying the name of the storage slot to use</param>
/// <param name="data">The data to be saved</param>
/// <summary>
/// Sets or updates the <paramref name="data"/> in local storage with the specified <paramref name="key"/>.
/// </summary>
/// <param name="key">A <see cref="string"/> value specifying the name of the storage slot to use</param>
/// <param name="data">The data to be saved</param>
/// <param name="cancellationToken">
/// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts
/// (<see cref="JSRuntime.DefaultAsyncTimeout"/>) from being applied.
/// </param>
/// <returns>A <see cref="ValueTask"/> representing the completion of the operation.</returns>
ValueTask SetItemAsync<T>(string key, T data);
ValueTask SetItemAsync<T>(string key, T data, CancellationToken? cancellationToken = null);

/// <summary>
/// Sets or updates the <paramref name="data"/> in local storage with the specified <paramref name="key"/>. Does not serialize the value before storing.
/// </summary>
/// <param name="key">A <see cref="string"/> value specifying the name of the storage slot to use</param>
/// <param name="data">The string to be saved</param>
/// <param name="cancellationToken">
/// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts
/// (<see cref="JSRuntime.DefaultAsyncTimeout"/>) from being applied.
/// </param>
/// <returns></returns>
ValueTask SetItemAsStringAsync(string key, string data);

ValueTask SetItemAsStringAsync(string key, string data, CancellationToken? cancellationToken = null);

event EventHandler<ChangingEventArgs> Changing;
event EventHandler<ChangedEventArgs> Changed;
}
Expand Down
17 changes: 9 additions & 8 deletions src/Blazored.LocalStorage/IStorageProvider.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
using System.Threading.Tasks;
using System.Threading;
using System.Threading.Tasks;

namespace Blazored.LocalStorage
{
internal interface IStorageProvider
{
void Clear();
ValueTask ClearAsync();
ValueTask ClearAsync(CancellationToken? cancellationToken = null);
bool ContainKey(string key);
ValueTask<bool> ContainKeyAsync(string key);
ValueTask<bool> ContainKeyAsync(string key, CancellationToken? cancellationToken = null);
string GetItem(string key);
ValueTask<string> GetItemAsync(string key);
ValueTask<string> GetItemAsync(string key, CancellationToken? cancellationToken = null);
string Key(int index);
ValueTask<string> KeyAsync(int index);
ValueTask<string> KeyAsync(int index, CancellationToken? cancellationToken = null);
int Length();
ValueTask<int> LengthAsync();
ValueTask<int> LengthAsync(CancellationToken? cancellationToken = null);
void RemoveItem(string key);
ValueTask RemoveItemAsync(string key);
ValueTask RemoveItemAsync(string key, CancellationToken? cancellationToken = null);
void SetItem(string key, string data);
ValueTask SetItemAsync(string key, string data);
ValueTask SetItemAsync(string key, string data, CancellationToken? cancellationToken = null);
}
}
41 changes: 21 additions & 20 deletions src/Blazored.LocalStorage/LocalStorageService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Blazored.LocalStorage.Serialization;

Expand All @@ -16,7 +17,7 @@ public LocalStorageService(IStorageProvider storageProvider, IJsonSerializer ser
_serializer = serializer;
}

public async ValueTask SetItemAsync<T>(string key, T data)
public async ValueTask SetItemAsync<T>(string key, T data, CancellationToken? cancellationToken = null)
{
if (string.IsNullOrWhiteSpace(key))
throw new ArgumentNullException(nameof(key));
Expand All @@ -27,12 +28,12 @@ public async ValueTask SetItemAsync<T>(string key, T data)
return;

var serialisedData = _serializer.Serialize(data);
await _storageProvider.SetItemAsync(key, serialisedData).ConfigureAwait(false);
await _storageProvider.SetItemAsync(key, serialisedData, cancellationToken).ConfigureAwait(false);

RaiseOnChanged(key, e.OldValue, data);
}

public async ValueTask SetItemAsStringAsync(string key, string data)
public async ValueTask SetItemAsStringAsync(string key, string data, CancellationToken? cancellationToken = null)
{
if (string.IsNullOrWhiteSpace(key))
throw new ArgumentNullException(nameof(key));
Expand All @@ -45,17 +46,17 @@ public async ValueTask SetItemAsStringAsync(string key, string data)
if (e.Cancel)
return;

await _storageProvider.SetItemAsync(key, data).ConfigureAwait(false);
await _storageProvider.SetItemAsync(key, data, cancellationToken).ConfigureAwait(false);

RaiseOnChanged(key, e.OldValue, data);
}

public async ValueTask<T> GetItemAsync<T>(string key)
public async ValueTask<T> GetItemAsync<T>(string key, CancellationToken? cancellationToken = null)
{
if (string.IsNullOrWhiteSpace(key))
throw new ArgumentNullException(nameof(key));

var serialisedData = await _storageProvider.GetItemAsync(key).ConfigureAwait(false);
var serialisedData = await _storageProvider.GetItemAsync(key, cancellationToken).ConfigureAwait(false);

if (string.IsNullOrWhiteSpace(serialisedData))
return default;
Expand All @@ -72,33 +73,33 @@ public async ValueTask<T> GetItemAsync<T>(string key)
}
}

public ValueTask<string> GetItemAsStringAsync(string key)
public ValueTask<string> GetItemAsStringAsync(string key, CancellationToken? cancellationToken = null)
{
if (string.IsNullOrWhiteSpace(key))
throw new ArgumentNullException(nameof(key));

return _storageProvider.GetItemAsync(key);
return _storageProvider.GetItemAsync(key, cancellationToken);
}

public ValueTask RemoveItemAsync(string key)
public ValueTask RemoveItemAsync(string key, CancellationToken? cancellationToken = null)
{
if (string.IsNullOrWhiteSpace(key))
throw new ArgumentNullException(nameof(key));

return _storageProvider.RemoveItemAsync(key);
return _storageProvider.RemoveItemAsync(key, cancellationToken);
}

public ValueTask ClearAsync()
=> _storageProvider.ClearAsync();
public ValueTask ClearAsync(CancellationToken? cancellationToken = null)
=> _storageProvider.ClearAsync(cancellationToken);

public ValueTask<int> LengthAsync()
=> _storageProvider.LengthAsync();
public ValueTask<int> LengthAsync(CancellationToken? cancellationToken = null)
=> _storageProvider.LengthAsync(cancellationToken);

public ValueTask<string> KeyAsync(int index)
=> _storageProvider.KeyAsync(index);
public ValueTask<string> KeyAsync(int index, CancellationToken? cancellationToken = null)
=> _storageProvider.KeyAsync(index, cancellationToken);

public ValueTask<bool> ContainKeyAsync(string key)
=> _storageProvider.ContainKeyAsync(key);
public ValueTask<bool> ContainKeyAsync(string key, CancellationToken? cancellationToken = null)
=> _storageProvider.ContainKeyAsync(key, cancellationToken);

public void SetItem<T>(string key, T data)
{
Expand Down Expand Up @@ -213,12 +214,12 @@ private ChangingEventArgs RaiseOnChangingSync(string key, object data)
return e;
}

private async Task<T> GetItemInternalAsync<T>(string key)
private async Task<T> GetItemInternalAsync<T>(string key, CancellationToken? cancellationToken = null)
{
if (string.IsNullOrEmpty(key))
throw new ArgumentNullException(nameof(key));

var serialisedData = await _storageProvider.GetItemAsync(key).ConfigureAwait(false);
var serialisedData = await _storageProvider.GetItemAsync(key, cancellationToken).ConfigureAwait(false);

if (string.IsNullOrWhiteSpace(serialisedData))
return default;
Expand Down
Loading

0 comments on commit 5b9947f

Please sign in to comment.