MeshWeaver gives every hub its own data layer — locally owned collections, initial seed data, and live synchronization from related hubs. This guide walks through the three core configuration primitives and shows how they compose into a working cross-hub data pipeline.
Cross-hub data pipeline: the Project Hub owns and seeds Status records; the Todo Hub pulls a live-synchronized copy via AddHubSource.
Core Primitives
| API | Purpose |
|---|---|
AddSource |
Register a local data collection within a hub |
WithInitialData |
Seed a collection with predefined records at startup |
AddHubSource |
Pull a live-synchronized copy of a collection from another hub |
Data Model Relationships
The Status type lives in the Project hub and flows into the Todo hub via AddHubSource. Neither hub has to duplicate business logic; the Todo hub simply declares a dependency on the parent's collection.
Data Flow Overview
Configuring a Local Source
Define the data model
Place your data model in Source/Status.cs. Using a record rather than an enum gives you richer metadata — descriptions, display order, and future extensibility without recompilation.
public record Status
{
[Key]
public string Id { get; init; } = string.Empty;
[Required]
public string Name { get; init; } = string.Empty;
public string? Description { get; init; }
public int Order { get; init; }
public static readonly Status Planning = new()
{
Id = "Planning", Name = "Planning",
Description = "Project is in planning phase", Order = 1
};
public static readonly Status Active = new()
{
Id = "Active", Name = "Active",
Description = "Project is actively being worked on", Order = 2
};
// ... additional status values
public static IEnumerable<Status> All => new[]
{
Planning, Active, OnHold, Completed, Cancelled
};
}
Wire up the source in the NodeType configuration
config => config
.WithContentType<Project>()
.AddData(data => data
.AddSource(source => source
.WithType<Status>(t => t.WithInitialData(Status.All))))
.AddLayout(layout => layout.AddDefaultLayoutAreas())
WithInitialData seeds the collection on first activation. Subsequent starts do not re-insert records that already exist in persistence.
Synchronizing Data from a Parent Hub
When to use AddHubSource
Use AddHubSource when a child hub needs read access to reference data owned by a parent. The child hub stays up-to-date automatically — no polling, no duplicated ownership.
Deriving the parent address
Hub addresses are hierarchical path segments. A Todo instance lives at ACME/ProductLaunch/Todo/AnalystBriefings; its owning Project hub is two segments up.
// Todo instance at: ACME/ProductLaunch/Todo/AnalystBriefings
// Parent Project at: ACME/ProductLaunch
// Formula: remove the last 2 segments (collection name + instance id)
new Address(config.Address.Segments.Take(config.Address.Segments.Length - 2).ToArray())
Configuration
config => config
.WithContentType<Todo>()
.AddData(data => data
.AddHubSource(
new Address(config.Address.Segments.Take(config.Address.Segments.Length - 2).ToArray()),
source => source.WithType<Status>()))
Initialization and Synchronization Sequence
When a message reaches a dormant Todo hub, the framework wakes it and completes full initialization — including the cross-hub Status sync — before the request is handled.
After initialization, any DataChangeRequest that arrives at the Todo hub is persisted to storage and fanned out to all subscribers.
Live Example
The cell below renders a summary of the configuration patterns covered on this page — a quick reference you can keep open alongside your code.
MeshWeaver.Layout.Controls.Stack
.WithView(MeshWeaver.Layout.Controls.Markdown("### Data Configuration Quick Reference"))
.WithView(MeshWeaver.Layout.Controls.Markdown(
"| Pattern | API | When to use |\n" +
"|---------|-----|-------------|\n" +
"| Local collection | `AddSource(...)` | Hub owns the data |\n" +
"| Seed on startup | `.WithInitialData(records)` | Reference / lookup data |\n" +
"| Cross-hub sync | `AddHubSource(address, ...)` | Child needs parent's data |\n"))
.WithView(MeshWeaver.Layout.Controls.Markdown(
$"*Rendered at {DateTime.Now:HH:mm:ss}*"))
Best Practices
Use data models instead of enums. Records provide descriptions, display order, and localization hooks. They can be extended at runtime without a recompile.
Initialize reference data at the owner. Call
WithInitialDataon the hub that owns the type, then let dependent hubs pull viaAddHubSource. Avoid seeding the same data in multiple places.
Derive addresses dynamically. Use
config.Address.Segmentsto compute relative addresses rather than hardcoding path strings. This makes NodeType configurations portable across namespaces.
Keep shared model definitions aligned. When using
AddHubSource, both hubs must reference the sameStatustype (same assembly or an identical record definition). A future MeshWeaver release will support shared data model assemblies to eliminate this duplication.
Complete NodeType JSON
Project Hub
{
"id": "Project",
"namespace": "ACME",
"nodeType": "NodeType",
"content": {
"$type": "NodeTypeDefinition",
"configuration": "config => config.WithContentType<Project>().AddData(data => data.AddSource(source => source.WithType<Status>(t => t.WithInitialData(Status.All)))).AddLayout(layout => layout.AddDefaultLayoutAreas())"
}
}
Todo Hub
{
"id": "Todo",
"namespace": "ACME/Project",
"nodeType": "NodeType",
"content": {
"$type": "NodeTypeDefinition",
"configuration": "config => config.WithContentType<Todo>().AddData(data => data.AddHubSource(new Address(config.Address.Segments.Take(config.Address.Segments.Length - 2).ToArray()), source => source.WithType<Status>())).AddDefaultLayoutAreas()"
}
}
With this configuration the Todo hub accesses live Status reference data from its parent Project hub, ensuring consistent status options across the entire hierarchy.