Skip to content

feat: Blazor WASM counter sample + fix BLite.Wasm TFM for project references#64

Merged
mrdevrobot merged 1 commit intomainfrom
copilot/add-sample-counter-wasm
Apr 17, 2026
Merged

feat: Blazor WASM counter sample + fix BLite.Wasm TFM for project references#64
mrdevrobot merged 1 commit intomainfrom
copilot/add-sample-counter-wasm

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 17, 2026

Addresses Issue 5 from WASM_SUPPORT.md: adds an end-to-end Blazor WebAssembly sample demonstrating BLite persistence in the browser via a counter app.

Sample — samples/BLite.BlazorWasm/

Minimal Blazor WASM app with a counter that survives page reloads:

  • Services/CounterStore.cs — singleton that calls BLiteWasm.CreateAsync("blite-counter-demo"), auto-selects storage backend (OPFS → IndexedDB → in-memory), and upserts a single counter document on every mutation
  • Pages/Counter.razor — increment / decrement / reset UI; displays active backend, last-saved timestamp, and persistence notice
  • Pages/Home.razor — landing page with quick-start snippet
  • wwwroot/blite-indexeddb.mjs / blite-opfs.mjs — JS interop modules (copied from BLite.Wasm/wwwroot) required by [JSImport] at runtime
// CounterStore.cs (core pattern)
Backend = BLiteWasm.DetectBestBackend();
_engine = await BLiteWasm.CreateAsync("blite-counter-demo", Backend);

var doc = _engine.CreateDocument(["name", "value", "updated_at"],
    b => b.AddString("name", "main")
         .AddInt32("value", Value)
         .AddInt64("updated_at", now.ToUnixTimeMilliseconds()));

_documentId = await _engine.InsertAsync("counters", doc);   // first run
await _engine.UpdateAsync("counters", _documentId.Value, doc); // subsequent
dotnet run --project samples/BLite.BlazorWasm/BLite.BlazorWasm.csproj
# open https://localhost:5001/counter

BLite.Wasm TFM fix

net10.0-browsernet10.0 — Blazor WASM projects target net10.0 (not -browser), so the old TFM produced a NU1201 restore error on project references. A new BrowserPlatform.cs adds [assembly: SupportedOSPlatform("browser")] to preserve the browser-only constraint that the old TFM provided implicitly.

Docs

WASM_SUPPORT.md — Issue 5 marked [Done]; running instructions added.

@mrdevrobot mrdevrobot marked this pull request as ready for review April 17, 2026 08:25
Copilot AI review requested due to automatic review settings April 17, 2026 08:25
@mrdevrobot mrdevrobot merged commit 0c4c404 into main Apr 17, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new end-to-end Blazor WebAssembly sample to demonstrate BLite persistence in-browser, and adjusts BLite.Wasm to use a project-reference-friendly TFM while preserving browser-only API annotation.

Changes:

  • Add samples/BLite.BlazorWasm/: a minimal Blazor WASM “persistent counter” app that uses BLiteWasm with OPFS → IndexedDB → in-memory fallback.
  • Change BLite.Wasm TFM from net10.0-browser to net10.0, adding an assembly-level [SupportedOSPlatform("browser")] to keep the browser-only constraint.
  • Update WASM_SUPPORT.md and include the new sample project in BLite.slnx.

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/BLite.Wasm/BrowserPlatform.cs Marks the assembly as browser-only via SupportedOSPlatform("browser").
src/BLite.Wasm/BLite.Wasm.csproj Switches TFM to net10.0 to avoid project-reference restore issues.
samples/BLite.BlazorWasm/wwwroot/index.html Adds the Blazor WASM host page for the sample.
samples/BLite.BlazorWasm/wwwroot/css/app.css Adds sample styling (loading/error UI + layout).
samples/BLite.BlazorWasm/wwwroot/blite-opfs.mjs Provides OPFS JS module required by BLite.Wasm [JSImport].
samples/BLite.BlazorWasm/wwwroot/blite-indexeddb.mjs Provides IndexedDB (+ WAL) JS module required by BLite.Wasm [JSImport].
samples/BLite.BlazorWasm/_Imports.razor Sets up common Razor imports for the sample.
samples/BLite.BlazorWasm/Services/CounterStore.cs Implements the persisted counter service backed by BLite browser storage.
samples/BLite.BlazorWasm/Program.cs Wires up the Blazor WASM app and registers CounterStore.
samples/BLite.BlazorWasm/Pages/NotFound.razor Adds a not-found page for the router.
samples/BLite.BlazorWasm/Pages/Home.razor Adds landing page describing the demo + quick-start snippet.
samples/BLite.BlazorWasm/Pages/Counter.razor Adds the persistent counter UI and status display.
samples/BLite.BlazorWasm/Layout/NavMenu.razor.css Adds nav menu styling.
samples/BLite.BlazorWasm/Layout/NavMenu.razor Adds navigation links (Home/Counter).
samples/BLite.BlazorWasm/Layout/MainLayout.razor.css Adds main layout styling.
samples/BLite.BlazorWasm/Layout/MainLayout.razor Adds main layout structure and GitHub link.
samples/BLite.BlazorWasm/BrowserPlatform.cs Marks the sample assembly as browser-only via SupportedOSPlatform("browser").
samples/BLite.BlazorWasm/BLite.BlazorWasm.csproj Introduces the sample project + references BLite.Wasm and ensures JS modules are present.
samples/BLite.BlazorWasm/App.razor Adds the app router and default layout wiring.
WASM_SUPPORT.md Marks Issue 5 as done and documents how to run the sample.
BLite.slnx Adds the new sample project to the solution.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +47 to +81
public async Task InitializeAsync()
{
if (IsInitialized)
return;

try
{
// Detect the backend before creating the engine so we can display it.
Backend = BLiteWasm.DetectBestBackend();
_engine = await BLiteWasm.CreateAsync("blite-counter-demo", Backend);

// Try to restore the previously saved counter value.
await foreach (var doc in _engine.FindAllAsync(CollectionName))
{
if (doc.TryGetString("name", out var name) && name == CounterName)
{
doc.TryGetInt32("value", out var saved);
Value = saved;

if (doc.TryGetId(out var id))
_documentId = id;

if (doc.TryGetValue("updated_at", out var tsVal) && tsVal.IsInt64)
LastSaved = DateTimeOffset.FromUnixTimeMilliseconds(tsVal.AsInt64);

break;
}
}

IsInitialized = true;
}
catch (Exception ex)
{
Error = $"BLite initialisation failed: {ex.Message}";
}
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InitializeAsync() sets Error on failure but never clears it on a subsequent successful initialization. Because IsInitialized stays false after a failure, retries are possible, but the UI will keep showing the old error unless Error is reset on success (or at the start of initialization).

Copilot uses AI. Check for mistakes.
Comment on lines +56 to +59
_engine = await BLiteWasm.CreateAsync("blite-counter-demo", Backend);

// Try to restore the previously saved counter value.
await foreach (var doc in _engine.FindAllAsync(CollectionName))
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This async method dereferences the nullable field _engine after await points (e.g., await foreach), which will typically produce nullable warnings and makes the code harder to reason about. Consider using a local non-null engine variable (capture the result of CreateAsync into a local, then assign the field) and use that local for the rest of the method.

Suggested change
_engine = await BLiteWasm.CreateAsync("blite-counter-demo", Backend);
// Try to restore the previously saved counter value.
await foreach (var doc in _engine.FindAllAsync(CollectionName))
var engine = await BLiteWasm.CreateAsync("blite-counter-demo", Backend);
_engine = engine;
// Try to restore the previously saved counter value.
await foreach (var doc in engine.FindAllAsync(CollectionName))

Copilot uses AI. Check for mistakes.
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>BLite WASM Demo</title>
<base href="/" />
<link rel="preload" id="webassembly" />
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<link rel="preload" id="webassembly" /> is missing the required attributes (at least href and as). As written it won't preload anything and may trigger HTML validation / browser console warnings; either remove it or specify the actual resource and as type you intend to preload.

Suggested change
<link rel="preload" id="webassembly" />

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants