Client Craft Hub Search documentation /

Search documentation

Implement and extend Client delivery

Browse documentation

Preview Version 0.1.0-alpha.16

Add a public data source to the Visual Builder

Implement IVisualDataProvider in the client website and register it with an Umbraco Composer. Describe stable labelled fields and return typed public values for the current site/culture. The Visual Builder owns the connection API; the host owns the source and its access rules.

A compatible Umbraco project with Visual Builder 0.1.0-alpha.15, directly or through ClientCraft 0.1.0-alpha.16. Place the two source files below in your website project; retain your existing Program.cs. For this .NET 10 / Umbraco 17.7.1 baseline, also pin System.Security.Cryptography.Xml 10.0.13 in the website project; it replaces the vulnerable transitive 10.0.10 dependency. Keep NuGet security auditing enabled. The example was rebuilt with this security pin.

Implementation steps

  1. Keep the extension in the client project

    Use the public provider interface rather than modifying installed package files. The example exposes a fictional service name, clearly marked as demonstration data. It does not query CRM contacts, prices, entitlements or credentials. Native Umbraco still owns pages, languages, media and publishing.

  2. Register a source and a labelled field

    Describe gives the source a stable key and the editor a readable label. ResolveAsync uses VisualDataContext supplied by the renderer and returns VisualDataValue.Text. Register the implementation through dependency injection in a native Composer. Do not add raw executable expressions or a per-page script selector.

    Source and field keys use lowercase letters, digits and hyphens; do not include dots. The registered example key is agency-public-service. The published VisualDataResolver validates this descriptor before exposing the source.

  3. Build and select the registered source

    Build the existing website, restart it and open a block that supports connected text. Select the registered example source and its Service name field. Preview the page in English and Portuguese; the public example changes the text with the culture. Use the native editor’s available source/field controls, not manually typed binding JSON.

  4. Make real sources recover safely

    When replacing the demonstration with an external public catalogue, honour cancellation and return Empty or Unavailable appropriately. Apply access rules before returning values; selecting a workspace is not authorisation. Never publish private customer records through a public binding. Use native content/media URL APIs when a separate block links to content or images.

Working example

Use the complete files below with the pinned published packages.

AgencyCatalogueProvider.cs csharp
using ClientCraft.VisualBuilder.Umbraco.Data;

namespace Agency.Website;

// Public demonstration data only. Never return CRM contacts, credentials or entitlements.
public sealed class AgencyCatalogueProvider : IVisualDataProvider
{
    public VisualDataSource Describe() => new(
        "agency-public-service",
        "Agency public service (example)",
        [new VisualDataField("name", "Service name", VisualDataKind.Text)],
        IsDemonstration: true);

    public Task<VisualDataResult> ResolveAsync(
        VisualDataContext context,
        CancellationToken cancellationToken)
    {
        cancellationToken.ThrowIfCancellationRequested();
        var name = context.Culture.StartsWith("pt", StringComparison.OrdinalIgnoreCase)
            ? "Manutenção de websites"
            : "Website maintenance";

        return Task.FromResult(new VisualDataResult(
            VisualDataStatus.Success,
            new Dictionary<string, VisualDataValue?>
            {
                ["name"] = new VisualDataValue.Text(name)
            }));
    }
}
AgencyCatalogueComposer.cs csharp
using ClientCraft.VisualBuilder.Umbraco.Data;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;

namespace Agency.Website;

public sealed class AgencyCatalogueComposer : IComposer
{
    public void Compose(IUmbracoBuilder builder)
        => builder.Services.AddSingleton<IVisualDataProvider, AgencyCatalogueProvider>();
}

Continue the integration