Skip to content

Commit

Permalink
Merge pull request #18 from jan-johansson-mr/add-config
Browse files Browse the repository at this point in the history
Added the same configuration option as is in LocalStorage
  • Loading branch information
chrissainty authored May 22, 2020
2 parents 9e9f4fc + 56fba9a commit 5df4dbb
Show file tree
Hide file tree
Showing 8 changed files with 169 additions and 34 deletions.
56 changes: 50 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ A library to provide access to session storage in Blazor applications

[![Build Status](https://dev.azure.com/blazored/SessionStorage/_apis/build/status/Blazored.SessionStorage?branchName=master)](https://dev.azure.com/blazored/SessionStorage/_build/latest?definitionId=1&branchName=master)

![Nuget](https://img.shields.io/nuget/v/blazored.sessionstorage.svg)
[![Nuget](https://img.shields.io/nuget/v/blazored.sessionstorage.svg)](https://www.nuget.org/packages/Blazored.SessionStorage/)

### Installing

You can install from NuGet using the following command:

`Install-Package Blazored.SessionStorage`

Or via the Visual Studio package manger.
Or via the Visual Studio package manager.

### Setup

You will need to register the session storage services with the service collection in your _startup.cs_ file.
You will need to register the session storage services with the service collection in your _Startup.cs_ file in Blazor Server.

```c#
public void ConfigureServices(IServiceCollection services)
Expand All @@ -24,6 +24,47 @@ public void ConfigureServices(IServiceCollection services)
}
```

Or in your _Program.cs_ file in Blazor WebAssembly.

```c#
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");

builder.Services.AddBlazoredSessionStorage();

await builder.Build().RunAsync();
}
```

### Configuration

The session storage provides options that can be modified by you at registration in your _Startup.cs_ file in Blazor Server.


```c#
public void ConfigureServices(IServiceCollection services)
{
services.AddBlazoredSessionStorage(config =>
config.JsonSerializerOptions.WriteIndented = true);
}
```
Or in your _Program.cs_ file in Blazor WebAssembly.

```c#
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");

builder.Services.AddBlazoredSessionStorage(config =>
config.JsonSerializerOptions.WriteIndented = true);

await builder.Build().RunAsync();
}
```

### Usage (Blazor WebAssembly)
To use Blazored.SessionStorage in Blazor WebAssembly, inject the `ISessionStorageService` per the example below.

Expand Down Expand Up @@ -64,9 +105,9 @@ With Blazor WebAssembly you also have the option of a synchronous API, if your u
```c#
@inject Blazored.SessionStorage.ISessionStorageService sessionStorage

@functions {
@code {

protected override async Task OnAfterRenderAsync()
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await sessionStorage.SetItemAsync("name", "John Smith");
var name = await sessionStorage.GetItemAsync<string>("name");
Expand All @@ -84,12 +125,15 @@ The APIs available are:
- ClearAsync()
- LengthAsync()
- KeyAsync()
- synchronous via `ISyncSessionStorageService`:
- ContainsKeyAsync()

- synchronous via `ISyncSessionStorageService` (Synchronous methods are **only** available in Blazor WebAssembly):
- SetItem()
- GetItem()
- RemoveItem()
- Clear()
- Length()
- Key()
- ContainsKey()

**Note:** Blazored.SessionStorage methods will handle the serialisation and de-serialisation of the data for you.
7 changes: 3 additions & 4 deletions src/Blazored.SessionStorage/Blazored.SessionStorage.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
<TargetFramework>netstandard2.0</TargetFramework>
<RazorLangVersion>3.0</RazorLangVersion>
<RootNamespace>Blazored.SessionStorage</RootNamespace>
<TypeScriptToolsVersion>3.2</TypeScriptToolsVersion>

<PackageId>Blazored.SessionStorage</PackageId>
<Version>1.0.11</Version>
Expand All @@ -18,10 +17,10 @@
<PackageTags>Blazor SessionStorage Blazored Razor Components</PackageTags>
<Company />
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components" Version="3.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="3.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components" Version="3.1.4" />
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="3.1.4" />
</ItemGroup>

</Project>
2 changes: 1 addition & 1 deletion src/Blazored.SessionStorage/ISessionStorageService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public interface ISessionStorageService

Task RemoveItemAsync(string key);

Task SetItemAsync(string key, object data);
Task SetItemAsync<T>(string key, T data);

event EventHandler<ChangingEventArgs> Changing;
event EventHandler<ChangedEventArgs> Changed;
Expand Down
2 changes: 1 addition & 1 deletion src/Blazored.SessionStorage/ISyncSessionStorageService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public interface ISyncSessionStorageService

void RemoveItem(string key);

void SetItem(string key, object data);
void SetItem<T>(string key, T data);

event EventHandler<ChangingEventArgs> Changing;
event EventHandler<ChangedEventArgs> Changed;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;

namespace Blazored.SessionStorage.JsonConverters
{
/// <summary>
/// The new Json.NET doesn't support Timespan at this time
/// https://github.com/dotnet/corefx/issues/38641
/// </summary>
public class TimespanJsonConverter : JsonConverter<TimeSpan>
{
/// <summary>
/// Format: Days.Hours:Minutes:Seconds:Milliseconds
/// </summary>
public const string TimeSpanFormatString = @"d\.hh\:mm\:ss\:FFF";

public override TimeSpan Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var s = reader.GetString();
if (string.IsNullOrWhiteSpace(s))
{
return TimeSpan.Zero;
}
else
{
TimeSpan parsedTimeSpan;
if (!TimeSpan.TryParseExact(s, TimeSpanFormatString, null, out 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.");
}
else
{
return parsedTimeSpan;
}
}
}

public override void Write(Utf8JsonWriter writer, TimeSpan value, JsonSerializerOptions options)
{
var timespanFormatted = $"{value.ToString(TimeSpanFormatString)}";
writer.WriteStringValue(timespanFormatted);
}
}
}
23 changes: 21 additions & 2 deletions src/Blazored.SessionStorage/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using Blazored.SessionStorage.JsonConverters;
using Blazored.SessionStorage.StorageOptions;
using Microsoft.Extensions.DependencyInjection;

namespace Blazored.SessionStorage
{
Expand All @@ -8,7 +11,23 @@ public static IServiceCollection AddBlazoredSessionStorage(this IServiceCollecti
{
return services
.AddScoped<ISessionStorageService, SessionStorageService>()
.AddScoped<ISyncSessionStorageService, SessionStorageService>();
.AddScoped<ISyncSessionStorageService, SessionStorageService>()
.Configure<SessionStorageOptions>(configureOptions =>
{
configureOptions.JsonSerializerOptions.Converters.Add(new TimespanJsonConverter());
});
}

public static IServiceCollection AddBlazoredSessionStorage(this IServiceCollection services, Action<SessionStorageOptions> configure)
{
return services
.AddScoped<ISessionStorageService, SessionStorageService>()
.AddScoped<ISyncSessionStorageService, SessionStorageService>()
.Configure<SessionStorageOptions>(configureOptions =>
{
configure?.Invoke(configureOptions);
configureOptions.JsonSerializerOptions.Converters.Add(new TimespanJsonConverter());
});
}
}
}
49 changes: 29 additions & 20 deletions src/Blazored.SessionStorage/SessionStorageService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Microsoft.JSInterop;
using Blazored.SessionStorage.StorageOptions;
using Microsoft.Extensions.Options;
using Microsoft.JSInterop;
using System;
using System.Text.Json;
using System.Threading.Tasks;
Expand All @@ -9,24 +11,31 @@ public class SessionStorageService : ISessionStorageService, ISyncSessionStorage
{
private readonly IJSRuntime _jSRuntime;
private readonly IJSInProcessRuntime _jSInProcessRuntime;
private readonly JsonSerializerOptions _jsonOptions;

public SessionStorageService(IJSRuntime jSRuntime)
public event EventHandler<ChangingEventArgs> Changing;
public event EventHandler<ChangedEventArgs> Changed;

public SessionStorageService(IJSRuntime jSRuntime, IOptions<SessionStorageOptions> options)
{
_jSRuntime = jSRuntime;
_jSInProcessRuntime = jSRuntime as IJSInProcessRuntime;
_jSRuntime = jSRuntime;
_jsonOptions = options.Value.JsonSerializerOptions;
_jSInProcessRuntime = jSRuntime as IJSInProcessRuntime;
}

public async Task SetItemAsync(string key, object data)
public async Task SetItemAsync<T>(string key, T data)
{
if (string.IsNullOrEmpty(key))
throw new ArgumentNullException(nameof(key));

var e = await RaiseOnChangingAsync(key, data);

if (e.Cancel)
return;

await _jSRuntime.InvokeAsync<object>("sessionStorage.setItem", key, JsonSerializer.Serialize(data));
return;

var serialisedData = JsonSerializer.Serialize(data, _jsonOptions);

await _jSRuntime.InvokeVoidAsync("sessionStorage.setItem", key, serialisedData);

RaiseOnChanged(key, e.OldValue, data);
}
Expand All @@ -39,9 +48,9 @@ public async Task<T> GetItemAsync<T>(string key)
var serialisedData = await _jSRuntime.InvokeAsync<string>("sessionStorage.getItem", key);

if (serialisedData == null)
return default(T);

return JsonSerializer.Deserialize<T>(serialisedData);
return default;

return JsonSerializer.Deserialize<T>(serialisedData, _jsonOptions);
}

public async Task RemoveItemAsync(string key)
Expand All @@ -58,7 +67,7 @@ public async Task RemoveItemAsync(string key)

public async Task<string> KeyAsync(int index) => await _jSRuntime.InvokeAsync<string>("sessionStorage.key", index);

public void SetItem(string key, object data)
public void SetItem<T>(string key, T data)
{
if (string.IsNullOrEmpty(key))
throw new ArgumentNullException(nameof(key));
Expand All @@ -71,7 +80,9 @@ public void SetItem(string key, object data)
if (e.Cancel)
return;

_jSInProcessRuntime.Invoke<object>("sessionStorage.setItem", key, JsonSerializer.Serialize(data));
var serialisedData = JsonSerializer.Serialize(data, _jsonOptions);

_jSInProcessRuntime.InvokeVoid("sessionStorage.setItem", key, serialisedData);

RaiseOnChanged(key, e.OldValue, data);
}
Expand All @@ -87,9 +98,9 @@ public T GetItem<T>(string key)
var serialisedData = _jSInProcessRuntime.Invoke<string>("sessionStorage.getItem", key);

if (serialisedData == null)
return default(T);

return JsonSerializer.Deserialize<T>(serialisedData);
return default;

return JsonSerializer.Deserialize<T>(serialisedData, _jsonOptions);
}

public void RemoveItem(string key)
Expand All @@ -100,15 +111,15 @@ public void RemoveItem(string key)
if (_jSInProcessRuntime == null)
throw new InvalidOperationException("IJSInProcessRuntime not available");

_jSInProcessRuntime.Invoke<object>("sessionStorage.removeItem", key);
_jSInProcessRuntime.InvokeVoid("sessionStorage.removeItem", key);
}

public void Clear()
{
if (_jSInProcessRuntime == null)
throw new InvalidOperationException("IJSInProcessRuntime not available");

_jSInProcessRuntime.Invoke<object>("sessionStorage.clear");
_jSInProcessRuntime.InvokeVoid("sessionStorage.clear");
}

public int Length()
Expand All @@ -127,7 +138,6 @@ public string Key(int index)
return _jSInProcessRuntime.Invoke<string>("sessionStorage.key", index);
}

public event EventHandler<ChangingEventArgs> Changing;
private async Task<ChangingEventArgs> RaiseOnChangingAsync(string key, object data)
{
var e = new ChangingEventArgs
Expand Down Expand Up @@ -156,7 +166,6 @@ private ChangingEventArgs RaiseOnChangingSync(string key, object data)
return e;
}

public event EventHandler<ChangedEventArgs> Changed;
private void RaiseOnChanged(string key, object oldValue, object data)
{
var e = new ChangedEventArgs
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Text.Json;

namespace Blazored.SessionStorage.StorageOptions
{
public class SessionStorageOptions
{
public JsonSerializerOptions JsonSerializerOptions { get; } = new JsonSerializerOptions
{
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
IgnoreNullValues = true,
IgnoreReadOnlyProperties = true,
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
ReadCommentHandling = JsonCommentHandling.Skip,
WriteIndented = false
};
}
}

0 comments on commit 5df4dbb

Please sign in to comment.