Introduction
Blazor Server apps need a safe and easy way to handle user sessions and private info. In this article, we'll learn How to create session storage using Protected Session Storage in Blazor Server. It's like a secret locker for your app data, adding an extra layer of security with the ProtectedSessionStorage service.
What is Session Storage?
In a Blazor Server application, session storage refers to a client-side storage mechanism that allows developers to store and retrieve data on the user's browser during a single session. Unlike local storage, which persists data even after the browser is closed and reopened, session storage is designed to hold information only for the duration of the user's session.
Create session storage in the Blazor Server
Let's create session storage in the Blazor Server Project. For creating Session Storage we need to follow these steps.
Step 1. Create a Blazor Server project
First, we need to create a Blazor Server project then you'll have a default page named index.razor. If you wish to customize this default page, you can do so by adjusting the route. For instance, you can change the route by adding @page "/your-custom-route" at the top of your desired page, allowing you to create your unique default page.
Step 2. Create a model named UserDetailsModel.cs
Create a model named UserDetailsModel.cs inside the 'Data' Folder which was already created when we initially set up the project, and write this code.
using System.ComponentModel.DataAnnotations;
namespace BlazorDemo.Data
{
public class UserDetailsModel
{
public Int64 UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public int Age { get; set; }
public int result { get; set; }
}
public class LoginModel
{
[EmailAddress(ErrorMessage = $"Email Address is not a valid.")]
[Required(ErrorMessage = $"Email Address is required.")]
[StringLength(50)]
public string Email { get; set; }
[Required(ErrorMessage = $"Password is required.")]
[StringLength(50)]
public string password { get; set; }
}
}
Step 3. Create a default page named login.razor
Now, we need to add a page named 'login.razor' inside the 'Pages' folder, which was already created when we initially set up the project, and write this code.
@page "/"
@using BlazorDemo.Data
@using BlazorDemo.Interfaces
@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
@inject ProtectedSessionStorage ProtectedSessionStore
@inject AuthenticationStateProvider AuthenticationStateProvider
@inject NavigationManager navigationManager
<div class="login-container">
<h3 class="heading mt-5">Login</h3>
<div class="separator mt-4"></div>
<EditForm Model="@loginmodel" OnValidSubmit="OnValidSubmit">
<DataAnnotationsValidator />
<div class="form-floating mb-15">
<InputText @bind-Value="loginmodel.Email" class="form-control input-username is-invalid" required="true" id="username" placeholder="[email protected]" autocomplete="off" />
<label for="Email">Username</label>
<div id="usernameFeedback" class="invalid-feedback">
<ValidationMessage For="@(() => loginmodel.Email)" />
</div>
</div>
<div class="form-floating mb-10">
<InputText @bind-Value="loginmodel.password" type="password" class="form-control input-password is-invalid" id="password" autocomplete="off" required="true" placeholder="Password" />
<label for="password">Password</label>
<div id="passwordFeedback" class="invalid-feedback">
<ValidationMessage For="@(() => loginmodel.password)" />
</div>
</div>
<div class="col-sm-12 mt-4 mb-10">
<button class="btn btn-warning d-block mx-auto w-25" disabled="@loading">
@if (loading)
{
<span class="spinner-border spinner-border-sm mr-1"></span>
}
Login
</button>
</div>
</EditForm>
</div>
@code {
UserDetailsModel userDetailsModels = new UserDetailsModel();
public LoginModel loginmodel = new LoginModel();
protected bool loading = false;
[Inject] IUserDetails iuserDetails { get; set; }
public async Task OnValidSubmit()
{
userDetailsModels = await iuserDetails.LoginClick(loginmodel);
await ProtectedSessionStore.SetAsync("UserSessionUserID", userDetailsModels.UserId);
await ProtectedSessionStore.SetAsync("UserSessionPassword", userDetailsModels.Password);
await ProtectedSessionStore.SetAsync("UserSessionFirstName", userDetailsModels.FirstName);
await ProtectedSessionStore.SetAsync("UserSessionLastName", userDetailsModels.LastName);
await ProtectedSessionStore.SetAsync("UserSessionEmailId", userDetailsModels.Email);
if (userDetailsModels.result == 1)
{
navigationManager.NavigateTo("/ViewUserDetails");
}
else
{
navigationManager.NavigateTo("/");
}
}
}
Code Explanation
@page "/"
This sets the URL route for this Blazor component to be the root ("/") of the application.
@using BlazorDemo.Data
@using BlazorDemo.Interfaces
@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
These statements define the namespaces to be used in the Razor component.
@inject ProtectedSessionStorage ProtectedSessionStore
@inject AuthenticationStateProvider AuthenticationStateProvider
@inject NavigationManager navigationManager
These lines use the @inject directive to inject services into the component. Here, it injects ProtectedSessionStorage for secure session storage, AuthenticationStateProvider for managing authentication state, and NavigationManager for programmatic navigation.
<EditForm Model="@loginmodel" OnValidSubmit="OnValidSubmit">
This sets up a Blazor EditForm component that wraps the form fields. It binds to the loginmodel and triggers the OnValidSubmit method when the form is submitted.
<InputText></InputText>
The form uses InputText components for email and password. DataAnnotationsValidator is used for client-side validation, and ValidationMessage displays error messages.
<button class="btn btn-warning d-block mx-auto w-25" disabled="@loading">
A button is provided for submitting the form. If the loading flag is true, a spinner indicates that the login process is ongoing.
@code {
// Code block containing the component's C# logic.
}
This is the code block where C# logic resides. It declares variables, sets up dependency injection for IUserDetails, and defines the OnValidSubmit method.
UserDetailsModel userDetailsModels = new UserDetailsModel();
userDetailsModels is an instance of UserDetailsModel to store information about the user.
public LoginModel loginmodel = new LoginModel();
loginmodel is an instance of LoginModel representing the user's login credentials.
protected bool loading = false;
loading is a boolean flag to track whether the login process is currently loading.
[Inject] IUserDetails iuserDetails { get; set; }
This line uses the [Inject] attribute to inject the IUserDetails interface, presumably representing user-related functionality.
public async Task OnValidSubmit()
{
userDetailsModels = await iuserDetails.LoginClick(loginmodel);
await ProtectedSessionStore.SetAsync("UserSessionUserID", userDetailsModels.UserId);
await ProtectedSessionStore.SetAsync("UserSessionPassword", userDetailsModels.Password);
await ProtectedSessionStore.SetAsync("UserSessionFirstName", userDetailsModels.FirstName);
await ProtectedSessionStore.SetAsync("UserSessionLastName", userDetailsModels.LastName);
await ProtectedSessionStore.SetAsync("UserSessionEmailId", userDetailsModels.Email);
if (userDetailsModels.result == 1)
{
navigationManager.NavigateTo("/ViewUserDetails");
}
else
{
navigationManager.NavigateTo("/");
}
}
- This method is triggered when the form is submitted (OnValidSubmit).
- It calls the LoginClick method on the injected iuserDetails service, passing the loginmodel.
- User details are then stored in the session using ProtectedSessionStore.
- Depending on the result property of userDetailsModels, the page is navigated to either "/ViewUserDetails" or the root ("/").
Step 4. Create an Interface named IUserDetails.cs
Inside the Interface folder, we need to add an interface named IUserDetails.cs and write this code.
using BlazorDemo.Data;
namespace BlazorDemo.Interfaces
{
public interface IUserDetails
{
public Task <UserDetailsModel> LoginClick(LoginModel loginmodel);
}
}
Step 5. Add a class inside the Data Folder
Create a class Inside the Date folder named UserDetails.cs and write this code to check whether the user login details are correct to not and if the details are correct get all UserDetails from the database.


Osama El-SayedPosted Dec 31, 2024, 7:08 PM
Any udates for .Net8 ?? because await _sessionStorage.GetAsync<string>(TokenKey) require using <Routes @rendermode="new InteractiveServerRenderMode(prerender: false)" /> which affect on js
Njumu LeatherPosted Oct 28, 2024, 2:07 PM
Have you used it in .net8 blazor app?
Andy SmithPosted Oct 17, 2024, 8:43 AM
It's probably worth noting Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage has been deprecated.
osamaPosted Jul 25, 2024, 4:01 PM
Can you show a complete code with CustomAuthenticationStateProvider and AuthorizeRouteView