Add AddSqlServer().AddDatabase()AddSqlCommander() support
- Dominant language
- C#
- Stars
- 6.3k
- Forks
- 991
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 196
Description
### Is there an existing issue for this?
- [x] 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()`:
```csharp
public static IResourceBuilder WithSqlCommander(
this IResourceBuilder builder,
Action>? 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
```csharp
var builder = DistributedApplication.CreateBuilder(args);
var sql = builder.AddSqlServer("sql");
var db = sql
.AddDatabase("mydb")
.WithSqlCommander(); // 👈 New extension method
builder.Build().Run();
```
### Advanced Configuration
```csharp
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`.
```csharp
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**
```csharp
public class SqlCommanderContainerResource : ContainerResource
{
public SqlCommanderContainerResource(string name) : base(name) { }
}
```
**Host Port Helper** (following the pgAdmin/phpMyAdmin pattern)
```csharp
public static IResourceBuilder WithHostPort(
this IResourceBuilder builder,
int? port)
{
ArgumentNullException.ThrowIfNull(builder);
return builder.WithEndpoint("http", endpoint =>
{
endpoint.Port = port;
});
}
```
### Connection String Format (Example)
For SQL auth:
```text
Server={endpoint.Resource.Name},{endpoint.TargetPort};
Database={databaseName};
User Id={userName};
Password={password};
TrustServerCertificate=True
```
For Azure Default Credential:
```text
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
- **Feature Parity**: Fills the SQL Server tooling gap highlighted in issue #7742.
- **Consistent API**: Mirrors `WithPgAdmin()`, `WithPgWeb()`, and `WithPhpMyAdmin()`.
- **Production-Safe**: Excluded from manifests so it isn’t accidentally deployed.
### 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:
```csharp
// Current manual approach (works, but not ideal)
var sql = builder.AddSqlServer("sql");
var db = sql.AddDatabase("mydb");
var sqlcmdr = builder
.AddProject("sqlcmdr")
.WithReference(db);
```
Native support would simplify this to:
```csharp
// Proposed approach
var db = builder
.AddSqlServer("sql")
.AddDatabase("mydb")
.WithSqlCommander();
```
### Related Issues
- #7742 – Add admin interface or integration for SqlServer containers similar to PgAdmin/PgWeb/MongoExpress (currently considered covered via CommunityToolkit DbGate, but this would provide a native, SQL Server–focused option).
### Documentation
- SQL Commander GitHub: https://github.com/JerryNixon/sql-commander
- SQL Commander Docker Hub: https://hub.docker.com/r/jerrynixon/sql-commander
---
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
Contributor guide
Assessment
This issue has not been assessed yet.