MeshWeaver generates UI where the data lives. Instead of shipping large datasets to clients and rendering them in the browser, computations happen server-side and only the rendered components stream across the wire. The result is dramatically lower network traffic and real-time interactivity without sacrificing data security. MessageHub Controls Language Data & Logic Event Handlers Portal ISyncStream HTML Renderer Event Forwarder Browser HTML View Thin Renderer User Events JSON stream HTML OnClick/Change ClickedEvent JSON Patch travels from Hub → Portal → Browser; user events flow back in reverse

Server-side rendering pipeline: computation and data stay in the Hub; only rendered components and JSON patches travel to the browser.

The Data Compression Principle

The design philosophy is easiest to grasp with a concrete example. Suppose you need to display a million-row dataset as a 10 × 10 summary table. The naive approach transfers all one million rows to the client; MeshWeaver transfers only the 100 aggregated numbers:

This pattern applies everywhere — charts, grids, KPI tiles — and becomes especially powerful when data is sensitive or very large.


The Controls Language

Inside a MessageHub, UI is described using the Controls Language: an immutable, declarative API whose objects serialize naturally to JSON.

// Server-side control definition
Controls.Stack
    .WithView(Controls.Text("Welcome!"), "Welcome")
    .WithView(Controls.Button("Click Me").WithClickAction(OnClick), "Button")
    .WithView(Controls.DataGrid(salesData), "Sales")

The resulting JSON streams to the Portal, which renders it as HTML for the browser. Because the control tree is plain data, it round-trips cleanly over any transport and is trivial to version or diff.


Two-Way Data Binding

Rendering is only half the story. MeshWeaver uses a walkie-talkie pattern where both the hub and the Portal hold a live ISynchronizationStream. Changes flow in both directions: control updates push outward to the browser, and user events push inward to the hub.

flowchart TB subgraph Hub["MessageHub"] C[Controls Language] C --> J[JSON Serialization] J --> HS[ISynchronizationStream] CH[Click Handler] DH[Data Change Handler] end subgraph Portal["Portal"] PS[ISynchronizationStream] PS --> R[HTML Renderer] end subgraph Browser["Browser"] V[View Display] end HS <-->|JSON / JSON Patch| PS R -->|HTML| V V -->|OnClick / OnChange| PS PS -->|ClickedEvent| CH PS -->|DataChangedEvent| DH
Layer Role
MessageHub Defines controls and owns data; processes click and change events
Portal Holds the server-side ISynchronizationStream; renders controls to HTML
Browser Thin display layer — shows HTML and forwards user events back to the Portal

Control Lifecycle

The sequence below shows a full round trip from hub to browser and back:

sequenceDiagram participant Hub as MessageHub participant Portal participant Browser Hub->>Portal: Stream (controls + data via JSON) Portal->>Portal: Render to HTML Portal->>Browser: HTML Browser->>Browser: Display Browser->>Portal: OnClick Portal->>Hub: ClickedEvent Hub->>Hub: Execute ClickAction

Incremental Updates

After the initial load, only changes travel over the wire. MeshWeaver uses JSON Patch (RFC 6902) for this:

[{"op": "replace", "path": "/areas/counter/Data", "value": 42}]

A counter incrementing once sends a single-operation patch rather than re-sending the entire control tree. This keeps real-time dashboards snappy even under heavy update rates.


Handling User Interactions

User interactions become hub messages. When a button is clicked, the browser sends OnClick to the Portal, which forwards a ClickedEvent to the hub and invokes the registered action. Click handlers are synchronous — compose any follow-up work as an observable and Subscribe:

Controls.Button("Save")
    .WithClickAction(context =>
    {
        // context.Area    – which control was clicked
        // context.Payload – custom data attached to the event
        // context.Hub     – hub reference for posting messages
        context.Hub.Post(new SaveRequest(data));   // fire-and-forget — no await
        return Task.CompletedTask;
    })

🚨 Never async context => await .... An await on a mesh operation inside a click handler runs on the hub's scheduler and deadlocks it. The handler body is synchronous; anything that produces a result is an IObservable<T> chain ending in .Subscribe(...). See AsynchronousCalls.md for the canonical patterns.


Available Controls

MeshWeaver ships a rich control library. The table below lists the most commonly used controls; see the complete controls reference for the full set including advanced layout, charting, and editor controls.

Control Purpose
TextFieldControl Text input with validation
SelectControl Dropdown selection
DataGridControl Tabular data display
ButtonControl Clickable actions
DialogControl Modal dialogs
EditFormControl Form containers
LayoutAreaControl Nested layout regions

Live Example

The cell below runs in the kernel and renders a small stack of controls — the same building blocks used throughout the framework:

MeshWeaver.Layout.Controls.Stack
    .WithView(MeshWeaver.Layout.Controls.Markdown("### Controls Language — live demo\nEach `.WithView(...)` call adds a child to this stack."))
    .WithView(MeshWeaver.Layout.Controls.Html("<p>A plain HTML paragraph rendered inside a stack control.</p>"))
    .WithView(MeshWeaver.Layout.Controls.Button("Click Me"))

Every user-visible string is localized

The portal renders its chrome in the viewer's language (English and German ship today), so text in a control is never a bare literal — it goes through the localization seam as you write it:

Controls.Button(host.Localize("ui.createRelease"))

Because a layout area renders per subscriber, the viewer's language is available on the server at render time, the same way their display time zone is. Resolution is explicit off AccessContext.Locale — never ambient CultureInfo.CurrentUICulture, which does not survive the hub's scheduler hops.

Text attached to a declaration carries its translation next to the English instead, so the two cannot drift:

[Description("Sync direction")]
[Translation("de", "Synchronisierungsrichtung")]
public SyncDirection Direction { get; init; }

Prefer wording that needs no translation at all — a language-neutral glyph (, ✏️, 🗑️) plus a translated tooltip beats a translated label. Full reference: Localization.


Why This Architecture?

Benefit How it is achieved
Bandwidth efficiency Transfer summaries and patches, never raw datasets
Real-time updates JSON Patch (RFC 6902) for incremental control-tree changes
Data security Sensitive data never leaves the server unnecessarily
Single source of truth All state lives server-side; the browser is a passive renderer
Flexibility Any control can be data-bound; controls compose freely
Reconnecting…
The server was updated. Reloading the page to pick up the latest version.