@page "/" @namespace DynamicDataWebBlazorSample @using DynamicDataWeb.Blazor @using Microsoft.AspNetCore.Components @implements IAsyncDisposable

DynamicDataWeb + Blazor

A real browser SourceCache and RxJS collection stream, rendered by Razor templates.

@if (_show) { @if (_cache is not null) {

Live items: @items.Count

    @foreach (var item in items) {
  • @item.Name
  • }
}
} @_status@_result
@code { public sealed record Item(int Id, string Name); private SourceCache? _cache; private BrowserSubscription? _observation; private TaskCompletionSource? _notification; private bool _show = true, _ready; private int _count; private string _status = "Loading", _result = ""; private async Task Initialize(BrowserModule module) { _count = 2; _cache = await SourceCache.CreateAsync(module, "id"); await _cache.AddOrUpdateManyAsync([new(1, "First item"), new(2, "Second item")]); _observation = await _cache.ObserveItemsAsync(items => { _notification?.TrySetResult(items.Length); return Task.CompletedTask; }); _ready = true; _status = "Ready"; } private async Task Add() { _notification = new(TaskCreationOptions.RunContinuationsAsynchronously); var expected = ++_count; await _cache!.AddOrUpdateAsync(new(expected, $"Item {expected}")); var observed = await _notification.Task.WaitAsync(TimeSpan.FromSeconds(15)); var lookup = await _cache.LookupAsync(expected); if (observed != expected || await _cache.GetCountAsync() != expected || !lookup.Found) throw new InvalidOperationException("The native cache or observable notification failed."); _result = "Passed"; } private async Task Cleanup() { if (_observation is not null) { await _observation.DisposeAsync(); _observation = null; } if (_cache is not null) { await _cache.DisposeAsync(); _cache = null; } } private async Task Toggle() { _ready = false; if (_show) await Cleanup(); _show = !_show; _status = _show ? "Loading" : "Unmounted"; _result = ""; } public async ValueTask DisposeAsync() { await Cleanup(); } }