Blex for Blazor

Reference

API reference

Every public type Blex ships, grouped by assembly and namespace, with a pointer to the page that explains it.

Members are documented in depth on the topic pages - this page is the index. Everything here is also XML-documented, so IntelliSense carries the same text.

Blex - attributes

Namespace Bit.Blex. These are the entire authoring surface of a store.

Type Description
BlexStoreAttribute Marks a partial class as a store. Properties: Name, Persist. See Stores & state.
BlexStateAttribute Marks a field as reactive state. See Stores & state.
BlexComputedAttribute Marks a parameterless ComputeXxx()/GetXxx() method as memoized derived state. See Computed state.
BlexActionAttribute Marks an OnXxx method as an action. Property: Name. See Actions.
BlexEffectAttribute Marks an async OnXxx method as an effect. Properties: Name, Concurrency, DebounceMilliseconds. See Effects.
BlexEffectConcurrency Enum: Parallel, Latest, Drop, Queue. See Effects.
At a glance
[BlexStore(Name = "cart", Persist = true)]
public partial class CartStore
{
    [BlexState]    private IReadOnlyList<CartLine> _lines = [];

    [BlexComputed] private decimal ComputeTotal() => Lines.Sum(l => l.Total);

    [BlexAction]   private void OnAdd(CartLine line) => Lines = [.. Lines, line];

    [BlexEffect(Concurrency = BlexEffectConcurrency.Drop)]
    private async Task OnCheckout(CancellationToken ct) => await _api.CheckoutAsync(Lines, ct);
}

Blex - core

Type Description
IBlexStore The store contract: Name, Persist, StateChanged, SerializeState(), DeserializeState().
BlexStoreBase Base class for every store. Change notification, batched dispatch, Batch, ResetState, RestoreState, Dispose() (cancels in-flight effects) and the protected hooks the generator uses.
BlexManager The central manager: store registry, middleware pipeline, action subscriptions, global state capture and restore, ResetAll, DevTools connection, error sink. See Cross-store coordination.
BlexActionContext What observers receive after an action: Store, ActionName, QualifiedName, Args, Sequence, Timestamp, GlobalState.
BlexPreActionContext What middleware receives before an action, plus IsCancelled and Cancel().
BlexActionErrorContext What the error hooks receive when an action body throws: Store, ActionName, QualifiedName, Args, Exception, Timestamp. See Middleware.
BlexActionArg readonly record struct (string Name, object? Value) - one captured action argument.
BlexOptions Configuration passed to AddBitBlexServices: DevToolsName, sanitizers, RedactDevToolsKeys, UseMiddleware, UseFilter, OnError, OnActionError.
BlexComparers Collection equality for selector subscriptions: Sequence<T>() and Set<T>(). See Components & selectors.
BlexSelector&lt;T&gt; A lazy, memoized derived value over the whole state tree, created with manager.CreateSelector(...): Value, IsValid, Invalidate(), Dispose(). See Cross-store coordination.
BlexError readonly record struct (string Source, Exception Exception, string? Detail) - an isolated pipeline failure. See Error isolation.
BlexJson The shared JsonSerializerOptions used by generated serialization.
IBlexDevTools The DevTools sink abstraction: Init and Send. See DevTools.

Blex - middleware

Type Description
IBlexMiddleware OnAction(BlexActionContext) plus the defaulted BeforeAction(BlexPreActionContext) and OnActionError(BlexActionErrorContext). See Middleware.
BlexDelegateMiddleware Forwards each applied action to an Action<BlexActionContext>.
BlexFilterMiddleware Vetoes an action when the supplied predicate returns false.

Blex - collections

Type Description
BlexEntityState&lt;TEntity, TKey&gt; Immutable normalized state: Ids, Entities, All, Count, Contains, Find, TryGet, this[id], Empty.
BlexEntityAdapter&lt;TEntity, TKey&gt; CRUD over that state, plus SelectId and SortComparer. See Entity adapter.

Blex - persistence

Type Description
IBlexStorage Async key/value sink: GetAsync, SetAsync, RemoveAsync.
IBlexExternalStorageChange Optional companion to IBlexStorage: reports keys written by another instance (another tab), enabling SyncAcrossTabs.
BlexPersistenceOptions KeyPrefix, DebounceInterval, DebounceMaxDelay, Version, Migrate, Merge, Partialize, OnRehydrated, SkipHydration, SyncAcrossTabs, OnExternalChange.
BlexStatePersistor The coordinator: StartAsync, RehydrateAsync, FlushAsync, ClearAsync, DisposeAsync, plus HasHydrated / Hydrated / WhenHydratedAsync(). See Persistence.

Blex - history

Type Description
BlexHistory In-app undo/redo over the global state tree: Undo/Redo, Jump/JumpToPast/JumpToFuture, UndoLabels/RedoLabels, Checkpoint, plus an optional filter and groupBy. See Undo & redo.

Blex - extension methods

Type Description
BitBlex AddBitBlexServices, AddBitBlexStore<T>, AddBitBlexPersistence, AddBitBlexHistory.
BlexStoreSubscriptionExtensions store.Subscribe(selector, onChanged, comparer, fireImmediately) in both single-value and previous/current forms. See Components & selectors.

Bit.Blex.Blazor

Namespace Bit.Blex.Blazor. Everything that touches JavaScript or the Blazor render tree lives here, which is why the core package has no such dependency.

Type Description
BlexProvider Root component: registers stores, restores prerendered and persisted state, starts history, connects DevTools. Parameters: EnableDevTools, PersistComponentState, ChildContent.
BlexComponentBase Optional component base with Subscribe, selector Subscribe, OwnsSubscription and a Dispose(bool) hook.
BlexBrowserStorage IBlexStorage over localStorage/sessionStorage through a small JS module. Also implements IBlexExternalStorageChange via the browser's storage event, which powers SyncAcrossTabs.
BlexBrowserStorageKind Enum: Local, Session.
BitBlexBlazor AddBitBlexLocalStoragePersistence, AddBitBlexSessionStoragePersistence.
BlexComponentStatePersistence Bridges stores to Blazor's PersistentComponentState for the prerender-to-interactive handoff.
BlexReduxDevToolsConnector The IBlexDevTools implementation that talks to the browser extension.

Bit.Blex.Testing

Namespace Bit.Blex.Testing.

Type Description
BlexTestHarness&lt;TStore&gt; Store + manager + action log in one object.
BlexTestHarness Static factory: For<TStore>(), For(store), WithMiddleware, WithFilter.
BlexActionLog Records dispatches: Actions, Last, Count, Names, QualifiedNames, Contains, CountOf, Clear.
BlexRecordedAction One recorded dispatch with its store, names, sequence, state snapshot and args.
BlexTestExtensions RecordActions, Snapshot, store.WaitForAsync, manager.WaitForAsync, CountNotifications. See Testing.

Generated members, by declaration

What the generator adds to your partial class, for each thing you declare.

You declareGenerated
[BlexStore] on partial class Foo partial class Foo : BlexStoreBase, override string Name, override JsonObject SerializeState(), override void DeserializeState(JsonObject)
[BlexStore(Persist = true)] override bool Persist => true
[BlexState] private T _foo; public T Foo { get; set; } - the setter routes through SetState; the field is included in both snapshot methods
[BlexComputed] T ComputeFoo() public T Foo { get; } plus __FooValid / __FooValue, and an entry in InvalidateComputed()
[BlexAction] void OnFoo(A a) public void Foo(A a)
[BlexAction] Task OnFoo(A a) public Task Foo(A a)
[BlexEffect] Task OnFoo(A a) public Task Foo(A a), public bool FooIsLoading, public Exception? FooError
[BlexEffect] Task OnFoo(A a, CancellationToken ct) the above, plus public void CancelFoo() - and note the token is not on the public signature

Reserved names

A generated member may not take one of these - they are inherited from BlexStoreBase or emitted by the generator itself. Collisions are reported as BLEX005.

Reserved
Name              Persist           StateChanged      SerializeState
DeserializeState  InvalidateComputed NotifyRestored   SetState
SetEffectState    BeginEffect       EndEffect         Dispatch
DispatchAsync     Batch             ResetState        RestoreState
IsRestoring       IsObserved        BeginAction       DispatchApprovedAsync
Dispose           IsDisposed        CancelEffects

JSON conventions

Snapshots use BlexJson.Options: JsonSerializerDefaults.Web, case-insensitive property matching and enums written as strings. Slices are keyed by the generated property name (Count, not _count), and the global tree is keyed by store name.

JSON
// A single store's SerializeState()
{ "Count": 3, "Step": 1 }

// BlexManager.CaptureGlobalState()
{
  "counter":  { "Count": 3, "Step": 1 },
  "contacts": { "Contacts": { "ids": [1, 2], "entities": { "1": { }, "2": { } } } },
  "settings": { "Accent": "violet", "Density": "Comfortable" }
}

// A persisted slice with options.Version > 0
{ "__blexVersion": 1, "state": { "Accent": "violet" } }
An unhandled error has occurred. Reload ๐Ÿ—™