Skip to content

Add AddSqlServer().AddDatabase()AddSqlCommander() support #13359

@JerryNixon

Description

@JerryNixon

Is there an existing issue for this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe the problem.

Feature Request: Add SQL Commander (WithSqlCommander()) to Aspire SQL Server Hosting

Issue Type

✨ Feature Request

Area

area-integrations – Issues pertaining to Aspire Integrations packages

Summary

Add native support for SQL Commander, a lightweight web-based SQL Server management tool, to the Aspire.Hosting.SqlServer package via a WithSqlCommander() extension method on SqlServerDatabaseResource. This would give SQL Server developers the same first-class database exploration experience that PostgreSQL and MySQL developers enjoy with WithPgAdmin(), WithPgWeb(), and WithPhpMyAdmin().

Motivation

Current Gap

SQL Server is the only major database in Aspire that lacks a built-in web UI management tool:

  • ✅ PostgreSQL has WithPgAdmin() and WithPgWeb()
  • ✅ MySQL has WithPhpMyAdmin()
  • ✅ MongoDB has WithMongoExpress()
  • ❌ SQL Server has no built-in web admin UI

This creates an inconsistent developer experience and forces SQL Server developers to:

  1. Manually copy connection strings from the Aspire dashboard
  2. Parse server, database, username, and password manually
  3. Open external tools like SSMS or VS Code with the mssql extension
  4. Repeatedly switch between IDE and database tool during debugging

Why SQL Commander?

SQL Commander is purpose-built for the Aspire development workflow.

Lightweight & Cloud-Native

  • Single-page web interface (no local installation required)
  • Instant startup, no sign-in required
  • Optimized for quick database exploration during development
  • Supports traditional SQL auth (username/password)
  • Supports Azure Default Credential (passwordless) for Azure SQL and SQL Server in Azure
  • Works seamlessly in local dev and Azure environments

Perfect for Debugging

  • Browse tables, views, stored procedures quickly
  • Execute ad-hoc queries with real-time feedback
  • Generate CREATE, SELECT, and DROP scripts
  • Export metadata as JSON for documentation or tooling
  • Light and dark mode support
  • VS Code integration (builds a vscode://ms-mssql.mssql/connect link)

Production-Safe

  • Intended for development and debugging only
  • Should be excluded from production manifests (similar to pgAdmin/phpMyAdmin)
  • No persistent state or configuration required (unless explicitly mounted)
  • Runs as a non-root user in the container
  • Exposes a health endpoint for orchestration

Proposed API

Following the established pattern from WithPgAdmin() and WithPhpMyAdmin():

public static IResourceBuilder<SqlServerDatabaseResource> WithSqlCommander(
    this IResourceBuilder<SqlServerDatabaseResource> builder,
    Action<IResourceBuilder<SqlCommanderContainerResource>>? configureContainer = null,
    string? containerName = null)

Note: Targeting SqlServerDatabaseResource lets the tool bind naturally to a specific database, while still being able to infer server information from the parent SqlServerServerResource.

Usage Example

var builder = DistributedApplication.CreateBuilder(args);

var sql = builder.AddSqlServer("sql");

var db = sql
    .AddDatabase("mydb")
    .WithSqlCommander(); // 👈 New extension method

builder.Build().Run();

Advanced Configuration

var db = builder
    .AddSqlServer("sql")
    .AddDatabase("mydb")
    .WithSqlCommander(configureContainer: container =>
    {
        container.WithHostPort(9000);                 // Custom host port
        container.WithEnvironment("SQLCMDR_FILE_LOG", "1"); // Enable file logging
    });

Multiple Databases / Instances

Today, SQL Commander is designed as one container per database. Each call to WithSqlCommander() would result in a separate container instance that is bound to that specific SqlServerDatabaseResource.

var sql = builder.AddSqlServer("sql");

// Each database gets its own SQL Commander container
var db1 = sql.AddDatabase("db1").WithSqlCommander(); // sqlcmdr-db1
var db2 = sql.AddDatabase("db2").WithSqlCommander(); // sqlcmdr-db2

// Or multiple SQL Server instances
var sql1 = builder.AddSqlServer("sql1");
var db3 = sql1.AddDatabase("db3").WithSqlCommander();

var sql2 = builder.AddSqlServer("sql2");
var db4 = sql2.AddDatabase("db4").WithSqlCommander();

This keeps the implementation simple and makes the binding between a given SQL Commander instance and a single database explicit. A future enhancement could optionally add a multi-database mode (e.g., one container with a database selector UI), but that is not required for an initial implementation.

Container Information

Registry: Docker Hub
Image: jerrynixon/sql-commander
Tag: latest (semantic version tags like 1.1.0 also available)
Port: 8080 (HTTP)
Base Image: mcr.microsoft.com/dotnet/aspnet:8.0
License: MIT

Container Configuration

Environment Variables:

  • ConnectionStrings__db – SQL Server connection string (to be auto-configured by Aspire)
  • ASPNETCORE_URLS – Default: http://+:8080
  • SQLCMDR_FILE_LOG – Optional: set to 1 to enable file logging (disabled by default)

Health Check:

  • Endpoint: GET /health
  • Response: { "status": "ok" }

Security:

  • Runs as non-root user (appuser)
  • No secrets baked into the image
  • Connection strings must be provided at runtime
  • Stateless design; persistence is opt-in via volume mounts

Implementation Approach

The implementation can closely follow the existing WithPhpMyAdmin() and WithPgAdmin() patterns, adapted for SQL Server and database resources:

  1. Per-Database Container Pattern (Initial Version)
    Keep the initial implementation simple and predictable by creating one SqlCommanderContainerResource per SqlServerDatabaseResource. This mirrors how SQL Commander is typically used today (one site bound to one database) and avoids the complexity of multi-database configuration and UI routing for a first iteration.

  2. Connection Configuration
    Configure ConnectionStrings__db via environment variables using Aspire’s parameter system, including:

    • Server host and port from the parent SqlServerServerResource primary endpoint
    • Database name from the SqlServerDatabaseResource
    • Credentials from the SQL Server resource (or rely on Azure identity where appropriate)
  3. Event-Driven Setup
    Subscribe to BeforeResourceStartedEvent for the SqlCommanderContainerResource to:

    • Discover SqlServerDatabaseResource (and their parents)
    • Generate appropriate connection strings
    • Optionally write config files if multi-database support is desired
  4. Automatic Exclusion from Deployment
    Use .ExcludeFromManifest() so SQL Commander is only used in local dev / orchestration scenarios and not deployed to production by default.

  5. Health Integration
    Use .WithHttpHealthCheck("/health") so Aspire waits for SQL Commander to be ready and can surface health in the dashboard.

Key Types

New Resource Type

public class SqlCommanderContainerResource : ContainerResource
{
    public SqlCommanderContainerResource(string name) : base(name) { }
}

Host Port Helper (following the pgAdmin/phpMyAdmin pattern)

public static IResourceBuilder<SqlCommanderContainerResource> WithHostPort(
    this IResourceBuilder<SqlCommanderContainerResource> builder,
    int? port)
{
    ArgumentNullException.ThrowIfNull(builder);

    return builder.WithEndpoint("http", endpoint =>
    {
        endpoint.Port = port;
    });
}

Connection String Format (Example)

For SQL auth:

Server={endpoint.Resource.Name},{endpoint.TargetPort};
Database={databaseName};
User Id={userName};
Password={password};
TrustServerCertificate=True

For Azure Default Credential:

Server={endpoint.Resource.Name},{endpoint.TargetPort};
Database={databaseName};
// No credentials in the connection string – SQL Commander uses Azure.Identity

(Exact behavior can align with how SQL Commander already handles Azure Default Credential.)

Benefits

For Developers

  • Consistent Experience: SQL Server developers get parity with PostgreSQL and MySQL.
  • Faster Debugging: No manual copying/parsing of connection strings.
  • Zero Extra Setup: Works out of the box once .WithSqlCommander() is called.
  • Modern Workflow: Web-based, accessible from the Aspire dashboard.
  • VS Code Integration: “Open in VS Code” support via the mssql extension.

For Aspire

For the Ecosystem

  • First-Class SQL Server Support for cloud-native .NET apps.
  • Azure-Ready via Azure Default Credential support.
  • Clear Example for future database management tooling integrations.

Real-World Usage

SQL Commander is already used alongside Aspire, but wired up manually:

// Current manual approach (works, but not ideal)
var sql = builder.AddSqlServer("sql");
var db  = sql.AddDatabase("mydb");

var sqlcmdr = builder
    .AddProject<Projects.SqlCmdr_Web>("sqlcmdr")
    .WithReference(db);

Native support would simplify this to:

// Proposed approach
var db = builder
    .AddSqlServer("sql")
    .AddDatabase("mydb")
    .WithSqlCommander();

Related Issues

Documentation


This feature request addresses a real gap in the Aspire developer experience and provides SQL Server developers with the same convenience that developers of other database platforms already enjoy. The proposal follows proven patterns from existing Aspire integrations and should require minimal, well-scoped changes to the Aspire.Hosting.SqlServer package and its related types.

Describe the solution you'd like

See above

Additional context

See above

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions