timewarpengineering / blazor-state Goto Github PK
View Code? Open in Web Editor NEWA Blazor State management library by TimeWarp.
License: The Unlicense
A Blazor State management library by TimeWarp.
License: The Unlicense
Not needed anymore (and current refers to preview 6 and 7)
Documentation is currently very miserable.
It should describe how to use the library in more detail:
Basic and minimal TODO example should be included in the docs for easier adoption.
Can I just inject the needed state into a blazor layout?
Hi there
Is there an new version for this release or do I create the state service differently as I am getting an exception when running the app.
blazor.webassembly.js:1 WASM: Error: Failed to start platform. Reason: [object XMLHttpRequest]
It looks like the BlazorStateComponent base class implements IDisposable but isnt virtual. How can we implement IDisposable in our own components derived from BlazorStateComponent?
Hey,
I am trying to implement the Blazor-state library in an new project i am working on. I also managed to get the redux dev tools working with the ASPNETCORE_ENVIRONMENT "Development" in my launchSettings.json.
But I also have a environment called "Test" where I want the redux dev tools to be enabled. But the moment I change the ASPNETCORE_ENVIRONMENT to "Test" the blazor-state.js is not published to the _content folder anymore?
So this is my first time building a state based app, but I'm pretty sure it shouldn't be like this.
If you start the TimewarpBlazorApp Template and go to the Counter Page, you can click the Button, which is fine. The Count increases as it should.
But if you spam it, every action will add a 2 new Subscribers, increasing the times the whole component is re-rendered with every click.
So when the Counter hits 140, you can really notice the slowdown.
Is there a way, to remove duplicate Subscriptions? Resetting the Store doesn't help either...
State is created by the Store when requested and doesn't already exist. It uses the DI Container to create the state but Initialize was being called in the constructor of the base class which would be called prior to the constructor in the derived class.
Thus Initialization couldn't use any of the to be constructed items.
Take the Counter component. Say you put 3 versions on the same page. If you click the button multiple times, the state changes in one component. If you navigate away and back, all three components now show the same state.
It would be useful to use the same component in an application without sharing state.
Or do you recommend another approach for this use case?
Hi I have a stackoverflow question here.
I am using mudblazor and blazor-state together it was working great until I ran into a problem where I was using an action to set the type of a DynamicComponent, I expected it to render and show the component which it doesn't. It looks like the dom is not updating, only when I click the link a second time the component shows up, I have uploaded the code here, any help will be much appreciated.e uploaded the code here, any help will be much appreciated.
I need to capture state changes in an InputBase component for custom controls. I can't inherit from BlazorStateComponent.
What's the best way to achieve this?
Microsoft.Extensions.DependencyInjection not supports lazy service registration, but in this case that would be useful. Do you have any ideas, how to solve this issue
For some reason the Nuget REST API doesn't return details about your package:
https://azuresearch-usnc.nuget.org/query?q=packageid:Blazor-State
I've sent a support email to Nuget about this, but thought I'll notify you as well.
This is a two fold question. One I have a component but rather than put the code behind in a code block (@code {...}) I have defined a partial class. But if I do that GetState is not resolved. Two, The only way I can do it is if in the razor I have @using BlazorState and @inherits BlazorStateComponent. But if I do that GetState returns null and throws an exception because it has determined that the state is null even though I have initialized the state and mutating the state seems to work fine. How can I handle this situation without putting all of the code in a @code block?
I've been following the tutorial available here. However, after completing the Displaying state in the user interface stage, I attempt to run the app and receive the following two errors:
InvalidOperationException: Error while validating the service descriptor 'ServiceType: BlazorState.Features.JavaScriptInterop.JsonRequestHandler Lifetime: Scoped ImplementationType: BlazorState.Features.JavaScriptInterop.JsonRequestHandler': Unable to resolve service for type 'System.Text.Json.JsonSerializerOptions' while attempting to activate 'BlazorState.Features.JavaScriptInterop.JsonRequestHandler'.
InvalidOperationException: Unable to resolve service for type 'System.Text.Json.JsonSerializerOptions' while attempting to activate 'BlazorState.Features.JavaScriptInterop.JsonRequestHandler'.
I copy of my source can be found here .
Currently running on preview 8 build 28405-07
I followed the tutorial under documentation and all seemed to work but I looked at the output of the debugger console in Chrome DEV Tools and I see these messages:
Redux DevTools are not installed.
ReduxDevTools.ts:53 Unable to connect to Redux DevTools.
Initialize.ts:12 InitializeJavaScriptInterop
Should I be concerned? They are not error messages but I don't think I am connected with the Chrome Redux DEV Tools.
Hi
I have tired many things to improve the performance but I am worried I am doing it very wrong. It appears that maybe memory is being recovered between calls as the first call return in about 400ms but after that it takes about 4000ms.
State object member is an array
public INQ_ID4U_ENT_DTO[] MeItems { get; private set; }
I get the data from the server like this
INQ_ID4U_ENT_DTO[] MeItems = await _httpClient.GetJsonAsync<INQ_ID4U_ENT_DTO[]>($"id4u_ent/inq_id4u_ent", "in4m_now");
Only when I set the state variable to the array returned from the HTTP call does it become very slow.
I am seeing these messages in the console at each call.
L: GC_MAJOR_SWEEP: major size: 2784K in use: 28752K
blazor.webassembly.js:1 L: GC_MAJOR: (LOS overflow) time 8.89ms, stw 8.90ms los size: 1024K in use: 8K
Should I not use the blazer state to receive and cache datasets?
thanks you
Julian
When using Redux DevTools, after following the tutorial, if I attempt to "Jump" to a point in time I get a WASM error of the following:
System.Text.Json.JsonException: The JSON value could not be converted to System.Int32. Path: $.id | LineNumber: 0 | BytePositionInLine: 376. ---> System.InvalidOperationException: Cannot get the value of a token type 'String' as a number.
Looking into it a bit it seems the id from states are serialized as strings, while Newtonsoft handled this well, System.Text.Json does not. Have you come across this before?
I'm dispatching two actions under one method. The state will change (Message1 first then 1 second later Message2) but the UI will only update after the method that calls the two message update actions finishes.
I've replicate this issue in this repo. I found this issue while at work trying to implement a loading screen.
To see this navigate to "/State" and click the button. The first false should turn true instantly and the second should turn true after one second.
The page is called "State" and the message handlers and actions are under Common/State/Details
After implementing the same state management using both Fluxor and Blazor-State, it strikes me that the most significant difference is that Blazor-State combines the notions of Reducers and Effects into one thing, called "Handlers". In Blazor-State, a handler is by default asynchronous, so that you can dispatch (called "Send" in Blazor-State) an action, then its handler can modify the state, then call out to a web service or other "outside" thing asynchronous, then modify the state again. So, for a routine action that gets data from a service, in Blazor-State, I need only one action and one handler. The caller can do things while the handler starts running, then await the single dispatch call when we want to react to it. On the await, the component can (will) rerender with the newly changed state (e.g. to show a Loading spinner based on the state) and then after the await completes, the component can (will) rerender with the newly changed state (e.g. to remove the spinner and show the new data from the state).
Fluxor has separate Effects and Reducers, so to do the same thing in Fluxor, I need two separate actions and thus two reducers, and an effect: One parameterless action that results in a reducer and invokes the Effect, then the Effect calls an outside service in a background task that my component can't see, then the effect dispatches a second action, whose reducer can change the state with the newly received data.
My naive look at things makes me appreciate the simpler model of Blazor-State with its combined effects and reducers--I don't see what the added complexity of separating them (in Fluxor) gives me as a benefit.
Your good friend Mr. P. Morris wants to keep Fluxor to the same pattern established in Redux/Flux and so isn't enamored with combining them. But more interestingly for Blazor-State, he says: "I think you have actually found a bug in Blazor State rather than a feature. As the changes are not being notified to subscribers, then you have to have a call to StateHasChanged before the await in Step 2 in order to see the middle changes, but then you are putting UI logic into your reducer and also tying your logic to a single UI framework. Essentially, your state is getting concerned with rendering details, and that's not a good mix."
But I see it as a feature and not a bug; there are many cases where I might want to change my state, let the components render, then change the state again and let them render again. It seems that narrower case is common enough to justify it.
I also don't see a confusion of concerns: the handler (what he calls reducer) need not call StateHasChanged, but it need only await the first asynchronous as in any ordinary asynchronous fashion. The component will automatically rerender on the first await.
Now there is nowhere in this pattern to allow any intermediate changes to cause a rerender--say I make three changes to the state, and await the first and second changes; the second change will not cause a rerender. How would you handle such a need to rerender if I wanted to update the state three times in a handler?
And finally, reacting to Mr. P. Morris, do you think this is a bug or a good feature? And is it a good feature just because it is useful, or does it actually follow from some design/architecture decision to break from the Flux pattern?
(This is spurred by a discussion in the Fluxor issues.)
Hi,
I have the one page with many tabs. Every tab has it's own instance of an object (Simulation 1, Simulation 2, ...), so every object has independent data.
If I create SimulationState class and then I change data on Simulation 1 Tab, state will be changed and data will be updated on all other tabs too.
So, it is possible to have a state per object instance? Any ideas?
Thank you.
It looks like the State is Initialized twice when a BlazorStateComponent is the opening page.
Steps to test with with the Blazor Counter example:
My workaround is a Loaded logic on the MainLayout.razor component:
bool Loaded { get; set; }
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
Loaded = true;
StateHasChanged();
}
base.OnAfterRender(firstRender);
}
No BlazorStateComponents are loaded until the Loaded flag is true.
The tutorial indicates
void IncrementCount()
{
Mediator.Send(new CounterState.IncrementCountAction { Amount = 5 });
}
But in realty the Send method returns a Task and requires a instance of the object. Should the tutorial be updated? So it seems the overall project will not compile. For example when I move this code in my own project I get:
namespace BreakpointManagement.Shared.Features.BreakpointManagement
{
public partial class BreakpointManagementState
{
public class UpdateProjectAction : IAction
{
public BreakpointProjectSummary Project { get; set; }
}
}
}
It seems that to call this method (Send) you have to have an instance of Mediator and the constructor depends on ServiceFactory. So the long and short of it is that I don't know how to create an instance of Mediator?
I think it will be a nice addition to be able to execute something when the component is disposed. Something like this maybe in BlazorStateComponent.cs
. What do you think?
protected virtual void OnDispose() { }
public void Dispose()
{
Subscriptions.Remove(this);
OnDispose();
}
Hi, I am using Blazor.State for a while now and I like it very much. I am used to MediatR, that made it a simple choice for me.
The new ASP.NET CORE roadmap shows, that Blazor server-side will be released first (called Razor-Components). It would be incredible valuable, If we could use Blazor.State for both modes.
Request: The store should be unique to the current user-session. Maybe even optional, to have a global-state (Themes, Locale ...) for everyone and personal state for the rest.
Do you think this is feasable?
Memory management could be something to think about too. Maybe saving state to disc or to Redis or SQL would give additional value.
Will Blazor-state support generics in the State something like this?
public partial class SomeState<T> : State<SomeState<T>>
{
public IEnumerable<T> List { get; private set; }
}
I was using Fluxor until I found out it would not support Generic types.
Fatal error in Mono IL Linker build 04-Nov-2020 18:57:16 /home/bamboo/.nuget/packages/microsoft.aspnetcore.components.webassembly.build/3.2.1/targets/Blazor.MonoRuntime.targets(326,5): error : Unhandled exception. Mono.Linker.MarkException: Error processing method: 'System.Void SmartWorkflow.Application.Processors.SaveWorkItemProcessor/<Run>d__6::MoveNext()' in assembly: 'SmartWorkflow.Application.dll' [/home/bamboo/bamboo-agent-home/xml-data/build-dir/PHOENIX-SWM1-TESTANDPUBLISH/src/Marvin/Client/Marvin.Client.csproj] build 04-Nov-2020 18:57:16 ---> Mono.Cecil.ResolutionException: Failed to resolve System.Threading.Tasks.Task
1<!!0> MediatR.IMediator::Send(MediatR.IRequest1<!!0>,System.Threading.CancellationToken) build 04-Nov-2020 18:57:16 at Mono.Linker.Steps.MarkStep.HandleUnresolvedMethod(MethodReference reference) build 04-Nov-2020 18:57:16 at Mono.Linker.Steps.MarkStep.MarkMethod(MethodReference reference) build 04-Nov-2020 18:57:16 at Mono.Linker.Steps.MarkStep.MarkInstruction(Instruction instruction) build 04-Nov-2020 18:57:16 at Mono.Linker.Steps.MarkStep.MarkMethodBody(MethodBody body) build 04-Nov-2020 18:57:16 at Mono.Linker.Steps.MarkStep.ProcessMethod(MethodDefinition method) build 04-Nov-2020 18:57:16 at Mono.Linker.Steps.MarkStep.ProcessQueue() build 04-Nov-2020 18:57:16 --- End of inner exception stack trace --- build 04-Nov-2020 18:57:16 at Mono.Linker.Steps.MarkStep.ProcessQueue() build 04-Nov-2020 18:57:16 at Mono.Linker.Steps.MarkStep.ProcessPrimaryQueue() build 04-Nov-2020 18:57:16 at Mono.Linker.Steps.MarkStep.Process() build 04-Nov-2020 18:57:16 at Mono.Linker.Steps.MarkStep.Process(LinkContext context) build 04-Nov-2020 18:57:16 at Mono.Linker.Pipeline.ProcessStep(LinkContext context, IStep step) build 04-Nov-2020 18:57:16 at Mono.Linker.Pipeline.Process(LinkContext context) build 04-Nov-2020 18:57:16 at Mono.Linker.Driver.Run(ILogger customLogger) build 04-Nov-2020 18:57:16 at Mono.Linker.Driver.Execute(String[] args, ILogger customLogger) build 04-Nov-2020 18:57:16 at Mono.Linker.Driver.Main(String[] args) build 04-Nov-2020 18:57:16 /home/bamboo/.nuget/packages/microsoft.aspnetcore.components.webassembly.build/3.2.1/targets/Blazor.MonoRuntime.targets(326,5): error : ILLink failed with exit code 134. [src/Marvin/Client/Marvin.Client.csproj]
The reference up there SmartWorkflow.Application uses the same Mediatr version as this project.
as soon as I reverted back to 3.2.4 it worked fine again.
Serverside or client-side although honestly, both would be nice.
Hi,
As the title say I would like to listen to the store to know when it has been updated to react to it. I cannot find a easy way to do it, could you provide some guidance?
What would be your guidance for singleton services?
I tried to implement a simple handler that takes a depency on the singleton service instead of the scoped store.
Unfortunately the subscriptions are scoped as well.
Updated to Preview 8 and cannot build my project.
When running I get the following error:
2>Unhandled Exception: Mono.Linker.MarkException: Error processing method: 'System.Void BlazorState.BlazorStateComponent::ReRender()' in assembly: 'BlazorState.dll' ---> Mono.Cecil.ResolutionException: Failed to resolve System.Threading.Tasks.Task Microsoft.AspNetCore.Components.ComponentBase::Invoke(System.Action)
2> at Mono.Linker.Steps.MarkStep.HandleUnresolvedMethod(MethodReference reference)
2> at Mono.Linker.Steps.MarkStep.MarkMethod(MethodReference reference)
2> at Mono.Linker.Steps.MarkStep.MarkInstruction(Instruction instruction)
2> at Mono.Linker.Steps.MarkStep.MarkMethodBody(MethodBody body)
2> at Mono.Linker.Steps.MarkStep.ProcessMethod(MethodDefinition method)
2> at Mono.Linker.Steps.MarkStep.ProcessQueue()
Most likely due to the fact that ComponentBase.Invoke
needs to be changed to ComponentBase.InvokeAsync
per https://devblogs.microsoft.com/aspnet/asp-net-core-and-blazor-updates-in-net-core-3-0-preview-8/
Might be other changes that need to be made as well.
Hi, I suggest combining the Features
and Pages
folders. The Counter.cshtml
(and in my case the additional Counter.cshtml.cs
) files should be placed beside the other code.
The whole concept of feature folders was to have exactly ONE place to look for one feature. Even CSS/SCSS
and JS
should be placed here IMHO.
You can just rename Pages
to Features
. Blazor
will find the pages.
I would even move NavMenu
and SurveyPrompt
into the Features
folder. They are components too.
The only exception has to be the MainLayout.cshtml
, it seems to be a Blazor
restriciton.
blazor.webassembly.js:1 Uncaught (in promise) Error: System.BadImageFormatException: Could not resolve field token 0x04000113, due to: Could not load type of field 'IN4SAdminClient.Startup+<>c:<>9__0_0' (1) due to: Could not resolve type with token 01000024 from typeref (expected class 'BlazorState.BlazorStateOptions' in assembly 'BlazorState, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null') assembly:BlazorState, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null type:BlazorState.BlazorStateOptions member:(null) assembly:IN4SAdminClient.dll type:<>c member:(null)
I noticed that small state changes that happen while an action is being handled do not always trigger 'StateHasChanged'.
The IsLoading variable isn't flipping while we are in the 10 second 'Thread.Sleep' [designed to simulate loading data].
Another thing to note is that using the Redux Dev Tools the states respond out of order.
The reason I mentioned small state changes is when we are using this in a production app (that actually gets data from the DB) sometimes the IsLoading variable change is detected.
The workflow I have implemented is as follows:
State:
public partial class AppState : State<AppState>
{
public DateTime? InstanceTime { get; private set; }
public DateTime? SecondInstanceTime { get; private set; }
public bool IsLoading { get; private set; }
public override void Initialize()
{
InstanceTime = null;
SecondInstanceTime = null;
IsLoading = false;
}
}
Action:
public partial class AppState
{
public class GetTimeAction : IAction
{
}
public class SetTimeAction : IAction
{
public DateTime timeObject { get;}
public SetTimeAction(DateTime dt)
{
timeObject = dt;
}
}
}
Handler:
public partial class AppState
{
public class GetTimeHandler : ActionHandler<GetTimeAction>
{
private readonly IMediator _mediator;
private AppState AppState => Store.GetState<AppState>();
public GetTimeHandler(IStore aStore, IMediator mediator) : base(aStore)
{
_mediator = mediator;
}
public override async Task<Unit> Handle(GetTimeAction aAction, CancellationToken aCancellationToken)
{
var dt = DateTime.Now;
await _mediator.Send(new SetTimeAction(dt), aCancellationToken);
AppState.InstanceTime = dt;
AppState.IsLoading = true;
return await Unit.Task;
}
}
public class SetTimeHandler : ActionHandler<SetTimeAction>
{
private readonly IMediator _mediator;
private AppState AppState => Store.GetState<AppState>();
public SetTimeHandler(IStore aStore, IMediator mediator) : base(aStore)
{
_mediator = mediator;
}
public override async Task<Unit> Handle(SetTimeAction aAction, CancellationToken aCancellationToken)
{
Thread.Sleep(10000);
AppState.SecondInstanceTime = aAction.timeObject;
AppState.IsLoading = false;
return await Unit.Task;
}
}
}
Index base:
public class IndexBase : BlazorStateComponent
{
protected AppState AppState => GetState<AppState>();
protected long DateTicks = DateTime.Now.Ticks;
protected async Task GetTimes()
{
await Mediator.Send(new AppState.GetTimeAction());
}
}
Index.razor
@page "/"
@inherits IndexBase
<button class="btn btn-info" @onclick="GetTimes">
Go!
</button>
<p>Page Load Time: @DateTicks</p>
<p>Page Is Loading: @AppState.IsLoading</p>
<br />
@if (AppState.InstanceTime.HasValue)
{
<p>First Time Ticks: @AppState.InstanceTime.Value.Ticks</p>
}
else
{
<p>First Time Ticks:</p>
}
@if (AppState.SecondInstanceTime.HasValue)
{
<p>Second Time Ticks: @AppState.SecondInstanceTime.Value.Ticks</p>
}
else
{
<p>Second Time Ticks:</p>
}
Hello,
When trying to jump to a specific state in redux-dev-tools we got the following error in the debug console:
Unhandled Exception:
System.Text.Json.JsonException: The JSON value could not be converted to System.Int32. Path: $.id | LineNumber: 0 | BytePositionInLine: 338. ---> System.InvalidOperationException: Cannot get the value of a token type 'String' as a number.
at System.Text.Json.Utf8JsonReader.TryGetInt32 (System.Int32& value) <0x3056c08 + 0x0001e> in <filename unknown>:0
at System.Text.Json.Utf8JsonReader.GetInt32 () <0x3056b30 + 0x00008> in <filename unknown>:0
at System.Text.Json.Serialization.Converters.JsonConverterInt32.Read (System.Text.Json.Utf8JsonReader& reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) <0x3054370 + 0x00004> in <filename unknown>:0
at System.Text.Json.JsonPropertyInfoNotNullable`4[TClass,TDeclaredProperty,TRuntimeProperty,TConverter].OnRead (System.Text.Json.ReadStack& state, System.Text.Json.Utf8JsonReader& reader) <0x317a730 + 0x0003c> in <filename unknown>:0
at System.Text.Json.JsonPropertyInfo.Read (System.Text.Json.JsonTokenType tokenType, System.Text.Json.ReadStack& state, System.Text.Json.Utf8JsonReader& reader) <0x2f20268 + 0x00088> in <filename unknown>:0
at System.Text.Json.JsonSerializer.HandleValue (System.Text.Json.JsonTokenType tokenType, System.Text.Json.JsonSerializerOptions options, System.Text.Json.Utf8JsonReader& reader, System.Text.Json.ReadStack& state) <0x2f1fe10 + 0x000a6> in <filename unknown>:0
at System.Text.Json.JsonSerializer.ReadCore (System.Text.Json.JsonSerializerOptions options, System.Text.Json.Utf8JsonReader& reader, System.Text.Json.ReadStack& readStack) <0x2f1f738 + 0x0008e> in <filename unknown>:0
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath (System.Text.Json.ReadStack& readStack, System.Text.Json.Utf8JsonReader& reader, System.Exception ex) <0x31d1828 + 0x00028> in <filename unknown>:0
at System.Text.Json.JsonSerializer.ReadCore (System.Text.Json.JsonSerializerOptions options, System.Text.Json.Utf8JsonReader& reader, System.Text.Json.ReadStack& readStack) <0x2f1f738 + 0x00320> in <filename unknown>:0
at System.Text.Json.JsonSerializer.ReadCore (System.Type returnType, System.Text.Json.JsonSerializerOptions options, System.Text.Json.Utf8JsonReader& reader) <0x30659a8 + 0x0002e> in <filename unknown>:0
at System.Text.Json.JsonSerializer.Deserialize (System.String json, System.Type returnType, System.Text.Json.JsonSerializerOptions options) <0x3065338 + 0x0017a> in <filename unknown>:0
at BlazorState.Features.JavaScriptInterop.JsonRequestHandler.Handle (System.String aRequestTypeAssemblyQualifiedName, System.String aRequestAsJson) <0x310ed78 + 0x0014c> in <filename unknown>:0
at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__7_1 (System.Object state) <0x31d55c8 + 0x0000c> in <filename unknown>:0
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context (System.Object state) <0x31d5578 + 0x00022> in <filename unknown>:0
at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) <0x285dbf8 + 0x00100> in <filename unknown>:0
at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) <0x285d9b8 + 0x00010> in <filename unknown>:0
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem () <0x31d5508 + 0x00038> in <filename unknown>:0
at System.Threading.ThreadPoolWorkQueue.Dispatch () <0x2f625b8 + 0x00102> in <filename unknown>:0
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback () <0x2f62220 + 0x00000> in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.Text.Json.JsonException: The JSON value could not be converted to System.Int32. Path: $.id | LineNumber: 0 | BytePositionInLine: 338. ---> System.InvalidOperationException: Cannot get the value of a token type 'String' as a number.
at System.Text.Json.Utf8JsonReader.TryGetInt32 (System.Int32& value) <0x3056c08 + 0x0001e> in <filename unknown>:0
at System.Text.Json.Utf8JsonReader.GetInt32 () <0x3056b30 + 0x00008> in <filename unknown>:0
at System.Text.Json.Serialization.Converters.JsonConverterInt32.Read (System.Text.Json.Utf8JsonReader& reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) <0x3054370 + 0x00004> in <filename unknown>:0
at System.Text.Json.JsonPropertyInfoNotNullable`4[TClass,TDeclaredProperty,TRuntimeProperty,TConverter].OnRead (System.Text.Json.ReadStack& state, System.Text.Json.Utf8JsonReader& reader) <0x317a730 + 0x0003c> in <filename unknown>:0
at System.Text.Json.JsonPropertyInfo.Read (System.Text.Json.JsonTokenType tokenType, System.Text.Json.ReadStack& state, System.Text.Json.Utf8JsonReader& reader) <0x2f20268 + 0x00088> in <filename unknown>:0
at System.Text.Json.JsonSerializer.HandleValue (System.Text.Json.JsonTokenType tokenType, System.Text.Json.JsonSerializerOptions options, System.Text.Json.Utf8JsonReader& reader, System.Text.Json.ReadStack& state) <0x2f1fe10 + 0x000a6> in <filename unknown>:0
at System.Text.Json.JsonSerializer.ReadCore (System.Text.Json.JsonSerializerOptions options, System.Text.Json.Utf8JsonReader& reader, System.Text.Json.ReadStack& readStack) <0x2f1f738 + 0x0008e> in <filename unknown>:0
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath (System.Text.Json.ReadStack& readStack, System.Text.Json.Utf8JsonReader& reader, System.Exception ex) <0x31d1828 + 0x00028> in <filename unknown>:0
at System.Text.Json.JsonSerializer.ReadCore (System.Text.Json.JsonSerializerOptions options, System.Text.Json.Utf8JsonReader& reader, System.Text.Json.ReadStack& readStack) <0x2f1f738 + 0x00320> in <filename unknown>:0
at System.Text.Json.JsonSerializer.ReadCore (System.Type returnType, System.Text.Json.JsonSerializerOptions options, System.Text.Json.Utf8JsonReader& reader) <0x30659a8 + 0x0002e> in <filename unknown>:0
at System.Text.Json.JsonSerializer.Deserialize (System.String json, System.Type returnType, System.Text.Json.JsonSerializerOptions options) <0x3065338 + 0x0017a> in <filename unknown>:0
at BlazorState.Features.JavaScriptInterop.JsonRequestHandler.Handle (System.String aRequestTypeAssemblyQualifiedName, System.String aRequestAsJson) <0x310ed78 + 0x0014c> in <filename unknown>:0
at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__7_1 (System.Object state) <0x31d55c8 + 0x0000c> in <filename unknown>:0
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context (System.Object state) <0x31d5578 + 0x00022> in <filename unknown>:0
at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) <0x285dbf8 + 0x00100> in <filename unknown>:0
at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) <0x285d9b8 + 0x00010> in <filename unknown>:0
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem () <0x31d5508 + 0x00038> in <filename unknown>:0
at System.Threading.ThreadPoolWorkQueue.Dispatch () <0x2f625b8 + 0x00102> in <filename unknown>:0
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback () <0x2f62220 + 0x00000> in <filename unknown>:0
Uncaught ExitStatusLe thread 0x1268 s'est arrêté avec le code 0 (0x0).
Just before this error message, we got the following log:
ReduxDevTools.MessageHandler
Redux Dev tools type: START maps to BlazorState.Pipeline.ReduxDevTools.StartRequest
Dispatching request of Type BlazorState.Pipeline.ReduxDevTools.StartRequest: {"type":"START","source":"@devtools-extension"}
ReduxDevTools.MessageHandler
Redux Dev tools type: DISPATCH maps to BlazorState.Pipeline.ReduxDevTools.JumpToStateRequest
Dispatching request of Type BlazorState.Pipeline.ReduxDevTools.JumpToStateRequest: {"type":"DISPATCH","payload":{"type":"JUMP_TO_ACTION","actionId":1},"state":"{\"BlazorApp1.Client.Features.Counter.CounterState\":{\"count\":8,\"guid\":\"c2eed289-fda1-494f-883a-c2245eee0284\"},\"BlazorState.Features.Routing.RouteState\":{\"route\":\"https://localhost:5001/\",\"guid\":\"2331cb89-6ee1-4a78-8f6e-24ecdf85aab5\"}}","id":"1","source":"@devtools-extension"}
Here the json formatted:
{
"type": "DISPATCH",
"payload": {
"type": "JUMP_TO_ACTION",
"actionId": 1
},
"state": "{\"BlazorApp1.Client.Features.Counter.CounterState\":{\"count\":8,\"guid\":\"c2eed289-fda1-494f-883a-c2245eee0284\"},\"BlazorState.Features.Routing.RouteState\":{\"route\":\"https://localhost:5001/\",\"guid\":\"2331cb89-6ee1-4a78-8f6e-24ecdf85aab5\"}}",
"id": "1",
"source": "@devtools-extension"
}
From my understanding, this is because of DispatchRequest and the property Id
internal class DispatchRequest<TPayload>
{
public int Id { get; set; }
public TPayload Payload { get; set; }
public string Source { get; set; }
public string State { get; set; }
public string Type { get; set; }
}
Indeed Id
is an integer and on the JSON it's a string
.
I'm using the redux-dev-tools version 2.17.0
Try following the instructions on https://timewarpengineering.github.io/blazor-state/Sample.html verbatim.
Your first compile error will come with GetState which appears not to exist. The second comes in implementing partials.
Basically, nothing works. I've just tried it twice.
Hi,
I'm using Blazor-state with the UseCloneStateBehavior enabled.
Everything worked fine until I introduce a value object in my state. This change throws a FieldAccessException when calling my reducer. I think this is because blazor-state doesn't know how to clone this value object, so I have implemented the IClonable interface for it, but that doesn't fix the issue.
Is there a way to make it work ?
thank you !
Hi
When i add your Nuget package "Blazor-State" (preview-6), a linked file "libman.json" appears in the project.
Is this file needed / intended?
It can not be deleted.
Cheers
Hi,
I am starting now my journey with Blazor. Is there any practice how to initialize the state from local storage?
public partial class UserProfileState : State<UserProfileState>
{
public string DisplayName { get; private set; }
public override void Initialize()
{
// here I would like to use local storage to check if I can init state from local storage
DisplayName = "";
}
}
blazor.state 1.0.0-preview6.19307.2-20190710-124031
.NET Core 3.0.100-preview6-012264
I found some time to experiment with the current Blazor preview and blazor.state. I seem to have ironed out most of the glitches but I have one problem, still:
I need to use IOrderedEnumerable<KeyValuePair<string, int>>
but AnyClone does not support this format.
Until now, I just implemented public override object Clone() => new TilesState(this);
but this does not work any longer.
One solution would be to have the Clone method optional. Use only if overridden.
If you have a better Idea, I am all ears.
Error:
AnyClone.TypeException: Unsupported IEnumerable type: OrderedEnumerable`2
at AnyClone.CloneProvider`1.
Hi there
thanks for the great library
Are there any plans to upgrade to support the latest preview?
thanks
Julian
Hi,
I played a bit with the code in the tutorial (https://timewarpengineering.github.io/blazor-state/Tutorial.html).
After that, I injected a IStore inside the NavMenu template.
In the code, I wrote the following: int Count => Store.GetState().Count;
Based on that, I am able to present the count value behind the Counter link in het NavMenu:
Counter (@count)
It initializes correctly when the application starts up.
Although the value is not updated on each click on the button on the Counter page but only after routing to another page.
How can I implement live updates on the NavMenu after every change in CounterState?
Thank you for your reply and help!
Regards,
Folkert
Hi, first of all thanks for sharing your work.
Hi, I want to try ReduxDevTools with blazor-state, but didn't found sample in docs
services.AddBlazorState(conf => {
conf.Assemblies = new[]{
typeof(Startup).Assembly,
};
conf.UseReduxDevToolsBehavior = true;
});
p.s. a
prefix for args name in public methods is annoing
I was having a play around with your timewarp-blazor template and I noticed an issue if you were to make the weather forecast service call an actual API instead of returning mock data.
In .\MyTimeWarpBlazorApp\Source\Server\Features\WeatherForecast\GetList\GetWeatherForecastsHandler.cs if you were to inject HttpClient, the noticeable error you'd see is "Error constructing handler for request of type MediatR.IRequestHandler" but in the InnerException you'd see the actual problem is "RemoteNavigationManager' has not been initialized".
To reproduce the error, you can just add a constructor in the above mentioned file with HttpClient as parameter to be injected.
I've done it in the below way following a thread about this problem:
private readonly IServiceProvider _provider;
public GetWeatherForecastsHandler(IServiceProvider provider)
{
_provider = provider;
}
public async Task<GetWeatherForecastsResponse> Handle
(
GetWeatherForecastsRequest aGetWeatherForecastsRequest,
CancellationToken aCancellationToken
)
{
HttpClient client = _provider.GetRequiredService<HttpClient>();
}
This is not a problem with Blazor-State itself (as I understand) but I'd like to see how differently you'd structure the api calls to get this working.
Thanking you in anticipation.
For all of these examples I am using Client-Side hosting of the Blazor application and I have a BreakpointManagementDisplay component that I am using to explore state management. So in index.razor I have
...
<BreakpointSummaryDisplay/>
...
One of the options to get current state is apparently moving the GetState function into the component as outlined on the main web page.. But this has some problems
The first is apparently 'this' needs to derive from a specific class which cannot be done as I understand it in the clients code-behind
The second is the protection level will no allow access
The other option for getting current state is to inherit from BlazorStateComponent. So I have the code in BreakpointSummaryDisplay.razor
@using BlazorState
@inherits BlazorStateComponent
Then in BreakpointSummaryDisplay.razor.cs
private BreakpointManagementState BreakpointManagementStateState => GetState<BreakpointManagementState>();
private BreakpointProjectSummary currentProject => BreakpointManagementStateState?.Project;
Apparently checking for Mono.Runtime is not useful anymore to check whether the blazor app is hosted serverside or clientside.
public bool HasMono => Type.GetType("Mono.Runtime") != null;
How can we check for running clientside / WASM under net5.0?
Anytime a handler mutates the state, any component that gets state properties and inherits from BlazorStateComponent
will automatically rerender. Right?
So that means that any component that depends on one part of that state but not another part will still rerender regardless of what part of the state they need. In other words, if my component shows MyState.A
but not MyState.B
, and there is a change to MyState.B
, my component will rerender even though it doesn't need to.
Suppose I enable a rather complex domain object to be edited piecemeal. So the user might edit a CommentsPanel
that internally uses CurrentOrderState.OrderComments
and a RushShippingPanel
that internally uses CurrentOrderState.IsRushShipping
, along with dozens of other properties. So now any change anywhere in the state will result in dozens of components being rerendered when it is more desirable that only one part at a time needs to be rerendered. Is there any way to get more granular with rerendering of components that inherit from BlazorStateComponent
? It strikes me that rerendering everything that depends on a state object when anything in that state object changes (because it's a whole new state each time) is a very blunt approach.
I am thinking there should be a way to avoid rerendering for unchanged parts of the state, as it is inevitable that even the simplest properties on a state object will themselves have properties, many of which won't change.
Side note: I am using the term "rerender" for the process by which .NET (in WebAssembly) runs the C# code to figure out the overall presentation state of each component in memory. After that, OnAfterRender
is called, then manipulating the DOM is a subsequent process. I try to avoid using the term "render" to mean "manipulating the DOM", since it seems Microsoft uses it to mean running the C# code.
For pages of significant scope, rerendering can be the source of much slowness. If I am showing a 30x10 cell table, and each cell has 1-3 components in it, it can be quite burdensome to rerender (run the C# code to determine what the DOM should become) hundreds of components. So it would be nice if there was a way to avoid rerendering a component if the parts of the state it depends on have not changed. I have written a small package to do this apart from state management, but I was hoping that changes due to state management wouldn't need such a thing (nor do I see a way to make them collaborate together).
Vue and React seem to automagically handle this (I think internally they compare previous state to new state on a per-property basis), but not so with Blazor (hence the need for StateHasChanged at all).
I've just started testing your library - great effort! appreciate your work!
Have you considered saving the user's state into session so that it's not lost due to authentication redirects when their token expires?
The ASP.net team has some instructions here.
I guess you're already serializing/deserializing for the redux tools / time travel and you already have an id/guid for each state instance so its just a matter of saving/retrieving from session in a custom Authentication.razor... I think I could do it, but it would take me 100x longer than you!
Regards
Brett
I'm wondering if the below can be changed to return back a Task
. Only asking because there's a chance that the app has to use the HttpClient
to make a request which is also async/await to get initial data for the state.
Hello everyone.
I think I found an error with CodeMaid.
I got this error first:
https://stackoverflow.com/questions/62747671/blazor-webassembly-project-intellisense-pops-an-error-the-type-or-namespace-n/62855830#62855830
After deactivating CodeMaid, the error disparears.
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.