Nextended.Aspire
📚 Vollständige API-Referenz — jeder öffentliche Typ und Member, erzeugt aus der kompilierten Assembly.
Konditionale Builder-Erweiterungen für den .NET-Aspire-AppHost, dazu typisierte Umgebungsvariablen aus Konfigurationsobjekten, HTTPS-Dev-Cert-Anbindung, Docker-Guards, Ressourcen aus GitHub-Repositories und npm-App-Erkennung.
Installation
dotnet add package Nextended.AspireIns AppHost-Projekt. Die übrigen Nextended.Aspire.Hosting.*-Pakete bauen darauf auf.
Der Gedanke
Ein AppHost sammelt Bedingungen an. Eine Ressource existiert nur in der lokalen Entwicklung, eine Referenz wird nur bei aktivem Feature-Flag verdrahtet, auf eine Warteschlange wird nur in der CI gewartet. Geradeheraus geschrieben wird Program.cs daraus eine Treppe aus if-Blöcken, in der in jedem Zweig dieselbe Builder-Kette noch einmal steht.
Jede Erweiterung hier ist die konditionale Form eines bestehenden Aspire-Aufrufs: Sie führt den Schritt aus, wenn die Bedingung greift, und gibt den Builder sonst unverändert zurück. Die Kette bleibt eine Kette.
Übersicht
| Bereich | API |
|---|---|
| Konditionale Referenzen | WithReferenceIf, WithReferencesIf — Überladungen für Ressourcen mit Verbindungszeichenfolge, mit Service Discovery, für EndpointReference und für (name, Uri?) |
| Konditionales Warten | WaitForIf, WaitForCompletionIf, WaitForIfResourceWithParent, WaitForCompletionIfResourceWithParent |
| Konditionaler Lebenszyklus | WithExplicitStartIf, WithActionIf |
| Typisierte Umgebung | WithEnvironments<T, TObject>(options[, prefix]), WithEnvironmentsIf, WithEnvironment(keyExpression, value) |
| Endpunkte | WithEndpointAsEnvironment, WithEndpointAsEnvironmentIf, WithEndpointsAsEnvironmentIf, WithEndpointList, GetFirstExistingEndpoint |
| Projektbenennung | AddWithAutoNaming<TProject>() |
| HTTPS | RunWithHttpsDevCertificate |
| Docker-Guards | IsDockerInstalled, IsDockerRunning, StartDocker, EnsureDockerIsRunning, EnsureDockerRunning, EnsureDockerRunningIf, EnsureDockerRunningIfLocalDebug |
| GitHub-Quellen | AddGithubRepository, WithGithubSource, EnsureGitCheckout |
| npm | AddAllNpmAppsInPath |
| Deployment-Domains | BuildDomainName, BuildDomainNames, BuildDeploymentDomain, BuildDeploymentDomains, BuildDeploymentDomainList |
Eine Kette statt einer Treppe
var builder = DistributedApplication.CreateBuilder(args);
var isLocal = builder.Environment.IsDevelopment();
var cache = isLocal ? builder.AddRedis("cache") : null;
var api = builder.AddProject<Projects.Api>("api")
// Abhängigkeit null? Der Aufruf ist wirkungslos — kein if, keine doppelte Kette.
.WithReferenceIf(cache)
.WithReferenceIf("legacy", legacyUri) // übersprungen, wenn legacyUri null ist
.WaitForIf(isLocal, database)
.WithExplicitStartIf(!isLocal); // in Produktion von Hand startenDie WithReferenceIf-Überladungen nehmen einen nullbaren Builder. „Die Ressource existiert vielleicht gar nicht" ist damit an der Aufrufstelle ausdrückbar, ohne Null-Prüfung.
Konfigurationsobjekte statt Umgebungsvariablen-Zeichenketten
record SmtpOptions(string Host, int Port, bool UseTls);
api.WithEnvironments(new SmtpOptions("localhost", 1025, false));Das Objekt wird mit __ als Trenner flachgeklopft und mit dem Typnamen präfigiert. Es entstehen SmtpOptions__Host, SmtpOptions__Port und SmtpOptions__UseTls — genau die Form, die die IConfiguration-Bindung erwartet. Der konsumierende Dienst liest sie mit Configuration.GetSection("SmtpOptions").Get<SmtpOptions>() wieder ein. Verschachtelte Objekte werden weiter aufgefaltet, ein ganzer Optionsbaum reist also in einem Aufruf.
Eigenes Präfix, wenn der Abschnitt anders heißt; WithEnvironmentsIf überspringt den ganzen Block, wenn das Optionsobjekt null ist:
api.WithEnvironments(smtpOptions, "Mail") // Mail__Host, Mail__Port, …
.WithEnvironmentsIf(featureOptions); // wirkungslos, wenn featureOptions null istFür einen einzelnen Wert gibt es eine refaktorierungssichere Form, die den Variablennamen aus dem Ausdruck ableitet:
api.WithEnvironment<Projects.Api, SmtpOptions>(o => o.Host, "smtp.internal");Projektnamen, die man nicht wiederholt
// Ressourcenname und Startprofil werden aus dem Projekttyp abgeleitet:
// PascalCase wird zu einem bindestrichgetrennten, Aspire-tauglichen Ressourcennamen.
var api = builder.AddWithAutoNaming<Projects.My_Api_Service>();Nicht an einem Container-Fehler scheitern, wenn Docker schlicht nicht läuft
builder.Build()
.EnsureDockerRunningIfLocalDebug()
.Run();IsDockerInstalled() und IsDockerRunning() stehen für eigene Verzweigungen bereit, StartDocker() startet den Daemon unter Windows.
HTTPS-Entwicklungszertifikat im Container
var app = builder.AddContainer("frontend", "my/frontend")
.RunWithHttpsDevCertificate();Das ASP.NET-Core-Entwicklungszertifikat wird exportiert und eingebunden. Eine containerisierte Ressource kann damit lokal HTTPS ausliefern, ohne Zertifikatsgefummel.
Ressourcen direkt aus einem Git-Repository
var tool = builder.AddGithubRepository("docs", "https://github.com/fgilde/Nextended");EnsureGitCheckout klont oder aktualisiert die Arbeitskopie vorher, die Ressource hat ihre Quellen also vor dem Build.
Jede npm-Anwendung in einem Ordner
// Eine NodeAppResource pro package.json unterhalb des Pfads.
var frontends = builder.AddAllNpmAppsInPath("../frontends");Die Hosting-Integrationen
Fertige Ressourcen auf Basis dieses Pakets, jeweils mit lauffähigem Beispiel-AppHost:
| Paket | Bringt mit |
|---|---|
| Supabase | Postgres, Auth, REST, Realtime, Storage, Studio, Kong, Edge Functions |
| n8n | Workflow-Automatisierung mit Postgres-Persistenz und typisiertem Trigger-Client |
| Grafana | Grafana, Prometheus, Loki, Tempo, Promtail, cAdvisor, OTel Collector |
| WebDataStudio | Browser-Datenbankstudio, verdrahtet mit Ihren Datenbanken |
| AspireUI | Der visuelle AppHost-Builder als Ressource |
| LocalAI | Selbst gehostete multimodale KI: Bilder, Sprache, Video |
| Php | PHP-Endpunkte als vollwertige Aspire-Ressourcen |
Unterstützte Frameworks
net8.0net9.0net10.0
Abhängigkeiten
- Nextended.Core
Aspire.Hosting.AppHost