Creating your first In Memory State Container with Blazor Server
Web technology has come along way in the relatively recent past. With the surge in popularity of SPAs and Javascript Frameworks a lot of developers have come to expect certain functionality out of the box. Blazor Server being a stateful application framework offers us a lot of functionality missing from the days of old stateless web. One of these features is In Memory State Management. This allows any razor component that injects the State Container to access properties in an almost ‘global’ fashion.
This tutorial will show you how to implement a bare bones state container that uses a MudBlazor DatePicker component. Keep in mind, this method doesn’t persist the data indefinitely and shouldn’t be used for any sensitive/complex data. It will only persist as long as the user is connected to the server via a circuit. People familiar with Sessions in Asp.net MVC Session['StartDate']
may find this is as a good replacement in Blazor Server.
If you’re interested in a more robust way to track state throughout your application you should look into Database State Management, Distributed Cache State Management, Browser Storage State Management, or fluxor.
Advantages
- It is easy to implement and use. You can simply use C# classes and properties to store and access the state of your application. You don't need to use any external services or libraries for state management.
-
It is fast and efficient. Since the state is stored in the memory of the server, there is no network latency or serialization overhead involved in accessing or updating the state.
-
It supports complex and rich state scenarios. You can store any type of data in the memory, such as objects, collections, graphs, etc. You can also use dependency injection to access services and components that depend on the state.
Disadvantages
- It consumes server resources. Storing the state in the memory of the server means that you need to allocate more memory for each user session. This can limit the scalability and performance of your application, especially if you have a large number of concurrent users or a long-lived state.
- It is not persistent or reliable. If the server crashes or restarts, or if the connection between the client and the server is lost, the state in the memory will be lost as well. This can result in data loss or inconsistency for your users.
- It is not secure. Storing sensitive data in the memory of the server can expose it to unauthorized access or tampering. You need to implement proper security measures to protect your data from malicious attacks.
We start by creating a new class called DateFilterStateContainer, this class is responsible for persisting a StartDate and EndDate DateTime property throughout the application.
DateFilterStateContainer.cs
public class DateFilterStateContainer
{
private DateTime start;
private DateTime end;
public DateTime StartDate
{
get => start;
set
{
start = value;
NotifyStateChanged();
}
}
public DateTime EndDate
{
get => end;
set
{
end = value;
NotifyStateChanged();
}
}
public event Action OnChange;
private void NotifyStateChanged() => OnChange?.Invoke();
}
Wire up the State Container for dependency injection.
Program.cs
builder.Services.AddScoped();
Here we use a MudBlazor DatePicker to set values for the State Container to store via the SetState method.
The SetState method simply binds the values from the DatePicker to the State Container.
StateHasChanged subscribes to the OnChange action delegate in the DateFilterStateContainer class. This is what notifies the State Container of changes from the UI. The State Container stores these values in memory to be retrieved at a later time.
Lastly when the user navigates away from this component the Dispose method is executed, unsubscribing the OnChange delegate. More info here on how that works.
Home.razor
@page "/"
@using Core.StateManagement
State Management
Set State
@code {
[Inject]
DateFilterStateContainer StateContainer { get; set; }
DateTime? StartDate { get; set; }
DateTime? EndDate { get; set; }
protected override void OnInitialized()
{
StateContainer.OnChange += StateHasChanged;
StartDate = DateTime.Now.AddDays(-3);
EndDate = DateTime.Now.AddDays(3);
}
void SetState()
{
StateContainer.StartDate = (DateTime)StartDate;
StateContainer.EndDate = (DateTime)EndDate;
Console.WriteLine($"State Set! {StateContainer.StartDate} - {StateContainer.EndDate}");
}
public void Dispose()
{
StateContainer.OnChange -= StateHasChanged;
}
}
Home.razor
Here we access the StartDate and EndDate properties contained within the DateFilterStateContainer.
AnotherComponent.razor
@page "/another-component"
What are the values in our state container?
@if(StateContainer is not null)
{
@StateContainer.StartDate
@StateContainer.EndDate
}
AnotherComponent.razor
AnotherComponent.razor.cs
using Core.StateManagement;
public partial class AnotherComponent
{
[Inject]
DateFilterStateContainer StateContainer { get; set; }
protected override async Task OnInitializedAsync()
{
StateContainer.OnChange += StateHasChanged;
base.OnInitialized();
}
public void Dispose()
{
StateContainer.OnChange -= StateHasChanged;
}
}
In-Memory State Management is one of the options for state management in Blazor Server. It has some advantages and disadvantages that you need to consider before choosing it for your application.
Want to learn more?
Service Collections with Blazor Server
What is a service collection? Service collections are a way of registering and resolving dependencies in C# applications using the built-in dependency injection (DI) system. Blazor Server is a web framework that allows you to run C# code on the server and interact with the user interface through a SignalR connection. To use service collections…
Read moreIn Memory State Management with Blazor Server
Creating your first In Memory State Container with Blazor Server Web technology has come along way in the relatively recent past. With the surge in popularity of SPAs and Javascript Frameworks a lot of developers have come to expect certain functionality out of the box. Blazor Server being a stateful application framework offers us a…
Read moreIHttpClientFactory vs. HttpClient
Why should you use IHttpClientFactory The main reason to use IHttpClientFactoryinstead of HttpClient directly is to manage the life cycle of HttpClient instances. HttpClient was designed to be instantiated once and reused throughout the application life cycle. If you continually instantiate new HttpClients you may unnecessarily be squandering resources. Another use case is for simplicities…
Read more