blazored / localstorage Goto Github PK
View Code? Open in Web Editor NEWA library to provide access to local storage in Blazor applications
Home Page: https://blazored.github.io/LocalStorage/
License: MIT License
A library to provide access to local storage in Blazor applications
Home Page: https://blazored.github.io/LocalStorage/
License: MIT License
Hi Team , I am trying to use local storage in my demo application and successfully implemented as you suggested but when i refresh the page local storage is getting empty.
Could you please suggest?
Hi,
With local storage, users (and developers) don't have to deal with login and password !
I am wondering if there is a manner to sync this local storage accross devices ?
I know that some browsers can sync history and other data.
The idea is to defer authentication and data managment to browsers since with Blazor WebAssembly, the browser is the OS.
I'm trying to inject LocalStorage in my own Service, sa shown below.
But LocalStorage is still sett to null in the function ConsumeCollection.
The HTTP injection is OK, and injection in a razor file is OK
using System.Net.Http;
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components;
namespace Padleloggen.Data
{
public class DataService
{
[Inject]
private HttpClient Http { get; set; }
[Inject]
private ILocalStorageService LocalStorage { get; set; }
public DataService(HttpClient hc, ILocalStorageService ls)
{
Http = hc;
LocalStorage = ls;
}
public async Task<string> ConsumeCollection<T>(string sUri) where T : IBaseElement, new()
{
List<T> collection = await Http.GetFromJsonAsync<List<T>>(sUri);
string key = typeof(T).Name.ToString() + "List";
await LocalStorage.SetItemAsync(key, collection);
return Http == null ? "null" : key;
}
}
}
Love the LocalStorage, thank you so much. I would like to use it in a data service class instead of just razor pages. What would be the syntax for putting it in a using?
Console.WriteLine($"Value for key {e.Key} changed from {e.OldValue} to {e.NewValue}");
The above code output statement does not seem to work, and does not output data in the console.
Hi Chris, I met a problem after upgrading my project in 3.2.0-preview3 (https://devblogs.microsoft.com/aspnet/blazor-webassembly-3-2-0-preview-3-release-now-available/)
the error i have is
Unhandled exception rendering component: Cannot consume scoped service 'Blazored.LocalStorage.ILocalStorageService' from singleton 'MyService'.
and indeed, i inject your ILocalStorageService in some services inject as singleton.
My project is dual mode serverside/webassembly, and by convention/logic i inject most of my services as singleton in webassembly and scoped in server side.
When i check how you register your service in AddBlazoredLocalStorage, i see you inject it as scoped.
I try to put all my services as scoped in my assembly project (i really don't want to do that, its just for test) and anyway at the end im unable to resolve all the dependency because the ILogger is still a singleton and i don't have control on this.
Microsoft don't really communicate on this update for this preview, but it look like more than a bug resolution than a regression, because for me even with the previous version it was not suppose to work (consume a scoped service from a singleton).
so what do you think about that ?
If you wan't to reproduce :
I wait for your feedback, if you are OK with the resolution i speak a can suggest a PR (upgrading the package + parameter in AddBlazoredLocalStorage to inject services as singleton)
thank you !
Julien
This fails:
protected override async Task OnAfterRenderAsync()
{
await localStorage.SetItemAsync("name", "John Smith");
var name = await localStorage.GetItemAsync<string>("name");
}
This works:
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await localStorage.SetItemAsync("name", "John Smith");
var name = await localStorage.GetItemAsync<string>("name");
}
Describe the bug
Upgrading a Blazor project with LocalStorage from preview 2 to preview 3, specifically Microsoft.AspNetCore.Components.WebAssembly 3.2.0-preview2.20160.5 to 3.2.0-preview3.20168.3 breaks Local Storage. This seems to be a services issue.
crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] blazor.webassembly.js:1:36074
Unhandled exception rendering component: Cannot consume scoped service 'Blazored.LocalStorage.ILocalStorageService' from singleton {nameOfMySingleton}
To Reproduce
Describe the bug
The change event doesn't seem to fire across tabs as described. Even the sample client app doesn't work for me in both Chrome and Edge (chromium).
To Reproduce
Steps to reproduce the behavior:
Expected behavior
I was hoping the event would fire and update each tab.
Hosting Model (is this issue happening with a certain hosting model?):
Hi there,
The docs show how to add the service to a typical server side project, but I haven't been able to work out how to setup the service in a Blazor client-side (WASM) Project.
Please advise.
Regards,
Steve Bond
Hi ,
The exception System.IO.FileNotFoundException: Could not load file or assembly 'System.Text.Json,
happens when using Blazored / LocalStorage in Azure function
here is the stack trace:
Category: Microsoft.AspNetCore.Server.IIS.Core.IISHttpServer
EventId: 2
RequestId: 80001161-0002-f200-b63f-84710c7967bb
RequestPath: /
SpanId: |371e91fa-4fdb7133ba2a2c99.
TraceId: 371e91fa-4fdb7133ba2a2c99
ParentId:
ActionId: 28e03650-b80c-4159-84b1-b8b1302365cb
ActionName: /_Host
Connection ID "17437937767379112288", Request ID "80001161-0002-f200-b63f-84710c7967bb": An unhandled exception was thrown by the application.
Exception:
System.IO.FileNotFoundException: Could not load file or assembly 'System.Text.Json, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.
File name: 'System.Text.Json, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
at Blazored.LocalStorage.LocalStorageService..ctor(IJSRuntime jSRuntime)
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor
2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.b__0(ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.AspNetCore.Components.ComponentFactory.<>c__DisplayClass5_0.g__Initialize|2(IServiceProvider serviceProvider, IComponent component)
at Microsoft.AspNetCore.Components.ComponentFactory.PerformPropertyInjection(IServiceProvider serviceProvider, IComponent instance)
at Microsoft.AspNetCore.Components.ComponentFactory.InstantiateComponent(IServiceProvider serviceProvider, Type componentType)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.InstantiateComponent(Type componentType)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.InstantiateChildComponentOnFrame(RenderTreeFrame& frame, Int32 parentComponentId)
at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewComponentFrame(DiffContext& diffContext, Int32 frameIndex)
at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewSubtree(DiffContext& diffContext, Int32 frameIndex)
at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InsertNewFrame(DiffContext& diffContext, Int32 newFrameIndex)
at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& diffContext, Int32 oldStartIndex, Int32 oldEndIndexExcl, Int32 newStartIndex, Int32 newEndIndexExcl)
at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.ComputeDiff(Renderer renderer, RenderBatchBuilder batchBuilder, Int32 componentId, ArrayRange1 oldTree, ArrayRange
1 newTree)
at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderInExistingBatch(RenderQueueEntry renderQueueEntry)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Components.Rendering.HtmlRenderer.HandleException(Exception exception)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()
at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessPendingRender()
at Microsoft.AspNetCore.Components.RenderTree.Renderer.AddToRenderQueue(Int32 componentId, RenderFragment renderFragment)
at Microsoft.AspNetCore.Components.RenderHandle.Render(RenderFragment renderFragment)
at Microsoft.AspNetCore.Components.ComponentBase.StateHasChanged()
at Microsoft.AspNetCore.Components.ComponentBase.CallOnParametersSetAsync()
at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
at Microsoft.AspNetCore.Components.Rendering.HtmlRenderer.HandleException(Exception exception)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.AddToPendingTasks(Task task)
at Microsoft.AspNetCore.Components.Rendering.ComponentState.SetDirectParameters(ParameterView parameters)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderRootComponentAsync(Int32 componentId, ParameterView initialParameters)
at Microsoft.AspNetCore.Components.Rendering.HtmlRenderer.CreateInitialRenderAsync(Type componentType, ParameterView initialParameters)
at Microsoft.AspNetCore.Components.Rendering.HtmlRenderer.RenderComponentAsync(Type componentType, ParameterView initialParameters)
at Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext.<>c__111.<<InvokeAsync>b__11_0>d.MoveNext() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.ViewFeatures.StaticComponentRenderer.PrerenderComponentAsync(ParameterView parameters, HttpContext httpContext, Type componentType) at Microsoft.AspNetCore.Mvc.ViewFeatures.ComponentRenderer.PrerenderedServerComponentAsync(HttpContext context, ServerComponentInvocationSequence invocationId, Type type, ParameterView parametersCollection) at Microsoft.AspNetCore.Mvc.ViewFeatures.ComponentRenderer.RenderComponentAsync(ViewContext viewContext, Type componentType, RenderMode renderMode, Object parameters) at Microsoft.AspNetCore.Mvc.TagHelpers.ComponentTagHelper.ProcessAsync(TagHelperContext context, TagHelperOutput output) at Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner.<RunAsync>g__Awaited|0_0(Task task, TagHelperExecutionContext executionContext, Int32 i, Int32 count) at ALSearch.Pages.Pages__Host.<ExecuteAsync>b__14_1() in C:\dev\ALSearch\ALSearch\ALSearch\Pages\_Host.cshtml:line 34 at Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext.SetOutputContentAsync() at ALSearch.Pages.Pages__Host.ExecuteAsync() in C:\dev\ALSearch\ALSearch\ALSearch\Pages\_Host.cshtml:line 5 at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context) at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, Boolean invokeViewStarts) at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context) at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable
1 statusCode)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable1 statusCode) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task) at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.HandleException(HttpContext context, ExceptionDispatchInfo edi) at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task) at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContextOfT
1.ProcessRequestAsync()
I tested int and string properties. The values in setTest exist in local storage but the default values are assigned to var getTest. If I make the setter public it works.
var setTest = new Test();
setTest.SetValues(2, "changed");
Console.WriteLine($"setTest: {setTest.IntValue} {setTest.StringValue}");
await LocalStorage.SetItemAsync("test", setTest);
var getTest = await LocalStorage.GetItemAsync("test");
Console.WriteLine($"getTest: {getTest.IntValue} {getTest.StringValue}");
public class Test
{
public Int32 IntValue { get; private set; } = 1;
public String StringValue { get; private set; } = "default";
public void SetValues(Int32 intValue, String stringValue)
{
IntValue = intValue;
StringValue = stringValue;
}
}
I'd love to see support for the [JsonIgnore] property attribute in model classes. For example, if you share models between the webassembly and WebAPI projects, there may be properties which are only applicable to the server instance. This would reduce noise when the localstorage is being inspected and also help obfuscate the IA of your codebase.
Is there anyway that I can determine how much LocalStorage has been used so far? I have no idea how much data is being stored since it has been Json serialized and is not in its original format.
If this is not possible, then is it a case of catching an 'out-of-memory' exception if I should exceed the amount available?
I would obviously much prefer a GetStorageUsed{Async} method.
Russ Sherlock
@chrissainty Chris,
The 'storage' event notifies only the non-active code on a change that happened in other tab/window. Also the event cannot be cancelled (speaking in JS native).
I was wondering, if you're interested in aligning the implementation to native feature of storage object. Here is possible implementation that removes before/after change event listeners, uses single storage event.
Thanks!
diff --git a/samples/BlazorSample/Pages/Index.cshtml b/samples/BlazorSample/Pages/Index.cshtml
index 5f990be..26646b2 100644
--- a/samples/BlazorSample/Pages/Index.cshtml
+++ b/samples/BlazorSample/Pages/Index.cshtml
@@ -56,8 +56,7 @@ Welcome to your new app.
await GetNameFromLocalStorage();
await GetLocalStorageLength();
- localStorage.Changed += (sender, e) =>
- {
+ localStorage.StorageChanged += (sender, e) => {
Console.WriteLine($"Value for key {e.Key} changed from {e.OldValue} to {e.NewValue}");
};
}
diff --git a/samples/BlazorSample/Pages/Sync.cshtml b/samples/BlazorSample/Pages/Sync.cshtml
index 59fb3e6..4160259 100644
--- a/samples/BlazorSample/Pages/Sync.cshtml
+++ b/samples/BlazorSample/Pages/Sync.cshtml
@@ -50,7 +50,7 @@
GetNameFromLocalStorage();
GetLocalStorageLength();
- localStorage.Changed += (sender, e) =>
+ localStorage.StorageChanged += (sender, e) =>
{
Console.WriteLine($"Value for key {e.Key} changed from {e.OldValue} to {e.NewValue}");
};
diff --git a/src/Blazored.LocalStorage/ChangingEventArgs.cs b/src/Blazored.LocalStorage/ChangingEventArgs.cs
deleted file mode 100644
index 63616f9..0000000
--- a/src/Blazored.LocalStorage/ChangingEventArgs.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using System;
-
-namespace Blazored.LocalStorage
-{
- public class ChangingEventArgs : ChangedEventArgs
- {
- public bool Cancel { get; set; }
- }
-}
diff --git a/src/Blazored.LocalStorage/ILocalStorageService.cs b/src/Blazored.LocalStorage/ILocalStorageService.cs
index 16ddbaa..acc1d7f 100644
--- a/src/Blazored.LocalStorage/ILocalStorageService.cs
+++ b/src/Blazored.LocalStorage/ILocalStorageService.cs
@@ -16,8 +16,6 @@ namespace Blazored.LocalStorage
Task RemoveItemAsync(string key);
Task SetItemAsync(string key, object data);
-
- event EventHandler<ChangingEventArgs> Changing;
- event EventHandler<ChangedEventArgs> Changed;
+ event EventHandler<StorageEventArgs> StorageChanged;
}
}
diff --git a/src/Blazored.LocalStorage/ISyncLocalStorageService.cs b/src/Blazored.LocalStorage/ISyncLocalStorageService.cs
index 0aa0f81..f36bf95 100644
--- a/src/Blazored.LocalStorage/ISyncLocalStorageService.cs
+++ b/src/Blazored.LocalStorage/ISyncLocalStorageService.cs
@@ -16,7 +16,6 @@ namespace Blazored.LocalStorage
void SetItem(string key, object data);
- event EventHandler<ChangingEventArgs> Changing;
- event EventHandler<ChangedEventArgs> Changed;
+ event EventHandler<StorageEventArgs> StorageChanged;
}
}
\ No newline at end of file
diff --git a/src/Blazored.LocalStorage/LocalStorageService.cs b/src/Blazored.LocalStorage/LocalStorageService.cs
index d9b7ca7..47d97d3 100644
--- a/src/Blazored.LocalStorage/LocalStorageService.cs
+++ b/src/Blazored.LocalStorage/LocalStorageService.cs
@@ -20,14 +20,7 @@ namespace Blazored.LocalStorage
if (string.IsNullOrEmpty(key))
throw new ArgumentNullException(nameof(key));
- var e = await RaiseOnChangingAsync(key, data);
-
- if (e.Cancel)
- return;
-
await _jSRuntime.InvokeAsync<object>("Blazored.LocalStorage.SetItem", key, Json.Serialize(data));
-
- RaiseOnChanged(key, e.OldValue, data);
}
public async Task<T> GetItemAsync<T>(string key)
@@ -64,14 +57,7 @@ namespace Blazored.LocalStorage
if (_jSInProcessRuntime == null)
throw new InvalidOperationException("IJSInProcessRuntime not available");
- var e = RaiseOnChangingSync(key, data);
-
- if (e.Cancel)
- return;
-
_jSInProcessRuntime.Invoke<object>("Blazored.LocalStorage.SetItem", key, Json.Serialize(data));
-
- RaiseOnChanged(key, e.OldValue, data);
}
T ISyncLocalStorageService.GetItem<T>(string key)
@@ -123,46 +109,48 @@ namespace Blazored.LocalStorage
return _jSInProcessRuntime.Invoke<string>("Blazored.LocalStorage.Key", index);
}
- public event EventHandler<ChangingEventArgs> Changing;
- private async Task<ChangingEventArgs> RaiseOnChangingAsync(string key, object data)
+ private EventHandler<StorageEventArgs> _storageChanged;
+ public event EventHandler<StorageEventArgs> StorageChanged
{
- var e = new ChangingEventArgs
+ add
{
- Key = key,
- OldValue = await GetItemAsync<object>(key),
- NewValue = data
- };
-
- Changing?.Invoke(this, e);
-
- return e;
- }
-
- private ChangingEventArgs RaiseOnChangingSync(string key, object data)
- {
- var e = new ChangingEventArgs
+ if (_storageChanged == null)
+ {
+ this._jSInProcessRuntime.InvokeAsync<object>(
+ "Blazored.LocalStorage.AddEventListener",
+ new DotNetObjectRef(this)
+ );
+ }
+ _storageChanged += value;
+ }
+ remove
{
- Key = key,
- OldValue = ((ISyncLocalStorageService)this).GetItem<object>(key),
- NewValue = data
- };
-
- Changing?.Invoke(this, e);
-
- return e;
+ _storageChanged -= value;
+ if (_storageChanged == null)
+ {
+ this._jSInProcessRuntime.InvokeAsync<object>("Blazored.LocalStorage.RemoveEventListener");
+ }
+ }
}
- public event EventHandler<ChangedEventArgs> Changed;
- private void RaiseOnChanged(string key, object oldValue, object data)
+ [JSInvokable]
+ public virtual void OnStorageChanged(string key, object oldValue, object newValue)
{
- var e = new ChangedEventArgs
+ EventHandler<StorageEventArgs> handler = _storageChanged;
+ if (handler != null)
{
- Key = key,
- OldValue = oldValue,
- NewValue = data
- };
-
- Changed?.Invoke(this, e);
+ handler(this, new StorageEventArgs
+ {
+ Key = key,
+ OldValue = oldValue,
+ NewValue = newValue,
+ });
+ }
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Blazored.LocalStorage/ChangedEventArgs.cs b/src/Blazored.LocalStorage/StorageEventArgs.cs
similarity index 51%
rename from src/Blazored.LocalStorage/ChangedEventArgs.cs
rename to src/Blazored.LocalStorage/StorageEventArgs.cs
index e3cffbf..f27d5eb 100644
--- a/src/Blazored.LocalStorage/ChangedEventArgs.cs
+++ b/src/Blazored.LocalStorage/StorageEventArgs.cs
@@ -1,11 +1,11 @@
-namespace Blazored.LocalStorage
+
+using System;
+
+namespace Blazored.LocalStorage
{
- public class ChangedEventArgs
+ public class StorageEventArgs : EventArgs
{
public string Key { get; set; }
-
- // NOTE: can't easily make event handlers generic
-
public object OldValue { get; set; }
public object NewValue { get; set; }
}
diff --git a/src/Blazored.LocalStorage/content/blazored.LocalStorage.ts b/src/Blazored.LocalStorage/content/blazored.LocalStorage.ts
index 2394ab5..cd26ea7 100644
--- a/src/Blazored.LocalStorage/content/blazored.LocalStorage.ts
+++ b/src/Blazored.LocalStorage/content/blazored.LocalStorage.ts
@@ -1,46 +1,77 @@
namespace Blazored.LocalStorage {
- class LocalStorage {
- public SetItem(key: string, data: string): void {
- window.localStorage.setItem(key, data);
- }
-
- public GetItem(key: string): string {
- return window.localStorage.getItem(key);
- }
-
- public RemoveItem(key: string): void {
- window.localStorage.removeItem(key);
- }
-
- public Clear(): void {
- window.localStorage.clear();
- }
-
- public Length(): number {
- return window.localStorage.length;
- }
-
- public Key(index: number): string {
- return window.localStorage.key(index);
- }
- }
-
- export function Load(): void {
- const localStorage = {
- LocalStorage: new LocalStorage()
- };
-
- if (window['Blazored']) {
- window['Blazored'] = {
- ...window['Blazored'],
- ...localStorage
- }
- } else {
- window['Blazored'] = {
- ...localStorage
- }
- }
+ class LocalStorage {
+ private instance: any | undefined = undefined;
+
+ constructor() {
+ this.OnStorageEvent = this.OnStorageEvent.bind(this);
+ this.AddEventListener = this.AddEventListener.bind(this);
+ }
+
+ SetItem(key: string, data: string): void {
+ window.localStorage.setItem(key, data);
+ }
+
+ GetItem(key: string): string | null {
+ return window.localStorage.getItem(key);
+ }
+
+ RemoveItem(key: string): void {
+ window.localStorage.removeItem(key);
+ }
+
+ Clear(): void {
+ window.localStorage.clear();
+ }
+
+ Length(): number {
+ return window.localStorage.length;
+ }
+
+ Key(index: number): string | null {
+ return window.localStorage.key(index);
+ }
+
+ OnStorageEvent(e: StorageEvent) {
+ if (!this.instance) return;
+ this.instance.invokeMethodAsync(
+ "OnStorageChanged",
+ e.key,
+ e.newValue,
+ e.oldValue
+ );
+ }
+
+ AddEventListener(instance: any): void {
+ window.removeEventListener("storage", this.OnStorageEvent, false);
+ this.instance = instance;
+ window.addEventListener("storage", this.OnStorageEvent, false);
+ }
+
+ RemoveEventListener(): void {
+ window.removeEventListener("storage", this.OnStorageEvent, false);
+ }
+ }
+
+ export function Load(): void {
+ const localStorage = {
+ LocalStorage: new LocalStorage()
+ };
+
+ if (window["Blazored"]) {
+ window["Blazored"] = {
+ ...window["Blazored"],
+ ...localStorage
+ };
+ } else {
+ window["Blazored"] = {
+ ...localStorage
+ };
}
+ }
+}
+
+interface Window {
+ [key: string]: any;
}
Blazored.LocalStorage.Load();
Getting this Exception:
2019-11-11 13:10:06.6198 Error System.Threading.Tasks.TaskCanceledException: A task was canceled.
at Microsoft.JSInterop.JSRuntime.InvokeWithDefaultCancellation[T](String identifier, Object[] args)
at Blazored.LocalStorage.LocalStorageService.GetItemAsync[T](String key)
at PegasusV6.Pages.Components.Basket.BasketComponent.OnAfterRenderAsync(Boolean firstRender) in C:\SOURCE\PegasusV6\PegasusV6\Pages\Components\Basket\BasketComponent.razor:line 88
When try getting LocalStorage that is bigger than 30 KB and I don't have a clue whats the reason...
on LINE:
var data = await LocalStorage.GetItemAsync("Basket");
Is there a known limitation or can I get rid of it anyhow?
SOURCE in a razor file:
protected override async Task OnAfterRenderAsync(bool firstRender)
{
My.Log.Info($"BasketComponent.OnAfterRender({firstRender})");
try
{
if (firstRender)
{
var data = await LocalStorage.GetItemAsync<BasketState>("Basket");
// TODO: Fill with correct prices
if (data != null)
{
AppState.Basket = data;
StateHasChanged();
}
AppState.Basket.OnBasketChanged -= new Action (async () => await UpdateBasketAtLocalStorage());
AppState.Basket.OnBasketChanged += new Action (async () => await UpdateBasketAtLocalStorage());
}
}
catch (Exception ex)
{
My.Log.Error(ex);
}
}
Hi, and thanks for your work !
I try to use your library in a server-side project with synchronous call, but when i call the GetItem (in onAfterRender method), I have this following error :
IJSInProcessRuntime not available
How to reproduce :
thanks for your help !
Julien
When trying to save the contents from the file here, then when retrieving, it gets stuck.
I tried an experiment and saved just 4 items then retrieve it. That worked. Needs to find a way to be able to retrieve from local storage even large amounts of text or large lists.
Describe the bug
When I try to save a jsonToken with ILocalStorageService.SetItemAsync()
a exception is thrown (I hope you can see something in the screenshot). My jsonToken was not saved. Trying GetItemAsync<string>
. I will stay to v2.1.3, that version is still working.
To Reproduce
Steps to reproduce the behavior:
Hosting Model (is this issue happening with a certain hosting model?):
Additional context
<PackageReference Include="Microsoft.AspNetCore.Blazor.HttpClient" Version="3.2.0-preview3.20168.3" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="3.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="3.2.0-preview3.20168.3" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="3.2.0-preview3.20168.3" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="3.2.0-preview3.20168.3" />
I am experimenting a little bit with blazor in my free time right now. Then I wanted to try out a blazor local storage and found this one and this one. I tryed the blazored local storage first out. And well there I get an error when I want to get an Item async.
So what I think is that the blazored local storage cannot acces the local storage of the browser.
Here is my Code:
@page "/counter"
@inject ILocalStorageService localStore
@if (currentCount.HasValue)
{
<p>Current count: <strong>@currentCount</strong></p>
<button @onclick="IncrementCount">Increment</button>
}
else
{
<p>Loading...</p>
}
@code {
private int? currentCount;
protected override async Task OnInitializedAsync()
{
currentCount = await localStore.GetItemAsync<int>("currentCount");
}
private async Task IncrementCount()
{
currentCount++;
await localStore.SetItemAsync("currentCount", currentCount);
}
}
I have read through the documentation and made the same steps. How can I fix this?
So I just found out, when I start the app and after that navigate to "/counter" it works, but when I reload it then it doesn't work anymore. When I change the route then to de default and then navigate again to "/counter" it works again.
So I found an issue with the same problem. I changed the Task to OnAfterRenderAsync(bool firstRender)
, but now the only thing I see is "Loading ..."
Hi, and thanks for your work !
can you add an "exist" method on your library ?
it's normally not so difficult, something like that
public async Task<bool> Exist(string key)
{
if (string.IsNullOrEmpty(key))
throw new ArgumentNullException(nameof(key));
var serialisedData = await _jSRuntime.InvokeAsync<string>("localStorage.getItem", key);
return serialisedData != null;
}
thanks !
Julien
Hi,
I have a strange situation when the GetItemAsync works for 10% of the cases!
It is a server-side blazor and it is called in OnAfterRenderAsync. The browser freeze for some time and display this message "attempting to reconnect to the server", then I got an empty result!
Here is my code:
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
try
{
/*if (firstRender)*/
_imageData = await _localStorage.GetItemAsync<string>("editor.imageData");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
Do you have any idea ? Its weird :-P
First of all, A little background: This is an app that started as a standalone Blazor project. I later added a Server-Side Blazor project to call into the standalone one (as a way to debug things locally before i publish the standalone one). I upgraded those throughout the Blazor versions and now into 0.9. It's quite likely i am doing something bad/unsupported/broken.
I have a login component that gets injected with ILocalStorageService
and attempts to call SetItem
on a successful login (<form onsubmit="async () => await DoStuffAndCallStorage()"
).
This throws an exception as such:
System.InvalidOperationException: IJSInProcessRuntime not available
at Blazored.LocalStorage.LocalStorageService.Blazored.LocalStorage.ISyncLocalStorageService.GetItem[T](String key)
at Blazored.LocalStorage.LocalStorageService.GetItem(String key)
at Blazored.LocalStorage.LocalStorageService.RaiseOnChanging(String key, Object data, ChangingEventArgs& e)
at Blazored.LocalStorage.LocalStorageService.SetItem(String key, Object data)
This used to work in 1.0.1, But quite a few things changed in this library since. I believe this is related to these changes:
.. where the call to GetItem
inside the event handler is forcing the usage of the sync version, Which obviously fails if you're in an async scenario/didn't inject the sync version on purpose to begin with.
Using .net core 3 preview 7. Getting exception:
System.TypeLoadException: Could not load type 'System.Text.Json.Serialization.JsonSerializer' from assembly 'System.Text.Json, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
at async Task<T> Blazored.LocalStorage.LocalStorageService.GetItemAsync<T>(string key)
at void System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start<TStateMachine>(ref TStateMachine stateMachine)
at void System.Runtime.CompilerServices.AsyncTaskMethodBuilder<TResult>.Start<TStateMachine>(ref TStateMachine stateMachine)
at Task<T> Blazored.LocalStorage.LocalStorageService.GetItemAsync<T>(string key)
I'm getting a NullRef exception on Exception thrown: 'System.NullReferenceException' in System.Private.CoreLib.dll when calling SetItemAsync using the code in the readme. This is server-side blazor 3.0.0 release
After updating my CSB app to v2.0.6 for Preview 7 I started seeing an issue on startup...
Microsoft.JSInterop.JSException: Could not find 'LocalStorage' in 'window.Blazored'.
Adding the script tag to my index.html, re the instructions for SSB, resolved the issue.
Hello Chris, I see there is an issue with timespan and the new JsonSerializer .NET (see https://github.com/dotnet/corefx/issues/38641)
Indeed, with the actual code, if I set a timespan item, it write this string representation hh:mm:ss
If i try to read this timespan with GetItem, i get an empty Timepsan wathever the value (without exception)
I have a PR ready for that wich add a JsonConverter dedicated to the timespan. It write the timespan at the standard string representation (d.hh:mm:ss:FFF) and read it with the same format.
It works well, but i have some interrogations on the behavior when the string is not in correct format (for example, a timespan store with only hh:mm:ss, in cas the value was not written with this library). There is few solutions:
What do you think about that ?
thanks !
Julien
I have a class I would like to store:
public class MyData
{
public string name;
public string address;
public int age;
public MyData()
{
name = "name";
address = "address";
age = 50;
}
}
MyData mydata = new MyData();
to store it, I need to serilaize to string:
await localStorage.SetItemAsync("mydata",JsonConvert.SerializeObject(mydata));
this is fine, it works ok.
but when I read it back as a string, I get an error
try{
string text = await localStorage.GetItemAsync<string>("mydata");
}
catch (Exception ex)
{
exstring = ex.Message;
return;
}
The JSON value could not be converted to System.String. Path: $ | LineNumber: 0 | BytePositionInLine: 1. address name
Is their anyway I can read the item back as a string and deserialize myself ?
Describe the bug
An app using LocalStorage does not work when deployed to Azure.
To Reproduce
Steps to reproduce the behavior:
private ILocalStorageService localStorage;
public CustomAuthenticationStateProvider(ILocalStorageService _localStorage)
{
localStorage = _localStorage;
}
services.AddBlazoredLocalStorage();
services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();
Check if it runs locally. Success.
Deplpoy to Azure.
Expected behavior
App is working the same as local.
Actual result
App has errors in console:
blazor.server.js:15 [2020-06-03T08:46:45.405Z] Error: The circuit failed to initialize.
e.log @ blazor.server.js:15
C @ blazor.server.js:8
(anonymous) @ blazor.server.js:8
(anonymous) @ blazor.server.js:1
e.invokeClientMethod @ blazor.server.js:1
e.processIncomingData @ blazor.server.js:1
connection.onreceive @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
a @ blazor.server.js:1
Promise.then (async)
c @ blazor.server.js:1
a @ blazor.server.js:1
Promise.then (async)
c @ blazor.server.js:1
a @ blazor.server.js:1
Promise.then (async)
c @ blazor.server.js:1
a @ blazor.server.js:1
Promise.then (async)
c @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
k @ blazor.server.js:1
e.poll @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
a @ blazor.server.js:1
Promise.then (async)
c @ blazor.server.js:1
a @ blazor.server.js:1
Promise.then (async)
c @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
k @ blazor.server.js:1
e.connect @ blazor.server.js:1
e.startTransport @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
B @ blazor.server.js:1
e.createTransport @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
a @ blazor.server.js:1
Promise.then (async)
c @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
B @ blazor.server.js:1
e.startInternal @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
B @ blazor.server.js:1
e.start @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
v @ blazor.server.js:1
e.startInternal @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
v @ blazor.server.js:1
e.startWithStateTransitions @ blazor.server.js:1
e.start @ blazor.server.js:1
(anonymous) @ blazor.server.js:8
(anonymous) @ blazor.server.js:8
(anonymous) @ blazor.server.js:8
(anonymous) @ blazor.server.js:8
r @ blazor.server.js:8
S @ blazor.server.js:8
(anonymous) @ blazor.server.js:8
(anonymous) @ blazor.server.js:8
(anonymous) @ blazor.server.js:8
(anonymous) @ blazor.server.js:8
r @ blazor.server.js:8
E @ blazor.server.js:8
(anonymous) @ blazor.server.js:8
n @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
(anonymous) @ blazor.server.js:1
Show 39 more frames
blazor.server.js:1 Uncaught (in promise) Error: Invocation canceled due to the underlying connection being closed.
at e.connectionClosed (blazor.server.js:1)
at e.connection.onclose (blazor.server.js:1)
at e.stopConnection (blazor.server.js:1)
at e.transport.onclose (blazor.server.js:1)
at e.raiseOnClose (blazor.server.js:1)
at e. (blazor.server.js:1)
at blazor.server.js:1
at Object.next (blazor.server.js:1)
at a (blazor.server.js:1)
Screenshots
If applicable, add screenshots to help explain your problem.
Hosting Model (is this issue happening with a certain hosting model?):
Additional context
If you remove LocalStorage in your CustomAuthenticationState provider class, then app works.
I have cloned the Blazored.Gitter repo and am trying to consolidate the SCSS. In trying to run the server side version of the project I receive an error from LocalStorage after entering my API key. It occurs on the source line of await LocalStorage.SetItem("GitterKey", apiKey);
`[2019-04-30T13:56:20.554Z] Error: Microsoft.JSInterop.JSException: Could not find 'Blazored' in 'window'.
d/<@http://localhost:50870/_framework/blazor.server.js:8:20878
d@http://localhost:50870/_framework/blazor.server.js:8:20839
beginInvokeJSFromDotNet/r<@http://localhost:50870/_framework/blazor.server.js:8:21429
beginInvokeJSFromDotNet@http://localhost:50870/_framework/blazor.server.js:8:21403
x</e.prototype.invokeClientMethod/<@http://localhost:50870/_framework/blazor.server.js:1:16651
x</e.prototype.invokeClientMethod@http://localhost:50870/_framework/blazor.server.js:1:16622
x</e.prototype.processIncomingData@http://localhost:50870/_framework/blazor.server.js:1:14619
e/this.connection.onreceive@http://localhost:50870/_framework/blazor.server.js:1:11163
N</e.prototype.connect/</</</i.onmessage@http://localhost:50870/_framework/blazor.server.js:1:30452
at Blazored.LocalStorage.LocalStorageService.GetItem[T](String key)
at Blazored.LocalStorage.LocalStorageService.RaiseOnChangingAsync(String key, Object data)
at Blazored.LocalStorage.LocalStorageService.SetItem(String key, Object data)
at Blazor.Gitter.Core.Components.Shared.AppState.SaveApiKey() in C:\Solutions\TemporarySolutions\Gitter\src\Blazor.Gitter.Core\Components\Shared\AppState.cs:line 115
at Blazor.Gitter.Core.Components.Pages.IndexModel.SignIn(Boolean remember) in C:\Solutions\TemporarySolutions\Gitter\src\Blazor.Gitter.Core\Components\Pages\Index.razor.cs:line 44
at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
at Microsoft.AspNetCore.Components.Rendering.Renderer.GetErrorHandledTask(Task taskToHandle) blazor.server.js:15:27350
log http://localhost:50870/_framework/blazor.server.js:15
b http://localhost:50870/_framework/blazor.server.js:8
v http://localhost:50870/_framework/blazor.server.js:8
invokeClientMethod http://localhost:50870/_framework/blazor.server.js:1
invokeClientMethod http://localhost:50870/_framework/blazor.server.js:1
processIncomingData http://localhost:50870/_framework/blazor.server.js:1
onreceive http://localhost:50870/_framework/blazor.server.js:1
onmessage http://localhost:50870/_framework/blazor.server.js:1
[2019-04-30T13:56:20.555Z] Information: Connection disconnected. blazor.server.js:1:5137
`
Given a component with this:
private bool DarkMode { get; set; }
public async void ToggleDarkMode(UIChangeEventArgs e)
{
await _SetDarkMode(!DarkMode);
}
private async Task _SetDarkMode(bool darkMode)
{
DarkMode = darkMode;
await localStorage.SetItem("DarkMode", DarkMode);
StateHasChanged();
Console.WriteLine($"DarkMode is now: {DarkMode}");
}
And an index.html
snippet like this:
<script type="text/javascript">
window.onstorage = function (ev) {
console.log(ev.key);
};
</script>
_SetDarkMode
does show up/toggle the value in Chrome's Application tab. However, the onstorage
event never fires that way.So I'm wondering if Chrome does something else to 'commit' the value (there doesn't appear to be a function like refresh()
or save()
), or if this is perhaps a side effect of the code running in an async or wasm context.
I have a class that has a property that is of an interface type. I decorated that property with [field:NonSerialized], but localStorage.SetItem serializes it as an empty set, and attempting to use GetItem throws an error: System.NotSupportedException: Deserialization of interface types is not supported. Type 'Blazored.LocalStorage.ISyncLocalStorageService'
Describe the bug
Either the docs or the nuget package, is missing a dependency on System.Text.Json. The app will crash if I don't add the nuget package manually.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
Preferably, this package should pull in System.Text.Json automatically.
Hosting Model (is this issue happening with a certain hosting model?):
Breaking change on 16.6.0 preview 5&6
When you start a blazor wasm app from the vs ide, it can't see any local storage values. It can save and then see its own storage values. Then if you close the app & start it again from the ide, the storage data is not there.
If the app is started directly from chrome using localhost address, the local storage works properly.
An issue has been created with the VS team:
dotnet/aspnetcore#21642
With the preview 8 update, adding <script src="_content/Blazored.LocalStorage/blazored-localstorage.js"></script> did not work. The browser reports this file cannot be found. As a workaround, I manually added blazored-localstorage.js to my client project and changed the script tag in index.html to point to that.
Hi, I face a problem using the library. Would it be possible to implement the feature presented below?
Is your feature request related to a problem? Please describe.
The interface ILocalStorageService does not provide any way to lists the key contained in local storage. In Javascript the solution is to iterate on the localStorage object.
This is however not implemented here and not alternative way is provided. Consequently, it's necessary to manually use the local storage to bookkeep the list of key, which is somewhat cumbersome.
Describe the solution you'd like
Implementation of the relevant interfaces (IEnumerable, IEnumerator) would allow consumers to use the same pattern as in Javascript to list keys present in local storage.
Describe alternatives you've considered
I've considered manually use the local storage to bookkeep the list of key.
Additional context
Keys are generated dynamically based on current time.
Describe the bug
localStorage.GetItemAsync<**string**>("test")
fails if localStorage record looks like this:
test|demoValue
If it is test|"demoValue" then everything works fine.
To Reproduce
Steps to reproduce the behavior:
Just add a new localStorage value manually in browser and try to read it with library. Try changing the value to be with and without quotes.
Expected behavior
Read the value without quotes as string as it's not expected to read our own localStorage values. Sometimes other library writes the values and we should read them.
Hosting Model (is this issue happening with a certain hosting model?):
Additional context
Using latest library package, 2.1.1
As far as I can tell you're passing all values during 'Set' through JsonSerializer.ToString
This means it's impossible to use my own serializer as I can't change the serializer settings to use custom types, and I can't pre-serialize and send as a string without it being converted.
Cyrillic Character Encoding Issues - "\u0420\u0443\u0441\u0441\u043A\u0438\u0439"
Hi,
I'm thinking of trying out Uno Platform and wondered if anyone knew or had tried Blazored LocalStorage with a Uno.Platform project. Going to go give it a shot but figured I'd ask.
Thanks,
Dave G
Describe the bug
If I create a brand new project and then install Blazored.LocalStorage
and start to use it straight away, it will throw an exception about File not found: System.Text.Json
To Reproduce
Steps to reproduce the behavior:
Blazored.LocalStorage
services.AddBlazoredLocalStorage();
and services.AddScoped<YourService>();
)Expected behavior
I think it should be compatible with the library within .Net Core or it should install the dependency automatically. (I'm not sure if System.Text.Json
is preinstalled but I can using
it. If I was wrong feel free to tell me!)
Screenshots
If I do not install System.Text.Json
here's what I get
Hosting Model (is this issue happening with a certain hosting model?):
I only tried:
Additional context
I'm using:
System.InvalidOperationException: JavaScript interop calls cannot be issued at this time. This is because the component is being prerendered and the page has not yet loaded in the browser or because the circuit is currently disconnected. Components must wrap any JavaScript interop calls in conditional logic to ensure those interop calls are not attempted during prerendering or while the client is disconnected.
at Microsoft.AspNetCore.Components.Server.Circuits.RemoteJSRuntime.BeginInvokeJS(Int64 asyncHandle, String identifier, String argsJson)
at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](String identifier, CancellationToken cancellationToken, Object[] args)
at Microsoft.JSInterop.JSRuntime.InvokeWithDefaultCancellation[T](String identifier, Object[] args)
at Blazored.LocalStorage.LocalStorageService.ContainKeyAsync(String key)
at FantyAdminWeb.Pages.Index.OnAfterRenderAsync(Boolean firstRender) in C:\git\fanty-tranfer-admin\Pages\Index.razor:line 405
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle)
My onafterrenderasync tasks:
await localStorage.SetItemAsync("healthcheck", true);
if (await localStorage.ContainKeyAsync("key"))
{
if (!string.IsNullOrEmpty(await localStorage.GetItemAsync<string>("key")))
{
amILogged = true;
}
if (amILogged)
{
try
{
createDepositsChart(DateTime.Now.AddDays(-7), DateTime.Now);
createUsersChart(DateTime.Now.AddDays(-7), DateTime.Now);
createRegistrationsChart(DateTime.Now.AddDays(-7), DateTime.Now);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
create charts methods are using "key" object from localStorage.
Error runs everytime when i go this site. Every GetItem is awaited.
If
createDepositsChart(DateTime.Now.AddDays(-7), DateTime.Now);
createUsersChart(DateTime.Now.AddDays(-7), DateTime.Now);
createRegistrationsChart(DateTime.Now.AddDays(-7), DateTime.Now);
are removed, all runs ok.
The NuGet package contains a tsconfig.json that I believe is included by mistake.
The file as far as I can see doesn't do anything and the package does not reference TypeScript as a dependency.
This extra file breaks my projects.
I think it's just a couple of nuget updates and modify the Json.Net use. Thank you.
Great work.
For my own benefit I created an example based on the count page coming with the default template. I thought it might be a simpler and more recognizable alternative sample. Use it if you think it makes sense.
@page "/counter"
@inject LocalStorage localStorage
@implements IDisposable
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private const string key = "count";
private int currentCount = 0;
protected override Task OnInitializedAsync()
{
localStorage.StorageChanged += StorageChanged;
currentCount = localStorage.GetItem<int?>(key) ?? 0;
return base.OnInitializedAsync();
}
private void StorageChanged(object sender, StorageEventArgs e)
{
if (e.Key == key)
{
currentCount = int.Parse(e.OldValue.ToString());
StateHasChanged();
}
}
private async Task IncrementCount()
{
var item = localStorage.GetItem<int?>(key) ?? 0;
item++;
currentCount = item;
await localStorage.SetItemAsync(key, item).ConfigureAwait(false);
}
public void Dispose()
{
localStorage.StorageChanged -= StorageChanged;
}
}
Hello Chris, since the last version it seem there is a bug on the integer serialisation.
When i try to retieve the value, i have this exception (at leats on server side project)
Unable to cast object of type 'System.String' to type 'System.Nullable`1[System.Int32]'.'
To reproduce this (on your sample project for example)
<div class="row">
<div class="col-md-4">
<button class="btn btn-primary" @onclick="SaveInteger">set 5 in local storage</button>
</div>
<div class="col-md-4">
<button class="btn btn-primary" @onclick="LoadInteger">read 5 in local storage</button>
</div>
<div class="col-md-4">
<h5>Value in local storage</h5>
@IntegerValue
</div>
</div>
int? IntegerValue;
async Task SaveInteger()
{
await localStorage.SetItemAsync("integerValue", 5);
}
async Task LoadInteger()
{
IntegerValue = await localStorage.GetItemAsync<int?>("integerValue");
this.StateHasChanged();
}
its the same thing if the integer is not nullable
thanks !
Describe the bug
For some reason data isn't over written when app is on IIS, when I run it on my visual studio, works perfect. See below code:
To Reproduce
On one page, this saves my user's data when logged in:
` async Task saveUID()
{
Users user = await Users.loginUser(Username, Password);
await localStorage.SetItemAsync("uid", user.id);
await localStorage.SetItemAsync("first_name", user.firstname);
await localStorage.SetItemAsync("userdata", user);
}
`
Then I go to user profile page, with following code:
protected override async Task OnInitializedAsync() { uid = await localStorage.GetItemAsync<int>("uid"); first_name = await localStorage.GetItemAsync<string>("first_name"); user = await Users.loginUser("", "", uid); }
Login with one user, read data, save new user data and try to read it.
Expected behavior
It should get data from localstorage, and as I said, when I run it in Visual Studio it works spot on, when I transfer it to IIS server, doesn't and
Hosting Model (is this issue happening with a certain hosting model?):
Otherwise you will get complete shutdown of the page if a JavaScript call fails.
You can see here a sample stack trace of my error:
Diese Ausnahme wurde ursprünglich bei dieser Aufrufliste ausgelöst:
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
System.Threading.Tasks.ValueTask.Result.get()
Microsoft.JSInterop.JSRuntime.InvokeWithDefaultCancellation(string, object[])
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
Blazored.LocalStorage.LocalStorageService.GetItemAsync(string)
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
...
Please be sure to check the readme file before raising an issue.
I am trying to use Blazor storage library in Blazor Hosted WebAssembly.
public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.Services.AddAuthorizationCore();
builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddBlazoredLocalStorage();
builder.Services.AddBlazoredSessionStorage();
builder.Services.AddScoped<AppStateInfo,AppStateInfo>();
builder.Services.AddScoped<CustomAuthenticationStateProvider>();
builder.Services.AddScoped<AuthenticationStateProvider>(provider =>
provider.GetRequiredService<CustomAuthenticationStateProvider>());
builder.Services.AddOptions();
var host = builder.Build();
await host.RunAsync();
}
}
Error i get is as follow
Unhandled exception rendering component: Unable to resolve service for type 'Blazored.LocalStorage.LocalStorageService' while attempting to activate 'myCustomApp.Services.CustomAuthenticationStateProvider'.
System.InvalidOperationException: Unable to resolve service for type 'Blazored.LocalStorage.LocalStorageService' while attempting to activate 'myCustomApp.CustomAuthenticationStateProvider'.
My Constructor looks like this and class is in the Blazor Client Project
public CustomAuthenticationStateProvider(Blazored.LocalStorage.LocalStorageService LocalStorage,
Blazored.SessionStorage.SessionStorageService SessionStorage, AppStateInfo AppStateInfo, HttpClient Http)
{
_localStorage = LocalStorage;
_SessionStorage = SessionStorage;
_appStateInfo = AppStateInfo;
_Http = Http;
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.