GithubHelp home page GithubHelp logo

blazored / sessionstorage Goto Github PK

View Code? Open in Web Editor NEW
388.0 10.0 40.0 7.37 MB

A library to provide access to session storage in Blazor applications

Home Page: https://blazored.github.io/SessionStorage/

License: MIT License

C# 100.00%
blazor blazored sessionstorage csharp blazor-interop blazor-webassembly blazor-server blazor-applications nuget browser-storage hacktoberfest

sessionstorage's Introduction

Nuget version Nuget downloads Build & Test Main

Blazored SessionStorage

Blazored SessionStorage is a library that provides access to the browsers session storage APIs for Blazor applications. An additional benefit of using this library is that it will handle serializing and deserializing values when saving or retrieving them.

Breaking Change (v1 > v2)

JsonSerializerOptions

From v4 onwards we use the default the JsonSerializerOptions for System.Text.Json instead of using custom ones. This will cause values saved to session storage with v3 to break things. To retain the old settings use the following configuration when adding Blazored SessionStorage to the DI container:

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 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

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):

<PackageReference Include="Blazored.SessionStorage" Version="x.x.x" />

You can also install via the .NET CLI with the following command:

dotnet add package Blazored.SessionStorage

If you're using Jetbrains Rider or Visual Studio you can also install via the built in NuGet package manager.

Setup

You will need to register the session storage services with the service collection in your Startup.cs file in Blazor Server.

public void ConfigureServices(IServiceCollection services)
{
    services.AddBlazoredSessionStorage();
}

Or in your Program.cs file in Blazor WebAssembly.

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

    builder.Services.AddBlazoredSessionStorage();

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

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:

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.

@inject Blazored.SessionStorage.ISessionStorageService sessionStorage

@code {

    protected override async Task OnInitializedAsync()
    {
        await sessionStorage.SetItemAsync("name", "John Smith");
        var name = await sessionStorage.GetItemAsync<string>("name");
    }

}

With Blazor WebAssembly you also have the option of a synchronous API, if your use case requires it. You can swap the ISessionStorageService for ISyncSessionStorageService which allows you to avoid use of async/await. For either interface, the method names are the same.

@inject Blazored.SessionStorage.ISyncSessionStorageService sessionStorage

@code {

    protected override void OnInitialized()
    {
        sessionStorage.SetItem("name", "John Smith");
        var name = sessionStorage.GetItem<string>("name");
    }

}

Usage (Blazor Server)

NOTE: Due to pre-rendering in Blazor Server you can't perform any JS interop until the OnAfterRender lifecycle method.

@inject Blazored.SessionStorage.ISessionStorageService sessionStorage

@code {

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await sessionStorage.SetItemAsync("name", "John Smith");
        var name = await sessionStorage.GetItemAsync<string>("name");
    }

}

The APIs available are:

  • asynchronous via ISessionStorageService:

    • SetItemAsync()
    • SetItemAsStringAsync()
    • GetItemAsync()
    • GetItemAsStringAsync()
    • RemoveItemAsync()
    • RemoveItemsAsync()
    • ClearAsync()
    • LengthAsync()
    • KeyAsync()
    • KeysAsync()
    • ContainKeyAsync()
  • synchronous via ISyncSessionStorageService (Synchronous methods are only available in Blazor WebAssembly):

    • SetItem()
    • SetItemAsString()
    • 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.

Configuring JSON Serializer Options

You can configure the options for the default serializer (System.Text.Json) when calling the AddBlazoredSessionStorage method to register services.

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();
}

Using a custom JSON serializer

By default, the library uses System.Text.Json. If you prefer to use a different JSON library for serialization--or if you want to add some custom logic when serializing or deserializing--you can provide your own serializer which implements the Blazored.SessionStorage.Serialization.IJsonSerializer interface.

To register your own serializer in place of the default one, you can do the following:

builder.Services.AddBlazoredSessionStorage();
builder.Services.Replace(ServiceDescriptor.Scoped<IJsonSerializer, MySerializer>());

You can find an example of this in the Blazor Server sample project. The standard serializer has been replaced with a new serializer which uses NewtonsoftJson.

Testing with bUnit

This library provides test extensions for use with the bUnit testing library. 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):

<PackageReference Include="Blazored.SessionStorage.TestExtensions" Version="x.x.x" />

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.

public class IndexPageTests : TestContext
{
    [Fact]
    public async Task SavesNameToSessionStorage()
    {
        // Arrange
        const string inputName = "John Smith";
        var sessionStorage = this.AddBlazoredSessionStorage();
        var cut = RenderComponent<BlazorWebAssembly.Pages.Index>();

        // Act
        cut.Find("#Name").Change(inputName);
        cut.Find("#NameButton").Click();
            
        // Assert
        var name = await sessionStorage.GetItemAsync<string>("name");
            
        Assert.Equal(inputName, name);
    }
}

sessionstorage's People

Contributors

baywet avatar chrissainty avatar daghb avatar dependabot[bot] avatar drma-tech avatar jan-johansson-mr avatar kim-ssi avatar q-sharp avatar rf-0 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sessionstorage's Issues

[Question] Session per browser

Please be sure to check the readme file before raising an issue.
Hi, i am currently experiencing issue regarding the session where when i login in mozilla and then i will login other account in the google chrome when i refresh my mozilla browser it show the account that i login in the chrome browser

here is my code
image

[Bug] Miss ContainKeyAsync

Describe the bug
Miss the Method ContainKeyAsync , in documentation is present but not in the code

Hosting Model (is this issue happening with a certain hosting model?):

  • Blazor Server

[Question] Serialize internal properties?

Hello,

I have a plain class

internal class NavigationStore
	{
		public string Page { get; set; }

		public string Route { get; set; }

		public object[] Parameters { get; set; }
	}

which is serialized in SessionStorage.
If I change modifier type from public to internal for properties, the properties are not serialized anymore.
Not sure if this behavior could be changed or even should be changed; is just a question.

Thanks,
Ion

[Question] Getting error when storing complex object

I'm attempting to store a complex object (EF Core entity) that has navigation properties which refer back to the parent entity. I've added a [JsonIgnore] attribute to my entities and my default JsonSerializerSettings ReferenceLoopHandling property is set to ReferenceLoopHandling.Ignore, but I continue to get the error:

Error: System.Text.Json.JsonException: A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 64. Consider using ReferenceHandler.Preserve on JsonSerializerOptions to support cycles.

I feel like I must be missing something, but I'm not sure what. Any ideas?

[Question] Error: The circuit has closed due to an error.

So, I have been using this package without issue. In a component I have designed I am calling SetItemAsync in the dispose method so that when it comes up on another page I can restore the state. I have suddenly noticed that this no longer seems to work. In particular, when I refresh the page with the component, I see the above error.
I'm using this with Blazor server with .net core 3.1. Has something recently changed that would break this?

How to handle on Page Refresh.

Like I have a login page and , from login success authentication i need to land on homepage with the session id.

Is it internally using browser's localstorage?

Thanks

unable to display the value of session storage in the example

<span>@Name</span>

@code { 
    public string Name { get; set; } 
    protected override async Task OnAfterRenderAsync()
    {
        await sessionStorage.SetItemAsync("name", "John Smith");
        var name = await sessionStorage.GetItemAsync<string>("name");
        Name = name;
    }
}

From this example, there is no way Name variable. When debugging you will see the value been set but the UI is not been updated. It's a serverside blazor application

[Question] Is it possible to store complex objects or just strings?

Specifically I am trying to store a WindowsIdentity.AccessToken.

Here is my _Host.cshtml.cs file

public class HostAuthenticationModel : PageModel
{
    public async Task<IActionResult> OnGet()
    {
        if (User.Identity.IsAuthenticated)
        {
            var windowsIdentity = (WindowsIdentity)User.Identity;
            AccessToken = windowsIdentity.AccessToken;
        }
        return Page();
    }

    public SafeAccessTokenHandle AccessToken { get; set; }
}

Here is my app.razor file

    [Parameter]
    public Microsoft.Win32.SafeHandles.SafeAccessTokenHandle AccessToken { get; set; }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            // Persist the AccessToken to local storage
            await sessionStorage.SetItemAsync("win_access_token", AccessToken);
        }
    }

And here I try to retrieve it in a razor component: var accessToken = await sessionStorage.GetItemAsync<Microsoft.Win32.SafeHandles.SafeAccessTokenHandle>("win_access_token");

I successfully retrieve the token, but its properties are not the same as when I stored them. Is something not surviving the serialization process?

Typo In README.md

Just a minor issue but in the Usage (Blazor WebAssembly) synchronous example.

The interface name is incorrect. ISyncStorageService is used but the actual interface name is ISyncSessionStorageService

Once I got over that it seems to be working great for me.

[Bug] SessionStorage Value Not Persisting on Page Refresh

Describe the bug
I am not able to persist values to the session storage in a WASM project when the user reloads the page.

To Reproduce
Steps to reproduce the behavior:

  1. Create a Blazor WASM app.
  2. Allow the page to load and observe the values in the code below.
  3. Once the page has loaded, hit the Chrome Reload button.
  4. Allow the page to load and observe the values in the code below.
[Inject]
    private Blazored.SessionStorage.ISessionStorageService SessionStorage { get; set; }

    public class TestSession {
        public int ID { get; set; }
    }

    protected override async Task OnInitializedAsync() {
        await base.OnInitializedAsync();
    
        const string Key = "__OnInitializedAsync";
        try {
            var state = await this.SessionStorage.GetItemAsync<TestSession?>(Key);
            var keys = await this.SessionStorage.KeysAsync();
            if (state == null) {
                TestSession value = new() {
                    ID = 100
                };
                await this.SessionStorage.SetItemAsync(Key, value);
            }
            state = await this.SessionStorage.GetItemAsync<TestSession?>(Key);
            Console.WriteLine(state);
        }
        catch (Exception ex) {
            Console.WriteLine(ex);
        }
    }
    
    protected override async Task OnAfterRenderAsync(bool firstRender) {
        await base.OnAfterRenderAsync(firstRender);
        
        if (!firstRender)
            return;
        
        const string Key = "__OnAfterRenderAsync";
        try {
            var state = await this.SessionStorage.GetItemAsync<TestSession?>(Key);
            var keys = await this.SessionStorage.KeysAsync();
            if (state == null) {
                TestSession value = new() {
                    ID = 300
                };
                await this.SessionStorage.SetItemAsync(Key, value);
            }
            state = await this.SessionStorage.GetItemAsync<TestSession?>(Key);
            Console.WriteLine(state);
        }
        catch (Exception ex) {
            Console.WriteLine(ex);
        }
    }

Expected behavior
During step 4, I would expect the TestPerson object to be persisted on both AfterRender and OnInitialized; however, they are not available.

Screenshots

Hosting Model (is this issue happening with a certain hosting model?):
Blazor WebAssembly package versions 7.0.5
Chrome version 116

Additional context
I am using the AddBlazoredSessionStorage() call.

"Duplicate Tab" issue.

I'd like an option/feature where, if the user selects "Duplicate Tab" in the browser, I can detect it that the session storage contents have been duplicated.

[Bug] Cannot use library with .NET 5 RC1

I am currently testing .NET 5.0 RC1. Unfortunately I had to find out that this library is not compatible with <TargetFramework>net5.0</TargetFramework>. Could you create a pre-release that is compatible? Thanks ๐Ÿ™‚

Session ID

Please be sure to check the readme file before raising an issue.
Does your component expose the Session ID?

I am converting an old .Net Framework app to Blazor Server .Net 6. There is some code that has to keep track of the Session ID as a lookup value to a SQL table. I would prefer to not have to rewrite this code as it is a bit of a kludge anyway. but the functionality was a must have for the client.

Essentially allows an admin to "impersonate" a regular user to assist with questions about their benefits etc. The admin gets to see what the regular user sees. Session ID is used to keep track of whether a use is being impersonated or not, and helps to restore everything when impersonation ends. That is the abridged version. It is way more complex, business rule wise.

Anyway, any help would be appreciated.

Thanks

Mark

blazored.sessionstorage is missing NuGet package README file

We've noticed that your package on NuGet.org is missing a README file.

Why READMEs are Important

A README is essential for users to understand your package's purpose and functionality quickly. It's the first thing users see on NuGet.org and helps them decide if your package meets their needs.

Get Started with READMEs

How to Add a README

If you're new to NuGet READMEs, follow guidance on how to add one to your package.

How to write high quality of READMEs

Follow a blog post with README best practices and a template file to help you get started.

We Value Your Feedback

We value your feedback. If you encounter any issues or have suggestions, please reply to this issue.

Thank you for your contribution to the NuGet community.

How to check the session is null or not

How do i check the session is null or not.
like
int customerid;
if(sessionstorage.GetItemAsync("CustomerID") == null)
{
nm.Navigate("/login");
}
else
{
customerid = sessionstorage.GetItemAsync("CustomerID");
}

this is not working. is there any problem? please help me.

Blazored session storage to work for objects.

Storing an object works just fine

Getting that object and deserializing it breaks
.
Person person = await sessionStorage.GetItemAsync("People");

I think this is related to another contributor mentioning system.text.json and the inherent issues with that dependency.

Just need a way to store objects in blazor for the entire session.

Using a singleton wont work obviously.

Using a scoped class seems to work until the class is injected on another page, and starts fresh again... ughhh

Is this a good use library to store the JWT and deal with AuthenticationStateProvider?

Using this kind of storage from a normal desktop/mobile browser keeps the storage and the session without any issue but as soon I Install it both on android and desktop every time that I open the app it seems like the session storage is gone, redirecting the user to the login page.
So I was wondering, am I using it right or there's something missing that I don't do to stop the installed version from losing the session storage?

[Bug] System.Text.Json v4.0.1.2 is not available on NuGet.org

Describe the bug
A blazor server-side project using the library will throw the following error because System.Text.Json Version=4.0.1.2 is not available on Nuget.org

FileLoadException: Could not load file or assembly 'System.Text.Json, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The located assembly's manifest definition does not match the assembly reference. (0x80131040)

Screenshot
image

To Reproduce

  • Install package
  • Make any call to it
  • Start project
  • Exception is thrown

Hosting Model (is this issue happening with a certain hosting model?):
Blazor Server

Additional context
Add any other context about the problem here.

Could the dependency on bUnit.Core be removed?

I've just found that our app is shipping bUnit.Core and on inspection, tracked it down to Blazored.SessionStorage.

Could this be removed from the production code perhaps?

You could still have a TestContentBase extension method in the Tests project, but it could create a ServiceCollection, call the production AddBlazoredSessionStorage to register all the DI (as it would in a production app) and then copy all the registrations over to the TestContext (switching out the IStorageProvider). That way you wouldn't need the duplicate DI registrations too!

Update documentation on Usage (Blazor Server)

This is just a comment that if you set the Blazor app render-mode to server, you do not need to wait for OnAfterRenderAsync. You can inject and use session storage on OnInitializedAsync or some other handler.
<app><component type="typeof(App)" render-mode="Server" /></app>

To provide option to use custom json serialize like newtonsoft

The system.text.json is not able to serialize many types where they are nested, atleast in my case. But newtonsoft json is able to serialize.

It would be great if there is an option to choose between Microsoft provided one and custom provider like newtonsoft.

Below is my middleware like implementation:

    public class BlazoredConverter
    {
        Blazored.SessionStorage.ISessionStorageService _sessionStorageService;
        public BlazoredConverter(Blazored.SessionStorage.ISessionStorageService sessionStorageService)
        {
            _sessionStorageService = sessionStorageService;
        }


        public async Task<T> Get<T>(string fetchForKey)
        {
            var t = await _sessionStorageService.GetItemAsync<string>(fetchForKey);
            if (t != null)
            {
                return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(t);
            }
            else { return default(T); }
        }

        public async Task<bool> Set<T>(string keyname, T TValue)
        {
            try
            {
                string r = Newtonsoft.Json.JsonConvert.SerializeObject(TValue);
                await _sessionStorageService.SetItemAsync<string>(keyname, r);
                return await Task.FromResult(true);
            }
            catch (Exception)
            {
                return await Task.FromResult(false);
            }
        }
    }

[Bug]GetItemAsync and SetItemAsync throw System.Threading.Tasks.TaskCanceledException: 'A task was canceled.'

In my new app, I'm trying to use SessionStorage to store larger graphs of objects (a few hundreds).

However, I often get 'A task was canceled' from GetItemAsync and SetItemAsync. Also, Blazor shows the message "Attempting to reconnect to server" both when doing local debugging and when deployed to an IIS server.

What is the performance of SessionStorage when storing and retrieving 100s of objects? Is it advisable to do so?

Hosting Model:

  • Blazor Server

[Question] Does accessing session storage work in `OnInitializedAsync` with render mode `Server(prerender=false)`?

I read through the documentation, where you say:

NOTE: Due to pre-rendering in Blazor Server you can't perform any JS interop until the OnAfterRender lifecycle method.

Now, I really don't like that because in my app I often have to do query data based on stuff in session storage (e.g. currently selected patient). Only being able to decide which patient I want to query data for in OnAfterRenderAsync would make my app slow, because just after rendering I would load data in that changes everything again.

Since I don't prerender, I thought I'd try to access session storage in OnInitializedAsync, which ... actually worked. Is this just a fluke or can I access session (and in extension local) storage in OnInitializedAsync when I don't prerender?

Thank you for the great library!
luetm

[Bug]Different Blazor Server apps on same web server can share session values

We have a strange bug where 2 different Blazor Server apps on the same web server can apparently access each other's session values.

The two apps each have their own application pool on the server.

The apps (A + B) share some session property names like "ProgramVersion" and "ResponsibleDeveloper" and it looks like they can get mixed up so A can show B's ProgramVersion and vice versa.

How could this be possible?

The two apps structured similarly, with a component that handles all session functionality. Some code is included below.

// abstract class shared by the two apps
public abstract class SessionStorageModelBase : ComponentBase
    {
        protected bool hasLoaded { get; private set; }

        [Inject]
        protected ISessionStorageService sessionStorage { get; set; }

        //
        // Summary:
        //     Multicast event for property change notifications.
        public event PropertyChangedEventHandler? PropertyChanged;

        public async Task PersistValue<T>(string propertyName, T value)
        {
            await sessionStorage.SetItemAsync(propertyName, value);
        }

        protected override async Task OnInitializedAsync()
        {
            await ReloadPropertyValuesFromSessionAsync();
            hasLoaded = true;
        }

        protected virtual Task ReloadPropertyValuesFromSessionAsync()
        {
            return Task.FromResult<object>(null);
        }

        // Summary:
        //     Stores the value in the session storage also.
        //
        // Parameters:
        //   setValue:
        //
        //   storage:
        //
        //   value:
        //
        //   propertyName:
        //
        // Type parameters:
        //   T:
        protected async Task<bool> SetProperty<T>(Action<T> setValue, T storage, T value, [CallerMemberName] string? propertyName = null)
        {
            if (object.Equals(storage, value))
            {
                return false;
            }

            setValue(value);
           
            await sessionStorage.SetItemAsync(propertyName, value);
           
            NotifyPropertyChanged(propertyName);
            return true;
        }
}

// Each app has their own inherited class:

public partial class MainModelComponent : SessionStorageModelBase
    {
        private string? version;

/// <summary>
        /// Public setter methods that takes care of storing in Session Storage, and also invokes PropertyChanged which can be caught by the active Blazor components to trigger re-rendering.
        /// </summary>
        /// <param name="val"></param>
        /// <returns></returns>
        public async Task SetProgramVersion(string? val)
        {
            await this.SetProperty((v) => this.version = v, this.version, val, nameof(this.ProgramVersion));
        }

        public string? ProgramVersion
        {
            get
            {
                return this.version;
            }

            private set
            {
                this.SetProperty(ref this.version, value);
            }
        }

protected override async Task ReloadPropertyValuesFromSessionAsync()
{
    // Here we (re-)load the session storage values.
    // This happens many times during a user session.
    // Is always called on browser refresh - maybe also on postback? Not during normal naviagtion and button clicks...
    // Remember to add any new persisted properties here.
    this.ProgramVersion = await this.sessionStorage.GetItemAsync<string?>(nameof(this.ProgramVersion));

    if (this.ProgramVersion == null)
            {
                // Here we load the app / session data that only needs to be read once.
                // This is the best place to do it to avoid a race condition with GetItemAsync.
                await this.SetProgramVersion(Util.GetVersion(typeof(Program)));

            }
}

}

[Bug] GetItemAync hangs

I am using Blazored.Session storage in my blazor server application. Both the setItemAsync getItemAsync work fine in debug and release mode if I have the debugger attached. When I host the web page and run the release version without the debugger attached the getItemAsync hangs. Any idea why this might be happening especially since it does not hang when the debugger is attached?

Session Timeout

Is there a timeout on the session and if so how can we set it?

[Bug] ContainsKeyAsync not present in API

Describe the bug
I've tried to find the ContainsKeyAsync method but it doesn't seem to exist

To Reproduce
Clone the repo, and try and add the line await sessionStorage.ContainsKeyAsync in Index.razor

Hosting Model (is this issue happening with a certain hosting model?):

  • Blazor Server

[Bug] SetItemAsync throws Microsoft.JSInterop.JSDisconnectedException: JavaScript interop calls cannot be issued at this time.

Sometimes we get this error from our deployed Blazor apps:

Microsoft.JSInterop.JSDisconnectedException: JavaScript interop calls cannot be issued at this time. This is because the circuit has disconnected and is being disposed.
at Microsoft.AspNetCore.Components.Server.Circuits.RemoteJSRuntime.BeginInvokeJS(Int64 asyncHandle, String identifier, String argsJson, JSCallResultType resultType, Int64 targetInstanceId)
at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, CancellationToken cancellationToken, Object[] args)
at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](String identifier, CancellationToken cancellationToken, Object[] args)
at Microsoft.JSInterop.JSRuntimeExtensions.InvokeAsync[TValue](IJSRuntime jsRuntime, String identifier, CancellationToken cancellationToken, Object[] args)
at Blazored.SessionStorage.BrowserStorageProvider.GetItemAsync(String key, Nullable1 cancellationToken) at Blazored.SessionStorage.SessionStorageService.GetItemInternalAsync[T](String key) at Blazored.SessionStorage.SessionStorageService.RaiseOnChangingAsync(String key, Object data) at Blazored.SessionStorage.SessionStorageService.SetItemAsync[T](String key, T data, Nullable1 cancellationToken)

Hosting Model (is this issue happening with a certain hosting model?):

  • Blazor Server

I searched, but could not find any other issues on Blazored/SessionStorage. However, there are plenty of examples of the same error text in other Blazor contexts.

Should this exception be handled by the caller or is it possible to fix?

[Feature Request] Serialize with lower case / camelCase

Is your feature request related to a problem? Please describe.
I would like to access the sessionStorage data from JS code, which expects camelCase syntax for field names.

Describe the solution you'd like
It'd be great to have an option to setup serialization options. Eg. in startup with an enum like "Serialization.Camelcase".

Describe alternatives you've considered
Using camelCase in .net.

Additional context
Great library! Thanks.

[Bug] Session Storage Limit

Describe the bug
Attempting to retrieve a list of stored objects from session storage causes the following error:
image

To Reproduce
Steps to reproduce the behavior:

  1. Create two new classes (these have been generated for me from EF Core). Here are the definitions:
    public partial class IISDashboardUserSetting
    {
        public string UserSettingId { get; set; }
        public string UserId { get; set; }
        public string SettingId { get; set; }
        public string Value { get; set; }
        public virtual IISDashboardSetting Setting { get; set; }
    }
    public partial class IISDashboardSetting
    {
        public IISDashboardSetting()
        {
            IISDashboardUserSettings = new HashSet<IISDashboardUserSetting>();
        }

        public string SettingId { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }

        [JsonIgnore]
        public virtual ICollection<IISDashboardUserSetting> IISDashboardUserSettings { get; set; }
    }
  1. From the database a populated a list of IISDashboardUserSettings with 113 items:
        public List<IISDashboardUserSetting> GetUserSettingsById(string userId)
        {
            using (var eQuipDBContext = eQuipContextFactory.CreateDbContext())
            {
                var userSettings = eQuipDBContext.IISDashboardUserSettings
                    .Include(s => s.Setting)
                    .Where(u => u.UserId == userId).ToList();

                return userSettings;
            }
        }
  1. Store the list in session storage:
            if (modelUserSettings != null || modelUserSettings.Count > 0)
            {
                //We have all the settings...
                await SessionStorageService.SetItemAsync("settings", modelUserSettings);
                StateHasChanged();
            }
  1. Attempt to retrieve the stored list:

image
image

        public async Task<List<IISDashboardUserSetting>> FetchUserSettingsFromStorage()
        {
            return await SessionStorageService.GetItemAsync<List<IISDashboardUserSetting>>("settings");
        }

Expected behavior
Expect to retrieve the list successfully for use in the application.

Screenshots
See above steps.

Hosting Model (is this issue happening with a certain hosting model?):

  • Blazor Server

Additional context
I removed 20 items and tested the same steps and the problem went away.

AddBlazoredSessionStorage() add public setter for options.JsonSerializerOptions

Is your feature request related to a problem? Please describe.
Currently we need to set each JsonSerializerOptions manually independently if we have a static method already defined.

Describe the solution you'd like
Allow for options.JsonSerializerOptions to be set so a static JsonSerializerOptions config can be reused instead of setting each property again.

Describe alternatives you've considered
Currently mapping everything manually (converters etc)

Additional context
Cleaner centralized code.

[Feature Request] Cancellation Token support

I'm was trying to create a common interface to bridge the two implementations of your LocalStorageSession and SessionStorageService. However, whilst the interface for the LocalStorageService has support for cancellation tokens in its methods, the storage service does not.

I would like to see CancellationToken support integrated with this library to bring it further into parity with the LocalStorage library.

Sessionstorage service not storing the value

Blazor Server app am calling below method in login page store username
await sessionStorage.SetItemAsync("Name",CurrentUser.Username);

and am using below method to retireive the save session name value but it is always getting null
var name = await _sessionStorageService.GetItemAsync("Name");

Please let me know the reasons why session not storing in my blazer server app

[Bug]GetItemAsync and SetItemAsync throw System.Threading.Tasks.TaskCanceledException: 'A task was canceled.'

Describe the bug
I'm trying to use SessionStorage to store larger graphs of objects (a few hundreds).

However, I often get a crash with the message 'A task was canceled' from GetItemAsync and SetItemAsync. Also, Blazor shows the message "Attempting to reconnect to server" both when doing local debugging and when deployed to an IIS server.

To Reproduce
Steps to reproduce the behavior:

Clone this repro project and run it:
https://github.com/tripleacoder/BlazorApp3

The project references an older version of the library, but the bug is still there when upgrading to v. 2.1.0.
The bug is also present when using the Newtonsoft JSON serializer instead of the default one.

Hosting Model (is this issue happening with a certain hosting model?):

  • Blazor Server

Additional context
Note: this is a copy of a previously closed issue. Not sure if it is better to re-open.
#33

SessionStorage v.1.0.10 gives me an error while publishing into Azure App Service

Hi Chris:

In my development environment, the latest version works fine (v.1.0.10) but when I published into an Azure App Service using the self contained mode it gaves the following error while browsing the application.

An error occurred while starting the application.
FileNotFoundException: Could not load file or assembly 'Blazored.SessionStorage, Version=1.0.10.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
AIP.UI.Startup.ConfigureServices(IServiceCollection services)

FileNotFoundException: Could not load file or assembly 'Blazored.SessionStorage, Version=1.0.10.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
AIP.UI.Startup.ConfigureServices(IServiceCollection services)
System.RuntimeMethodHandle.InvokeMethod(object target, object[] arguments, Signature sig, bool constructor, bool wrapExceptions)
System.Reflection.RuntimeMethodInfo.Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.InvokeCore(object instance, IServiceCollection services)
Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder+<>c__DisplayClass9_0.g__Startup|0(IServiceCollection serviceCollection)
Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.Invoke(object instance, IServiceCollection services)
Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder+<>c__DisplayClass8_0.b__0(IServiceCollection services)
Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.UseStartup(Type startupType, HostBuilderContext context, IServiceCollection services)
Microsoft.AspNetCore.Hosting.GenericWebHostBuilder+<>c__DisplayClass12_0.b__0(HostBuilderContext context, IServiceCollection services)
Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider()
Microsoft.Extensions.Hosting.HostBuilder.Build()
AIP.UI.Program.Main(string[] args) in Program.cs

I reverted the version to prior one (1.0.9), and the application runs.

Is this is an issue in the latest version or I am missing a a configuration.

Thanks

David

[Question] Get sessions values in ASP Controllers

Hi there!
I'm currently injecting the ISessionStorageService in my Blazor pages, and then using the OnAfterRenderAsync method to fetch my data. Although using OnInitializedAsync throws an error, that is logical, how can I manage sessions in an ASP Controller?
I tried using the [Inject] field declaration and giving the service in my controller's constructor, but I still have the "JavaScript not loaded" error (Blazor is not yet rendered).
Any ideas? Here's my current code if it can helps anyhow:

using Microsoft.AspNetCore.Mvc;
using PatreonResources.Components.Utilities;

namespace PatreonResources.Components.Pages;

[ApiController]
[Route("api")]
public class DownloadController : ControllerBase
{
    
    [HttpGet, DisableRequestSizeLimit]
    [Route("download")]
    public async Task<IActionResult> Download(string ResourceId)
    {
        var resource = ResourceData.GetResources().Result.FirstOrDefault(x => x.Id == ResourceId);
        if (resource is null)
            return NotFound();
        
        var file = Path.Combine("Resources", $"{ResourceId}.jar");
        
        var memory = new MemoryStream();
        await using(var stream = new FileStream(file, FileMode.Open))
        {
            await stream.CopyToAsync(memory);
        }
        
        memory.Position = 0;
        return File(memory, "application/octet-stream", $"{resource.Name} v{resource.Version}.jar");
    }
}

[Question] Using System.Text.Json.JsonSerializer.SerializeToUtf8Bytes

Hi,

I have a list of complex objects that are rendered in a Telerik Blazor Grid. When I select items in the grid the grid's OnItemSelected event sends anIEnumerable<T> of all the selected items in the grid.

I can save this to a property in the Blazor component.

What I want to be able to do is persist that data so that if a user navigates away from the page that has the grid and then returns back I can populate the grid and select the items in the grid that were selected before.

I thought I would try and use System.Text.Json.JsonSerializer.SerializeToUtf8Bytes as it's suppose to be quicker than storing as a JSON string and therefore I'm also assuming it might take up less storage space in the browser's session storage.

Would I be able to use System.Text.Json.JsonSerializer.SerializeToUtf8Bytes to create a byte[] then store and retrieve that byte[] array like this:

// Local page property with selected grid items
public IEnumerable<ComplexObj> SelectedItems { get; set; }

// Convert selected items of type ComplexObj to
var jsonUtf8Bytes = JsonSerializer.SerializeToUtf8Bytes<IEnumerable<ComplexObj>>(SelectedItems, new JsonSerializerOptions());

// Store byte array to browser session storage
await sessionStorage.SetItemAsync("selectedItems", jsonUtf8Bytes);

// Retrieve byte array from session storage
var jsonUtf8Bytes = await sessionStorage.GetItemAsync<byte[]>("selectedItems");

// Convert byte array to readonly span of bytes
var readOnlySpan = new ReadOnlySpan<byte>(jsonUtf8Bytes);

// DeSerialize span back to list of ComplexObj type
var obj = JsonSerializer.Deserialize<IEnumerable<ComplexObj>>(readOnlySpan);

session.GetItemAsync("authToken") - does not return the value nor does it throw an exception

On each call to the request gateway from the library code the login token Is fetched from sessionStorage except in some case it just returns - no exception thrown nor is the code execution completed.

Hosting Model (is this issue happening with a certain hosting model?):

  • Blazor Server
  • Windows 11

Additional context
The following link is a short video with a breakpoint that is manually toggled so show the continuation of the execution up until it just returns without a token or exception.

https://app.screencast.com/Cc9PMBodePFLZ

[Question] How to read browser session storage?

When I try to read something from the session storage managed by the browser I get a json deserializing exception. I guess the GetItemAsync tries to deserialize the file?

How should I go about reading some data from the session storage which hasn't been serialized to json?

(The goal is to read an access token stored in the session storage, which is stored by the browser)

[Question] Blazored.LocalStorage and Blazored.SessionStorage store the same values differently

Hi, I have some code where I want to be able to store a value in either Session Storage or Local Storage. I am using both of your libraries to access them. I expected the data stored to be in exactly the same format in both, no matter which "provider" I used.

I have an interface like this:

    public interface IStorageProvider
    {
        Task    SetItemAsync<T>(string key, T data);
    }

and 2 classes like these:

    public class LocalStorageProvider : IStorageProvider
    {
        private readonly ILocalStorageService _localStorage;
        ...
        public Task SetItemAsync<T>(string key, T data) => _localStorage.SetItemAsync(key, data);
    }

    public class SessionStorageProvider : IStorageProvider
    {
        private readonly ISessionStorageService _sessionStorage;
        ...
        public Task SetItemAsync<T>(string key, T data) => _sessionStorage.SetItemAsync(key, data);
    }

But the values is stored in Local/Session Storage are not the same. Here is what gets stored in Session Storage when I set a JSON string:
"{\u0022FilterValue\u0022:\u0022\u0022,\u0022Shown\u0022:true,\u0022SortDirection\u0022:0,\u0022SortIndex\u0022:0}"
And the same value stored in Local Storage:
{"FilterValue":"","Shown":true,"SortDirection":0,"SortIndex":0}

Not sure if I am doing something wrong or not...
Thanks!

Reading 'existing / normal' values from session storage is not possible

The current implementation from GetItemAsync<string>("key") reads the value as string, but also deserializes using JSON.

This means that I cannot use GetItemAsync for reading existing / normal string-values from the SessionStorage (these values are added to the SessionStorage by other code)

Proposals can be:

  1. In case deserializing the string value into json object fails, just return the string value
  2. Add another method like GetLegacyStringAsync("key") or GetStringAsync("key")

What do you think?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.