I AM ACTIVELY UPDATING ON NUGET AND README, HMU FOR FEATURE REQUESTS -> [email protected]
#There is a known issue with DI/for EFCore Provider, I will be releasing a fix asap
- More DI syntax for built-in providers (services.AddSqlBladeState(), .AddEfCoreBladeState())
- Cleaned up and fixed some issues with SQL and EFCore Providers
- Added support for additional sql types through sql provider
BladeState is a lightweight server-side dependency injection state persistence library for .NET applications.
It provides dependency-injected storage for persisting state across requests without relying on HttpContext.Session
.
- π Server-side storage abstraction
- β‘ Easy integration with Dependency Injection
- π Works across Razor & Blazor server applications
- π§ Extensible design for custom providers (e.g. Redis, SQL, Memory Cache)
Install via NuGet:
dotnet add package BladeState
BladeState includes multiple built-in providers for persisting state:
Stores state in in-memory cache for the lifetime of the application.
using BladeState;
using BladeState.Models;
using BladeState.Providers;
builder.Services.AddMemoryCacheBladeState<MyState>();
The SQL provider stores state in a relational database table using JSON serialization.
CREATE TABLE BladeState (
InstanceId NVARCHAR(256) PRIMARY KEY,
[Data] NVARCHAR(MAX) NOT NULL
);
using Microsoft.Data.SqlClient;
using BladeState;
using BladeState.Models;
using BladeState.Providers;
var profile = new BladeStateProfile();
builder.Services.AddSqlBladeState<MyState>(
() => new SqlConnection("Server=localhost;Database=BladeStateDb;User Id=yourUserId;Password=YourStrong(!)Password;TrustServerCertificate=True;"),
profile,
SqlType.MySql
);
- Uses a simple key/value table (
InstanceId
,Data
). - JSON serialization handled automatically.
Stores state in Redis using StackExchange.Redis
.
using BladeState.Providers;
using StackExchange.Redis;
builder.Services.AddSingleton<IConnectionMultiplexer>(
ConnectionMultiplexer.Connect("localhost")
);
builder.Services.AddRedisBladeState<MyState>(
new BladeStateProfile
{
InstanceName = "MyAppUsingRedis" //If InstanceName is not provided the value will be 'BladeState'
}
);
- Stores JSON under a Redis key formatted like
{BladeStateProfile.InstanceName}:{BladeStateProfile.InstanceId}
. - Fast, distributed, great for scale-out.
Uses an Entity Framework DbContext
to persist state directly in your model.
## 1. Create your EF Core `DbContext`
Define a `DbContext` that includes your `BladeStateEntity` set. This is where BladeState will persist state.
- Optionally you may inherit from the IBladeStateEntity to extend for your organization
```csharp
using BladeState.Models;
using Microsoft.EntityFrameworkCore;
namespace MyApp.Data;
public class MyDbContext : DbContext
{
public LicenseDbContext(DbContextOptions<MyDbContext> options)
: base(options) { }
// Required for BladeState
public DbSet<BladeStateEntity> BladeStates { get; set; }
}
Register your DbContext
with EF Core.
// --- EF Core ---
builder.Services.AddDbContext<MyDbContext>(options =>
options.UseSqlite(
builder.Configuration.GetConnectionString("MyConnection")
)
);
In your appsettings.json
, define the BladeState profile:
{
"BladeState": {
"Profile": {
"AutoEncrypt": true,
"EncryptionKey": "your-crypto-key"
}
}
}
Then load it inside Program.cs
:
// --- BladeState ---
BladeStateProfile profile = builder.Configuration
.GetSection("BladeState:Profile")
.Get<BladeStateProfile>();
Now wire up the EF Core provider for your state type.
// Register EfCoreBladeStateProvider with your types
builder.Services.AddEfCoreBladeState<MyState, BladeStateEntity, MyDbContext>(profile);
Hereβs what each type parameter means:
License
β Your state type (TState
)BladeStateEntity
β Entity model (TEntity
) storing the serialized stateLicenseDbContext
β EF CoreDbContext
(TDbContext
) that manages persistence
DbContext
must includeDbSet<BladeStateEntity>
.AddDbContext
should be Scoped.- Use
AddEfCoreBladeState<TState, TEntity, TDbContext>(profile)
for wiring.
Provider | Best For | Pros | Cons |
---|---|---|---|
Memory Cache | Performance and application level processing | Simple, next to no overhead, fast | Requires custom handling for persistence if necessary |
SQL | Simple persistence in relational DB | Works out of the box, JSON storage | Tied to SQL dialect, less efficient than Redis |
Redis | High-performance distributed cache | Fast, scalable, great for web farms | Requires Redis infrastructure, persistence optional |
EF Core | Strongly-typed relational models | Uses your existing EF models, schema-first | More overhead, requires migrations |
-- this syntax is included primarily to extend BladeState with your own providers
Usage:
builder.Services.AddBladeState<MyState, SqlBladeStateProvider<MyState>>();
public class MyService
{
private readonly BladeStateProvider<MyState> _stateProvider;
public MyService(BladeStateProvider<MyState> stateProvider)
{
_stateProvider = stateProvider;
}
public async Task DoWorkAsync()
{
var state = await _stateProvider.LoadStateAsync();
state.Counter++;
await _stateProvider.SaveStateAsync(state);
}
}
var profile = new BladeStateProfile
{
InstanceId = string.Empty,
InstanceName = "MyApplicationState",
InstanceTimeout = TimeSpan.FromMinutes(120),
SaveOnInstanceTimeout = true,
AutoEncrypt = true,
EncryptionKey = "my-crypto-key"
}
You can configure profiles from appsettings.json and register them directly with a couple simple steps:
- Add the following structure to your appsettings.json file
{
"BladeState": {
"Profile": {
"InstanceId": "MyApplicationState",
"EncryptionKey": "my-crypto-key"
}
}
}
- Get the section and pass the BladeStateProfile to the 'AddBladeState();' extension method in your Program.cs
using BladeState;
using BladeState.Models;
using BladeState.Providers;
var profile = builder.Configuration.GetSection("BladeState:Profile").Get<BladeStateProfile>();
builder.Services.AddBladeState<MyAppState, SqlBladeStateProvider<MyAppState>>(profile);
BladeState automatically encrypts persisted state data using AES encryption.
Enabled by default β you donβt need to do anything.
Encryption key β if not provided, BladeState will generate one automatically, simplifying encryption and decryption without explicit wire-up.
You may also supply your own key by configuring a BladeStateProfile
, example below:
var profile = new BladeStateProfile
{
AutoEncrypt = true, // enable encryption
EncryptionKey = "my-crypto-key" // optional custom key
};
builder.Services.AddBladeState<MyAppState, SqlBladeStateProvider<MyAppState>>(profile);
Optionally (and NOT to be used for Production Environments - the universe frowns heavily upon that action π): You may turn off encryption β you can explicitly disable it via AutoEncrypt in your profile:
This is not necessary even when wiring up your own BladeStateProvider. The Decrypt/Encrypt State methods should be explicitly used.
var profile = new BladeStateProfile
{
AutoEncrypt = false // disables automatic crypto transforms in the 'out of the box' providers
};
builder.Services.AddBladeState<MyAppState, RedisBladeStateProvider<MyAppState>>(profile);
When a provider method is called an event will be raised to be handled by consuming components and services. This is useful for reliable UI updates.
// inject the provider
[Inject]
required public MemoryCacheBladeStateProvider<MyState> Provider { get; set; }
// add an event handler (anonymously)
Provider.OnStateChange += (sender, args) =>
{
// get updated state if need be
var state = args.State;
// do something
Console.WriteLine($"State changed: {args.EventType} for {args.InstanceId}! There are now {state.Items.Count} items!");
};
// add a custom handler
Provider.OnStateChange += MyCustomEventHandler;
This project is licensed under the MIT License - see the LICENSE file for details.