diff --git a/.github/workflows/ci-main.yml b/.github/workflows/ci-main.yml
index 3f35b26..b7c42a5 100644
--- a/.github/workflows/ci-main.yml
+++ b/.github/workflows/ci-main.yml
@@ -7,12 +7,10 @@ on:
types: [ published ]
env:
- NETCORE_VERSION: '5.0.202'
+ NETCORE_VERSION: '7.0.x'
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
PROJECT_NAME: SessionStorage
- GITHUB_FEED: https://nuget.pkg.github.com/Blazored/
- GITHUB_USER: chrissainty
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NUGET_FEED: https://api.nuget.org/v3/index.json
NUGET_KEY: ${{ secrets.NUGET_KEY }}
@@ -38,60 +36,24 @@ jobs:
- name: Build
run: dotnet build -c Release --no-restore src/Blazored.$PROJECT_NAME/Blazored.$PROJECT_NAME.csproj
- - name: Test
- run: dotnet test -c Release
+ - name: Build Test Extensions
+ run: dotnet build -c Release --no-restore src/Blazored.$PROJECT_NAME.TestExtensions/Blazored.$PROJECT_NAME.TestExtensions.csproj
- - name: Pack
- run: dotnet pack -v normal -c Release --no-restore --include-symbols --include-source -p:PackageVersion=$GITHUB_RUN_ID src/Blazored.$PROJECT_NAME/Blazored.$PROJECT_NAME.*proj
+ - name: Test Local Storage
+ run: dotnet test -c Release --no-restore --verbosity normal tests/Blazored.$PROJECT_NAME.Tests
- - name: Publish Sample Site
- run: dotnet publish -c Release samples/BlazorWebAssembly/BlazorWebAssembly.csproj
-
- - name: Rewrite base href
- uses: SteveSandersonMS/ghaction-rewrite-base-href@v1
- with:
- html_path: samples/BlazorWebAssembly/bin/Release/net5.0/publish/wwwroot/index.html
- base_href: /${{ env.PROJECT_NAME }}/
-
- - name: Deploy to Github Pages
- uses: JamesIves/github-pages-deploy-action@releases/v3
- with:
- ACCESS_TOKEN: $GITHUB_TOKEN
- BASE_BRANCH: main # The branch the action should deploy from.
- BRANCH: gh-pages # The branch the action should deploy to.
- FOLDER: samples/BlazorWebAssembly/bin/Release/net5.0/publish/wwwroot # The folder the action should deploy.
- SINGLE_COMMIT: true
-
- - name: Upload Artifact
- uses: actions/upload-artifact@v2
- with:
- name: nupkg
- path: ./src/Blazored.${{ env.PROJECT_NAME }}/bin/Release/*.nupkg
- prerelease:
- needs: build
- if: github.event_name != 'release'
- runs-on: ubuntu-latest
- steps:
- - name: Download Artifact
- uses: actions/download-artifact@v1
- with:
- name: nupkg
- - name: Push to GitHub Feed
- run: |
- for f in ./nupkg/*.nupkg
- do
- curl -vX PUT -u "$GITHUB_USER:$GITHUB_TOKEN" -F package=@$f $GITHUB_FEED
- done
deploy:
needs: build
if: github.event_name == 'release'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
+
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: ${{ env.NETCORE_VERSION }}
+
- name: Create Release NuGet package
run: |
arrTag=(${GITHUB_REF//\// })
@@ -100,11 +62,25 @@ jobs:
VERSION="${VERSION//v}"
echo Clean Version: $VERSION
dotnet pack -v normal -c Release --include-symbols --include-source -p:PackageVersion=$VERSION -o nupkg src/Blazored.$PROJECT_NAME/Blazored.$PROJECT_NAME.*proj
- - name: Push to GitHub Feed
- run: |
- for f in ./nupkg/*.nupkg
- do
- curl -vX PUT -u "$GITHUB_USER:$GITHUB_TOKEN" -F package=@$f $GITHUB_FEED
- done
+ dotnet pack -v normal -c Release --include-symbols --include-source -p:PackageVersion=$VERSION -o nupkg src/Blazored.$PROJECT_NAME.TestExtensions/Blazored.$PROJECT_NAME.TestExtensions.csproj
+
- name: Push to NuGet Feed
- run: dotnet nuget push ./nupkg/*.nupkg --source $NUGET_FEED --skip-duplicate --api-key $NUGET_KEY
+ run: dotnet nuget push ./nupkg/*.nupkg --source $NUGET_FEED --api-key $NUGET_KEY --skip-duplicate
+
+ - name: Publish Sample Site
+ run: dotnet publish -c Release samples/BlazorWebAssembly/BlazorWebAssembly.csproj
+
+ - name: Rewrite base href
+ uses: SteveSandersonMS/ghaction-rewrite-base-href@v1
+ with:
+ html_path: samples/BlazorWebAssembly/bin/Release/net7.0/publish/wwwroot/index.html
+ base_href: /${{ env.PROJECT_NAME }}/
+
+ - name: Deploy to Github Pages
+ uses: JamesIves/github-pages-deploy-action@releases/v3
+ with:
+ ACCESS_TOKEN: $GITHUB_TOKEN
+ BASE_BRANCH: main # The branch the action should deploy from.
+ BRANCH: gh-pages # The branch the action should deploy to.
+ FOLDER: samples/BlazorWebAssembly/bin/Release/net7.0/publish/wwwroot # The folder the action should deploy.
+ SINGLE_COMMIT: true
diff --git a/.github/workflows/ci-pr.yml b/.github/workflows/ci-pr.yml
index 7d718cc..1584fc7 100644
--- a/.github/workflows/ci-pr.yml
+++ b/.github/workflows/ci-pr.yml
@@ -5,7 +5,7 @@ on:
branches: [ main ]
env:
- NETCORE_VERSION: '5.0.202'
+ NETCORE_VERSION: '7.0.x'
PROJECT_NAME: Blazored.SessionStorage
jobs:
@@ -23,8 +23,11 @@ jobs:
- name: Restoring packages...
run: dotnet restore
- - name: Building project...
+ - name: Building Session Storage...
run: dotnet build --configuration Release --no-restore src/$PROJECT_NAME/$PROJECT_NAME.csproj
+ - name: Build Session Storage Test Extensions
+ run: dotnet build -c Release --no-restore src/$PROJECT_NAME.TestExtensions/$PROJECT_NAME.TestExtensions.csproj
+
- name: Testing...
- run: dotnet test --no-restore --verbosity normal
\ No newline at end of file
+ run: dotnet test -c Release --no-restore --verbosity normal tests/$PROJECT_NAME.Tests
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 3e759b7..d2d12b1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -179,6 +179,8 @@ PublishScripts/
# NuGet Packages
*.nupkg
+*.snupkg
+
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
diff --git a/Blazored.SessionStorage.sln b/Blazored.SessionStorage.sln
index e084bba..4e05906 100644
--- a/Blazored.SessionStorage.sln
+++ b/Blazored.SessionStorage.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.28531.58
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31717.71
MinimumVisualStudioVersion = 15.0.26124.0
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blazored.SessionStorage", "src\Blazored.SessionStorage\Blazored.SessionStorage.csproj", "{EFA12DC3-35DE-449C-88F2-2BD7576CAF2C}"
EndProject
@@ -13,6 +13,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorServer", "samples\Bla
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9170D7A9-70CE-48E3-88A3-F11D2983103E}"
ProjectSection(SolutionItems) = preProject
+ .gitignore = .gitignore
.github\workflows\ci-main.yml = .github\workflows\ci-main.yml
.github\workflows\ci-pr.yml = .github\workflows\ci-pr.yml
README.md = README.md
@@ -23,7 +24,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B82A5126
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blazored.SessionStorage.Tests", "tests\Blazored.SessionStorage.Tests\Blazored.SessionStorage.Tests.csproj", "{5A6A013E-325D-4A5F-B2FA-659B4FD2BDBC}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "bUnitExample", "samples\bUnitExample\bUnitExample.csproj", "{10F6FB83-3135-4B73-B0EB-D008A31AE8FA}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bUnitExample", "samples\bUnitExample\bUnitExample.csproj", "{10F6FB83-3135-4B73-B0EB-D008A31AE8FA}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blazored.SessionStorage.TestExtensions", "src\Blazored.SessionStorage.TestExtensions\Blazored.SessionStorage.TestExtensions.csproj", "{528AE63D-0043-4A63-9151-92107397EE02}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -95,6 +98,18 @@ Global
{10F6FB83-3135-4B73-B0EB-D008A31AE8FA}.Release|x64.Build.0 = Release|Any CPU
{10F6FB83-3135-4B73-B0EB-D008A31AE8FA}.Release|x86.ActiveCfg = Release|Any CPU
{10F6FB83-3135-4B73-B0EB-D008A31AE8FA}.Release|x86.Build.0 = Release|Any CPU
+ {528AE63D-0043-4A63-9151-92107397EE02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {528AE63D-0043-4A63-9151-92107397EE02}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {528AE63D-0043-4A63-9151-92107397EE02}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {528AE63D-0043-4A63-9151-92107397EE02}.Debug|x64.Build.0 = Debug|Any CPU
+ {528AE63D-0043-4A63-9151-92107397EE02}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {528AE63D-0043-4A63-9151-92107397EE02}.Debug|x86.Build.0 = Debug|Any CPU
+ {528AE63D-0043-4A63-9151-92107397EE02}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {528AE63D-0043-4A63-9151-92107397EE02}.Release|Any CPU.Build.0 = Release|Any CPU
+ {528AE63D-0043-4A63-9151-92107397EE02}.Release|x64.ActiveCfg = Release|Any CPU
+ {528AE63D-0043-4A63-9151-92107397EE02}.Release|x64.Build.0 = Release|Any CPU
+ {528AE63D-0043-4A63-9151-92107397EE02}.Release|x86.ActiveCfg = Release|Any CPU
+ {528AE63D-0043-4A63-9151-92107397EE02}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Directory.Build.props b/Directory.Build.props
index 28acef2..8f1e9e9 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -2,8 +2,8 @@
- 3.1.14
- 5.0.5
+ 6.0.12
+ 7.0.1
\ No newline at end of file
diff --git a/README.md b/README.md
index e0f165b..3d1e274 100644
--- a/README.md
+++ b/README.md
@@ -12,19 +12,20 @@ From v4 onwards we use the default the `JsonSerializerOptions` for `System.Text.
To retain the old settings use the following configuration when adding Blazored SessionStorage to the DI container:
```csharp
-builder.Services.AddBlazoredSessionStorage(config =>
- config.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
- config.JsonSerializerOptions.IgnoreNullValues = true;
- config.JsonSerializerOptions.IgnoreReadOnlyProperties = true;
- config.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
- config.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
- config.JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip;
- config.JsonSerializerOptions.WriteIndented = false;
+builder.Services.AddBlazoredSessionStorage(config => {
+ config.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
+ config.JsonSerializerOptions.IgnoreNullValues = true;
+ config.JsonSerializerOptions.IgnoreReadOnlyProperties = true;
+ config.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
+ config.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
+ config.JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip;
+ config.JsonSerializerOptions.WriteIndented = false;
+ }
);
```
### SetItem[Async] method now serializes string values
-Prior to v2 we bypassed the serialization of string values as it seemed a pointless as string can be stored directly. However, this led to some edge cases where nullable strings were being saved as the string `"null"`. Then when retrieved, instead of being null the value was `"null"`. By serializing strings this issue is taken care of.
+Prior to v2 we bypassed the serialization of string values as it seemed pointless as string can be stored directly. However, this led to some edge cases where nullable strings were being saved as the string `"null"`. Then when retrieved, instead of being null the value was `"null"`. By serializing strings this issue is taken care of.
For those who wish to save raw string values, a new method `SetValueAsString[Async]` is available. This will save a string value without attempting to serialize it and will throw an exception if a null string is attempted to be saved.
## Installing
@@ -41,7 +42,7 @@ You can also install via the .NET CLI with the following command:
dotnet add package Blazored.SessionStorage
```
-If you're using Visual Studio you can also install via the built in NuGet package manager.
+If you're using Jetbrains Rider or Visual Studio you can also install via the built in NuGet package manager.
## Setup
@@ -68,6 +69,17 @@ public static async Task Main(string[] args)
}
```
+### Registering services as Singleton - Blazor WebAssembly **ONLY**
+99% of developers will want to register Blazored SessionStorage using the method described above. However, in some very specific scenarios,
+developers may have a need to register services as Singleton as apposed to Scoped. This is possible by using the following method:
+
+```csharp
+builder.Services.AddBlazoredSessionStorageAsSingleton();
+```
+
+**This method will not work with Blazor Server applications as Blazor's JS interop services are registered as Scoped and cannot be injected into Singletons.**
+
+
## Usage (Blazor WebAssembly)
To use Blazored.SessionStorage in Blazor WebAssembly, inject the `ISessionStorageService` per the example below.
@@ -127,9 +139,11 @@ The APIs available are:
- GetItemAsync()
- GetItemAsStringAsync()
- RemoveItemAsync()
+ - RemoveItemsAsync()
- ClearAsync()
- LengthAsync()
- KeyAsync()
+ - KeysAsync()
- ContainKeyAsync()
- synchronous via `ISyncSessionStorageService` (Synchronous methods are **only** available in Blazor WebAssembly):
@@ -138,9 +152,11 @@ The APIs available are:
- GetItem()
- GetItemAsString()
- RemoveItem()
+ - RemovesItem()
- Clear()
- Length()
- Key()
+ - Keys()
- ContainKey()
**Note:** Blazored.SessionStorage methods will handle the serialisation and de-serialisation of the data for you, the exception is the `GetItemAsString[Async]` method which will return the raw string value from session storage.
@@ -177,6 +193,24 @@ You can find an example of this in the Blazor Server sample project. The standar
## Testing with bUnit
This library provides test extensions for use with the [bUnit testing library](https://bunit.dev/). Using these test extensions will provide an in memory implementation which mimics session storage allowing more realistic testing of your components.
+### Installing
+
+To install the package add the following line to you csproj file replacing x.x.x with the latest version number (found at the top of this file):
+
+```
+
+```
+
+You can also install via the .NET CLI with the following command:
+
+```
+dotnet add package Blazored.SessionStorage.TestExtensions
+```
+
+If you're using Jetbrains Rider or Visual Studio you can also install via the built in NuGet package manager.
+
+### Usage example
+
Below is an example test which uses these extensions. You can find an example project which shows this code in action in the samples folder.
```c#
diff --git a/samples/BlazorServer/BlazorServer.csproj b/samples/BlazorServer/BlazorServer.csproj
index e6ebf48..98d95a3 100644
--- a/samples/BlazorServer/BlazorServer.csproj
+++ b/samples/BlazorServer/BlazorServer.csproj
@@ -1,11 +1,11 @@
- net5.0
+ net7.0
-
+
diff --git a/samples/BlazorWebAssembly/BlazorWebAssembly.csproj b/samples/BlazorWebAssembly/BlazorWebAssembly.csproj
index 7011596..f1d4e0d 100644
--- a/samples/BlazorWebAssembly/BlazorWebAssembly.csproj
+++ b/samples/BlazorWebAssembly/BlazorWebAssembly.csproj
@@ -1,13 +1,13 @@
- net5.0
+ net7.0
-
-
-
+
+
+
diff --git a/samples/bUnitExample/bUnitExample.csproj b/samples/bUnitExample/bUnitExample.csproj
index 6d5685c..5d0efb7 100644
--- a/samples/bUnitExample/bUnitExample.csproj
+++ b/samples/bUnitExample/bUnitExample.csproj
@@ -1,25 +1,25 @@
- net5.0
+ net7.0
-
-
-
-
-
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitiveall
-
+ runtime; build; native; contentfiles; analyzers; buildtransitiveall
+
diff --git a/src/Blazored.SessionStorage/Testing/BUnitLocalStorageTestExtensions.cs b/src/Blazored.SessionStorage.TestExtensions/BUnitSessionStorageTestExtensions.cs
similarity index 52%
rename from src/Blazored.SessionStorage/Testing/BUnitLocalStorageTestExtensions.cs
rename to src/Blazored.SessionStorage.TestExtensions/BUnitSessionStorageTestExtensions.cs
index efaadcf..4de3433 100644
--- a/src/Blazored.SessionStorage/Testing/BUnitLocalStorageTestExtensions.cs
+++ b/src/Blazored.SessionStorage.TestExtensions/BUnitSessionStorageTestExtensions.cs
@@ -1,16 +1,17 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using Blazored.SessionStorage;
using Blazored.SessionStorage.JsonConverters;
using Blazored.SessionStorage.Serialization;
using Blazored.SessionStorage.StorageOptions;
+using Blazored.SessionStorage.TestExtensions;
using Microsoft.Extensions.DependencyInjection;
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Blazored.SessionStorage;
-using Blazored.SessionStorage.Testing;
namespace Bunit
{
[ExcludeFromCodeCoverage]
public static class BUnitSessionStorageTestExtensions
+
{
public static ISessionStorageService AddBlazoredSessionStorage(this TestContextBase context)
=> AddBlazoredSessionStorage(context, null);
@@ -18,20 +19,16 @@ public static ISessionStorageService AddBlazoredSessionStorage(this TestContextB
public static ISessionStorageService AddBlazoredSessionStorage(this TestContextBase context, Action configure)
{
if (context is null)
- throw new ArgumentNullException(nameof(context));
+ throw new ArgumentNullException(nameof(context));
+
+ var sessionStorageOptions = new SessionStorageOptions();
+ configure?.Invoke(sessionStorageOptions);
+ sessionStorageOptions.JsonSerializerOptions.Converters.Add(new TimespanJsonConverter());
- context.Services
- .AddSingleton()
- .AddSingleton()
- .AddSingleton()
- .AddSingleton()
- .Configure(configureOptions =>
- {
- configure?.Invoke(configureOptions);
- configureOptions.JsonSerializerOptions.Converters.Add(new TimespanJsonConverter());
- });
+ var localStorageService = new SessionStorageService(new InMemoryStorageProvider(), new SystemTextJsonSerializer(sessionStorageOptions));
+ context.Services.AddSingleton(localStorageService);
- return context.Services.GetService();
+ return localStorageService;
}
}
}
diff --git a/src/Blazored.SessionStorage.TestExtensions/Blazored.SessionStorage.TestExtensions.csproj b/src/Blazored.SessionStorage.TestExtensions/Blazored.SessionStorage.TestExtensions.csproj
new file mode 100644
index 0000000..40800be
--- /dev/null
+++ b/src/Blazored.SessionStorage.TestExtensions/Blazored.SessionStorage.TestExtensions.csproj
@@ -0,0 +1,57 @@
+
+
+
+ net6.0;net7.0
+
+ Chris Sainty
+
+ Copyright 2020 (c) Chris Sainty. All rights reserved.
+ A testing library to provide helper extensions for Blazored.SessionStorage
+ true
+ snupkg
+
+
+ Blazored.SessionStorage.TestExtensions
+ Blazored;Blazor;Razor;Components;SessionStorage;Session Storage;ASP.NET Core;CSharp;Web
+ MIT
+ https://github.com/Blazored/SessionStorage
+ icon.png
+ git
+ https://github.com/Blazored/SessionStorage
+
+
+ true
+ true
+ true
+ Blazored.SessionStorage.snk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_Parameter1>
+ Blazored.SessionStorage.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001007527e122cc36dc13c695a4f43b7c2da3f631aed456ed309140c0d52262323e25d84bef7feddc8bd29cfe46ec652186cb10e059eedabf2ff000b977a2376a613dccfb092de6c243e0888db4c66a084124b2c1799bda4bbb2f70fed0382fc1cbdafa6dc0f4baccdc2cee55234f8a5ad76645c315523fee5352d9f01036e48b13e3
+
+
+
+
+
+
+
+
+
diff --git a/src/Blazored.SessionStorage.TestExtensions/Blazored.SessionStorage.snk b/src/Blazored.SessionStorage.TestExtensions/Blazored.SessionStorage.snk
new file mode 100644
index 0000000..18e2ce3
Binary files /dev/null and b/src/Blazored.SessionStorage.TestExtensions/Blazored.SessionStorage.snk differ
diff --git a/src/Blazored.SessionStorage.TestExtensions/InMemoryStorageProvider.cs b/src/Blazored.SessionStorage.TestExtensions/InMemoryStorageProvider.cs
new file mode 100644
index 0000000..36615c0
--- /dev/null
+++ b/src/Blazored.SessionStorage.TestExtensions/InMemoryStorageProvider.cs
@@ -0,0 +1,93 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Blazored.SessionStorage.TestExtensions
+{
+ internal class InMemoryStorageProvider : IStorageProvider
+ {
+ private readonly Dictionary _dataStore = new();
+
+ public void Clear()
+ => _dataStore.Clear();
+
+ public ValueTask ClearAsync(CancellationToken cancellationToken = default)
+ {
+ _dataStore.Clear();
+ return new ValueTask(Task.CompletedTask);
+ }
+
+ public bool ContainKey(string key)
+ => _dataStore.ContainsKey(key);
+
+ public ValueTask ContainKeyAsync(string key, CancellationToken cancellationToken = default)
+ => new(ContainKey(key));
+
+ public string GetItem(string key)
+ => _dataStore.TryGetValue(key, out var value) ? value : default;
+
+ public ValueTask GetItemAsync(string key, CancellationToken cancellationToken = default)
+ => new(GetItem(key));
+
+ public string Key(int index)
+ => index > _dataStore.Count - 1 ? default : _dataStore.ElementAt(index).Key;
+
+ public IEnumerable Keys()
+ => _dataStore.Keys.ToList();
+
+ public ValueTask KeyAsync(int index, CancellationToken cancellationToken = default)
+ => new(Key(index));
+
+ public ValueTask> KeysAsync(CancellationToken cancellationToken = default)
+ => new(_dataStore.Keys.ToList());
+
+ public int Length()
+ => _dataStore.Count;
+
+ public ValueTask LengthAsync(CancellationToken cancellationToken = default)
+ => new(Length());
+
+ public void RemoveItem(string key)
+ => _dataStore.Remove(key);
+
+ public ValueTask RemoveItemAsync(string key, CancellationToken cancellationToken = default)
+ {
+ RemoveItem(key);
+ return new ValueTask(Task.CompletedTask);
+ }
+
+ public void RemoveItems(IEnumerable keys)
+ {
+ foreach (var key in keys)
+ {
+ _dataStore.Remove(key);
+ }
+ }
+
+ public ValueTask RemoveItemsAsync(IEnumerable keys, CancellationToken cancellationToken = default)
+ {
+ RemoveItems(keys);
+
+ return new ValueTask(Task.CompletedTask);
+ }
+
+ public void SetItem(string key, string data)
+ {
+ if (_dataStore.ContainsKey(key))
+ {
+ _dataStore[key] = data;
+ }
+ else
+ {
+ _dataStore.Add(key, data);
+ }
+ }
+
+ public ValueTask SetItemAsync(string key, string data, CancellationToken cancellationToken = default)
+ {
+ SetItem(key, data);
+ return new ValueTask(Task.CompletedTask);
+ }
+ }
+}
diff --git a/src/Blazored.SessionStorage/Blazored.SessionStorage.csproj b/src/Blazored.SessionStorage/Blazored.SessionStorage.csproj
index 8191ad3..07ebd5d 100644
--- a/src/Blazored.SessionStorage/Blazored.SessionStorage.csproj
+++ b/src/Blazored.SessionStorage/Blazored.SessionStorage.csproj
@@ -1,7 +1,7 @@
- netstandard2.1;net5.0
+ net6.0;net7.0Chris Sainty
@@ -26,22 +26,16 @@
Blazored.SessionStorage.snk
-
- 3.0
-
-
-
+
-
-
-
+
+
-
-
-
-
+
+
+
@@ -49,7 +43,19 @@
-
+
+ <_Parameter1>
+ Blazored.SessionStorage.TestExtensions, PublicKey=00240000048000009400000006020000002400005253413100040000010001007527e122cc36dc13c695a4f43b7c2da3f631aed456ed309140c0d52262323e25d84bef7feddc8bd29cfe46ec652186cb10e059eedabf2ff000b977a2376a613dccfb092de6c243e0888db4c66a084124b2c1799bda4bbb2f70fed0382fc1cbdafa6dc0f4baccdc2cee55234f8a5ad76645c315523fee5352d9f01036e48b13e3
+
+
+
+
+
+
+ <_Parameter1>
+ Blazored.SessionStorage.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001007527e122cc36dc13c695a4f43b7c2da3f631aed456ed309140c0d52262323e25d84bef7feddc8bd29cfe46ec652186cb10e059eedabf2ff000b977a2376a613dccfb092de6c243e0888db4c66a084124b2c1799bda4bbb2f70fed0382fc1cbdafa6dc0f4baccdc2cee55234f8a5ad76645c315523fee5352d9f01036e48b13e3
+
+
-
+
\ No newline at end of file
diff --git a/src/Blazored.SessionStorage/BrowserStorageProvider.cs b/src/Blazored.SessionStorage/BrowserStorageProvider.cs
index 7f68520..883c4bb 100644
--- a/src/Blazored.SessionStorage/BrowserStorageProvider.cs
+++ b/src/Blazored.SessionStorage/BrowserStorageProvider.cs
@@ -1,87 +1,352 @@
-using Microsoft.JSInterop;
+using Microsoft.JSInterop;
using System;
+using System.Collections.Generic;
+using System.Threading;
using System.Threading.Tasks;
+using Blazored.SessionStorage.Exceptions;
-namespace Blazored.SessionStorage
+namespace Blazored.SessionStorage;
+
+internal class BrowserStorageProvider : IStorageProvider
{
- internal class BrowserStorageProvider : IStorageProvider
+ private const string StorageNotAvailableMessage = "Unable to access the browser storage. This is most likely due to the browser settings.";
+
+ private readonly IJSRuntime _jSRuntime;
+ private readonly IJSInProcessRuntime _jSInProcessRuntime;
+
+ public BrowserStorageProvider(IJSRuntime jSRuntime)
+ {
+ _jSRuntime = jSRuntime;
+ _jSInProcessRuntime = jSRuntime as IJSInProcessRuntime;
+ }
+
+ public async ValueTask ClearAsync(CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ await _jSRuntime.InvokeVoidAsync("sessionStorage.clear", cancellationToken);
+ }
+ catch (Exception exception)
+ {
+ if (IsStorageDisabledException(exception))
+ {
+ throw new BrowserStorageDisabledException(StorageNotAvailableMessage, exception);
+ }
+
+ throw;
+ }
+ }
+
+ public async ValueTask GetItemAsync(string key, CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ return await _jSRuntime.InvokeAsync("sessionStorage.getItem", cancellationToken, key);
+ }
+ catch (Exception exception)
+ {
+ if (IsStorageDisabledException(exception))
+ {
+ throw new BrowserStorageDisabledException(StorageNotAvailableMessage, exception);
+ }
+
+ throw;
+ }
+ }
+
+ public async ValueTask KeyAsync(int index, CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ return await _jSRuntime.InvokeAsync("sessionStorage.key", cancellationToken, index);
+ }
+ catch (Exception exception)
+ {
+ if (IsStorageDisabledException(exception))
+ {
+ throw new BrowserStorageDisabledException(StorageNotAvailableMessage, exception);
+ }
+
+ throw;
+ }
+ }
+
+ public async ValueTask> KeysAsync(CancellationToken cancellationToken = default)
{
- private readonly IJSRuntime _jSRuntime;
- private readonly IJSInProcessRuntime _jSInProcessRuntime;
+ try
+ {
+ return await _jSRuntime.InvokeAsync>("eval", cancellationToken, "Object.keys(sessionStorage)");
+ }
+ catch (Exception exception)
+ {
+ if (IsStorageDisabledException(exception))
+ {
+ throw new BrowserStorageDisabledException(StorageNotAvailableMessage, exception);
+ }
+
+ throw;
+ }
+ }
- public BrowserStorageProvider(IJSRuntime jSRuntime)
+ public async ValueTask ContainKeyAsync(string key, CancellationToken cancellationToken = default)
+ {
+ try
{
- _jSRuntime = jSRuntime;
- _jSInProcessRuntime = jSRuntime as IJSInProcessRuntime;
+ return await _jSRuntime.InvokeAsync("sessionStorage.hasOwnProperty", cancellationToken, key);
}
+ catch (Exception exception)
+ {
+ if (IsStorageDisabledException(exception))
+ {
+ throw new BrowserStorageDisabledException(StorageNotAvailableMessage, exception);
+ }
- public ValueTask ClearAsync()
- => _jSRuntime.InvokeVoidAsync("sessionStorage.clear");
+ throw;
+ }
+ }
- public ValueTask GetItemAsync(string key)
- => _jSRuntime.InvokeAsync("sessionStorage.getItem", key);
+ public async ValueTask LengthAsync(CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ return await _jSRuntime.InvokeAsync("eval", cancellationToken, "sessionStorage.length");
+ }
+ catch (Exception exception)
+ {
+ if (IsStorageDisabledException(exception))
+ {
+ throw new BrowserStorageDisabledException(StorageNotAvailableMessage, exception);
+ }
- public ValueTask KeyAsync(int index)
- => _jSRuntime.InvokeAsync("sessionStorage.key", index);
+ throw;
+ }
+ }
- public ValueTask ContainKeyAsync(string key)
- => _jSRuntime.InvokeAsync("sessionStorage.hasOwnProperty", key);
+ public async ValueTask RemoveItemAsync(string key, CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ await _jSRuntime.InvokeVoidAsync("sessionStorage.removeItem", cancellationToken, key);
+ }
+ catch (Exception exception)
+ {
+ if (IsStorageDisabledException(exception))
+ {
+ throw new BrowserStorageDisabledException(StorageNotAvailableMessage, exception);
+ }
- public ValueTask LengthAsync()
- => _jSRuntime.InvokeAsync("eval", "sessionStorage.length");
+ throw;
+ }
+ }
- public ValueTask RemoveItemAsync(string key)
- => _jSRuntime.InvokeVoidAsync("sessionStorage.removeItem", key);
+ public async ValueTask RemoveItemsAsync(IEnumerable keys, CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ foreach (var key in keys)
+ {
+ await _jSRuntime.InvokeVoidAsync("sessionStorage.removeItem", cancellationToken, key);
+ }
+ }
+ catch (Exception exception)
+ {
+ if (IsStorageDisabledException(exception))
+ {
+ throw new BrowserStorageDisabledException(StorageNotAvailableMessage, exception);
+ }
- public ValueTask SetItemAsync(string key, string data)
- => _jSRuntime.InvokeVoidAsync("sessionStorage.setItem", key, data);
+ throw;
+ }
+ }
- public void Clear()
+ public async ValueTask SetItemAsync(string key, string data, CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ await _jSRuntime.InvokeVoidAsync("sessionStorage.setItem", cancellationToken, key, data);
+ }
+ catch (Exception exception)
+ {
+ if (IsStorageDisabledException(exception))
+ {
+ throw new BrowserStorageDisabledException(StorageNotAvailableMessage, exception);
+ }
+
+ throw;
+ }
+ }
+
+ public void Clear()
+ {
+ CheckForInProcessRuntime();
+ try
{
- CheckForInProcessRuntime();
_jSInProcessRuntime.InvokeVoid("sessionStorage.clear");
}
+ catch (Exception exception)
+ {
+ if (IsStorageDisabledException(exception))
+ {
+ throw new BrowserStorageDisabledException(StorageNotAvailableMessage, exception);
+ }
+
+ throw;
+ }
+ }
- public string GetItem(string key)
+ public string GetItem(string key)
+ {
+ CheckForInProcessRuntime();
+ try
{
- CheckForInProcessRuntime();
return _jSInProcessRuntime.Invoke("sessionStorage.getItem", key);
}
+ catch (Exception exception)
+ {
+ if (IsStorageDisabledException(exception))
+ {
+ throw new BrowserStorageDisabledException(StorageNotAvailableMessage, exception);
+ }
- public string Key(int index)
+ throw;
+ }
+ }
+
+ public string Key(int index)
+ {
+ CheckForInProcessRuntime();
+ try
{
- CheckForInProcessRuntime();
return _jSInProcessRuntime.Invoke("sessionStorage.key", index);
}
+ catch (Exception exception)
+ {
+ if (IsStorageDisabledException(exception))
+ {
+ throw new BrowserStorageDisabledException(StorageNotAvailableMessage, exception);
+ }
- public bool ContainKey(string key)
+ throw;
+ }
+ }
+
+ public IEnumerable Keys()
+ {
+ CheckForInProcessRuntime();
+ try
+ {
+ return _jSInProcessRuntime.Invoke>("eval", "Object.keys(sessionStorage)");
+ }
+ catch (Exception exception)
+ {
+ if (IsStorageDisabledException(exception))
+ {
+ throw new BrowserStorageDisabledException(StorageNotAvailableMessage, exception);
+ }
+
+ throw;
+ }
+ }
+
+ public bool ContainKey(string key)
+ {
+ CheckForInProcessRuntime();
+ try
{
- CheckForInProcessRuntime();
return _jSInProcessRuntime.Invoke("sessionStorage.hasOwnProperty", key);
}
+ catch (Exception exception)
+ {
+ if (IsStorageDisabledException(exception))
+ {
+ throw new BrowserStorageDisabledException(StorageNotAvailableMessage, exception);
+ }
- public int Length()
+ throw;
+ }
+ }
+
+ public int Length()
+ {
+ CheckForInProcessRuntime();
+ try
{
- CheckForInProcessRuntime();
return _jSInProcessRuntime.Invoke("eval", "sessionStorage.length");
}
+ catch (Exception exception)
+ {
+ if (IsStorageDisabledException(exception))
+ {
+ throw new BrowserStorageDisabledException(StorageNotAvailableMessage, exception);
+ }
+
+ throw;
+ }
+ }
+
+ public void RemoveItem(string key)
+ {
+ CheckForInProcessRuntime();
+ try
+ {
+ _jSInProcessRuntime.InvokeVoid("sessionStorage.removeItem", key);
+ }
+ catch (Exception exception)
+ {
+ if (IsStorageDisabledException(exception))
+ {
+ throw new BrowserStorageDisabledException(StorageNotAvailableMessage, exception);
+ }
- public void RemoveItem(string key)
+ throw;
+ }
+ }
+
+ public void RemoveItems(IEnumerable keys)
+ {
+ CheckForInProcessRuntime();
+ try
{
- CheckForInProcessRuntime();
- _jSInProcessRuntime.InvokeVoidAsync("sessionStorage.removeItem", key);
+ foreach (var key in keys)
+ {
+ _jSInProcessRuntime.InvokeVoid("sessionStorage.removeItem", key);
+ }
+ }
+ catch (Exception exception)
+ {
+ if (IsStorageDisabledException(exception))
+ {
+ throw new BrowserStorageDisabledException(StorageNotAvailableMessage, exception);
+ }
+
+ throw;
}
+ }
- public void SetItem(string key, string data)
+ public void SetItem(string key, string data)
+ {
+ CheckForInProcessRuntime();
+ try
{
- CheckForInProcessRuntime();
_jSInProcessRuntime.InvokeVoid("sessionStorage.setItem", key, data);
}
-
- private void CheckForInProcessRuntime()
+ catch (Exception exception)
{
- if (_jSInProcessRuntime == null)
- throw new InvalidOperationException("IJSInProcessRuntime not available");
+ if (IsStorageDisabledException(exception))
+ {
+ throw new BrowserStorageDisabledException(StorageNotAvailableMessage, exception);
+ }
+
+ throw;
}
}
+
+ private void CheckForInProcessRuntime()
+ {
+ if (_jSInProcessRuntime == null)
+ throw new InvalidOperationException("IJSInProcessRuntime not available");
+ }
+
+ private static bool IsStorageDisabledException(Exception exception)
+ => exception.Message.Contains("Failed to read the 'sessionStorage' property from 'Window'");
}
diff --git a/src/Blazored.SessionStorage/ChangedEventArgs.cs b/src/Blazored.SessionStorage/ChangedEventArgs.cs
index fae2781..f20fba4 100644
--- a/src/Blazored.SessionStorage/ChangedEventArgs.cs
+++ b/src/Blazored.SessionStorage/ChangedEventArgs.cs
@@ -1,12 +1,11 @@
using System.Diagnostics.CodeAnalysis;
-namespace Blazored.SessionStorage
+namespace Blazored.SessionStorage;
+
+[ExcludeFromCodeCoverage]
+public class ChangedEventArgs
{
- [ExcludeFromCodeCoverage]
- public class ChangedEventArgs
- {
- public string Key { get; set; }
- public object OldValue { get; set; }
- public object NewValue { get; set; }
- }
+ public string Key { get; set; }
+ public object OldValue { get; set; }
+ public object NewValue { get; set; }
}
\ No newline at end of file
diff --git a/src/Blazored.SessionStorage/ChangingEventArgs.cs b/src/Blazored.SessionStorage/ChangingEventArgs.cs
index 047a3e3..032c9e4 100644
--- a/src/Blazored.SessionStorage/ChangingEventArgs.cs
+++ b/src/Blazored.SessionStorage/ChangingEventArgs.cs
@@ -1,11 +1,10 @@
using System;
using System.Diagnostics.CodeAnalysis;
-namespace Blazored.SessionStorage
+namespace Blazored.SessionStorage;
+
+[ExcludeFromCodeCoverage]
+public class ChangingEventArgs : ChangedEventArgs
{
- [ExcludeFromCodeCoverage]
- public class ChangingEventArgs : ChangedEventArgs
- {
- public bool Cancel { get; set; }
- }
-}
+ public bool Cancel { get; set; }
+}
\ No newline at end of file
diff --git a/src/Blazored.SessionStorage/Exceptions/BrowserStorageDisabledException.cs b/src/Blazored.SessionStorage/Exceptions/BrowserStorageDisabledException.cs
new file mode 100644
index 0000000..212a658
--- /dev/null
+++ b/src/Blazored.SessionStorage/Exceptions/BrowserStorageDisabledException.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Blazored.SessionStorage.Exceptions;
+
+public class BrowserStorageDisabledException : Exception
+{
+ public BrowserStorageDisabledException()
+ {
+ }
+
+ public BrowserStorageDisabledException(string message) : base(message)
+ {
+ }
+
+ public BrowserStorageDisabledException(string message, Exception inner) : base(message, inner)
+ {
+ }
+}
diff --git a/src/Blazored.SessionStorage/ISessionStorageService.cs b/src/Blazored.SessionStorage/ISessionStorageService.cs
index f9d7a3f..e35d989 100644
--- a/src/Blazored.SessionStorage/ISessionStorageService.cs
+++ b/src/Blazored.SessionStorage/ISessionStorageService.cs
@@ -1,74 +1,99 @@
using System;
+using System.Collections.Generic;
+using System.Threading;
using System.Threading.Tasks;
+using Microsoft.JSInterop;
-namespace Blazored.SessionStorage
+namespace Blazored.SessionStorage;
+
+public interface ISessionStorageService
{
- public interface ISessionStorageService
- {
- ///
- /// Clears all data from session storage.
- ///
- /// A representing the completion of the operation.
- ValueTask ClearAsync();
+ ///
+ /// Clears all data from session storage.
+ ///
+ /// A representing the completion of the operation.
+ ValueTask ClearAsync(CancellationToken cancellationToken = default);
- ///
- /// Retrieve the specified data from session storage and deseralise it to the specfied type.
- ///
- /// A value specifying the name of the session storage slot to use
- /// A representing the completion of the operation.
- ValueTask GetItemAsync(string key);
+ ///
+ /// Retrieve the specified data from session storage and deseralise it to the specfied type.
+ ///
+ /// A value specifying the name of the session storage slot to use
+ /// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts () from being applied.
+ /// A representing the completion of the operation.
+ ValueTask GetItemAsync(string key, CancellationToken cancellationToken = default);
- ///
- /// Retrieve the specified data from session storage as a .
- ///
- /// A value specifying the name of the storage slot to use
- /// A representing the completion of the operation.
- ValueTask GetItemAsStringAsync(string key);
+ ///
+ /// Retrieve the specified data from session storage as a .
+ ///
+ /// A value specifying the name of the storage slot to use
+ /// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts () from being applied.
+ /// A representing the completion of the operation.
+ ValueTask GetItemAsStringAsync(string key, CancellationToken cancellationToken = default);
- ///
- /// Return the name of the key at the specified .
- ///
- ///
- /// A representing the completion of the operation.
- ValueTask KeyAsync(int index);
+ ///
+ /// Return the name of the key at the specified .
+ ///
+ ///
+ /// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts () from being applied.
+ /// A representing the completion of the operation.
+ ValueTask KeyAsync(int index, CancellationToken cancellationToken = default);
+
+ ///
+ /// Returns a collection of strings representing the names of the keys in the Session storage.
+ ///
+ /// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts () from being applied.
+ /// A representing the completion of the operation.
+ ValueTask> KeysAsync(CancellationToken cancellationToken = default);
- ///
- /// Checks if the exists in session storage, but does not check its value.
- ///
- /// A value specifying the name of the storage slot to use
- /// A representing the completion of the operation.
- ValueTask ContainKeyAsync(string key);
+ ///
+ /// Checks if the exists in session storage, but does not check its value.
+ ///
+ /// A value specifying the name of the storage slot to use
+ /// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts () from being applied.
+ /// A representing the completion of the operation.
+ ValueTask ContainKeyAsync(string key, CancellationToken cancellationToken = default);
- ///
- /// The number of items stored in session storage.
- ///
- /// A representing the completion of the operation.
- ValueTask LengthAsync();
+ ///
+ /// The number of items stored in session storage.
+ ///
+ /// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts () from being applied.
+ /// A representing the completion of the operation.
+ ValueTask LengthAsync(CancellationToken cancellationToken = default);
- ///
- /// Remove the data with the specified .
- ///
- /// A value specifying the name of the storage slot to use
- /// A representing the completion of the operation.
- ValueTask RemoveItemAsync(string key);
+ ///
+ /// Remove the data with the specified .
+ ///
+ /// A value specifying the name of the storage slot to use
+ /// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts () from being applied.
+ /// A representing the completion of the operation.
+ ValueTask RemoveItemAsync(string key, CancellationToken cancellationToken = default);
+
+ ///
+ /// Removes a collection of .
+ ///
+ /// A IEnumerable collection of strings specifying the name of the storage slot to remove
+ /// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts () from being applied.
+ /// A representing the completion of the operation.
+ ValueTask RemoveItemsAsync(IEnumerable keys, CancellationToken cancellationToken = default);
- ///
- /// Sets or updates the in session storage with the specified .
- ///
- /// A value specifying the name of the storage slot to use
- /// The data to be saved
- /// A representing the completion of the operation.
- ValueTask SetItemAsync(string key, T data);
+ ///
+ /// Sets or updates the in session storage with the specified .
+ ///
+ /// A value specifying the name of the storage slot to use
+ /// The data to be saved
+ /// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts () from being applied.
+ /// A representing the completion of the operation.
+ ValueTask SetItemAsync(string key, T data, CancellationToken cancellationToken = default);
- ///
- /// Sets or updates the in session storage with the specified . Does not serialize the value before storing.
- ///
- /// A value specifying the name of the storage slot to use
- /// The string to be saved
- ///
- ValueTask SetItemAsStringAsync(string key, string data);
+ ///
+ /// Sets or updates the in session storage with the specified . Does not serialize the value before storing.
+ ///
+ /// A value specifying the name of the storage slot to use
+ /// The string to be saved
+ /// A cancellation token to signal the cancellation of the operation. Specifying this parameter will override any default cancellations such as due to timeouts () from being applied.
+ /// A representing the completion of the operation.
+ ValueTask SetItemAsStringAsync(string key, string data, CancellationToken cancellationToken = default);
- event EventHandler Changing;
- event EventHandler Changed;
- }
+ event EventHandler Changing;
+ event EventHandler Changed;
}
diff --git a/src/Blazored.SessionStorage/IStorageProvider.cs b/src/Blazored.SessionStorage/IStorageProvider.cs
index a45f204..0bd2c7f 100644
--- a/src/Blazored.SessionStorage/IStorageProvider.cs
+++ b/src/Blazored.SessionStorage/IStorageProvider.cs
@@ -1,22 +1,26 @@
-using System.Threading.Tasks;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
-namespace Blazored.SessionStorage
+namespace Blazored.SessionStorage;
+
+internal interface IStorageProvider
{
- internal interface IStorageProvider
- {
- void Clear();
- ValueTask ClearAsync();
- bool ContainKey(string key);
- ValueTask ContainKeyAsync(string key);
- string GetItem(string key);
- ValueTask GetItemAsync(string key);
- string Key(int index);
- ValueTask KeyAsync(int index);
- int Length();
- ValueTask LengthAsync();
- void RemoveItem(string key);
- ValueTask RemoveItemAsync(string key);
- void SetItem(string key, string data);
- ValueTask SetItemAsync(string key, string data);
- }
-}
\ No newline at end of file
+ void Clear();
+ ValueTask ClearAsync(CancellationToken cancellationToken = default);
+ bool ContainKey(string key);
+ ValueTask ContainKeyAsync(string key, CancellationToken cancellationToken = default);
+ string GetItem(string key);
+ ValueTask GetItemAsync(string key, CancellationToken cancellationToken = default);
+ string Key(int index);
+ ValueTask KeyAsync(int index, CancellationToken cancellationToken = default);
+ IEnumerable Keys();
+ ValueTask> KeysAsync(CancellationToken cancellationToken = default);
+ int Length();
+ ValueTask LengthAsync(CancellationToken cancellationToken = default);
+ void RemoveItem(string key);
+ ValueTask RemoveItemAsync(string key, CancellationToken cancellationToken = default);
+ ValueTask RemoveItemsAsync(IEnumerable keys, CancellationToken cancellationToken = default);
+ void SetItem(string key, string data);
+ ValueTask SetItemAsync(string key, string data, CancellationToken cancellationToken = default);
+}
diff --git a/src/Blazored.SessionStorage/ISyncSessionStorageService.cs b/src/Blazored.SessionStorage/ISyncSessionStorageService.cs
index 0017e89..d972a1a 100644
--- a/src/Blazored.SessionStorage/ISyncSessionStorageService.cs
+++ b/src/Blazored.SessionStorage/ISyncSessionStorageService.cs
@@ -1,70 +1,82 @@
using System;
+using System.Collections.Generic;
-namespace Blazored.SessionStorage
+namespace Blazored.SessionStorage;
+
+public interface ISyncSessionStorageService
{
- public interface ISyncSessionStorageService
- {
- ///
- /// Clears all data from session storage.
- ///
- void Clear();
+ ///
+ /// Clears all data from session storage.
+ ///
+ void Clear();
- ///
- /// Retrieve the specified data from session storage as a .
- ///
- /// A value specifying the name of the session storage slot to use
- /// The data from the specified as a
- T GetItem(string key);
+ ///
+ /// Retrieve the specified data from session storage as a .
+ ///
+ /// A value specifying the name of the session storage slot to use
+ /// The data from the specified as a
+ T GetItem(string key);
- ///
- /// Retrieve the specified data from session storage as a .
- ///
- /// A value specifying the name of the storage slot to use
- /// The data associated with the specified as a
- string GetItemAsString(string key);
+ ///
+ /// Retrieve the specified data from session storage as a .
+ ///
+ /// A value specifying the name of the storage slot to use
+ /// The data associated with the specified as a
+ string GetItemAsString(string key);
- ///
- /// Return the name of the key at the specified .
- ///
- ///
- /// The name of the key at the specified
- string Key(int index);
+ ///
+ /// Return the name of the key at the specified .
+ ///
+ ///
+ /// The name of the key at the specified
+ string Key(int index);
+
+ ///
+ /// Get the keys of all items stored in session storage.
+ ///
+ /// The keys of all items stored in session storage
+ IEnumerable Keys();
- ///
- /// Checks if the exists in session storage, but does not check its value.
- ///
- /// A value specifying the name of the storage slot to use
- /// Boolean indicating if the specified exists
- bool ContainKey(string key);
+ ///
+ /// Checks if the exists in session storage, but does not check its value.
+ ///
+ /// A value specifying the name of the storage slot to use
+ /// Boolean indicating if the specified exists
+ bool ContainKey(string key);
- ///
- /// The number of items stored in session storage.
- ///
- /// The number of items stored in session storage
- int Length();
+ ///
+ /// The number of items stored in session storage.
+ ///
+ /// The number of items stored in session storage
+ int Length();
- ///
- /// Remove the data with the specified .
- ///
- /// A value specifying the name of the storage slot to use
- void RemoveItem(string key);
+ ///
+ /// Remove the data with the specified .
+ ///
+ /// A value specifying the name of the storage slot to use
+ void RemoveItem(string key);
+
+ ///
+ /// Removes a collection of .
+ ///
+ /// A IEnumerable collection of strings specifying the name of the storage slot to remove
+ void RemoveItems(IEnumerable keys);
- ///
- /// Sets or updates the in session storage with the specified .
- ///
- /// A value specifying the name of the storage slot to use
- /// The data to be saved
- void SetItem(string key, T data);
+ ///
+ /// Sets or updates the in session storage with the specified .
+ ///
+ /// A value specifying the name of the storage slot to use
+ /// The data to be saved
+ void SetItem(string key, T data);
- ///
- /// Sets or updates the in session storage with the specified . Does not serialize the value before storing.
- ///
- /// A value specifying the name of the storage slot to use
- /// The string to be saved
- ///
- void SetItemAsString(string key, string data);
+ ///
+ /// Sets or updates the in session storage with the specified . Does not serialize the value before storing.
+ ///
+ /// A value specifying the name of the storage slot to use
+ /// The string to be saved
+ ///
+ void SetItemAsString(string key, string data);
- event EventHandler Changing;
- event EventHandler Changed;
- }
+ event EventHandler Changing;
+ event EventHandler Changed;
}
diff --git a/src/Blazored.SessionStorage/JsonConverters/TimespanJsonConverter.cs b/src/Blazored.SessionStorage/JsonConverters/TimespanJsonConverter.cs
index b67e0a8..2a81538 100644
--- a/src/Blazored.SessionStorage/JsonConverters/TimespanJsonConverter.cs
+++ b/src/Blazored.SessionStorage/JsonConverters/TimespanJsonConverter.cs
@@ -5,39 +5,38 @@
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
-namespace Blazored.SessionStorage.JsonConverters
+namespace Blazored.SessionStorage.JsonConverters;
+
+///
+/// The new Json.NET doesn't support Timespan at this time
+/// https://github.com/dotnet/corefx/issues/38641
+///
+public class TimespanJsonConverter : JsonConverter
{
///
- /// The new Json.NET doesn't support Timespan at this time
- /// https://github.com/dotnet/corefx/issues/38641
+ /// Format: Days.Hours:Minutes:Seconds:Milliseconds
///
- public class TimespanJsonConverter : JsonConverter
- {
- ///
- /// Format: Days.Hours:Minutes:Seconds:Milliseconds
- ///
- public const string TimeSpanFormatString = @"d\.hh\:mm\:ss\:FFF";
+ public const string TimeSpanFormatString = @"d\.hh\:mm\:ss\:FFF";
- public override TimeSpan Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ public override TimeSpan Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ var s = reader.GetString();
+ if (string.IsNullOrWhiteSpace(s))
{
- var s = reader.GetString();
- if (string.IsNullOrWhiteSpace(s))
- {
- return TimeSpan.Zero;
- }
-
- if (!TimeSpan.TryParseExact(s, TimeSpanFormatString, null, out var parsedTimeSpan))
- {
- throw new FormatException($"Input timespan is not in an expected format : expected {Regex.Unescape(TimeSpanFormatString)}. Please retrieve this key as a string and parse manually.");
- }
-
- return parsedTimeSpan;
+ return TimeSpan.Zero;
}
- public override void Write(Utf8JsonWriter writer, TimeSpan value, JsonSerializerOptions options)
+ if (!TimeSpan.TryParseExact(s, TimeSpanFormatString, null, out var parsedTimeSpan))
{
- var timespanFormatted = $"{value.ToString(TimeSpanFormatString)}";
- writer.WriteStringValue(timespanFormatted);
+ throw new FormatException($"Input timespan is not in an expected format : expected {Regex.Unescape(TimeSpanFormatString)}. Please retrieve this key as a string and parse manually.");
}
+
+ return parsedTimeSpan;
+ }
+
+ public override void Write(Utf8JsonWriter writer, TimeSpan value, JsonSerializerOptions options)
+ {
+ var timespanFormatted = $"{value.ToString(TimeSpanFormatString)}";
+ writer.WriteStringValue(timespanFormatted);
}
}
diff --git a/src/Blazored.SessionStorage/PublicKey.snk b/src/Blazored.SessionStorage/PublicKey.snk
deleted file mode 100644
index 031abef..0000000
Binary files a/src/Blazored.SessionStorage/PublicKey.snk and /dev/null differ
diff --git a/src/Blazored.SessionStorage/PublicKey.txt b/src/Blazored.SessionStorage/PublicKey.txt
deleted file mode 100644
index 0a9702e..0000000
--- a/src/Blazored.SessionStorage/PublicKey.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-
-Microsoft (R) .NET Framework Strong Name Utility Version 4.0.30319.0
-Copyright (c) Microsoft Corporation. All rights reserved.
-
-Public key token is 6f8d36f00e4891c3
diff --git a/src/Blazored.SessionStorage/Serialization/IJsonSerializer.cs b/src/Blazored.SessionStorage/Serialization/IJsonSerializer.cs
index 9bccf18..e1a99c5 100644
--- a/src/Blazored.SessionStorage/Serialization/IJsonSerializer.cs
+++ b/src/Blazored.SessionStorage/Serialization/IJsonSerializer.cs
@@ -1,8 +1,7 @@
-namespace Blazored.SessionStorage.Serialization
+namespace Blazored.SessionStorage.Serialization;
+
+public interface IJsonSerializer
{
- public interface IJsonSerializer
- {
- string Serialize(T obj);
- T Deserialize(string text);
- }
+ string Serialize(T obj);
+ T Deserialize(string text);
}
diff --git a/src/Blazored.SessionStorage/Serialization/SystemTextJsonSerializer.cs b/src/Blazored.SessionStorage/Serialization/SystemTextJsonSerializer.cs
index 8100bab..a4b893f 100644
--- a/src/Blazored.SessionStorage/Serialization/SystemTextJsonSerializer.cs
+++ b/src/Blazored.SessionStorage/Serialization/SystemTextJsonSerializer.cs
@@ -1,29 +1,26 @@
using Blazored.SessionStorage.StorageOptions;
using Microsoft.Extensions.Options;
-using System.Runtime.CompilerServices;
using System.Text.Json;
-[assembly: InternalsVisibleTo("Blazored.SessionStorage.Tests, PublicKey=" +
-"00240000048000009400000006020000002400005253413100040000010001007527e122cc36dc" +
-"13c695a4f43b7c2da3f631aed456ed309140c0d52262323e25d84bef7feddc8bd29cfe46ec6521" +
-"86cb10e059eedabf2ff000b977a2376a613dccfb092de6c243e0888db4c66a084124b2c1799bda" +
-"4bbb2f70fed0382fc1cbdafa6dc0f4baccdc2cee55234f8a5ad76645c315523fee5352d9f01036" +
-"e48b13e3")]
-namespace Blazored.SessionStorage.Serialization
+namespace Blazored.SessionStorage.Serialization;
+
+internal class SystemTextJsonSerializer : IJsonSerializer
{
- internal class SystemTextJsonSerializer : IJsonSerializer
+ private readonly JsonSerializerOptions _options;
+
+ public SystemTextJsonSerializer(IOptions options)
{
- private readonly JsonSerializerOptions _options;
+ _options = options.Value.JsonSerializerOptions;
+ }
- public SystemTextJsonSerializer(IOptions options)
- {
- _options = options.Value.JsonSerializerOptions;
- }
+ public SystemTextJsonSerializer(SessionStorageOptions sessionStorageOptions)
+ {
+ _options = sessionStorageOptions.JsonSerializerOptions;
+ }
- public T Deserialize(string data)
- => JsonSerializer.Deserialize(data, _options);
+ public T Deserialize(string data)
+ => JsonSerializer.Deserialize(data, _options);
- public string Serialize(T data)
- => JsonSerializer.Serialize(data, _options);
- }
-}
+ public string Serialize(T data)
+ => JsonSerializer.Serialize(data, _options);
+}
\ No newline at end of file
diff --git a/src/Blazored.SessionStorage/ServiceCollectionExtensions.cs b/src/Blazored.SessionStorage/ServiceCollectionExtensions.cs
index 9b1e2bf..795a92c 100644
--- a/src/Blazored.SessionStorage/ServiceCollectionExtensions.cs
+++ b/src/Blazored.SessionStorage/ServiceCollectionExtensions.cs
@@ -5,26 +5,54 @@
using Blazored.SessionStorage.StorageOptions;
using Microsoft.Extensions.DependencyInjection;
-namespace Blazored.SessionStorage
+namespace Blazored.SessionStorage;
+
+[ExcludeFromCodeCoverage]
+public static class ServiceCollectionExtensions
{
- [ExcludeFromCodeCoverage]
- public static class ServiceCollectionExtensions
- {
- public static IServiceCollection AddBlazoredSessionStorage(this IServiceCollection services)
- => AddBlazoredSessionStorage(services, null);
+ public static IServiceCollection AddBlazoredSessionStorage(this IServiceCollection services)
+ => AddBlazoredSessionStorage(services, null);
- public static IServiceCollection AddBlazoredSessionStorage(this IServiceCollection services, Action configure)
- {
- return services
- .AddScoped()
- .AddScoped()
- .AddScoped()
- .AddScoped()
- .Configure(configureOptions =>
- {
- configure?.Invoke(configureOptions);
- configureOptions.JsonSerializerOptions.Converters.Add(new TimespanJsonConverter());
- });
- }
+ public static IServiceCollection AddBlazoredSessionStorage(this IServiceCollection services, Action configure)
+ {
+ return services
+ .AddScoped()
+ .AddScoped()
+ .AddScoped()
+ .AddScoped()
+ .Configure(configureOptions =>
+ {
+ configure?.Invoke(configureOptions);
+ configureOptions.JsonSerializerOptions.Converters.Add(new TimespanJsonConverter());
+ });
+ }
+
+ ///
+ /// Registers the Blazored SessionStorage services as singletons. This should only be used in Blazor WebAssembly applications.
+ /// Using this in Blazor Server applications will cause unexpected and potentially dangerous behaviour.
+ ///
+ ///
+ public static IServiceCollection AddBlazoredSessionStorageAsSingleton(this IServiceCollection services)
+ => AddBlazoredSessionStorageAsSingleton(services, null);
+
+ ///
+ /// Registers the Blazored SessionStorage services as singletons. This should only be used in Blazor WebAssembly applications.
+ /// Using this in Blazor Server applications will cause unexpected and potentially dangerous behaviour.
+ ///
+ ///
+ ///
+ ///
+ public static IServiceCollection AddBlazoredSessionStorageAsSingleton(this IServiceCollection services, Action configure)
+ {
+ return services
+ .AddSingleton()
+ .AddSingleton()
+ .AddSingleton()
+ .AddSingleton()
+ .Configure(configureOptions =>
+ {
+ configure?.Invoke(configureOptions);
+ configureOptions.JsonSerializerOptions.Converters.Add(new TimespanJsonConverter());
+ });
}
}
diff --git a/src/Blazored.SessionStorage/SessionStorageService.cs b/src/Blazored.SessionStorage/SessionStorageService.cs
index 64434c3..c9b429d 100644
--- a/src/Blazored.SessionStorage/SessionStorageService.cs
+++ b/src/Blazored.SessionStorage/SessionStorageService.cs
@@ -1,268 +1,289 @@
using System;
+using System.Collections.Generic;
using System.Text.Json;
+using System.Threading;
using System.Threading.Tasks;
using Blazored.SessionStorage.Serialization;
-namespace Blazored.SessionStorage
+namespace Blazored.SessionStorage;
+
+internal class SessionStorageService : ISessionStorageService, ISyncSessionStorageService
{
- internal class SessionStorageService : ISessionStorageService, ISyncSessionStorageService
+ private readonly IStorageProvider _storageProvider;
+ private readonly IJsonSerializer _serializer;
+
+ public SessionStorageService(IStorageProvider storageProvider, IJsonSerializer serializer)
{
- private readonly IStorageProvider _storageProvider;
- private readonly IJsonSerializer _serializer;
+ _storageProvider = storageProvider;
+ _serializer = serializer;
+ }
- public SessionStorageService(IStorageProvider storageProvider, IJsonSerializer serializer)
- {
- _storageProvider = storageProvider;
- _serializer = serializer;
- }
+ public ValueTask RemoveItemsAsync(IEnumerable keys, CancellationToken cancellationToken = default)
+ => _storageProvider.RemoveItemsAsync(keys, cancellationToken);
- public async ValueTask SetItemAsync(string key, T data)
- {
- if (string.IsNullOrWhiteSpace(key))
- throw new ArgumentNullException(nameof(key));
+ public async ValueTask SetItemAsync(string key, T data, CancellationToken cancellationToken = default)
+ {
+ if (string.IsNullOrWhiteSpace(key))
+ throw new ArgumentNullException(nameof(key));
- var e = await RaiseOnChangingAsync(key, data).ConfigureAwait(false);
+ var e = await RaiseOnChangingAsync(key, data).ConfigureAwait(false);
- if (e.Cancel)
- return;
+ if (e.Cancel)
+ return;
- var serialisedData = _serializer.Serialize(data);
- await _storageProvider.SetItemAsync(key, serialisedData).ConfigureAwait(false);
+ var serialisedData = _serializer.Serialize(data);
+ await _storageProvider.SetItemAsync(key, serialisedData, cancellationToken).ConfigureAwait(false);
- RaiseOnChanged(key, e.OldValue, data);
- }
+ RaiseOnChanged(key, e.OldValue, data);
+ }
- public async ValueTask SetItemAsStringAsync(string key, string data)
- {
- if (string.IsNullOrWhiteSpace(key))
- throw new ArgumentNullException(nameof(key));
+ public async ValueTask SetItemAsStringAsync(string key, string data, CancellationToken cancellationToken = default)
+ {
+ if (string.IsNullOrWhiteSpace(key))
+ throw new ArgumentNullException(nameof(key));
- if (data is null)
- throw new ArgumentNullException(nameof(data));
+ if (data is null)
+ throw new ArgumentNullException(nameof(data));
- var e = await RaiseOnChangingAsync(key, data).ConfigureAwait(false);
+ var e = await RaiseOnChangingAsync(key, data).ConfigureAwait(false);
- if (e.Cancel)
- return;
+ if (e.Cancel)
+ return;
- await _storageProvider.SetItemAsync(key, data).ConfigureAwait(false);
+ await _storageProvider.SetItemAsync(key, data, cancellationToken).ConfigureAwait(false);
- RaiseOnChanged(key, e.OldValue, data);
- }
+ RaiseOnChanged(key, e.OldValue, data);
+ }
+
+ public async ValueTask GetItemAsync(string key, CancellationToken cancellationToken = default)
+ {
+ if (string.IsNullOrWhiteSpace(key))
+ throw new ArgumentNullException(nameof(key));
- public async ValueTask GetItemAsync(string key)
+ var serialisedData = await _storageProvider.GetItemAsync(key, cancellationToken).ConfigureAwait(false);
+
+ if (string.IsNullOrWhiteSpace(serialisedData))
+ return default;
+
+ try
{
- if (string.IsNullOrWhiteSpace(key))
- throw new ArgumentNullException(nameof(key));
-
- var serialisedData = await _storageProvider.GetItemAsync(key).ConfigureAwait(false);
-
- if (string.IsNullOrWhiteSpace(serialisedData))
- return default;
-
- try
- {
- return _serializer.Deserialize(serialisedData);
- }
- catch (JsonException e) when (e.Path == "$" && typeof(T) == typeof(string))
- {
- // For backward compatibility return the plain string.
- // On the next save a correct value will be stored and this Exception will not happen again, for this 'key'
- return (T)(object)serialisedData;
- }
+ return _serializer.Deserialize(serialisedData);
}
-
- public ValueTask GetItemAsStringAsync(string key)
+ catch (JsonException e) when (e.Path == "$" && typeof(T) == typeof(string))
{
- if (string.IsNullOrWhiteSpace(key))
- throw new ArgumentNullException(nameof(key));
-
- return _storageProvider.GetItemAsync(key);
+ // For backward compatibility return the plain string.
+ // On the next save a correct value will be stored and this Exception will not happen again, for this 'key'
+ return (T)(object)serialisedData;
}
+ }
- public ValueTask RemoveItemAsync(string key)
- {
- if (string.IsNullOrWhiteSpace(key))
- throw new ArgumentNullException(nameof(key));
+ public ValueTask GetItemAsStringAsync(string key, CancellationToken cancellationToken = default)
+ {
+ if (string.IsNullOrWhiteSpace(key))
+ throw new ArgumentNullException(nameof(key));
- return _storageProvider.RemoveItemAsync(key);
- }
+ return _storageProvider.GetItemAsync(key, cancellationToken);
+ }
- public ValueTask ClearAsync()
- => _storageProvider.ClearAsync();
+ public ValueTask RemoveItemAsync(string key, CancellationToken cancellationToken = default)
+ {
+ if (string.IsNullOrWhiteSpace(key))
+ throw new ArgumentNullException(nameof(key));
- public ValueTask LengthAsync()
- => _storageProvider.LengthAsync();
+ return _storageProvider.RemoveItemAsync(key, cancellationToken);
+ }
- public ValueTask KeyAsync(int index)
- => _storageProvider.KeyAsync(index);
+ public ValueTask ClearAsync(CancellationToken cancellationToken = default)
+ => _storageProvider.ClearAsync(cancellationToken);
- public ValueTask ContainKeyAsync(string key)
- => _storageProvider.ContainKeyAsync(key);
+ public ValueTask LengthAsync(CancellationToken cancellationToken = default)
+ => _storageProvider.LengthAsync(cancellationToken);
- public void SetItem(string key, T data)
- {
- if (string.IsNullOrWhiteSpace(key))
- throw new ArgumentNullException(nameof(key));
+ public ValueTask KeyAsync(int index, CancellationToken cancellationToken = default)
+ => _storageProvider.KeyAsync(index, cancellationToken);
- var e = RaiseOnChangingSync(key, data);
+ public ValueTask> KeysAsync(CancellationToken cancellationToken = default)
+ => _storageProvider.KeysAsync(cancellationToken);
- if (e.Cancel)
- return;
+ public ValueTask ContainKeyAsync(string key, CancellationToken cancellationToken = default)
+ => _storageProvider.ContainKeyAsync(key, cancellationToken);
- var serialisedData = _serializer.Serialize(data);
- _storageProvider.SetItem(key, serialisedData);
+ public void SetItem(string key, T data)
+ {
+ if (string.IsNullOrWhiteSpace(key))
+ throw new ArgumentNullException(nameof(key));
- RaiseOnChanged(key, e.OldValue, data);
- }
+ var e = RaiseOnChangingSync(key, data);
- public void SetItemAsString(string key, string data)
- {
- if (string.IsNullOrWhiteSpace(key))
- throw new ArgumentNullException(nameof(key));
+ if (e.Cancel)
+ return;
- if (data is null)
- throw new ArgumentNullException(nameof(data));
+ var serialisedData = _serializer.Serialize(data);
+ _storageProvider.SetItem(key, serialisedData);
- var e = RaiseOnChangingSync(key, data);
+ RaiseOnChanged(key, e.OldValue, data);
+ }
- if (e.Cancel)
- return;
+ public void SetItemAsString(string key, string data)
+ {
+ if (string.IsNullOrWhiteSpace(key))
+ throw new ArgumentNullException(nameof(key));
- _storageProvider.SetItem(key, data);
+ if (data is null)
+ throw new ArgumentNullException(nameof(data));
- RaiseOnChanged(key, e.OldValue, data);
- }
+ var e = RaiseOnChangingSync(key, data);
+
+ if (e.Cancel)
+ return;
+
+ _storageProvider.SetItem(key, data);
+
+ RaiseOnChanged(key, e.OldValue, data);
+ }
+
+ public T GetItem(string key)
+ {
+ if (string.IsNullOrWhiteSpace(key))
+ throw new ArgumentNullException(nameof(key));
- public T GetItem(string key)
+ var serialisedData = _storageProvider.GetItem(key);
+
+ if (string.IsNullOrWhiteSpace(serialisedData))
+ return default;
+
+ try
{
- if (string.IsNullOrWhiteSpace(key))
- throw new ArgumentNullException(nameof(key));
-
- var serialisedData = _storageProvider.GetItem(key);
-
- if (string.IsNullOrWhiteSpace(serialisedData))
- return default;
-
- try
- {
- return _serializer.Deserialize(serialisedData);
- }
- catch (JsonException e) when (e.Path == "$" && typeof(T) == typeof(string))
- {
- // For backward compatibility return the plain string.
- // On the next save a correct value will be stored and this Exception will not happen again, for this 'key'
- return (T)(object)serialisedData;
- }
+ return _serializer.Deserialize(serialisedData);
}
-
- public string GetItemAsString(string key)
+ catch (JsonException e) when (e.Path == "$" && typeof(T) == typeof(string))
{
- if (string.IsNullOrWhiteSpace(key))
- throw new ArgumentNullException(nameof(key));
-
- return _storageProvider.GetItem(key);
+ // For backward compatibility return the plain string.
+ // On the next save a correct value will be stored and this Exception will not happen again, for this 'key'
+ return (T)(object)serialisedData;
}
+ }
- public void RemoveItem(string key)
- {
- if (string.IsNullOrWhiteSpace(key))
- throw new ArgumentNullException(nameof(key));
+ public string GetItemAsString(string key)
+ {
+ if (string.IsNullOrWhiteSpace(key))
+ throw new ArgumentNullException(nameof(key));
+ return _storageProvider.GetItem(key);
+ }
+
+ public void RemoveItem(string key)
+ {
+ if (string.IsNullOrWhiteSpace(key))
+ throw new ArgumentNullException(nameof(key));
+
+ _storageProvider.RemoveItem(key);
+ }
+
+ public void RemoveItems(IEnumerable keys)
+ {
+ if (keys == null)
+ throw new ArgumentNullException(nameof(keys));
+
+ foreach (var key in keys)
+ {
_storageProvider.RemoveItem(key);
}
+ }
- public void Clear()
- => _storageProvider.Clear();
+ public void Clear()
+ => _storageProvider.Clear();
- public int Length()
- => _storageProvider.Length();
+ public int Length()
+ => _storageProvider.Length();
- public string Key(int index)
- => _storageProvider.Key(index);
+ public string Key(int index)
+ => _storageProvider.Key(index);
+
+ public IEnumerable Keys()
+ => _storageProvider.Keys();
- public bool ContainKey(string key)
- => _storageProvider.ContainKey(key);
+ public bool ContainKey(string key)
+ => _storageProvider.ContainKey(key);
- public event EventHandler Changing;
- private async Task RaiseOnChangingAsync(string key, object data)
+ public event EventHandler Changing;
+ private async Task RaiseOnChangingAsync(string key, object data)
+ {
+ var e = new ChangingEventArgs
{
- var e = new ChangingEventArgs
- {
- Key = key,
- OldValue = await GetItemInternalAsync