dotnet/orleans · error · InvalidOperationException

Orleans Dashboard services have not been registered. Please

Error message

Orleans Dashboard services have not been registered. Please call AddDashboard on ISiloBuilder or IClientBuilder.

What it means

InvalidOperationException from MapOrleansDashboard (the endpoint-routing extension) when EmbeddedAssetProvider is not registered in the DI container. The dashboard's endpoint mapper resolves the asset provider to serve static files; if AddDashboard was never called on the silo/client builder, the service is absent and the extension throws at endpoint configuration.

Source

Thrown at src/Dashboard/Orleans.Dashboard/ServiceCollectionExtensions.cs:98

    /// <example>
    /// <code>
    /// // Basic usage
    /// app.MapOrleansDashboard();
    ///
    /// // With authentication
    /// app.MapOrleansDashboard().RequireAuthorization();
    ///
    /// // With custom base path
    /// app.MapOrleansDashboard(routePrefix: "/dashboard");
    /// </code>
    /// </example>
    public static RouteGroupBuilder MapOrleansDashboard(
        this IEndpointRouteBuilder endpoints,
        [StringSyntax("Route")] string? routePrefix = null)
    {
        // Create static assets provider
        var assets = endpoints.ServiceProvider.GetService<EmbeddedAssetProvider>()
            ?? throw new InvalidOperationException("Orleans Dashboard services have not been registered. " +
                "Please call AddDashboard on ISiloBuilder or IClientBuilder.");

        // Create a route group for all dashboard endpoints
        var group = endpoints.MapGroup(routePrefix ?? "");

        // Static assets - these match the paths referenced in the built CSS/HTML
        // When a routePrefix is specified, redirect requests without trailing slash to include it.
        // This ensures relative asset paths (like index.min.js) resolve correctly.
        group.MapGet("/", (HttpContext ctx) =>
        {
            if (!string.IsNullOrEmpty(routePrefix) && ctx.Request.Path.Value?.EndsWith('/') == false)
            {
                // Redirect to the same path with a trailing slash, preserving the query string
                var redirectUrl = $"{ctx.Request.PathBase}{ctx.Request.Path}/{ctx.Request.QueryString}";
                return Results.Redirect(redirectUrl, permanent: true);
            }
            return assets.ServeAsset("index.html", ctx);
        });

View on GitHub (pinned to fca799fa70)

Solutions

  1. Call builder.AddDashboard() (ISiloBuilder or IClientBuilder) before calling app.MapOrleansDashboard().
  2. Ensure AddDashboard is registered in the same composition root whose ServiceProvider the endpoint route resolves.
  3. If conditionally registering, guard MapOrleansDashboard with the same condition.

Example fix

// before
app.MapOrleansDashboard(); // throws: provider not registered

// after
builder.Host.ConfigureContainer<ISiloBuilder>(b => b.AddDashboard());
app.MapOrleansDashboard();
Defensive patterns

Strategy: validation

Validate before calling

if (services.All(s => s.ServiceType != typeof(EmbeddedAssetProvider)))
    throw new InvalidOperationException("Call builder.AddDashboard() first");
app.MapOrleansDashboard();

Type guard

static bool DashboardRegistered(IServiceCollection s) =>
    s.Any(x => x.ServiceType == typeof(EmbeddedAssetProvider));

Try / catch

try { app.MapOrleansDashboard(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("AddDashboard"))
{ logger.LogCritical(ex, "Dashboard services missing; call AddDashboard"); throw; }

Prevention

When it happens

Trigger: Calling app.MapOrleansDashboard() (or the minimal-API route group) without first calling builder.AddDashboard(...) on the ISiloBuilder or IClientBuilder. The check happens when the endpoint route is built, i.e. usually at Program.cs startup.

Common situations: Copying the MapOrleansDashboard() line from docs without the corresponding AddDashboard(...) registration, or registering the dashboard on the client but mapping endpoints against the silo's service provider (or vice versa). Also when AddDashboard is conditionally registered (e.g. only in Development) but MapOrleansDashboard runs in all environments.

Related errors


AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13). Data as JSON: /api/errors/093acd350bc44abd. Report an issue: GitHub.