diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index 269a59508c..37d832ab98 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -2,31 +2,31 @@ "redirections": [ { "source_path_from_root": "/docs/storage/quickstart-azure-storage.md", - "redirect_url": "/dotnet/aspire/storage/azure-storage" + "redirect_url": "https://aspire.dev/integrations/cloud/azure/azure-storage-blobs/" }, { "source_path_from_root": "/docs/storage/azure-storage.md", - "redirect_url": "/dotnet/aspire/storage/azure-storage-integrations" + "redirect_url": "https://aspire.dev/integrations/cloud/azure/azure-storage-blobs/" }, { "source_path_from_root": "/docs/database/quickstart-sql-server.md", - "redirect_url": "/dotnet/aspire/database/sql-server-integrations" + "redirect_url": "https://aspire.dev/integrations/databases/sql-server/" }, { "source_path_from_root": "/docs/get-started/quickstart-build-your-first-aspire-app.md", - "redirect_url": "/dotnet/aspire/get-started/build-your-first-aspire-app" + "redirect_url": "https://aspire.dev/get-started/first-app/" }, { "source_path_from_root": "/docs/messaging/quickstart-messaging.md", - "redirect_url": "/dotnet/aspire/messaging/messaging-integrations" + "redirect_url": "https://aspire.dev/integrations/cloud/azure/azure-service-bus/" }, { "source_path_from_root": "/docs/caching/quickstart-caching.md", - "redirect_url": "/dotnet/aspire/caching/caching-integrations" + "redirect_url": "https://aspire.dev/integrations/caching/redis/" }, { "source_path_from_root": "/docs/app-host-overview.md", - "redirect_url": "/dotnet/aspire/fundamentals/app-host-overview" + "redirect_url": "https://aspire.dev/get-started/app-host/" }, { "source_path_from_root": "/docs/components-overview.md", @@ -58,11 +58,11 @@ }, { "source_path_from_root": "/docs/openai/azureai-openai-component.md", - "redirect_url": "/dotnet/aspire/azureai/azureai-openai-integration" + "redirect_url": "https://aspire.dev/integrations/cloud/azure/azure-openai/" }, { "source_path_from_root": "/docs/azureai/azureai-openai-component.md", - "redirect_url": "/dotnet/aspire/azureai/azureai-openai-integration" + "redirect_url": "https://aspire.dev/integrations/cloud/azure/azure-openai/" }, { "source_path_from_root": "/docs/troubleshooting/allowunsecuredtransport.md", @@ -94,87 +94,87 @@ }, { "source_path_from_root": "/docs/authentication/keycloak-component.md", - "redirect_url": "/dotnet/aspire/authentication/keycloak-integration" + "redirect_url": "https://aspire.dev/integrations/security/keycloak/" }, { "source_path_from_root": "/docs/azureai/azureai-search-document-component.md", - "redirect_url": "/dotnet/aspire/azureai/azureai-search-document-integration" + "redirect_url": "https://aspire.dev/integrations/cloud/azure/azure-ai-search/" }, { "source_path_from_root": "/docs/caching/caching-components-deployment.md", - "redirect_url": "/dotnet/aspire/caching/caching-integrations-deployment" + "redirect_url": "https://aspire.dev/integrations/caching/redis/" }, { "source_path_from_root": "/docs/caching/caching-components.md", - "redirect_url": "/dotnet/aspire/caching/caching-integrations" + "redirect_url": "https://aspire.dev/integrations/caching/redis/" }, { "source_path_from_root": "/docs/caching/stackexchange-redis-component.md", - "redirect_url": "/dotnet/aspire/caching/stackexchange-redis-integration" + "redirect_url": "https://aspire.dev/integrations/caching/redis/" }, { "source_path_from_root": "/docs/caching/stackexchange-redis-distributed-caching-component.md", - "redirect_url": "/dotnet/aspire/caching/stackexchange-redis-distributed-caching-integration" + "redirect_url": "https://aspire.dev/integrations/caching/redis-distributed/" }, { "source_path_from_root": "/docs/caching/stackexchange-redis-output-caching-component.md", - "redirect_url": "/dotnet/aspire/caching/stackexchange-redis-output-caching-integration" + "redirect_url": "https://aspire.dev/integrations/caching/redis-output/" }, { "source_path_from_root": "/docs/database/azure-cosmos-db-component.md", - "redirect_url": "/dotnet/aspire/database/azure-cosmos-db-integration" + "redirect_url": "https://aspire.dev/integrations/cloud/azure/azure-cosmos-db/" }, { "source_path_from_root": "/docs/database/azure-cosmos-db-entity-framework-component.md", - "redirect_url": "/dotnet/aspire/database/azure-cosmos-db-entity-framework-integration" + "redirect_url": "https://aspire.dev/integrations/cloud/azure/azure-cosmos-db/" }, { "source_path_from_root": "/docs/database/milvus-component.md", - "redirect_url": "/dotnet/aspire/database/milvus-integration" + "redirect_url": "https://aspire.dev/integrations/databases/milvus/" }, { "source_path_from_root": "/docs/database/mongodb-component.md", - "redirect_url": "/dotnet/aspire/database/mongodb-integration" + "redirect_url": "https://aspire.dev/integrations/databases/mongodb/" }, { "source_path_from_root": "/docs/database/mysql-component.md", - "redirect_url": "/dotnet/aspire/database/mysql-integration" + "redirect_url": "https://aspire.dev/integrations/databases/mysql/" }, { "source_path_from_root": "/docs/database/mysql-entity-framework-component.md", - "redirect_url": "/dotnet/aspire/database/mysql-entity-framework-integration" + "redirect_url": "https://aspire.dev/integrations/databases/mysql-ef/" }, { "source_path_from_root": "/docs/database/oracle-entity-framework-component.md", - "redirect_url": "/dotnet/aspire/database/oracle-entity-framework-integration" + "redirect_url": "https://aspire.dev/integrations/databases/oracle-ef/" }, { "source_path_from_root": "/docs/database/postgresql-component.md", - "redirect_url": "/dotnet/aspire/database/postgresql-integration" + "redirect_url": "https://aspire.dev/integrations/databases/postgres/postgres-get-started/" }, { "source_path_from_root": "/docs/database/postgresql-entity-framework-component.md", - "redirect_url": "/dotnet/aspire/database/postgresql-entity-framework-integration" + "redirect_url": "https://aspire.dev/integrations/databases/efcore/postgresql/" }, { "source_path_from_root": "/docs/database/qdrant-component.md", - "redirect_url": "/dotnet/aspire/database/qdrant-integration" + "redirect_url": "https://aspire.dev/integrations/databases/qdrant/" }, { "source_path_from_root": "/docs/database/sql-server-component-deployment.md", - "redirect_url": "/dotnet/aspire/database/sql-server-integration-deployment" + "redirect_url": "https://aspire.dev/integrations/databases/sql-server/" }, { "source_path_from_root": "/docs/database/sql-server-component.md", - "redirect_url": "/dotnet/aspire/database/sql-server-integration" + "redirect_url": "https://aspire.dev/integrations/databases/sql-server/" }, { "source_path_from_root": "/docs/database/sql-server-components.md", - "redirect_url": "/dotnet/aspire/database/sql-server-integrations" + "redirect_url": "https://aspire.dev/integrations/databases/sql-server/" }, { "source_path_from_root": "/docs/database/sql-server-entity-framework-component.md", - "redirect_url": "/dotnet/aspire/database/sql-server-entity-framework-integration" + "redirect_url": "https://aspire.dev/integrations/databases/sql-server/" }, { "source_path_from_root": "/docs/extensibility/custom-component.md", @@ -198,71 +198,83 @@ }, { "source_path_from_root": "/docs/logging/seq-component.md", - "redirect_url": "/dotnet/aspire/logging/seq-integration" + "redirect_url": "https://aspire.dev/integrations/observability/seq/" }, { "source_path_from_root": "/docs/messaging/azure-event-hubs-component.md", - "redirect_url": "/dotnet/aspire/messaging/azure-event-hubs-integration" + "redirect_url": "https://aspire.dev/integrations/cloud/azure/azure-event-hubs/" }, { "source_path_from_root": "/docs/messaging/azure-service-bus-component.md", - "redirect_url": "/dotnet/aspire/messaging/azure-service-bus-integration" + "redirect_url": "https://aspire.dev/integrations/cloud/azure/azure-service-bus/" }, { "source_path_from_root": "/docs/messaging/azure-web-pubsub-component.md", - "redirect_url": "/dotnet/aspire/messaging/azure-web-pubsub-integration" + "redirect_url": "https://aspire.dev/integrations/cloud/azure/azure-web-pubsub/" }, { "source_path_from_root": "/docs/messaging/kafka-component.md", - "redirect_url": "/dotnet/aspire/messaging/kafka-integration" + "redirect_url": "https://aspire.dev/integrations/messaging/apache-kafka/" }, { "source_path_from_root": "/docs/messaging/messaging-components.md", - "redirect_url": "/dotnet/aspire/messaging/messaging-integrations" + "redirect_url": "https://aspire.dev/integrations/cloud/azure/azure-service-bus/" }, { "source_path_from_root": "/docs/messaging/nats-component.md", - "redirect_url": "/dotnet/aspire/messaging/nats-integration" + "redirect_url": "https://aspire.dev/integrations/messaging/nats/" }, { "source_path_from_root": "/docs/messaging/rabbitmq-client-component.md ", - "redirect_url": "/dotnet/aspire/messaging/rabbitmq-client-integration" + "redirect_url": "https://aspire.dev/integrations/messaging/rabbitmq/" }, { "source_path_from_root": "/docs/search/elasticsearch-component.md", - "redirect_url": "/dotnet/aspire/search/elasticsearch-integration" + "redirect_url": "https://aspire.dev/integrations/databases/elasticsearch/" }, { "source_path_from_root": "/docs/security/azure-security-key-vault-component.md", - "redirect_url": "/dotnet/aspire/security/azure-security-key-vault-integration" + "redirect_url": "https://aspire.dev/integrations/cloud/azure/azure-key-vault/" }, { "source_path_from_root": "/docs/storage/azure-storage-components.md", - "redirect_url": "/dotnet/aspire/storage/azure-storage-integrations" + "redirect_url": "https://aspire.dev/integrations/cloud/azure/azure-storage-blobs/" }, { "source_path_from_root": "/docs/storage/azure-storage-blobs-component.md", - "redirect_url": "/dotnet/aspire/storage/azure-storage-blobs-integration" + "redirect_url": "https://aspire.dev/integrations/cloud/azure/azure-storage-blobs/" }, { "source_path_from_root": "/docs/storage/azure-storage-queues-component.md", - "redirect_url": "/dotnet/aspire/storage/azure-storage-queues-integration" + "redirect_url": "https://aspire.dev/integrations/cloud/azure/azure-storage-queues/" }, { "source_path_from_root": "/docs/storage/azure-storage-tables-component.md", - "redirect_url": "/dotnet/aspire/storage/azure-storage-tables-integration" + "redirect_url": "https://aspire.dev/integrations/cloud/azure/azure-storage-tables/" }, { "source_path_from_root": "/docs/extensibility/custom-resources.md", - "redirect_url": "/dotnet/aspire/extensibility/custom-hosting-integration" + "redirect_url": "https://aspire.dev/integrations/custom-integrations/hosting-integrations/" }, { "source_path_from_root": "/docs/extensibility/custom-integration.md", - "redirect_url": "/dotnet/aspire/extensibility/custom-client-integration" + "redirect_url": "https://aspire.dev/integrations/custom-integrations/client-integrations/" }, { "source_path_from_root": "/docs/extensibility/implement-auth-from-resource-to-integration.md", - "redirect_url": "/dotnet/aspire/extensibility/secure-communication-between-integrations" + "redirect_url": "https://aspire.dev/integrations/custom-integrations/secure-communication/" + }, + { + "source_path_from_root": "/docs/extensibility/custom-hosting-integration.md", + "redirect_url": "https://aspire.dev/integrations/custom-integrations/hosting-integrations/" + }, + { + "source_path_from_root": "/docs/extensibility/custom-client-integration.md", + "redirect_url": "https://aspire.dev/integrations/custom-integrations/client-integrations/" + }, + { + "source_path_from_root": "/docs/extensibility/secure-communication-between-integrations.md", + "redirect_url": "https://aspire.dev/integrations/custom-integrations/secure-communication/" }, { "source_path_from_root": "/docs/messaging/rabbitmq-client-integration.md", @@ -334,11 +346,11 @@ }, { "source_path_from_root": "/docs/fundamentals/build-container-images.md", - "redirect_url": "/dotnet/aspire/fundamentals/custom-deployments" + "redirect_url": "https://aspire.dev/deployment/custom-deployments/" }, { "source_path_from_root": "/docs/deployment/aspire-deploy/local-deployment-state.md", - "redirect_url": "/dotnet/aspire/deployment/deployment-state-caching" + "redirect_url": "https://aspire.dev/deployment/deployment-state-caching/" }, { "source_path_from_root": "/docs/get-started/upgrade-to-aspire-9.md", @@ -406,7 +418,7 @@ }, { "source_path_from_root": "/docs/caching/caching-integrations.md", - "redirect_url": "https://aspire.dev/integrations/caching/" + "redirect_url": "https://aspire.dev/integrations/caching/redis/" }, { "source_path_from_root": "/docs/caching/stackexchange-redis-caching-overview.md", @@ -458,15 +470,15 @@ }, { "source_path_from_root": "/docs/database/entity-framework-core-integration-overview.md", - "redirect_url": "https://aspire.dev/integrations/databases/ef-core/" + "redirect_url": "https://aspire.dev/integrations/databases/efcore/overview/" }, { "source_path_from_root": "/docs/database/ef-core-migrations.md", - "redirect_url": "https://aspire.dev/integrations/databases/ef-core-migrations/" + "redirect_url": "https://aspire.dev/integrations/databases/efcore/migrations/" }, { "source_path_from_root": "/docs/database/seed-database-data.md", - "redirect_url": "https://aspire.dev/integrations/databases/seed-database/" + "redirect_url": "https://aspire.dev/integrations/databases/efcore/seed-database/" }, { "source_path_from_root": "/docs/database/azure-cosmos-db-integration.md", @@ -506,11 +518,11 @@ }, { "source_path_from_root": "/docs/database/postgresql-integration.md", - "redirect_url": "https://aspire.dev/integrations/databases/postgres/" + "redirect_url": "https://aspire.dev/integrations/databases/postgres/postgres-get-started/" }, { "source_path_from_root": "/docs/database/postgresql-entity-framework-integration.md", - "redirect_url": "https://aspire.dev/integrations/databases/postgres-ef/" + "redirect_url": "https://aspire.dev/integrations/databases/efcore/postgresql/" }, { "source_path_from_root": "/docs/database/milvus-integration.md", @@ -526,7 +538,7 @@ }, { "source_path_from_root": "/docs/storage/azure-storage-integrations.md", - "redirect_url": "https://aspire.dev/integrations/cloud/azure/azure-storage/" + "redirect_url": "https://aspire.dev/integrations/cloud/azure/azure-storage-blobs/" }, { "source_path_from_root": "/docs/storage/azure-storage-blobs-integration.md", @@ -542,11 +554,11 @@ }, { "source_path_from_root": "/docs/messaging/messaging-integrations.md", - "redirect_url": "https://aspire.dev/integrations/messaging/" + "redirect_url": "https://aspire.dev/integrations/overview/" }, { "source_path_from_root": "/docs/messaging/kafka-integration.md", - "redirect_url": "https://aspire.dev/integrations/messaging/kafka/" + "redirect_url": "https://aspire.dev/integrations/messaging/apache-kafka/" }, { "source_path_from_root": "/docs/messaging/azure-event-hubs-integration.md", @@ -582,7 +594,7 @@ }, { "source_path_from_root": "/docs/azure/configure-aca-environments.md", - "redirect_url": "https://aspire.dev/integrations/compute/azure-container-apps/" + "redirect_url": "https://aspire.dev/integrations/cloud/azure/configure-container-apps/" }, { "source_path_from_root": "/docs/azure/container-app-jobs.md", @@ -859,6 +871,186 @@ { "source_path_from_root": "/docs/service-discovery/overview.md", "redirect_url": "https://aspire.dev/fundamentals/service-discovery/" + }, + { + "source_path_from_root": "/docs/fundamentals/annotations-overview.md", + "redirect_url": "https://aspire.dev/fundamentals/annotations-overview/" + }, + { + "source_path_from_root": "/docs/app-host/configuration.md", + "redirect_url": "https://aspire.dev/app-host/configuration/" + }, + { + "source_path_from_root": "/docs/app-host/certificate-trust.md", + "redirect_url": "https://aspire.dev/app-host/certificate-trust/" + }, + { + "source_path_from_root": "/docs/app-host/eventing.md", + "redirect_url": "https://aspire.dev/app-host/eventing/" + }, + { + "source_path_from_root": "/docs/app-host/persistent-containers.md", + "redirect_url": "https://aspire.dev/app-host/persistent-containers/" + }, + { + "source_path_from_root": "/docs/app-host/withdockerfile.md", + "redirect_url": "https://aspire.dev/app-host/withdockerfile/" + }, + { + "source_path_from_root": "/docs/app-host/executable-resources.md", + "redirect_url": "https://aspire.dev/app-host/executable-resources/" + }, + { + "source_path_from_root": "/docs/get-started/add-aspire-existing-app.md", + "redirect_url": "https://aspire.dev/get-started/add-aspire-existing-app/" + }, + { + "source_path_from_root": "/docs/get-started/aspire-overview.md", + "redirect_url": "https://aspire.dev/get-started/what-is-aspire/" + }, + { + "source_path_from_root": "/docs/get-started/build-your-first-aspire-app.md", + "redirect_url": "https://aspire.dev/get-started/first-app/" + }, + { + "source_path_from_root": "/docs/fundamentals/app-host-overview.md", + "redirect_url": "https://aspire.dev/get-started/app-host/" + }, + { + "source_path_from_root": "/docs/cli-reference/aspire.md", + "redirect_url": "https://aspire.dev/reference/cli/commands/aspire/" + }, + { + "source_path_from_root": "/docs/cli-reference/aspire-add.md", + "redirect_url": "https://aspire.dev/reference/cli/commands/aspire-add/" + }, + { + "source_path_from_root": "/docs/cli-reference/aspire-config.md", + "redirect_url": "https://aspire.dev/reference/cli/commands/aspire-config/" + }, + { + "source_path_from_root": "/docs/cli-reference/aspire-config-list.md", + "redirect_url": "https://aspire.dev/reference/cli/commands/aspire-config-list/" + }, + { + "source_path_from_root": "/docs/cli-reference/aspire-config-get.md", + "redirect_url": "https://aspire.dev/reference/cli/commands/aspire-config-get/" + }, + { + "source_path_from_root": "/docs/cli-reference/aspire-config-set.md", + "redirect_url": "https://aspire.dev/reference/cli/commands/aspire-config-set/" + }, + { + "source_path_from_root": "/docs/cli-reference/aspire-config-delete.md", + "redirect_url": "https://aspire.dev/reference/cli/commands/aspire-config-delete/" + }, + { + "source_path_from_root": "/docs/cli-reference/aspire-deploy.md", + "redirect_url": "https://aspire.dev/reference/cli/commands/aspire-deploy/" + }, + { + "source_path_from_root": "/docs/cli-reference/aspire-exec.md", + "redirect_url": "https://aspire.dev/reference/cli/commands/aspire-exec/" + }, + { + "source_path_from_root": "/docs/cli-reference/aspire-new.md", + "redirect_url": "https://aspire.dev/reference/cli/commands/aspire-new/" + }, + { + "source_path_from_root": "/docs/cli-reference/aspire-publish.md", + "redirect_url": "https://aspire.dev/reference/cli/commands/aspire-publish/" + }, + { + "source_path_from_root": "/docs/cli-reference/aspire-run.md", + "redirect_url": "https://aspire.dev/reference/cli/commands/aspire-run/" + }, + { + "source_path_from_root": "/docs/cli-reference/aspire-update.md", + "redirect_url": "https://aspire.dev/reference/cli/commands/aspire-update/" + }, + { + "source_path_from_root": "/docs/cli/overview.md", + "redirect_url": "https://aspire.dev/reference/cli/overview/" + }, + { + "source_path_from_root": "/docs/cli/install.md", + "redirect_url": "https://aspire.dev/reference/cli/overview/" + }, + { + "source_path_from_root": "/docs/cli/config-settings.md", + "redirect_url": "https://aspire.dev/reference/cli/overview/" + }, + { + "source_path_from_root": "/docs/cli/install-script-reference.md", + "redirect_url": "https://aspire.dev/reference/cli/overview/" + }, + { + "source_path_from_root": "/docs/deployment/overview.md", + "redirect_url": "https://aspire.dev/deployment/overview/" + }, + { + "source_path_from_root": "/docs/fundamentals/custom-deployments.md", + "redirect_url": "https://aspire.dev/deployment/custom-deployments/" + }, + { + "source_path_from_root": "/docs/deployment/deployment-state-caching.md", + "redirect_url": "https://aspire.dev/deployment/deployment-state-caching/" + }, + { + "source_path_from_root": "/docs/deployment/manifest-format.md", + "redirect_url": "https://aspire.dev/deployment/manifest-format/" + }, + { + "source_path_from_root": "/docs/deployment/aspire-deploy/aca-deployment-aspire-cli.md", + "redirect_url": "https://aspire.dev/deployment/azure/aca-deployment-aspire-cli/" + }, + { + "source_path_from_root": "/docs/deployment/aspire-deploy/azure-security-best-practices.md", + "redirect_url": "https://aspire.dev/deployment/azure/azure-security-best-practices/" + }, + { + "source_path_from_root": "/docs/fundamentals/external-parameters.md", + "redirect_url": "https://aspire.dev/fundamentals/external-parameters/" + }, + { + "source_path_from_root": "/docs/fundamentals/persist-data-volumes.md", + "redirect_url": "https://aspire.dev/fundamentals/persist-data-volumes/" + }, + { + "source_path_from_root": "/docs/extensibility/interaction-service.md", + "redirect_url": "https://aspire.dev/extensibility/interaction-service/" + }, + { + "source_path_from_root": "/docs/fundamentals/networking-overview.md", + "redirect_url": "https://aspire.dev/fundamentals/networking-overview/" + }, + { + "source_path_from_root": "/docs/fundamentals/custom-resource-commands.md", + "redirect_url": "https://aspire.dev/fundamentals/custom-resource-commands/" + }, + { + "source_path_from_root": "/docs/fundamentals/http-commands.md", + "redirect_url": "https://aspire.dev/fundamentals/http-commands/" + }, + { + "source_path_from_root": "/docs/fundamentals/custom-resource-urls.md", + "redirect_url": "https://aspire.dev/fundamentals/custom-resource-urls/" + }, + { + "source_path_from_root": "/docs/get-started/build-aspire-apps-with-python.md", + "redirect_url": "https://aspire.dev/get-started/first-app/?lang=python" + }, + { + "source_path_from_root": "/docs/get-started/build-aspire-apps-with-nodejs.md", + "redirect_url": "https://aspire.dev/integrations/frameworks/javascript/" + }, + { + "source_path_from_root": "/docs/fundamentals/integrations-overview.md", + "redirect_url": "https://aspire.dev/integrations/overview/" + }, + { + "source_path_from_root": "/docs/reference/aspire-faq.yml", + "redirect_url": "https://discord.com/invite/h87kDAHQgJ" } ] } diff --git a/docs/app-host/certificate-trust.md b/docs/app-host/certificate-trust.md deleted file mode 100644 index 266fe46a6a..0000000000 --- a/docs/app-host/certificate-trust.md +++ /dev/null @@ -1,281 +0,0 @@ ---- -title: Certificate trust customization in Aspire -description: Learn how to customize trusted certificates for Executable and Container resources in Aspire to enable secure communication. -ms.date: 11/10/2025 -ai-usage: ai-assisted ---- - -# Certificate trust customization in Aspire - -In Aspire, you can customize which certificates resources consider trusted for TLS/HTTPS traffic. This is particularly useful for resources that don't use the system's root trusted certificates by default, such as containerized applications, Python apps, and Node.js apps. By configuring certificate trust, you enable these resources to communicate securely with services that use certificates they wouldn't otherwise trust, including the Aspire dashboard's OTLP endpoint. - -> [!IMPORTANT] -> Certificate trust customization only applies at run time. Custom certificates aren't included in publish or deployment artifacts. - -## When to use certificate trust customization - -Certificate trust customization is valuable when: - -- Resources need to trust the ASP.NET Core Development Certificate for local HTTPS communication. -- Containerized services must communicate with the dashboard over HTTPS. -- Python or Node.js applications need to trust custom certificate authorities. -- You're working with services that have specific certificate trust requirements. -- Resources need to establish secure telemetry connections to the Aspire dashboard. - -## Development certificate trust - -By default, Aspire attempts to add trust for the ASP.NET Core Development Certificate to resources that wouldn't otherwise trust it. This enables resources to communicate with the dashboard OTEL collector endpoint over HTTPS and any other HTTPS endpoints secured by the development certificate. - -You can control this behavior at the per-resource level using the `WithDeveloperCertificateTrust` API or through AppHost configuration settings. - -### Configure development certificate trust per resource - -To explicitly enable or disable development certificate trust for a specific resource: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -// Explicitly enable development certificate trust -var nodeApp = builder.AddNpmApp("frontend", "../frontend") - .WithDeveloperCertificateTrust(trust: true); - -// Disable development certificate trust -var pythonApp = builder.AddPythonApp("api", "../api", "main.py") - .WithDeveloperCertificateTrust(trust: false); - -builder.Build().Run(); -``` - -## Certificate authority collections - -Certificate authority collections allow you to bundle custom certificates and make them available to resources. You create a collection using the `AddCertificateAuthorityCollection` method and then reference it from resources that need to trust those certificates. - -### Create and use a certificate authority collection - -```csharp -using System.Security.Cryptography.X509Certificates; - -var builder = DistributedApplication.CreateBuilder(args); - -// Load your custom certificates -var certificates = new X509Certificate2Collection(); -certificates.ImportFromPemFile("path/to/certificate.pem"); - -// Create a certificate authority collection -var certBundle = builder.AddCertificateAuthorityCollection("my-bundle") - .WithCertificates(certificates); - -// Apply the certificate bundle to resources -builder.AddNpmApp("my-project", "../myapp") - .WithCertificateAuthorityCollection(certBundle); - -builder.Build().Run(); -``` - -In the preceding example, the certificate bundle is created with custom certificates and then applied to a Node.js application, enabling it to trust those certificates. - -## Certificate trust scopes - -Certificate trust scopes control how custom certificates interact with a resource's default trusted certificates. Different scopes provide flexibility in managing certificate trust based on your application's requirements. - -The `WithCertificateTrustScope` API accepts a `CertificateTrustScope` value to specify the trust behavior. - -### Default trust scopes - -Different resource types have different default trust scopes: - -- **Append**: The default for most resources, appending custom certificates to the default trusted certificates. -- **System**: The default for Python projects, which combines custom certificates with system root certificates because Python doesn't properly support Append mode. -- **None**: The default for .NET projects on Windows, as there's no way to automatically change the default system store source. - -### Append mode - -Attempts to append the configured certificates to the default trusted certificates for a given resource. This mode is useful when you want to add trust for additional certificates while maintaining trust for the system's default certificates. - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -builder.AddNodeApp("api", "../api") - .WithCertificateTrustScope(CertificateTrustScope.Append); - -builder.Build().Run(); -``` - -> [!NOTE] -> Not all languages and runtimes support Append mode. For example, Python doesn't natively support appending certificates to the default trust store. - -### Override mode - -Attempts to override a resource to only trust the configured certificates, replacing the default trusted certificates entirely. This mode is useful when you need strict control over which certificates are trusted. - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var certBundle = builder.AddCertificateAuthorityCollection("custom-certs") - .WithCertificates(myCertificates); - -builder.AddPythonModule("api", "./api", "uvicorn") - .WithCertificateAuthorityCollection(certBundle) - .WithCertificateTrustScope(CertificateTrustScope.Override); - -builder.Build().Run(); -``` - -### System mode - -Attempts to combine the configured certificates with the default system root certificates and use them to override the default trusted certificates for a resource. This mode is intended to support Python or other languages that don't work well with Append mode. - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -builder.AddPythonApp("worker", "../worker", "main.py") - .WithCertificateTrustScope(CertificateTrustScope.System); - -builder.Build().Run(); -``` - -### None mode - -Disables all custom certificate trust for the resource, causing it to rely solely on its default certificate trust behavior. - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -builder.AddContainer("service", "myimage") - .WithCertificateTrustScope(CertificateTrustScope.None); - -builder.Build().Run(); -``` - -## Custom certificate trust configuration - -For advanced scenarios, you can specify custom certificate trust behavior using a callback API. This callback allows you to customize the command line arguments and environment variables required to configure certificate trust for different resource types. - -### Configure certificate trust with a callback - -Use `WithCertificateTrustConfiguration` to customize how certificate trust is configured for a resource: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -builder.AddContainer("api", "myimage") - .WithCertificateTrustConfiguration(async (ctx) => - { - // Add a command line argument - ctx.Arguments.Add("--use-system-ca"); - - // Set environment variables with certificate paths - // CertificateBundlePath resolves to the path of the custom certificate bundle file - ctx.EnvironmentVariables["MY_CUSTOM_CERT_VAR"] = ctx.CertificateBundlePath; - - // CertificateDirectoriesPath resolves to paths containing individual certificates - ctx.EnvironmentVariables["CERTS_DIR"] = ctx.CertificateDirectoriesPath; - - await Task.CompletedTask; - }); - -builder.Build().Run(); -``` - -The callback receives a `CertificateTrustConfigurationCallbackAnnotationContext` that provides: - -- `Scope`: The `CertificateTrustScope` for the resource. -- `Arguments`: Command line arguments for the resource. Values can be strings or path providers like `CertificateBundlePath` or `CertificateDirectoriesPath`. -- `EnvironmentVariables`: Environment variables for configuring certificate trust. The dictionary key is the environment variable name; values can be strings or path providers. By default, includes `SSL_CERT_DIR` and may include `SSL_CERT_FILE` if Override or System scope is configured. -- `CertificateBundlePath`: A value provider that resolves to the path of a custom certificate bundle file. -- `CertificateDirectoriesPath`: A value provider that resolves to paths containing individual certificates. - -Default implementations are provided for Node.js, Python, and container resources. Container resources rely on standard OpenSSL configuration options, with default values that support the majority of common Linux distributions. - -### Configure container certificate paths - -For container resources, you can customize where certificates are stored and accessed using `WithContainerCertificatePaths`: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -builder.AddContainer("api", "myimage") - .WithContainerCertificatePaths( - customCertificatesDestination: "/custom/certs/path", - defaultCertificateBundlePaths: ["/etc/ssl/certs/ca-certificates.crt"], - defaultCertificateDirectoryPaths: ["/etc/ssl/certs"]); - -builder.Build().Run(); -``` - -The `WithContainerCertificatePaths` API accepts three optional parameters: - -- `customCertificatesDestination`: Overrides the base path in the container where custom certificate files are placed. If not set or set to `null`, the default path of `/usr/lib/ssl/aspire` is used. -- `defaultCertificateBundlePaths`: Overrides the path(s) in the container where a default certificate authority bundle file is located. When the `CertificateTrustScope` is Override or System, the custom certificate bundle is additionally written to these paths. If not set or set to `null`, a set of default certificate paths for common Linux distributions is used. -- `defaultCertificateDirectoryPaths`: Overrides the path(s) in the container where individual trusted certificate files are found. When the `CertificateTrustScope` is Append, these paths are concatenated with the path to the uploaded certificate artifacts. If not set or set to `null`, a set of default certificate paths for common Linux distributions is used. - -> [!NOTE] -> All desired paths must be configured in a single call to `WithContainerCertificatePaths` as only the most recent call to the API is honored. - -## Common scenarios - -### Enable HTTPS telemetry to the dashboard - -By default, Aspire enables development certificate trust for resources, allowing them to send telemetry to the dashboard over HTTPS: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -// Development certificate trust is enabled by default -var nodeApp = builder.AddNpmApp("frontend", "../frontend"); -var pythonApp = builder.AddPythonApp("api", "../api", "main.py"); - -builder.Build().Run(); -``` - -### Trust custom certificates in containers - -When working with containerized services that need to trust custom certificates: - -```csharp -using System.Security.Cryptography.X509Certificates; - -var builder = DistributedApplication.CreateBuilder(args); - -// Load custom CA certificates -var customCerts = new X509Certificate2Collection(); -customCerts.Import("corporate-ca.pem"); - -var certBundle = builder.AddCertificateAuthorityCollection("corporate-certs") - .WithCertificates(customCerts); - -// Apply to container -builder.AddContainer("service", "myservice:latest") - .WithCertificateAuthorityCollection(certBundle); - -builder.Build().Run(); -``` - -### Disable certificate trust for Python apps - -Python projects use System mode by default. To disable certificate trust customization for a Python app: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -// Disable certificate trust for Python apps -builder.AddPythonModule("api", "./api", "uvicorn") - .WithCertificateTrustScope(CertificateTrustScope.None); - -builder.Build().Run(); -``` - -## Limitations - -Certificate trust customization has the following limitations: - -- Currently supported only in run mode, not in publish mode. -- Not all languages and runtimes support all trust scope modes. -- Python applications don't natively support Append mode. -- Custom certificate trust requires appropriate runtime support within the resource. - -## See also - -- [Host external executables in Aspire](executable-resources.md) -- [Add Dockerfiles to your .NET app model](withdockerfile.md) -- [AppHost configuration](configuration.md) diff --git a/docs/app-host/configuration.md b/docs/app-host/configuration.md deleted file mode 100644 index 2df663b392..0000000000 --- a/docs/app-host/configuration.md +++ /dev/null @@ -1,112 +0,0 @@ ---- -title: Aspire AppHost configuration -description: Learn about the Aspire AppHost configuration options. -ms.date: 04/15/2025 -ms.topic: reference ---- - -# AppHost configuration - -The AppHost project configures and starts your distributed application (). When a `DistributedApplication` runs it reads configuration from the AppHost. Configuration is loaded from environment variables that are set on the AppHost and . - -Configuration includes: - -- Settings for hosting the resource service, such as the address and authentication options. -- Settings used to start the [Aspire dashboard](https://aspire.dev/dashboard/overview/), such the dashboard's frontend and OpenTelemetry Protocol (OTLP) addresses. -- Internal settings that Aspire uses to run the AppHost. These are set internally but can be accessed by integrations that extend Aspire. - -AppHost configuration is provided by the AppHost launch profile. The AppHost has a launch settings file call _launchSettings.json_ which has a list of launch profiles. Each launch profile is a collection of related options which defines how you would like `dotnet` to start your application. - -```json -{ - "$schema": "https://json.schemastore.org/launchsettings.json", - "profiles": { - "https": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "applicationUrl": "https://localhost:17134;http://localhost:15170", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development", - "DOTNET_ENVIRONMENT": "Development", - "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21030", - "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22057" - } - } - } -} -``` - -The preceding launch settings file: - -- Has one launch profile named `https`. -- Configures an Aspire AppHost project: - - The `applicationUrl` property configures the dashboard launch address (`ASPNETCORE_URLS`). - - Environment variables such as `ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL` and `ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL` are set on the AppHost. - -For more information, see [Aspire and launch profiles](https://aspire.dev/fundamentals/launch-profiles/). - -> [!NOTE] -> Configuration described on this page is for Aspire AppHost project. To configure the standalone dashboard, see [dashboard configuration](https://aspire.dev/dashboard/configuration/). - -## Common configuration - -| Option | Default value | Description | -|--|--|--| -| `ASPIRE_ALLOW_UNSECURED_TRANSPORT` | `false` | Allows communication with the AppHost without https. `ASPNETCORE_URLS` (dashboard address) and `ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL` (AppHost resource service address) must be secured with HTTPS unless true. | -| `ASPIRE_CONTAINER_RUNTIME` | `docker` | Allows the user of alternative container runtimes for resources backed by containers. Possible values are `docker` (default) or `podman`. See [Setup and tooling overview for more details](../fundamentals/setup-tooling.md). | -| `ASPIRE_VERSION_CHECK_DISABLED` | `false` | When set to `true`, Aspire doesn't check for newer versions on startup. | - -## Aspire version update notifications - -When an Aspire app starts, it checks if a newer version of Aspire is available on NuGet. If a new version is found, a notification appears in the dashboard with the latest version number, [a link to upgrade instructions](https://aka.ms/dotnet/aspire/update-latest), and button to ignore that version in the future. - -:::image type="content" source="../whats-new/media/dashboard-update-notification.png" lightbox="../whats-new/media/dashboard-update-notification.png" alt-text="Screenshot of dashboard showing a version update notification with upgrade options."::: - -The version check runs only when: - -- The dashboard is enabled (interaction service is available). -- At least 2 days have passed since the last check. -- The check hasn't been disabled via the `ASPIRE_VERSION_CHECK_DISABLED` configuration setting. -- The app is not running in publish mode. - -Updates are manual. You need to edit your project file to upgrade the Aspire SDK and package versions. - -## Resource service - -A resource service is hosted by the AppHost. The resource service is used by the dashboard to fetch information about resources which are being orchestrated by Aspire. - -| Option | Default value | Description | -|--|--|--| -| `ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL` | `null` | Configures the address of the resource service hosted by the AppHost. Automatically generated with _launchSettings.json_ to have a random port on localhost. For example, `https://localhost:17037`. | -| `ASPIRE_DASHBOARD_RESOURCESERVICE_APIKEY` | Automatically generated 128-bit entropy token. | The API key used to authenticate requests made to the AppHost's resource service. The API key is required if the AppHost is in run mode, the dashboard isn't disabled, and the dashboard isn't configured to allow anonymous access with `ASPIRE_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS`. | - -## Dashboard - -By default, the dashboard is automatically started by the AppHost. The dashboard supports [its own set of configuration](https://aspire.dev/dashboard/configuration/), and some settings can be configured from the AppHost. - -| Option | Default value | Description | -|--|--|--| -| `ASPNETCORE_URLS` | `null` | Dashboard address. Must be `https` unless `ASPIRE_ALLOW_UNSECURED_TRANSPORT` or `DistributedApplicationOptions.AllowUnsecuredTransport` is true. Automatically generated with _launchSettings.json_ to have a random port on localhost. The value in launch settings is set on the `applicationUrls` property. | -| `ASPNETCORE_ENVIRONMENT` | `Production` | Configures the environment the dashboard runs as. For more information, see [Use multiple environments in ASP.NET Core](/aspnet/core/fundamentals/environments). | -| `ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL` | `http://localhost:18889` if no gRPC endpoint is configured. | Configures the dashboard OTLP gRPC address. Used by the dashboard to receive telemetry over OTLP. Set on resources as the `OTEL_EXPORTER_OTLP_ENDPOINT` env var. The `OTEL_EXPORTER_OTLP_PROTOCOL` env var is `grpc`. Automatically generated with _launchSettings.json_ to have a random port on localhost. | -| `ASPIRE_DASHBOARD_OTLP_HTTP_ENDPOINT_URL` | `null` | Configures the dashboard OTLP HTTP address. Used by the dashboard to receive telemetry over OTLP. If only `ASPIRE_DASHBOARD_OTLP_HTTP_ENDPOINT_URL` is configured then it is set on resources as the `OTEL_EXPORTER_OTLP_ENDPOINT` env var. The `OTEL_EXPORTER_OTLP_PROTOCOL` env var is `http/protobuf`. | -| `ASPIRE_DASHBOARD_CORS_ALLOWED_ORIGINS` | `null` | Overrides the CORS allowed origins configured in the dashboard. This setting replaces the default behavior of calculating allowed origins based on resource endpoints. | -| `ASPIRE_DASHBOARD_FRONTEND_BROWSERTOKEN` | Automatically generated 128-bit entropy token. | Configures the frontend browser token. This is the value that must be entered to access the dashboard when the auth mode is BrowserToken. If no browser token is specified then a new token is generated each time the AppHost is launched. | -| `ASPIRE_DASHBOARD_TELEMETRY_OPTOUT` | `false` | Configures the dashboard to never send [usage telemetry](https://aspire.dev/dashboard/microsoft-collected-dashboard-telemetry/). | -| `ASPIRE_DASHBOARD_AI_DISABLED` | `false` | [GitHub Copilot in the dashboard](https://aspire.dev/dashboard/copilot/) is available when the AppHost is launched by a supported IDE. When set to `true` Copilot is disabled in the dashboard and no Copilot UI is visible. | -| `ASPIRE_DASHBOARD_FORWARDEDHEADERS_ENABLED` | `false` | Enables the Forwarded headers middleware that replaces the scheme and host values on the Request context with the values coming from the `X-Forwarded-Proto` and `X-Forwarded-Host` headers. | - -## Internal - -Internal settings are used by the AppHost and integrations. Internal settings aren't designed to be configured directly. - -| Option | Default value | Description | -|--|--|--| -| `AppHost:Directory` | The content root if there's no project. | Directory of the project where the AppHost is located. Accessible from the . | -| `AppHost:Path` | The directory combined with the application name. | The path to the AppHost. It combines the directory with the application name. | -| `AppHost:Sha256` | It is created from the AppHost name when the AppHost is in publish mode. Otherwise it is created from the AppHost path. | Hex encoded hash for the current application. The hash is based on the location of the app on the current machine so it is stable between launches of the AppHost. | -| `AppHost:OtlpApiKey` | Automatically generated 128-bit entropy token. | The API key used to authenticate requests sent to the dashboard OTLP service. The value is present if needed: the AppHost is in run mode, the dashboard isn't disabled, and the dashboard isn't configured to allow anonymous access with `ASPIRE_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS`. | -| `AppHost:BrowserToken` | Automatically generated 128-bit entropy token. | The browser token used to authenticate browsing to the dashboard when it is launched by the AppHost. The browser token can be set by `ASPIRE_DASHBOARD_FRONTEND_BROWSERTOKEN`. The value is present if needed: the AppHost is in run mode, the dashboard isn't disabled, and the dashboard isn't configured to allow anonymous access with `ASPIRE_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS`. | -| `AppHost:ResourceService:AuthMode` | `ApiKey`. If `ASPIRE_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS` is true then the value is `Unsecured`. | The authentication mode used to access the resource service. The value is present if needed: the AppHost is in run mode and the dashboard isn't disabled. | -| `AppHost:ResourceService:ApiKey` | Automatically generated 128-bit entropy token. | The API key used to authenticate requests made to the AppHost's resource service. The API key can be set by `ASPIRE_DASHBOARD_RESOURCESERVICE_APIKEY`. The value is present if needed: the AppHost is in run mode, the dashboard isn't disabled, and the dashboard isn't configured to allow anonymous access with `ASPIRE_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS`. | diff --git a/docs/app-host/eventing.md b/docs/app-host/eventing.md deleted file mode 100644 index 58fdded32b..0000000000 --- a/docs/app-host/eventing.md +++ /dev/null @@ -1,124 +0,0 @@ ---- -title: Eventing in Aspire -description: Learn how to use the .NET eventing features with Aspire. -ms.date: 08/07/2025 -ms.custom: sfi-ropc-nochange ---- - -# Eventing in Aspire - -In Aspire, eventing allows you to publish and subscribe to events during various [AppHost life cycles](xref:dotnet/aspire/app-host#apphost-life-cycles). Eventing is more flexible than life cycle events. Both let you run arbitrary code during event callbacks, but eventing offers finer control of event timing, publishing, and provides supports for custom events. - -The eventing mechanisms in Aspire are part of the [πŸ“¦ Aspire.Hosting](https://www.nuget.org/packages/Aspire.Hosting) NuGet package. This package provides a set of interfaces and classes in the namespace that you use to publish and subscribe to events in your Aspire AppHost project. Eventing is scoped to the AppHost itself and the resources within. - -In this article, you learn how to use the eventing features in Aspire. - -## AppHost eventing - -The following events are available in the AppHost and occur in the following order: - -1. : This event is raised before the AppHost starts. -1. : This event is raised per resource after its endpoints are allocated. -1. : This event is raised after the AppHost created resources. - -All of the preceding events are analogous to the [AppHost life cycles](xref:dotnet/aspire/app-host#apphost-life-cycles). That is, an implementation of the could handle these events just the same. With the eventing API, however, you can run arbitrary code when these events are raised and event define custom eventsβ€”any event that implements the interface. - -### Subscribe to AppHost events - -To subscribe to the built-in AppHost events, use the eventing API. After you have a distributed application builder instance, walk up to the property and call the API. Consider the following sample AppHost _AppHost.cs_ file: - -:::code source="snippets/AspireApp/AspireApp.AppHost/AppHost.cs"::: - -The preceding code is based on the starter template with the addition of the calls to the `Subscribe` API. The `Subscribe` API returns a instance that you can use to unsubscribe from the event. It's common to discard the returned subscriptions, as you don't usually need to unsubscribe from events as the entire app is torn down when the AppHost is shut down. - -When the AppHost is run, by the time the Aspire dashboard is displayed, you should see the following log output in the console: - -:::code language="Plaintext" source="snippets/AspireApp/AspireApp.AppHost/Console.txt" highlight="2,10,12,14,16,22"::: - -The log output confirms that event handlers are executed in the order of the AppHost life cycle events. The subscription order doesn't affect execution order. The `BeforeStartEvent` is triggered first, followed by each resource's `ResourceEndpointsAllocatedEvent`, and finally `AfterResourcesCreatedEvent`. - -## Resource eventing - -In addition to the AppHost events, you can also subscribe to resource events. Resource events are raised specific to an individual resource. Resource events are defined as implementations of the interface. The following resource events are available in the listed order: - -1. : Raised by orchestrators to signal to resources that they should initialize themselves. -1. : Raised when the orchestrator allocates endpoints for a resource. -1. : Raised when a connection string becomes available for a resource. -1. : Raised before the orchestrator starts a new resource. -1. : Raised when a resource initially transitions to a ready state. - -### Subscribe to resource events - -To subscribe to resource events, use the convenience-based extension methodsβ€”`On*`. After you have a distributed application builder instance, and a resource builder, walk up to the instance and chain a call to the desired `On*` event API. Consider the following sample _AppHost.cs_ file: - -:::code source="snippets/AspireApp/AspireApp.ResourceAppHost/AppHost.cs"::: - -The preceding code subscribes to the `InitializeResourceEvent`, `ResourceReadyEvent`, `ResourceEndpointsAllocatedEvent`, `ConnectionStringAvailableEvent`, and `BeforeResourceStartedEvent` events on the `cache` resource. When is called, it returns an where `T` is a . Chain calls to the `On*` methods to subscribe to the events. The `On*` methods return the same instance, so you can chain multiple calls: - -- `OnInitializeResource`: Subscribes to the . -- `OnResourceEndpointsAllocated`: Subscribes to the event. -- `OnConnectionStringAvailable`: Subscribes to the event. -- `OnBeforeResourceStarted`: Subscribes to the event. -- `OnResourceReady`: Subscribes to the event. - -When the AppHost is run, by the time the Aspire dashboard is displayed, you should see the following log output in the console: - -:::code language="Plaintext" source="snippets/AspireApp/AspireApp.ResourceAppHost/Console.txt" highlight="8,10,12,14,20"::: - -> [!NOTE] -> Some events block execution. For example, when the `BeforeResourceStartedEvent` is published, the resource startup blocks until all subscriptions for that event on a given resource finish executing. Whether an event blocks or not depends on how you publish it (see the following section). - -## Publish events - -When subscribing to any of the built-in events, you don't need to publish the event yourself as the AppHost orchestrator manages to publish built-in events on your behalf. However, you can publish custom events with the eventing API. To publish an event, you have to first define an event as an implementation of either the or interface. You need to determine which interface to implement based on whether the event is a global AppHost event or a resource-specific event. - -Then, you can subscribe and publish the event by calling the either of the following APIs: - -- : Publishes an event to all subscribes of the specific event type. -- : Publishes an event to all subscribes of the specific event type with a specified dispatch behavior. - -### Provide an `EventDispatchBehavior` - -When events are dispatched, you can control how the events are dispatched to subscribers. The event dispatch behavior is specified with the `EventDispatchBehavior` enum. The following behaviors are available: - -- : Fires events sequentially and blocks until they're all processed. -- : Fires events concurrently and blocks until they're all processed. -- : Fires events sequentially but doesn't block. -- : Fires events concurrently but doesn't block. - -The default behavior is `EventDispatchBehavior.BlockingSequential`. To override this behavior, when calling a publishing API such as , provide the desired behavior as an argument. - -## AppHost life cycle events - -Eventing offers the most flexibility. However, this section explains the alternative: life cycle events. - -The Aspire AppHost exposes several life cycles that you can hook into by implementing the interface. The following lifecycle methods are available: - -| Order | Method | Description | -|--|--|--| -| **1** | | Runs before the distributed application starts. | -| **2** | | Runs after the orchestrator allocates endpoints for resources in the application model. | -| **3** | | Runs after the resource was created by the orchestrator. | - -### Register a life cycle hook - -To register a life cycle hook, implement the interface and register the hook with the AppHost using the API: - -:::code source="../fundamentals/snippets/lifecycles/AspireApp/AspireApp.AppHost/AppHost.cs"::: - -The preceding code: - -- Implements the interface as a `LifecycleLogger`. -- Registers the life cycle hook with the AppHost using the API. -- Logs a message for all the events. - -When this AppHost is run, the life cycle hook is executed for each event. The following output is generated: - -:::code language="Plaintext" source="../fundamentals/snippets/lifecycles/AspireApp/AspireApp.AppHost/Console.txt" highlight="2,10,16"::: - -The preferred way to hook into the AppHost life cycle is to use the eventing API. For more information, see [AppHost eventing](#apphost-eventing). - -## See also - -- [Aspire orchestration overview](../fundamentals/app-host-overview.md) -- [Orchestrate resources in Aspire](../fundamentals/orchestrate-resources.md) diff --git a/docs/app-host/executable-resources.md b/docs/app-host/executable-resources.md deleted file mode 100644 index a49d344b8e..0000000000 --- a/docs/app-host/executable-resources.md +++ /dev/null @@ -1,203 +0,0 @@ ---- -title: Host external executables in Aspire -description: Learn how to use ExecutableResource and AddExecutable to host external executable applications in your Aspire app host. -ms.date: 08/11/2025 -ai-usage: ai-assisted ---- - -# Host external executables in Aspire - -In Aspire, you can host external executable applications alongside your projects using the method. This capability is useful when you need to integrate executable applications or tools into your distributed application, such as Node.js applications, Python scripts, or specialized CLI tools. - -## When to use executable resources - -Use executable resources when you need to: - -- Host non-.NET applications that don't have containerized equivalents. -- Integrate command-line tools or utilities into your application. -- Run external processes that other resources depend on. -- Develop with tools that provide local development servers. - -Common examples include: - -- **Frontend development servers**: Tools like [Vercel CLI](https://vercel.com/docs/cli), Vite, or webpack dev server. -- **Language-specific applications**: Node.js apps, Python scripts, or Go applications. -- **Database tools**: Migration utilities or database seeders. -- **Build tools**: Asset processors or code generators. - -## Basic usage - -The method requires a resource name, the executable path, and optionally command-line arguments and a working directory: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -// Basic executable without arguments -var nodeApp = builder.AddExecutable("frontend", "node", ".", "server.js"); - -// Executable with command-line arguments -var pythonApp = builder.AddExecutable( - "api", "python", ".", "-m", "uvicorn", "main:app", "--reload", "--host", "0.0.0.0", "--port", "8000"); - -builder.Build().Run(); -``` - -This code demonstrates setting up a basic executable resource. The first example runs a Node.js server script, while the second starts a Python application using Uvicorn with specific configuration options passed as arguments directly to the AddExecutable method. - -## Resource dependencies and environment configuration - -You can provide command-line arguments directly in the AddExecutable call and configure environment variables for resource dependencies. Executable resources can reference other resources and access their connection information. - -### Arguments in the AddExecutable call - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -// Arguments provided directly in AddExecutable -var app = builder.AddExecutable("vercel-dev", "vercel", ".", "dev", "--listen", "3000"); -``` - -### Resource dependencies with environment variables - -For arguments that depend on other resources, use environment variables: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var redis = builder.AddRedis("cache"); -var postgres = builder.AddPostgres("postgres").AddDatabase("appdb"); - -var app = builder.AddExecutable("worker", "python", ".", "worker.py") - .WithReference(redis) // Provides ConnectionStrings__cache - .WithReference(postgres); // Provides ConnectionStrings__appdb -``` - -When one resource depends on another, `WithReference` passes along environment variables containing the dependent resource's connection details. For example, the `worker` executable's reference to `redis` and `postgres` provides it with the `ConnectionStrings__cache` and `ConnectionStrings__appdb` environment variables, which contain connection strings to these resources. - -### Access specific endpoint information - -For more control over how connection information is passed to your executable: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var redis = builder.AddRedis("cache"); - -var app = builder.AddExecutable("app", "node", ".", "app.js") - .WithReference(redis) - .WithEnvironment(context => - { - // Provide individual connection details - context.EnvironmentVariables["REDIS_HOST"] = redis.Resource.PrimaryEndpoint.Property(EndpointProperty.Host); - context.EnvironmentVariables["REDIS_PORT"] = redis.Resource.PrimaryEndpoint.Property(EndpointProperty.Port); - }); -``` - -## Practical example: Vercel CLI - -Here's a complete example using the [Vercel CLI](https://vercel.com/docs/cli) to host a frontend application with a backend API: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -// Backend API -var api = builder.AddProject("api") - .WithExternalHttpEndpoints(); - -// Frontend with Vercel CLI -var frontend = builder.AddExecutable( - "vercel-dev", "vercel", ".", "dev", "--listen", "3000") - .WithEnvironment("API_URL", api.GetEndpoint("http")) - .WithHttpEndpoint(port: 3000, name: "http"); - -builder.Build().Run(); -``` - -## Configure endpoints - -Executable resources can expose HTTP endpoints that other resources can reference: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var frontend = builder.AddExecutable( - "vite-dev", "npm", ".", "run", "dev", "--", "--port", "5173", "--host", "0.0.0.0") - .WithHttpEndpoint(port: 5173, name: "http"); - -// Another service can reference the frontend -var e2eTests = builder.AddExecutable("playwright", "npx", ".", "playwright", "test") - .WithEnvironment("BASE_URL", frontend.GetEndpoint("http")); -``` - -## Environment configuration - -Configure environment variables for your executable: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var app = builder.AddExecutable( - "api", "uvicorn", ".", "main:app", "--reload", "--host", "0.0.0.0") - .WithEnvironment("DEBUG", "true") - .WithEnvironment("LOG_LEVEL", "info") - .WithEnvironment(context => - { - // Dynamic environment variables - context.EnvironmentVariables["START_TIME"] = DateTimeOffset.UtcNow.ToString(); - }); -``` - -## Publishing with PublishAsDockerfile - -For production deployment, executable resources need to be containerized. Use the method to specify how the executable should be packaged: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var app = builder.AddExecutable( - "frontend", "npm", ".", "start", "--port", "3000") - .PublishAsDockerfile(); -``` - -When you call `PublishAsDockerfile()`, Aspire generates a Dockerfile during the publish process. You can customize this by providing your own Dockerfile: - -### Custom Dockerfile for publishing - -Create a `Dockerfile` in your executable's working directory: - -```dockerfile -FROM node:22-alpine -WORKDIR /app -COPY package*.json ./ -RUN npm ci --only=production -COPY . . -EXPOSE 3000 -CMD ["npm", "start"] -``` - -Then reference it in your app host: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var app = builder.AddExecutable("frontend", "npm", ".", "start") - .PublishAsDockerfile([new DockerfileBuildArg("NODE_ENV", "production")]); -``` - -## Best practices - -When working with executable resources: - -1. **Use explicit paths**: For better reliability, use full paths to executables when possible. -1. **Handle dependencies**: Use `WithReference` to establish proper dependency relationships. -1. **Configure explicit start**: Use `WithExplicitStart()` for executables that shouldn't start automatically. -1. **Prepare for deployment**: Always use `PublishAsDockerfile()` for production scenarios. -1. **Environment isolation**: Use environment variables rather than command-line arguments for sensitive configuration. -1. **Resource naming**: Use descriptive names that clearly identify the executable's purpose. - -## See also - -- [App host overview](../fundamentals/app-host-overview.md) -- [Add Dockerfiles to the app model](withdockerfile.md) -- [Node.js apps in Aspire](../get-started/build-aspire-apps-with-nodejs.md) -- [Python apps in Aspire](../get-started/build-aspire-apps-with-python.md) diff --git a/docs/app-host/persistent-containers.md b/docs/app-host/persistent-containers.md deleted file mode 100644 index 626ea31039..0000000000 --- a/docs/app-host/persistent-containers.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -title: Persistent container lifetimes in Aspire -description: Learn how to configure containers to persist and be re-used between Aspire AppHost runs. -ms.date: 07/15/2025 ---- - -# Persistent container lifetimes in Aspire - -In Aspire, containers follow a typical lifecycle where they're created when the AppHost starts and destroyed when it stops. However, you can specify that you want to use **persistent containers**, which deviate from this standard lifecycle. Persistent containers are created and started by the Aspire orchestrator but aren't destroyed when the AppHost stops, allowing them to persist between runs. - -This feature is particularly beneficial for containers that have long startup times, such as databases, as it eliminates the need to wait for these services to initialize on every AppHost restart. - -## Configure a persistent container - -To configure a container resource with a persistent lifetime, use the method and pass : - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var postgres = builder.AddPostgres("postgres") - .WithLifetime(ContainerLifetime.Persistent); - -var db = postgres.AddDatabase("inventorydb"); - -builder.AddProject("inventory") - .WithReference(db); - -builder.Build().Run(); -``` - -In the preceding example, the PostgreSQL container is configured to persist between AppHost runs, while the `inventory` project references the database as normal. - -## Dashboard visualization - -The Aspire dashboard shows persistent containers with a distinctive pin icon (πŸ“Œ) to help you identify them: - -:::image type="content" source="../whats-new/media/persistent-container.png" lightbox="../whats-new/media/persistent-container.png" alt-text="Screenshot of the Aspire dashboard showing a persistent container with a pin icon."::: - -After the AppHost stops, persistent containers continue running and can be seen in your container runtime (such as Docker Desktop): - -:::image type="content" source="../whats-new/media/persistent-container-docker-desktop.png" lightbox="../whats-new/media/persistent-container-docker-desktop.png" alt-text="Screenshot of Docker Desktop showing a persistent RabbitMQ container still running after the AppHost stopped."::: - -## Configuration change detection - -Persistent containers are automatically recreated when the AppHost detects meaningful configuration changes. Aspire tracks a hash of the configuration used to create each container and compares it to the current configuration on subsequent runs. If the configuration differs, the container is recreated with the new settings. - -This mechanism ensures that persistent containers stay synchronized with your AppHost configuration without requiring manual intervention. - -## Container naming and uniqueness - -By default, persistent containers use a naming pattern that combines: - -- The service name you specify in your AppHost. -- A postfix based on a hash of the AppHost project path. - -This naming scheme ensures that persistent containers are unique to each AppHost project, preventing conflicts when multiple Aspire projects use the same service names. - -For example, if you have a service named `"postgres"` in an AppHost project located at `/path/to/MyApp.AppHost`, the container name might be `postgres-abc123def` where `abc123def` is derived from the project path hash. - -### Custom container names - -For advanced scenarios, you can set a custom container name using the method: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var postgres = builder.AddPostgres("postgres") - .WithLifetime(ContainerLifetime.Persistent) - .WithContainerName("my-shared-postgres"); - -builder.Build().Run(); -``` - -When you specify a custom container name, Aspire first checks if a container with that name already exists. If a container with that name exists and was previously created by Aspire, it follows the normal persistent container behavior and can be automatically recreated if the configuration changes. If a container with that name exists but wasn't created by Aspire, it won't be managed or recreated by the AppHost. If no container with the custom name exists, Aspire creates a new one. - -## Manual cleanup - -> [!IMPORTANT] -> Persistent containers aren't automatically removed when you stop the AppHost. To delete these containers, you must manually stop and remove them using your container runtime. - -You can clean up persistent containers using Docker CLI commands: - -```bash -# Stop the container -docker stop my-container-name - -# Remove the container -docker rm my-container-name -``` - -Alternatively, you can use Docker Desktop or your preferred container management tool to stop and remove persistent containers. - -## Use cases and benefits - -Persistent containers are ideal for: - -- **Database services**: PostgreSQL, SQL Server, MySQL, and other databases that take time to initialize and load data. -- **Message brokers**: RabbitMQ, Redis, and similar services that benefit from maintaining state between runs. -- **Development data**: Containers with test data or configurations that you want to preserve during development iterations. -- **Shared services**: Services that multiple AppHosts or development team members can share. - -## See also - -- [Orchestrate resources in Aspire](../fundamentals/orchestrate-resources.md) -- [Aspire AppHost overview](../fundamentals/app-host-overview.md) -- [What's new in Aspire 9.0](../whats-new/dotnet-aspire-9.md#persistent-containers) diff --git a/docs/app-host/withdockerfile.md b/docs/app-host/withdockerfile.md deleted file mode 100644 index f7a9e64368..0000000000 --- a/docs/app-host/withdockerfile.md +++ /dev/null @@ -1,141 +0,0 @@ ---- -title: Add Dockerfiles to your .NET app model -description: Learn how to add Dockerfiles to your .NET app model. -ms.date: 09/30/2025 ---- - -# Add Dockerfiles to your .NET app model - -With Aspire it's possible to specify a _Dockerfile_ to build when the [AppHost](../fundamentals/app-host-overview.md) is started using either the or extension methods. - -These two methods serve different purposes: - -- ****: Creates a new container resource from an existing Dockerfile. Use this when you want to add a custom containerized service to your app model. -- ****: Customizes an existing container resource (like a database or cache) to use a different Dockerfile. Use this when you want to modify the default container image for an Aspire component. - -Both methods expect an existing Dockerfile in the specified context pathβ€”neither method creates a Dockerfile for you. - -## When to use AddDockerfile vs WithDockerfile - -Choose the appropriate method based on your scenario: - -**Use when:** - -- You want to add a custom containerized service to your app model. -- You have an existing Dockerfile for a custom application or service. -- You need to create a new container resource that isn't provided by Aspire components. - -**Use when:** - -- You want to customize an existing Aspire component (like PostgreSQL, Redis, etc.). -- You need to replace the default container image with a custom one. -- You want to maintain the strongly typed resource builder and its extension methods. -- You have specific requirements that the default container image doesn't meet. - -## Add a Dockerfile to the app model - -In the following example the extension method is used to specify a container by referencing the context path for the container build. - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var container = builder.AddDockerfile( - "mycontainer", "relative/context/path"); -``` - -Unless the context path argument is a rooted path the context path is interpreted as being relative to the AppHost projects directory (where the AppHost `*.csproj` folder is located). - -By default the name of the _Dockerfile_ which is used is `Dockerfile` and is expected to be within the context path directory. It's possible to explicitly specify the _Dockerfile_ name either as an absolute path or a relative path to the context path. - -This is useful if you wish to modify the specific _Dockerfile_ being used when running locally or when the AppHost is deploying. - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var container = builder.ExecutionContext.IsRunMode - ? builder.AddDockerfile( - "mycontainer", "relative/context/path", "Dockerfile.debug") - : builder.AddDockerfile( - "mycontainer", "relative/context/path", "Dockerfile.release"); -``` - -## Customize existing container resources - -When using the return value is an `IResourceBuilder`. Aspire includes many custom resource types that are derived from . - -Using the extension method it's possible to take an existing Aspire component (like PostgreSQL, Redis, or SQL Server) and replace its default container image with a custom one built from your own Dockerfile. This allows you to continue using the strongly typed resource types and their specific extension methods while customizing the underlying container. - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -// This replaces the default PostgreSQL container image with a custom one -// built from your Dockerfile, while keeping PostgreSQL-specific functionality -var pgsql = builder.AddPostgres("pgsql") - .WithDockerfile("path/to/context") - .WithPgAdmin(); // Still works because it's still a PostgreSQL resource -``` - -## Pass build arguments - -The method can be used to pass arguments into the container image build. - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var container = builder.AddDockerfile("mygoapp", "relative/context/path") - .WithBuildArg("GO_VERSION", "1.22"); -``` - -The value parameter on the method can be a literal value (`boolean`, `string`, `int`) or it can be a resource builder for a [parameter resource](../fundamentals/external-parameters.md). The following code replaces the `GO_VERSION` with a parameter value that can be specified at deployment time. - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var goVersion = builder.AddParameter("goversion"); - -var container = builder.AddDockerfile("mygoapp", "relative/context/path") - .WithBuildArg("GO_VERSION", goVersion); -``` - -Build arguments correspond to the [`ARG` command](https://docs.docker.com/build/guide/build-args/) in _Dockerfiles_. Expanding the preceding example, this is a multi-stage _Dockerfile_ which specifies specific container image version to use as a parameter. - -```dockerfile -# Stage 1: Build the Go program -ARG GO_VERSION=1.22 -FROM golang:${GO_VERSION} AS builder -WORKDIR /build -COPY . . -RUN go build mygoapp.go - -# Stage 2: Run the Go program -FROM mcr.microsoft.com/cbl-mariner/base/core:2.0 -WORKDIR /app -COPY --from=builder /build/mygoapp . -CMD ["./mygoapp"] -``` - -> [!NOTE] -> Instead of hardcoding values into the container image, it's recommended to use environment variables for values that frequently change. This avoids the need to rebuild the container image whenever a change is required. - -## Pass build secrets - -In addition to build arguments it's possible to specify build secrets using which are made selectively available to individual commands in the _Dockerfile_ using the `--mount=type=secret` syntax on `RUN` commands. - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var accessToken = builder.AddParameter("accesstoken", secret: true); - -var container = builder.AddDockerfile("myapp", "relative/context/path") - .WithBuildSecret("ACCESS_TOKEN", accessToken); -``` - -For example, consider the `RUN` command in a _Dockerfile_ which exposes the specified secret to the specific command: - -```dockerfile -# The helloworld command can read the secret from /run/secrets/ACCESS_TOKEN -RUN --mount=type=secret,id=ACCESS_TOKEN helloworld -``` - -> [!CAUTION] -> Caution should be exercised when passing secrets in build environments. This is often done when using a token to retrieve dependencies from private repositories or feeds before a build. It is important to ensure that the injected secrets are not copied into the final or intermediate images. diff --git a/docs/architecture/overview.md b/docs/architecture/overview.md index 0753120d6f..ce07ed0d17 100644 --- a/docs/architecture/overview.md +++ b/docs/architecture/overview.md @@ -37,7 +37,7 @@ Most importantly, the translation process itself is highly extensible. You can d ### Modality and extensibility -Aspire operates in two primary modes, each tailored to streamline your specific needsβ€”detailed in the following section. Both modes use a robust set of familiar APIs and a rich ecosystem of [integrations](../fundamentals/integrations-overview.md). Each integration simplifies working with a common service, framework, or platform, such as Redis, PostgreSQL, Azure services, or Orleans, for example. These integrations work together like puzzle pieces, enabling you to define resources, express dependencies, and configure behavior effortlesslyβ€”whether you're running locally or deploying to production. +Aspire operates in two primary modes, each tailored to streamline your specific needsβ€”detailed in the following section. Both modes use a robust set of familiar APIs and a rich ecosystem of [integrations](https://aspire.dev/integrations/overview/). Each integration simplifies working with a common service, framework, or platform, such as Redis, PostgreSQL, Azure services, or Orleans, for example. These integrations work together like puzzle pieces, enabling you to define resources, express dependencies, and configure behavior effortlesslyβ€”whether you're running locally or deploying to production. Why is modality important when it comes to the AppHost's execution context? This is because it allows you to define your app model once and with the appropriate APIs, specify how resources operate in each mode. Consider the following collection of resources: @@ -79,11 +79,11 @@ https://mermaid.live/edit#pako:eNptUl1vozAQ_CvWPrUSTQkQQlBViYRWRbrecQWp0tV92IAbr :::image type="content" source="media/publish-app-topology-thumb.png" alt-text="Published app topology" lightbox="media/publish-app-topology.png"::: -For more information on how to use publish mode, see [Aspire deployments](../deployment/overview.md). +For more information on how to use publish mode, see [Aspire deployments](https://aspire.dev/deployment/overview/). ## Dev-time orchestration -In run mode, [the AppHost orchestrates](../fundamentals/app-host-overview.md) all resources defined in your app model. But how does it achieve this? +In run mode, [the AppHost orchestrates](https://aspire.dev/get-started/app-host/) all resources defined in your app model. But how does it achieve this? > [!IMPORTANT] > The AppHost isn't a production runtime. It's a development-time orchestration tool that simplifies the process of running and debugging your application locally. @@ -120,7 +120,7 @@ In this section, several key questions are answered to help you understand how t The orchestration process follows a layered architecture. At its core, the AppHost represents the developer's desired view of the distributed application's resources. DCP ensures that this desired state is realized by orchestrating the resources and maintaining consistency. -The [app model](../fundamentals/app-host-overview.md#define-the-app-model) serves as a blueprint for DCP to orchestrate your application. Under the hood, the AppHost is a .NET console application powered by the [πŸ“¦ Aspire.Hosting.AppHost](https://www.nuget.org/packages/Aspire.Hosting.AppHost) NuGet package. This package includes build targets that register orchestration dependencies, enabling seamless dev-time orchestration. +The [app model](https://aspire.dev/get-started/app-host/#define-the-app-model) serves as a blueprint for DCP to orchestrate your application. Under the hood, the AppHost is a .NET console application powered by the [πŸ“¦ Aspire.Hosting.AppHost](https://www.nuget.org/packages/Aspire.Hosting.AppHost) NuGet package. This package includes build targets that register orchestration dependencies, enabling seamless dev-time orchestration. DCP is a Kubernetes-compatible API server, meaning it uses the same network protocols and conventions as Kubernetes. This compatibility allows the Aspire AppHost to leverage existing Kubernetes libraries for communication. Specifically, the AppHost contains an implementation of the `k8s.KubernetesClient` (from the [πŸ“¦ KubernetesClient](https://www.nuget.org/packages/KubernetesClient) NuGet package), which is a .NET client for Kubernetes. This client is used to communicate with the DCP API server, enabling the AppHost to delegate orchestration tasks to DCP. @@ -130,7 +130,7 @@ When you run the AppHost, it performs the first step of "lowering" by translatin :::image type="content" source="media/app-host-dcp-flow-thumb.png" alt-text="A flow diagram depicting how the AppHost delegates to DCP." lightbox="media/app-host-dcp-flow.png"::: -For more information on the AppHost and APIs for building the app model, see [Aspire orchestration overview](../fundamentals/app-host-overview.md). +For more information on the AppHost and APIs for building the app model, see [Aspire orchestration overview](https://aspire.dev/get-started/app-host/). ### Developer Control Plane @@ -156,7 +156,7 @@ DCP performs the following tasks: - Creates and starts containers. - Runs executables with the required arguments and environment variables. - Monitors resources: - - Provides change notifications about objects managed within DCP, including process IDs, running status, and exit codes (the AppHost subscribes to these changes to manage the [application's lifecycle](../app-host/eventing.md) effectively). + - Provides change notifications about objects managed within DCP, including process IDs, running status, and exit codes (the AppHost subscribes to these changes to manage the [application's lifecycle](https://aspire.dev/app-host/eventing/) effectively). - Starts the developer dashboard. Continuing from the [diagram in the previous](#app-host-dcp-flow) section, consider the following diagram that helps to visualize the responsibilities of DCP: @@ -167,7 +167,7 @@ Continuing from the [diagram in the previous](#app-host-dcp-flow) section, consi DCP logs are streamed back to the AppHost, which then forwards them to the developer dashboard. While the developer dashboard exposes commands such as start, stop, and restart, these commands are not part of DCP itself. Instead, they are implemented by the app model runtime, specifically within its "dashboard service" component. These commands operate by manipulating DCP objectsβ€”creating new ones, deleting old ones, or updating their properties. For example, restarting a .NET project involves stopping and deleting the existing representing the project and creating a new one with the same specifications. -For more information on container networking, see [How container networks are managed](../fundamentals/networking-overview.md#how-container-networks-are-managed). +For more information on container networking, see [How container networks are managed](https://aspire.dev/fundamentals/networking-overview/#how-container-networks-are-managed). ## Developer dashboard @@ -181,7 +181,7 @@ The dashboard provides a user-friendly interface for inspecting resource states, The dashboard provides a set of commands for managing resources, such as start, stop, and restart. While commands appear as intuitive actions in the dashboard UI, under the hood, they operate by manipulating DCP objects. For more information, see [Stop or Start a resource](https://aspire.dev/dashboard/explore/#stop-or-start-a-resource). -In addition to these built-in commands, you can define custom commands tailored to your application's needs. These custom commands are registered in the app model and seamlessly integrated into the dashboard, providing enhanced flexibility and control. Learn more about custom commands in [Custom resource commands in Aspire](../fundamentals/custom-resource-commands.md). +In addition to these built-in commands, you can define custom commands tailored to your application's needs. These custom commands are registered in the app model and seamlessly integrated into the dashboard, providing enhanced flexibility and control. Learn more about custom commands in [Custom resource commands in Aspire](https://aspire.dev/fundamentals/custom-resource-commands/). ### Real-time log streaming @@ -191,5 +191,5 @@ The developer dashboard is more than just a toolβ€”it's your command center for ## See also -- [Orchestration overview](../fundamentals/app-host-overview.md) +- [Orchestration overview](https://aspire.dev/get-started/app-host/) - [Explore the Aspire dashboard](https://aspire.dev/dashboard/explore/) diff --git a/docs/cli-reference/aspire-add.md b/docs/cli-reference/aspire-add.md deleted file mode 100644 index b382c486d3..0000000000 --- a/docs/cli-reference/aspire-add.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: aspire add command -description: Learn about the aspire add command and its usage. This command adds an integration package to an Aspire AppHost project. -ms.date: 07/11/2025 ---- -# aspire add command - -**This article applies to:** βœ”οΈ Aspire CLI 9.4.0 and later versions - -## Name - -`aspire add` - Add an integration to the Aspire project. - -## Synopsis - -```Command -aspire add [] [options] -``` - -## Description - -The `aspire add` command searches for an integration package and adds it to the Aspire AppHost. - -[!INCLUDE [project-search-logic-description](includes/project-search-logic-description.md)] - -## Arguments - -The following arguments are available: - -- **`integration`** - - The name of the integration to add (for example: redis, postgres). - - If a partial name or invalid name is provided, the CLI searches NuGet for approximate matches and prints them in the terminal for the user to select. If no results are found, all packages are listed. - -## Options - -The following options are available: - -- [!INCLUDE [option-project](includes/option-project.md)] - -- **`-v, --version`** - - The version of the integration to add. - -- **`-s, --source`** - - The NuGet source to use for the integration. - -- [!INCLUDE [option-help](includes/option-help.md)] - -- [!INCLUDE [option-debug](includes/option-debug.md)] - -- [!INCLUDE [option-wait](includes/option-wait.md)] - -## Examples - -- Finds an AppHost project and lists all Aspire integration packages from NuGet: - - ```Command - aspire add - ``` - -- Finds an AppHost project and adds the **kafka** (Aspire.Hosting.Kafka) integration package: - - ```Command - aspire add kafka --version 9.3.2 - ``` diff --git a/docs/cli-reference/aspire-config-delete.md b/docs/cli-reference/aspire-config-delete.md deleted file mode 100644 index 6ce48d01aa..0000000000 --- a/docs/cli-reference/aspire-config-delete.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -title: aspire config delete command -description: Learn about the aspire config delete command and its usage. This command deletes an Aspire CLI config value by key name. -ms.date: 07/11/2025 ---- -# aspire config delete command - -**This article applies to:** βœ”οΈ Aspire CLI 9.4.0 and later versions - -## Name - -`aspire config delete` - Delete a configuration value. - -## Synopsis - -```Command -aspire config delete [options] -``` - -## Description - -The `aspire config delete` command deletes a config value by key name. - -[!INCLUDE [config-file-description](includes/config-file-description.md)] - -The command returns the following exit codes: - -- `0`—The command succeeded. -- `1`—The supplied key doesn't exist in the config file, or the config file is missing. - -## Arguments - -The following arguments are available: - -- **`key`** - - The configuration key to delete. - -## Options - -The following options are available: - -- **`-g, --global`** - - Delete the configuration value from the global `$HOME/.aspire/globalsettings.json` instead of the local settings file. - -- [!INCLUDE [option-help](includes/option-help.md)] - -- [!INCLUDE [option-debug](includes/option-debug.md)] - -- [!INCLUDE [option-wait](includes/option-wait.md)] - -## Available settings - -The following config settings are available: - -[!INCLUDE [config-settings-table](includes/config-settings-table.md)] diff --git a/docs/cli-reference/aspire-config-get.md b/docs/cli-reference/aspire-config-get.md deleted file mode 100644 index 0b6882eda0..0000000000 --- a/docs/cli-reference/aspire-config-get.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -title: aspire config get command -description: Learn about the aspire config get command and its usage. This command gets an Aspire CLI config value by key name. -ms.date: 07/11/2025 ---- -# aspire config get command - -**This article applies to:** βœ”οΈ Aspire CLI 9.4.0 and later versions - -## Name - -`aspire config get` - Get a configuration value. - -## Synopsis - -```Command -aspire config get [options] -``` - -## Description - -The `aspire config get` command retrieves a config value by key name. - -[!INCLUDE [config-file-description](includes/config-file-description.md)] - -If the config value doesn't exist in a local settings file, the config file is retrieved from the global settings file. - -The command returns the following exit codes: - -- `0`—The command succeeded. -- `10`—The supplied key doesn't exist in the config file, or the config file is missing. - -## Arguments - -The following arguments are available: - -- **`key`** - - The configuration key to retrieve. - -## Options - -The following options are available: - -- [!INCLUDE [option-help](includes/option-help.md)] - -- [!INCLUDE [option-debug](includes/option-debug.md)] - -- [!INCLUDE [option-wait](includes/option-wait.md)] - -## Available settings - -The following config settings are available: - -[!INCLUDE [config-settings-table](includes/config-settings-table.md)] diff --git a/docs/cli-reference/aspire-config-list.md b/docs/cli-reference/aspire-config-list.md deleted file mode 100644 index d2b3a1b75e..0000000000 --- a/docs/cli-reference/aspire-config-list.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -title: aspire config list command -description: Learn about the aspire config list command and its usage. This command lists all Aspire CLI config values. -ms.date: 07/11/2025 ---- -# aspire config list command - -**This article applies to:** βœ”οΈ Aspire CLI 9.4.0 and later versions - -## Name - -`aspire config list` - List all configuration values. - -## Synopsis - -```Command -aspire config list [options] -``` - -## Description - -The `aspire config list` command lists all config value by key name. - -[!INCLUDE [config-file-description](includes/config-file-description.md)] - -This command lists both the global and local settings. If a local setting overrides a global setting, only the local setting is displayed. - -## Options - -The following options are available: - -- [!INCLUDE [option-help](includes/option-help.md)] - -- [!INCLUDE [option-debug](includes/option-debug.md)] - -- [!INCLUDE [option-wait](includes/option-wait.md)] diff --git a/docs/cli-reference/aspire-config-set.md b/docs/cli-reference/aspire-config-set.md deleted file mode 100644 index 4a0daecb17..0000000000 --- a/docs/cli-reference/aspire-config-set.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: aspire config set command -description: Learn about the aspire config set command and its usage. This command sets an Aspire CLI config value by key name. -ms.date: 09/24/2025 ---- -# aspire config set command - -**This article applies to:** βœ”οΈ Aspire CLI 9.4.0 and later versions - -## Name - -`aspire config set` - Set a configuration value. - -## Synopsis - -```Command -aspire config set [options] -``` - -## Description - -The `aspire config set` command sets a config value by key name. - -[!INCLUDE [config-file-description](includes/config-file-description.md)] - -## Arguments - -The following arguments are available: - -- **`key`** - - The configuration key to update. - - > [!TIP] - > For available keys, see the [Settings](#available-settings) section. Look for names that start with the `features` prefix. Feature toggles are boolean values that enable or disable specific features in the Aspire CLI. - -- **`value`** - - The configuration value to set. - -## Options - -The following options are available: - -- **`-g, --global`** - - Set the configuration value globally in `$HOME/.aspire/globalsettings.json` instead of the local settings file. - -- [!INCLUDE [option-help](includes/option-help.md)] - -- [!INCLUDE [option-debug](includes/option-debug.md)] - -- [!INCLUDE [option-wait](includes/option-wait.md)] - -## Available settings - -The following config settings are available: - -[!INCLUDE [config-settings-table](includes/config-settings-table.md)] diff --git a/docs/cli-reference/aspire-config.md b/docs/cli-reference/aspire-config.md deleted file mode 100644 index a9fd2ada13..0000000000 --- a/docs/cli-reference/aspire-config.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: aspire config command -description: Learn about the aspire config command and its usage. This command driver is used to manage the Aspire CLI config settings. -ms.date: 09/24/2025 ---- -# aspire config command - -**This article applies to:** βœ”οΈ Aspire CLI 9.4.0 and later versions - -## Name - -`aspire config` - Manage configuration settings. - -## Synopsis - -```Command -aspire config [command] [options] -``` - -## Description - -The `aspire config` command manages the Aspire CLI config settings. - -[!INCLUDE [config-file-description](includes/config-file-description.md)] - -## Options - -The following options are available: - -- [!INCLUDE [option-help](includes/option-help.md)] - -- [!INCLUDE [option-debug](includes/option-debug.md)] - -- [!INCLUDE [option-wait](includes/option-wait.md)] - -## Commands - -The following commands are available: - -| Command | Status | Function | -|-----------------------------------------------------------|--------|--------------------------------| -| [`aspire config list`](aspire-config-list.md) | Stable | List all configuration values. | -| [`aspire config get `](aspire-config-get.md) | Stable | Get a configuration value. | -| [`aspire config set `](aspire-config-set.md) | Stable | Set a configuration value. | -| [`aspire config delete `](aspire-config-delete.md) | Stable | Delete a configuration value. | - -## Available settings - -The following config settings are available: - -[!INCLUDE [config-settings-table](includes/config-settings-table.md)] diff --git a/docs/cli-reference/aspire-deploy.md b/docs/cli-reference/aspire-deploy.md deleted file mode 100644 index 216f9cc086..0000000000 --- a/docs/cli-reference/aspire-deploy.md +++ /dev/null @@ -1,116 +0,0 @@ ---- -title: aspire deploy command -description: Learn about the aspire deploy command and its usage. This command first runs publishing mode, then invokes resource deployments declared by the AppHost. -ms.date: 09/25/2025 ---- -# aspire deploy command (Preview) - -**This article applies to:** βœ”οΈ Aspire CLI 9.4.0 and later versions. - - - -## Name - -`aspire deploy` - Deploy a codebase orchestrated with Aspire to specified targets. - -[!INCLUDE [mode-preview](includes/mode-preview.md)] - -## Synopsis - -```Command -aspire deploy [options] [[--] ...] -``` - -## Description - -The `aspire deploy` command first invokes the [`aspire publish`](./aspire-publish.md) command. After which, Aspire invokes all `DeployingCallbackAnnotation` resource annotations, in the order they're declared. - -[!INCLUDE [project-search-logic-description](includes/project-search-logic-description.md)] - -The command performs the following steps to deploy an app orchestrated with Aspire: - -- Creates or modifies the `.aspire/settings.json` config file in the current directory, and sets the `appHostPath` config value to the path of the AppHost project file. -- Installs or verifies that Aspire's local hosting certificates are installed and trusted. -- Builds the AppHost project and its resources. -- Starts the AppHost and its resources. -- Invokes all resource annotations. -- Invokes all `DeployingCallbackAnnotation` resource annotations. - -## Options - -The following options are available: - -- **`--`** - - Delimits arguments to `aspire publish` from arguments for the AppHost. All arguments after this delimiter are passed to the apphost. - -- [!INCLUDE [option-project](includes/option-project.md)] - -- **`-e, --environment`** - - The deployment environment name. Defaults to `production`. Each environment maintains its own isolated deployment state file. - -- **`--clear-cache`** - - Clears the cached deployment state for the specified environment before deploying. When used, the deployment prompts for all values but doesn't save them to cache. - -- **`-o, --output-path`** - - The output path for deployment artifacts. Defaults to a folder named _deploy_ in the current directory. - -- [!INCLUDE [option-help](includes/option-help.md)] - -- [!INCLUDE [option-debug](includes/option-debug.md)] - -- [!INCLUDE [option-wait](includes/option-wait.md)] - -## Examples - -- Search the current directory structure for AppHost projects to build, publish, and deploy: - - ```Command - aspire deploy - ``` - -- Publish and deploy an Aspire apphost and its dependencies: - - ```Command - aspire deploy --project './projects/apphost/orchestration.AppHost.csproj' - ``` - -- Publish and deploy an Aspire AppHost with arguments: - - ```Command - aspire deploy --project './projects/apphost/orchestration.AppHost.csproj' -- -fast - ``` - -- Deploy to a specific environment: - - ```Command - aspire deploy --environment staging - ``` - -- Clear cached deployment state and deploy: - - ```Command - aspire deploy --clear-cache - ``` - -- Clear cached deployment state for a specific environment: - - ```Command - aspire deploy --environment staging --clear-cache - ``` - -## See also - -- [Deployment state caching](../deployment/deployment-state-caching.md) diff --git a/docs/cli-reference/aspire-exec.md b/docs/cli-reference/aspire-exec.md deleted file mode 100644 index 7bc871ae0e..0000000000 --- a/docs/cli-reference/aspire-exec.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: aspire exec command -description: Learn about the aspire exec command and its usage. This command builds and runs an Aspire AppHost project, then sends commands to a resource. -ms.date: 09/24/2025 ---- -# aspire exec command (Preview) - -**This article applies to:** βœ”οΈ Aspire CLI 9.4.0 and later versions. - -> [!NOTE] -> This command is disabled by default. To use it, turn on the feature toggle by running: -> -> ```Aspire -> aspire config set features.execCommandEnabled true -> ``` -> -> For more information, see [aspire config command](aspire-config.md). - -## Name - -`aspire exec` - Run an Aspire AppHost to execute a command against the resource. - -[!INCLUDE [mode-preview](includes/mode-preview.md)] - -## Synopsis - -```Command -aspire exec [options] [[--] ...] -``` - -## Description - -The `aspire exec` command runs a command in the context of one of the resources defined in the AppHost. - -You must specify either the `--resource` or the `--start-resource` option, and you must provide parameters with the `--` option. - -[!INCLUDE [project-search-logic-description](includes/project-search-logic-description.md)] - -## Options - -The following options are available: - -- **`--`** - - Delimits arguments to `aspire exec` from arguments for the resource. All arguments after this delimiter are passed to the resource. - -- [!INCLUDE [option-project](includes/option-project.md)] - -- **`-r, --resource`** - - The name of the target resource to execute the command against. - -- **`-s, --start-resource`** - - The name of the target resource to start and execute the command against. - -- [!INCLUDE [option-help](includes/option-help.md)] - -- [!INCLUDE [option-debug](includes/option-debug.md)] - -- [!INCLUDE [option-wait](includes/option-wait.md)] - -## Examples - -- Builds and runs the AppHost project, then sends the command `migrate` to the `database1` resource: - - ```Command - aspire exec --resource database1 -- migrate - ``` diff --git a/docs/cli-reference/aspire-new.md b/docs/cli-reference/aspire-new.md deleted file mode 100644 index 662b58aa6d..0000000000 --- a/docs/cli-reference/aspire-new.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: aspire new command -description: Learn about the aspire new command and its usage. This command creates new Aspire projects or solutions. -ms.date: 07/11/2025 ---- -# aspire new command - -**This article applies to:** βœ”οΈ Aspire CLI 9.4.0 and later versions. - -## Name - -`aspire new` - Create a new Aspire project or solution. - -## Synopsis - -```Command -aspire new [command] [options] -``` - -## Description - -The `aspire new` command is the driver for creating Aspire projects, apps, or solutions, based on the Aspire templates. Each command specifies the template to use, and the options for the driver specify the options for the template. - -This command defaults to **interactive** mode. When executed without any options, the command prompts you for the project template and version, name, and output folder. When the `--name`, `--output`, and `--version` options are provided, the command runs **non-interactive** and generates files based on the command template. - -## Options - -The following options are available: - -- **`-n, --name`** - - The name of the project to create. - -- **`-o, --output`** - - The output path for the project. - -- **`-s, --source`** - - The NuGet source to use for the project templates. - -- **`-v, --version`** - - The version of the project templates to use. - -- [!INCLUDE [option-help](includes/option-help.md)] - -- [!INCLUDE [option-debug](includes/option-debug.md)] - -- [!INCLUDE [option-wait](includes/option-wait.md)] - -## Commands - -Each command represents a template. Pass the `--help` parameter to the template command to print the options available to the template. - -| Command | Template | -|--------------------------|------------------------------| -| `aspire` | Aspire Empty App | -| `aspire-apphost` | Aspire AppHost | -| `aspire-mstest` | Aspire Test Project (MSTest) | -| `aspire-nunit` | Aspire Test Project (NUnit) | -| `aspire-servicedefaults` | Aspire Service Defaults | -| `aspire-starter` | Aspire Starter App | -| `aspire-xunit` | Aspire Test Project (xUnit) | - -## Examples - -- Create an Aspire solution from the template. Because the template was selected (`aspire-starter`), you're prompted for the name, output folder, and template version. - - ```Command - aspire new aspire-starter - ``` - -- Create an AppHost project named `aspireapp` from the **9.4.0** templates and place the output in a folder named `aspire1`. - - ```Command - aspire new aspire-apphost --version 9.4.0 --name aspireapp1 --output ./aspire1 - ``` diff --git a/docs/cli-reference/aspire-publish.md b/docs/cli-reference/aspire-publish.md deleted file mode 100644 index 3bb9ebcaa5..0000000000 --- a/docs/cli-reference/aspire-publish.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -title: aspire publish command -description: Learn about the aspire publish command and its usage. This command invokes resource publishers declared by the apphost to serialize resources to disk. -ms.date: 07/11/2025 ---- -# aspire publish command (Preview) - -**This article applies to:** βœ”οΈ Aspire CLI 9.4.0 and later versions. - -## Name - -`aspire publish` - Generates deployment artifacts for an Aspire AppHost project. - -[!INCLUDE [mode-preview](includes/mode-preview.md)] - -## Synopsis - -```Command -aspire publish [options] [[--] ...] -``` - -## Description - -The `aspire publish` command publishes resources by serializing them to disk. When this command is run, Aspire invokes registered annotations for resources, in the order they're declared. These annotations serialize a resource so that it can be consumed by deployment tools. - -[!INCLUDE [project-search-logic-description](includes/project-search-logic-description.md)] - -The command performs the following steps to run an Aspire AppHost: - -- Creates or modifies the `.aspire/settings.json` config file in the current directory, and sets the `appHostPath` config value to the path of the AppHost project file. -- Installs or verifies that Aspire's local hosting certificates are installed and trusted. -- Builds the AppHost project and its resources. -- Starts the AppHost and its resources. -- Invokes all annotations for resources. - -## Options - -The following options are available: - -- **`--`** - - Delimits arguments to `aspire publish` from arguments for the AppHost. All arguments after this delimiter are passed to the AppHost. - -- [!INCLUDE [option-project](includes/option-project.md)] - -- **`-o, --output-path`** - - The output path for the generated artifacts. Defaults the current directory. - -- [!INCLUDE [option-help](includes/option-help.md)] - -- [!INCLUDE [option-debug](includes/option-debug.md)] - -- [!INCLUDE [option-wait](includes/option-wait.md)] - -## Examples - -- Search the current directory structure for AppHost projects to build and publish: - - ```Command - aspire publish - ``` - -- Publish a specific AppHost project: - - ```Command - aspire publish --project './projects/apphost/orchestration.AppHost.csproj' - ``` - -- Publish a specific AppHost project with arguments: - - ```Command - aspire publish --project './projects/apphost/orchestration.AppHost.csproj' -- -fast - ``` diff --git a/docs/cli-reference/aspire-run.md b/docs/cli-reference/aspire-run.md deleted file mode 100644 index c57e794ac9..0000000000 --- a/docs/cli-reference/aspire-run.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -title: aspire run command -description: Learn about the aspire run command and its usage. This command runs an Aspire AppHost. -ms.date: 07/11/2025 ---- -# aspire run command - -**This article applies to:** βœ”οΈ Aspire CLI 9.4.0 and later versions. - -## Name - -`aspire run` - Run an Aspire AppHost in development mode. - -## Synopsis - -```Command -aspire run [options] [[--] ...] -``` - -## Description - -The `aspire run` command runs the AppHost project in development mode, which configures the Aspire environment, builds and starts resources defined by the AppHost, launches the web dashboard, and prints a list of endpoints. - -[!INCLUDE [project-search-logic-description](includes/project-search-logic-description.md)] - -The command performs the following steps to run an Aspire AppHost: - -- Creates or modifies the `.aspire/settings.json` config file in the current directory, and sets the `appHostPath` config value to the path of the AppHost project file. -- Installs or verifies that Aspire's local hosting certificates are installed and trusted. -- Builds the AppHost project and its resources. -- Starts the AppHost and its resources. -- Starts the dashboard. - -The following snippet is an example of the output displayed by the `aspire run` command: - -```Aspire CLI -Dashboard: https://localhost:17178/login?t=17f974bf68e390b0d4548af8d7e38b65 - - Logs: /home/vscode/.aspire/cli/logs/apphost-1295-2025-07-14-18-16-13.log -``` - -## Options - -The following options are available: - -- **`--`** - - Delimits arguments to `aspire run` from arguments for the AppHost being run. All arguments after this delimiter are passed to the AppHost run. - -- [!INCLUDE [option-project](includes/option-project.md)] - -- **`-w, --watch`** - - Start project resources in watch mode. - -- [!INCLUDE [option-help](includes/option-help.md)] - -- [!INCLUDE [option-debug](includes/option-debug.md)] - -- [!INCLUDE [option-wait](includes/option-wait.md)] - -## Examples - -- Search the current directory structure for AppHost projects to build and run: - - ```Command - aspire run - ``` - -- Run a specific AppHost project: - - ```Command - aspire run --project './projects/apphost/orchestration.AppHost.csproj' - ``` - -- Run a specific AppHost project with arguments: - - ```Command - aspire run --project './projects/apphost/orchestration.AppHost.csproj' -- -fast - ``` diff --git a/docs/cli-reference/aspire-update.md b/docs/cli-reference/aspire-update.md deleted file mode 100644 index 90df33a5f7..0000000000 --- a/docs/cli-reference/aspire-update.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -title: aspire update command -description: Learn about the aspire update command and its usage. This command updates Aspire integration package versions in an AppHost-based solution to the latest versions on a selected channel. -ms.date: 09/24/2025 ---- - -# aspire update command (Preview) - -**This article applies to:** βœ”οΈ Aspire CLI 9.5.2 and later versions. - -## Name - -`aspire update` - Update Aspire integration packages to the latest versions for a chosen channel. - -[!INCLUDE [mode-preview](includes/mode-preview.md)] - -## Synopsis - -```Command -aspire update [options] -``` - -## Description - -The `aspire update` command scans an AppHost-based solution and updates Aspire-related NuGet packages (core and integration packages) to the latest versions published on a user-selected channel (for example: `stable`, `preview`, or `daily`). The command: - -- Locates the AppHost project automatically (prompts if multiple or none located). -- Prompts you to choose a channel sourced from configured NuGet feeds. -- Detects outdated Aspire packages and computes safe upgrade targets. -- Updates package versions either inline (``) or via Central Package Management (`Directory.Packages.props`). -- Updates `NuGet.config` file if required to make sure that package sources and package source mappings are appropriate for the channel selected. -- Skips packages already at the latest channel-compatible version. - -Typical reasons to run this command include adopting the latest stable servicing fixes, trying preview features, or experimenting with daily builds. After updating, build or run your solution (for example with `aspire run`) to validate changes. - -## Options - -The following options are available: - -- [!INCLUDE [option-project](includes/option-project.md)] -- [!INCLUDE [option-help](includes/option-help.md)] -- [!INCLUDE [option-debug](includes/option-debug.md)] -- [!INCLUDE [option-wait](includes/option-wait.md)] - -## Examples - -- Update Aspire packages in the current solution (interactive channel selection): - - ```Command - aspire update - ``` - -- Update packages for a specific AppHost project path: - - ```Command - aspire update --project './src/MyApp.AppHost/MyApp.AppHost.csproj' - ``` - -- Example interactive session (conceptual): - - ```Command - $ aspire update - Detected AppHost: MyApp.AppHost.csproj - Select channel: - default - stable - > daily - Updating Aspire.Hosting 9.5.1 -> 9.5.2-daily.20241023.1 - Updating Aspire.Azure.Cosmos 9.5.1 -> 9.5.2-daily.20241023.1 - Done. - ``` - -> [!NOTE] -> Commit your repository before updating so you can easily revert if a preview or daily build intro diff --git a/docs/cli-reference/aspire.md b/docs/cli-reference/aspire.md deleted file mode 100644 index cc6f707fca..0000000000 --- a/docs/cli-reference/aspire.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -title: aspire command -description: Learn about the aspire command (the generic driver for the Aspire CLI) and its usage. -ms.date: 09/25/2025 ---- -# aspire command - -**This article applies to:** βœ”οΈ Aspire CLI 9.4.0 and later versions. - -## Name - -`aspire` - The generic driver for the Aspire CLI. - -## Synopsis - -To get information about the available commands and the environment: - -```Command -aspire [command] [options] -``` - -## Description - -The `aspire` command provides commands for working with Aspire projects. For example, `aspire run` runs your Aspire AppHost. - -## Options - -The following options are available when `aspire` is used by itself, without specifying a command. For example, `aspire --version`. - -- [!INCLUDE [option-help](includes/option-help.md)] - -- [!INCLUDE [option-version](includes/option-version.md)] - -- [!INCLUDE [option-debug](includes/option-debug.md)] - -- [!INCLUDE [option-wait](includes/option-wait.md)] - -## Commands - -The following commands are available: - -| Command | Status | Function | -|--|--|--| -| [`aspire add`](aspire-add.md) | Stable | Add an integration to the Aspire project. | -| [`aspire config`](aspire-config.md) | Stable | Configures the Aspire environment. | -| [`aspire deploy`](aspire-deploy.md) | Preview | Deploys the artifacts created by `aspire publish`. | -| [`aspire exec`](aspire-exec.md) | Preview | Similar to the `aspire run` command, but passes commands to the apphost. | -| [`aspire new`](aspire-new.md) | Stable | Create an Aspire sample project from a template. | -| [`aspire publish`](aspire-publish.md) | Preview | Generates deployment artifacts for an Aspire apphost project. | -| [`aspire run`](aspire-run.md) | Stable | Run an Aspire apphost for local development. | -| [`aspire update`](aspire-update.md) | Preview | Update Aspire project packages to the latest compatible versions. | - - - -## Examples - -- Create an Aspire solution from the template: - - ```Command - aspire new aspire-starter - ``` - -- Run an Aspire AppHost: - - ```Command - aspire run - ``` diff --git a/docs/cli/config-settings.md b/docs/cli/config-settings.md deleted file mode 100644 index b769702ca5..0000000000 --- a/docs/cli/config-settings.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: Configuration settings -description: Learn about -ms.date: 09/25/2025 -ms.topic: overview ---- - -# What is Aspire CLI configuration? - -The Aspire CLI uses a configuration file to control its behavior. You can configure feature flags to enable or disable CLI features, and specify which AppHost project the CLI should use by default for an Aspire solution. - -The settings file is stored in a `.aspire` folder and is named `settings.json`. Settings files can be stored locally or globally. - -The following snippet is an example `.aspire/settings.json` file: - -```json -{ - "appHostPath": "../AspireShop/AspireShop.AppHost/AspireShop.AppHost.csproj", - "features": { - "deployCommandEnabled": "true" - } -} -``` - -## Config file locations - -A global Aspire CLI settings file is stored at `$HOME/.aspire/globalsettings.json`, and is used as the default settings for the CLI. A local settings file overwrites the settings from the global file. Local settings files are stored at `./.aspire/settings.json`. - -## Generating a config file - -The CLI automatically generates a local settings file when you run a command that requires interaction with the AppHost, or if you set a config option. For example, `aspire run` searches for an AppHost project, and when found, generates the `./.aspire/settings.json` file with the `appHostPath` setting set to the project it found. - -> [!IMPORTANT] -> `appHostPath` can be set globally, but the CLI ignores it and only reads it in the local settings file. - -## Settings - -The Aspire CLI supports two categories of configuration settings: - -- **Feature flags**\ -These settings enable or disable specific CLI features. All feature flag setting names start with `feature.` - -- **CLI behavior**\ -These settings control how the CLI operates. Currently, the only CLI behavior setting is `appHostPath`, which specifies the location of the AppHost project. - -The following table lists the settings that can be set in the config file: - -[!INCLUDE [config-settings-table](../cli-reference/includes/config-settings-table.md)] - -## CLI commands - -| Command | Status | Function | -|--|--|--| -| [`aspire config`](../cli-reference/aspire-config-list.md) | Stable | Command driver for managing Aspire configuration. | -| [`aspire config list`](../cli-reference/aspire-config-list.md) | Stable | List all configuration values. | -| [`aspire config get `](../cli-reference/aspire-config-get.md) | Stable | Get a configuration value. | -| [`aspire config set `](../cli-reference/aspire-config-set.md) | Stable | Set a configuration value. | -| [`aspire config delete `](../cli-reference/aspire-config-delete.md) | Stable | Delete a configuration value. | diff --git a/docs/cli/install-script-reference.md b/docs/cli/install-script-reference.md deleted file mode 100644 index d0d98e17ce..0000000000 --- a/docs/cli/install-script-reference.md +++ /dev/null @@ -1,166 +0,0 @@ ---- -title: aspire-install script reference -description: Learn about the aspire-install scripts to install the Aspire CLI. Use the Aspire CLI to create, run, and manage Aspire projects. -author: adegeo -ms.author: adegeo -ms.date: 08/28/2025 -ai-usage: ai-assisted -#customer intent: As a developer, I need the aspire-install script reference so that I know what options it provides when installing the Aspire CLI. ---- - -# aspire-install script reference - -This article contains the syntax of the aspire install PowerShell and Bash scripts. To download the script, see [Install as a native executable](install.md#install-as-a-native-executable). - -## Name - -`aspire-install.ps1` | `aspire-install.sh` - Scripts used to install the Aspire CLI. - -## Synopsis - -Windows: - -```powershell -aspire-install.ps1 [-InstallPath ] [-Version ] [-Quality ] - [-OS ] [-Architecture ] [-KeepArchive] [-Help]" -``` - -Linux/macOS: - -```bash -aspire-install.sh [--install-path ] [--version ] [--quality ] - [--os ] [--arch ] [--keep-archive] [--verbose] [--help] -``` - -## Description - -The `aspire-install` scripts perform a nonadmin installation of the Aspire CLI. - -> [!IMPORTANT] -> The Aspire CLI is **still in preview** and under active development. - -### Script behavior - -Both scripts behave the same way. They download the Aspire CLI for the target platform, install it to the specified location, and add it to your PATH environment variable. - -By default, the installation scripts download and install the latest stable release of the Aspire CLI. Specify a different version with the `-Version|--version` argument or a different quality level with the `-Quality|--quality` argument. - -Unless changed with the `-InstallPath|--install-path` argument, the script installs to a user-specific location: `%USERPROFILE%\.aspire\bin` on Windows or `$HOME/.aspire/bin` on Linux/macOS. - -## Options - -- **`-InstallPath|--install-path `** - - Specifies the installation path. The directory is created if it doesn't exist. The default value is *%USERPROFILE%\.aspire\bin* on Windows and *$HOME/.aspire/bin* on Linux/macOS. The Aspire CLI executable is placed directly in this directory. - -- **`-Version|--version `** - - Represents a specific version to install. For example: `9.4`. If not specified, the latest stable version is installed. - -- **`-Quality|--quality `** - - Downloads the specified quality build. The possible values are: - - - `release`: The latest stable release (default). - - `staging`: Builds from the current release branch (prerelease builds). - - `dev`: Latest builds from the `main` branch (development builds). - - The different quality values signal different stages of the release process: - - - `release`: The final stable releases of the Aspire CLI. Intended for production use. - - `staging`: Prerelease builds intended for testing upcoming releases. Not recommended for production use. - - `dev`: The latest builds from the main development branch. They're built frequently and aren't fully tested. Not recommended for production use but can be used to test specific features or fixes immediately after they're merged. - -- **`-OS|--os `** - - Specifies the operating system for which the CLI is being installed. Possible values are: `win`, `linux`, `linux-musl`, `osx`. - - The parameter is optional and should only be used when it's required to override the operating system that is detected by the script. - -- **`-Architecture|--arch `** - - Architecture of the Aspire CLI binaries to install. Possible values are `x64`, `x86`, `arm64`. The default behavior is to autodetect the current system architecture. - -- **`-KeepArchive|--keep-archive`** - - If you set this option, the script keeps the downloaded archive files and temporary directory after installation. By default, the script deletes the archive after extraction and cleans up the temporary directory. - -- **`--verbose`** - - Displays diagnostics information. (Linux/macOS only) - -- **`-Help|--help`** - - Prints help information for the script. - -## Examples - -- Install the latest stable version to the default location: - - Windows: - - ```powershell - .\aspire-install.ps1 - ``` - - macOS/Linux: - - ```bash - ./aspire-install.sh - ``` - -- Install to a custom directory: - - Windows: - - ```powershell - .\aspire-install.ps1 -InstallPath 'C:\Tools\Aspire' - ``` - - macOS/Linux: - - ```bash - ./aspire-install.sh --install-path "/usr/local/bin" - ``` - -- Install a specific version: - - Windows: - - ```powershell - .\aspire-install.ps1 -Version '9.4' - ``` - - macOS/Linux: - - ```bash - ./aspire-install.sh --version "9.4" - ``` - -- Install development builds: - - Windows: - - ```powershell - .\aspire-install.ps1 -Quality 'dev' - ``` - - macOS/Linux: - - ```bash - ./aspire-install.sh --quality "dev" - ``` - -- Install with verbose output (Linux/macOS only): - - ```bash - ./aspire-install.sh --verbose - ``` - -## Uninstall - -There's no uninstall script. Delete the installation directory, such as `%USERPROFILE%\.aspire\bin` on Windows or `$HOME/.aspire/bin` on Linux/macOS. - -## See also - -- [Install Aspire CLI](install.md) diff --git a/docs/cli/install.md b/docs/cli/install.md deleted file mode 100644 index 7668e04a3e..0000000000 --- a/docs/cli/install.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -title: Install Aspire CLI -description: Learn how to install Aspire CLI, which is a .NET global tool. Use the Aspire CLI to create, run, and manage Aspire projects. -author: adegeo -ms.author: adegeo -ms.topic: install-set-up-deploy -ms.date: 08/29/2025 - -#customer intent: As a developer, I want to install the Aspire CLI so that I can create, run, and manage Aspire projects. - ---- - -# Install Aspire CLI - -This article teaches you how to install the Aspire CLI, which is a CLI tool used to manage your Aspire projects. - -## Prerequisites - -- [.NET SDK 9.0](https://dotnet.microsoft.com/download/dotnet/9.0). - -## Install as a native executable - -The compiled version of the Aspire CLI can be installed using the Aspire CLI installation script. The script is available for PowerShell and Bash. - -01. Open a terminal. -01. Download the script and save it as a file: - - ```powershell - Invoke-RestMethod https://aspire.dev/install.ps1 -OutFile aspire-install.ps1 - ``` - - ```bash - curl -sSL https://aspire.dev/install.sh -o aspire-install.sh - ``` - -01. Run the script to install the stable release build of Aspire. - - You should see output similar to the following snippet: - - ```Output - Downloading from: https://aka.ms/dotnet/9/aspire/ga/daily/aspire-cli-win-x64.zip - Aspire CLI successfully installed to: C:\Users\name\.aspire\bin\aspire.exe - Added C:\Users\username\.aspire\bin to PATH for current session - Added C:\Users\username\.aspire\bin to user PATH environment variable - - The aspire cli is now available for use in this and new sessions. - ``` - -For more information about the install script, see [aspire-install script reference](install-script-reference.md). - -> [!TIP] -> You can download and run the script in a single command: -> -> Windows: -> -> ```powershell -> Invoke-Expression "& { $(Invoke-RestMethod https://aspire.dev/install.ps1) }" -> ``` -> -> macOS/Linux: -> -> ```bash -> curl -sSL https://aspire.dev/install.sh | bash -> ``` - -## Install as a .NET global tool - -Use the `dotnet tool` command to install the Aspire CLI global tool. The name of the global tool is [Aspire.Cli](https://www.nuget.org/packages/Aspire.CLI). - -01. Open a terminal. -01. Run the following command to install Aspire CLI: - - ```dotnetcli - dotnet tool install -g Aspire.Cli --prerelease - ``` - -## Validation - -To validate that the global tool is installed, use the `--version` option to query Aspire CLI for a version number: - -```Aspire -aspire --version -``` - -If that command works, you're presented with the version of the Aspire CLI tool: - -```Aspire -9.4.0 -``` - -## See also - -- [aspire-install script reference](install-script-reference.md). diff --git a/docs/cli/overview.md b/docs/cli/overview.md deleted file mode 100644 index cc43294e8f..0000000000 --- a/docs/cli/overview.md +++ /dev/null @@ -1,100 +0,0 @@ ---- -title: Aspire CLI Overview and Commands -description: Learn about the Aspire CLI commands for creating projects, running an AppHost, and adding integrations. Get started with command-line tools to build and manage distributed applications efficiently. -titleSuffix: "" -ms.date: 09/25/2025 -ms.topic: overview -ms.custom: - - ai-gen-docs-bap - - ai-gen-title - - ai-seo-date:06/26/2025 - - ai-gen-description ---- - -# Aspire CLI Overview - -The Aspire CLI (`aspire` command) is a cross-platform tool that provides command-line functionality to create, manage, run, and publish polyglot Aspire projects. Use the Aspire CLI to streamline development workflows and coordinate services for distributed applications. - -The Aspire CLI is an interactive-first experience. - -- [Install the Aspire CLI.](install.md) -- [`aspire` command reference.](../cli-reference/aspire.md) - -> [!TIP] -> For a step-by-step tutorial that uses the `aspire deploy` command, see [Deploy an Aspire project to Azure Container Apps with the Aspire CLI](../deployment/aspire-deploy/aca-deployment-aspire-cli.md). - -## Use templates - -[_Command reference: `aspire new`_](../cli-reference/aspire-new.md) - -The `aspire new` command is an interactive-first CLI experience, and is used to create one or more Aspire projects. As part of creating a project, Aspire CLI ensures that the latest Aspire project templates are installed into the `dotnet` system. - -Use the `aspire new` command to create an Aspire project from a list of templates. Once a template is selected, the name of the project is set, and the output folder is chosen, `aspire` downloads the latest templates and generates one or more projects. - -While command line parameters can be used to automate the creation of an Aspire project, the Aspire CLI is an interactive-first experience. - -## Start the Aspire AppHost - -[_Command reference: `aspire run`_](../cli-reference/aspire-run.md) - -The `aspire run` command runs the AppHost project in development mode, which configures the Aspire environment, builds and starts resources defined by the AppHost, launches the web dashboard, and prints a list of endpoints. - -When `aspire run` starts, it searches the current directory for an AppHost project. If a project isn't found, the sub directories are searched until one is found. If no AppHost project is found, Aspire stops. Once a project is found, Aspire CLI takes the following steps: - -- Installs or verifies that Aspire's local hosting certificates are installed and trusted. -- Builds the AppHost project and its resources. -- Starts the AppHost and its resources. -- Starts the dashboard. - -The following snippet is an example of the output displayed by the `aspire run` command: - -```Aspire CLI -Dashboard: https://localhost:17178/login?t=17f974bf68e390b0d4548af8d7e38b65 - - Logs: /home/vscode/.aspire/cli/logs/apphost-1295-2025-07-14-18-16-13.log -``` - -## Add integrations - -[_Command reference: `aspire add`_](../cli-reference/aspire-add.md) - -The `aspire add` command is an easy way to add official integration packages to your AppHost project. Use this as an alternative to a NuGet search through your IDE. You can run `aspire add ` if you know the name or NuGet ID of the integration package. If you omit a name or ID, the tool provides a list of packages to choose from. If you provide a partial name or ID, the tool filters the list of packages with items that match the provided value. - -## Publish Aspire applications (preview) - -[_Command reference: `aspire publish`_](../cli-reference/aspire-publish.md) - -The `aspire publish` command publishes resources by serializing them to disk. When this command is run, Aspire invokes registered resource annotations, in the order they're declared. These annotations serialize a resource so that it can be consumed by deployment tools. - -Some integrations automatically register a `PublishingCallbackAnnotation` for you, for example: - -- generates Bicep assets. -- generates docker-compose yaml. -- generates Kubernetes Helm charts. - -## Deploy Aspire applications (preview) - -[_Command reference: `aspire deploy`_](../cli-reference/aspire-deploy.md) - -The `aspire deploy` command is similar to `aspire publish`. After Aspire has invoked the publishing annotations to serialize resources to disk, it invokes `DeployingCallbackAnnotation` resource annotations, in the order they're declared. - -As of Aspire 9.4, Aspire doesn't include any default deployment annotations for its resources, you must use the `DeployingCallbackAnnotation` to build your own. - -> [!TIP] -> Consider this a good way to deploy your Aspire solution to a staging or testing environment. - -## Manage Aspire configuration - -[_Command reference: `aspire config`_](../cli-reference/aspire-config.md) - -The `aspire config` command lets you manage Aspire CLI configuration settings. Use it to `list`, `get`, `set`, or `delete` configuration values that control CLI behavior. This command is also used to toggle features on or off. - -For more information about Aspire CLI configuration, see [What is Aspire configuration?](config-settings.md) - -## Run commands in resource context (preview) - -[_Command reference: `aspire exec`_](../cli-reference/aspire-exec.md) - -The `aspire exec` command runs a command in the context of a specific Aspire resource, inheriting that resource's configuration, including environment variables, connection strings, and working directory. This is particularly useful for scenarios like running Entity Framework migrations where you need to run commands with the same configuration as your application. For example, you can run `aspire exec --resource api -- dotnet ef migrations add Init` to run Entity Framework commands with the proper database connection strings automatically configured. - -[!INCLUDE [aspire exec feature flag note](includes/exec-feature-flag-note.md)] diff --git a/docs/compatibility/9.2/azure-openaideployment-obsolete.md b/docs/compatibility/9.2/azure-openaideployment-obsolete.md index b8b466edb1..e049f18826 100644 --- a/docs/compatibility/9.2/azure-openaideployment-obsolete.md +++ b/docs/compatibility/9.2/azure-openaideployment-obsolete.md @@ -8,7 +8,7 @@ ms.custom: https://github.com/dotnet/docs-aspire/issues/3059 # AzureOpenAIDeployment obsolete -In Aspire 9.2, Azure OpenAI deployments are modeled as Aspire child resources instead of simple objects. This change aligns with the design of other [hosting integrations](../../fundamentals/integrations-overview.md#hosting-integrations) and enables referencing deployments using . As a result, the previous APIs for adding deployments are now obsolete. +In Aspire 9.2, Azure OpenAI deployments are modeled as Aspire child resources instead of simple objects. This change aligns with the design of other [hosting integrations](https://aspire.dev/integrations/overview/#hosting-integrations) and enables referencing deployments using . As a result, the previous APIs for adding deployments are now obsolete. ## Version introduced diff --git a/docs/compatibility/toc.yml b/docs/compatibility/toc.yml index 9a3735621f..6407f8fc9b 100644 --- a/docs/compatibility/toc.yml +++ b/docs/compatibility/toc.yml @@ -2,7 +2,7 @@ items: - name: Aspire href: ../index.yml - name: Aspire overview - href: ../get-started/aspire-overview.md + href: https://aspire.dev/get-started/what-is-aspire/ - name: Breaking changes href: breaking-changes.md - name: Aspire 13.0 diff --git a/docs/deployment/aspire-deploy/aca-deployment-aspire-cli.md b/docs/deployment/aspire-deploy/aca-deployment-aspire-cli.md deleted file mode 100644 index 1703ecdea4..0000000000 --- a/docs/deployment/aspire-deploy/aca-deployment-aspire-cli.md +++ /dev/null @@ -1,279 +0,0 @@ ---- -title: Deploy Aspire projects to Azure Container Apps using the Aspire CLI -description: Learn how to use the Aspire CLI command to deploy Aspire projects to Azure Container Apps. -ms.date: 09/25/2025 -ai-usage: ai-assisted ---- - -# Deploy an Aspire project to Azure Container Apps using Aspire CLI - -The [`aspire deploy`](../../cli-reference/aspire-deploy.md) CLI command provides a streamlined way to deploy Aspire applications directly to Azure Container Apps. This command automates the entire deployment process, from building container images to provisioning Azure infrastructure and deploying your applications. This article walks you through using the `aspire deploy` command to deploy an Aspire solution to Container Apps. You'll learn how to complete the following tasks: - -> [!div class="checklist"] -> -> - Use the `aspire deploy` command to deploy to Container Apps. -> - Validate Azure CLI authentication for deployment. -> - Provision Azure infrastructure using Bicep templates. -> - Build and push container images to Azure Container Registry. -> - Deploy compute resources to Container Apps. -> - Monitor deployment progress and access the deployed application. - -[!INCLUDE [aspire-prereqs](../../includes/aspire-prereqs.md)] - -Before using the `aspire deploy` command, ensure you have the following: - -- **Azure CLI**: Installed and authenticated with your Azure account. -- **Docker**: Installed for building container images. -- **Azure subscription**: With appropriate permissions to create resources. - -## Enable the deploy command - -The `aspire deploy` command is currently in preview and disabled by default. To enable it: - -```Aspire -aspire config set features.deployCommandEnabled true -``` - -## Authenticate with Azure - -Before deploying, you must authenticate with Azure CLI. Run the following command: - -```azurecli -az login -``` - -This command opens a web browser for you to sign in with your Azure credentials. The `aspire deploy` command automatically validates your Azure CLI authentication before proceeding with deployment. For more information, see: - -- [Sign in with Azure CLI](/cli/azure/authenticate-azure-cli). -- [The `aspire deploy` command reference](/dotnet/aspire/cli-reference/aspire-deploy). - -## Create an Aspire project - -As a starting point, this article assumes you've created an Aspire project from the **Aspire Starter Application** template. For more information, see [Quickstart: Build your first Aspire project](../../get-started/build-your-first-aspire-app.md). - -To configure your project for Azure Container Apps deployment, add a package reference to your AppHost project that includes the [`πŸ“¦Aspire.Hosting.Azure.AppContainers](https://www.nuget.org/packages/Aspire.Hosting.Azure.AppContainers) NuGet package: - -```xml - - - - - - Exe - net9.0 - enable - enable - 7b352f08-305b-4032-9a21-90deb02efc04 - - - - - - - - -``` - -In your AppHost project's _AppHost.cs_ file, add the Container Apps environment: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -// Add Azure Container Apps environment -var containerAppEnv = builder.AddAzureContainerAppEnvironment("aspire-env"); - -// Add your services -var cache = builder.AddRedis("cache"); - -var apiService = builder.AddProject("apiservice") - .WithExternalHttpEndpoints(); - -builder.AddProject("webfrontend") - .WithExternalHttpEndpoints() - .WithReference(cache) - .WithReference(apiService); - -builder.Build().Run(); -``` - -For more information, see [Configure Azure Container Apps environments](https://aspire.dev/integrations/cloud/azure/configure-container-apps/). - -### Resource naming - -[!INCLUDE [azure-container-app-naming](../../includes/azure-container-app-naming.md)] - -## Deploy with aspire deploy - -Once your project is configured, deploy it using the `aspire deploy` command: - -```Aspire -aspire deploy -``` - -> [!TIP] -> The `aspire deploy` command is interactive by default. To deploy without prompts, set these environment variables first: -> -> - `Azure__SubscriptionId`: Target Azure subscription ID. -> - `Azure__Location`: Azure region (for example, `eastus`). -> - `Azure__ResourceGroup`: Resource group name to create or reuse. - -You can also specify additional options: - -```Aspire -aspire deploy --project ./MyApp.AppHost/MyApp.AppHost.csproj -``` - -## Deployment process - -The `aspire deploy` command performs the following steps automatically. First, the command validates that you're authenticated with Azure CLI. If you're not logged in, you'll see an error message prompting you to run `az login`. - -Next, Aspire prompts you for the Azure subscription, location, and resource group name that the deployment should be targeted to. The subscriptions and locations that are accessible depend on the Azure account that is authenticated with the Azure CLI from the step above. - -Next, Aspire analyzes your application model and prompts for any required deployment parameters that don't have values set. You'll see prompts like: - -```Output -There are unresolved parameters that need to be set. Please provide values for them. [y/n] (n): y -Please provide values for the unresolved parameters. Parameters can be saved to user secrets for future use. -weatherApiKey: -Save to user secrets: [y/n] (n): n -``` - -> [!NOTE] -> The CLI continuously prompts until all unresolved parameters are provided with values. The `aspire deploy` command caches deployment state locally to streamline subsequent deployments. For more information, see [Deployment state caching](../deployment-state-caching.md). - -Once parameters are collected, Azure infrastructure is provisioned using Bicep templates. This step creates the necessary Azure resources including the Container Apps environment, Container Registry, and any backing services like Redis caches: - -```Output -Step 3: Deploying Azure resources - - βœ“ DONE: Deploying aca-env 00:01:08 - Successfully provisioned aca-env - βœ“ DONE: Deploying storage 00:00:04 - Successfully provisioned storage - βœ“ DONE: Deploying cosmosdb 00:01:08 - Successfully provisioned cosmosdb - βœ“ DONE: Deploying apiservice-identity 00:00:03 - Successfully provisioned apiservice-identity - βœ“ DONE: Deploying apiservice-roles-storage 00:00:11 - Successfully provisioned apiservice-roles-storage - βœ“ DONE: Deploying apiservice-roles-cosmosdb 00:01:10 - Successfully provisioned apiservice-roles-cosmosdb -``` - -After infrastructure provisioning, your application projects are built as container images and pushed to Azure Container Registry. - -```Output -Step 4: Building container images for resources - - βœ“ DONE: Checking Docker health 00:00:00 - Docker is healthy. - βœ“ DONE: Building image: apiservice 00:00:04 - Building image for apiservice completed - βœ“ DONE: Building image: webfrontend 00:00:05 - Building image for webfrontend completed - -βœ… COMPLETED: Building container images completed - -Step 5: Authenticating to container registries - - βœ“ DONE: Logging in to acrname 00:00:08 - Successfully logged in to acrname - -βœ… COMPLETED: Successfully authenticated to 1 container registries - -Step 6: Pushing 2 images to container registries - - βœ“ DONE: Pushing apiservice to acrname 00:00:04 - Successfully pushed apiservice to acrname.azurecr.io/apiservice:aspire-deploy-20250922203320 - βœ“ DONE: Pushing webfrontend to acrname 00:00:04 - Successfully pushed webfrontend to acrname.azurecr.io/webfrontend:aspire-deploy-20250922203320 - -βœ… COMPLETED: Successfully pushed 2 images to container registries -``` - -Finally, all .NET projects that were built as container images from the previous step, are pushed to provisioned Azure Container Registryβ€”where they'll live, making them available to Container Apps: - -```Output -Step 7: Deploying compute resources - - βœ“ DONE: Deploying apiservice 00:00:35 - Successfully deployed apiservice to https://apiservice.proudplant-5c457a5d.westus2.azurecontainerapps.io - βœ“ DONE: Deploying webfrontend 00:00:19 - Successfully deployed webfrontend to https://webfrontend.proudplant-5c457a5d.westus2.azurecontainerapps.io - -βœ… COMPLETED: Successfully deployed 2 compute resources -``` - -Upon successful deployment, you'll see the Aspire dashboard URL where you can monitor and manage your deployed application: - -```Output -βœ… Deployment completed successfully. View Aspire dashboard at https://aspire-env.proudwater-12345678.eastus.azurecontainerapps.io -``` - -For more information on what options are available on the `aspire deploy` command and examples of how to supply them on the CLI, see the [`aspire deploy` command reference](../../cli-reference/aspire-deploy.md). - -## Monitor deployment - -During deployment, you can monitor progress through: - -1. **Console output**: Real-time progress updates and status messages. -1. **Azure portal**: View resources being created in your resource group. -1. **Azure CLI**: Use `az containerapp list` to see deployed applications. - -## Troubleshooting deployment - -When using the `aspire deploy` command, you may encounter various issues during deployment. Use this section to learn common problems and we provide you with tips for troubleshooting, helping you quickly identify and fix errors. With the right approach and understanding of common issues, you can ensure a smoother deployment process. - -### Authentication issues - -If you encounter authentication errors: - -```bash -❌ Azure CLI authentication failed. Please run 'az login' to authenticate before deploying. -``` - -Run `az login` and ensure you have the necessary permissions in your Azure subscription. For more information, see [Sign in with Azure CLI](/cli/azure/authenticate-azure-cli). - -### Resource naming conflicts - -If resource names conflict with existing Azure resources, modify your resource names in the AppHost: - -```csharp -var containerAppEnv = builder.AddAzureContainerAppEnvironment( - "my-unique-env-name" - ); -``` - -### Container build failures - -If container builds fail, ensure: - -- Docker is running and accessible. -- Your project builds successfully locally: `dotnet build`. -- Container runtime is properly configured. - -## Access your deployed application - -After successful deployment: - -1. **Aspire Dashboard**: Access the dashboard URL provided in the deployment output. -1. **Application endpoints**: Find your application URLs in the Azure portal under Container Apps. -1. **Azure CLI**: List endpoints using: - - ```azurecli - az containerapp show --name --resource-group --query properties.configuration.ingress.fqdn - ``` - -## Clean up resources - -To remove deployed resources, delete the resource group: - -```azurecli -az group delete --name -``` - -## Next steps - -- [aspire deploy command reference](../../cli-reference/aspire-deploy.md). -- [Customize Azure deployments in Aspire](customize-deployments.md). -- [Azure security best practices for Aspire apps](azure-security-best-practices.md). diff --git a/docs/deployment/aspire-deploy/aca-deployment-visual-studio.md b/docs/deployment/aspire-deploy/aca-deployment-visual-studio.md index 4f2b04784d..20dea27a91 100644 --- a/docs/deployment/aspire-deploy/aca-deployment-visual-studio.md +++ b/docs/deployment/aspire-deploy/aca-deployment-visual-studio.md @@ -21,7 +21,7 @@ Aspire projects are designed to run in containerized environments. Azure Contain ## Create an Aspire project -As a starting point, this article assumes that you've created an Aspire project from the **Aspire Starter Application** template. For more information, see [Quickstart: Build your first Aspire project](../../get-started/build-your-first-aspire-app.md). +As a starting point, this article assumes that you've created an Aspire project from the **Aspire Starter Application** template. For more information, see [Quickstart: Build your first Aspire project](https://aspire.dev/get-started/first-app/). ### Resource naming diff --git a/docs/deployment/aspire-deploy/azure-security-best-practices.md b/docs/deployment/aspire-deploy/azure-security-best-practices.md deleted file mode 100644 index 0c2234f4c7..0000000000 --- a/docs/deployment/aspire-deploy/azure-security-best-practices.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -title: Azure security best practices for Aspire deployments -description: Learn about the default security posture of Aspire deployments to Azure Container Apps and additional steps to enhance security. -ms.date: 09/23/2025 -uid: deployment/azure/azure-security-best-practices ---- - -# Azure security best practices for Aspire deployments - -When you deploy Aspire applications to Azure using the Aspire CLI or Azure Developer CLI (`azd`), the platform provides several security features by default. This article explains the default security posture and provides guidance on additional steps you can take to enhance the security of your applications. - -> [!div class="checklist"] -> -> - Understand the default security configuration for Aspire deployments -> - Learn about built-in security features in Azure Container Apps -> - Implement additional security hardening measures -> - Configure secure communication between services -> - Apply security best practices for production deployments - -## Default security posture - -When you deploy an Aspire application to Azure Container Apps using `azd`, several security measures are automatically configured: - -### Container-level security - -**Secure base images**: Aspire generates container images using secure Microsoft-maintained base images that are regularly updated with security patches. - -**Non-root execution**: Containers run with non-root user permissions by default, reducing the attack surface. - -**Minimal image surface**: The generated containers include only the necessary runtime components, following the principle of least privilege. - -### Network security - -**Private networking**: Azure Container Apps environments use virtual networks with private IP addresses for internal communication between services. - -**Secure service-to-service communication**: Inter-service communication uses Azure Container Apps' built-in service discovery with encrypted traffic. - -**HTTPS endpoints**: Public-facing endpoints are automatically configured with HTTPS using Azure-managed certificates. - -### Identity and access management - -**Managed identities**: Azure Container Apps are configured with system-assigned managed identities by default, eliminating the need to store credentials in your application code. - -**Azure RBAC integration**: Resources are deployed with appropriate role-based access control (RBAC) permissions. - -### Configuration and secrets management - -**Secure configuration**: Application configuration is stored in Azure App Configuration when available, separate from your application code. - -**Environment variables**: Sensitive configuration values are injected as secure environment variables rather than being embedded in container images. - -## Additional security hardening - -While Aspire provides good security defaults, you can implement additional measures for enhanced protection: - -### Enable Azure Key Vault integration - -Store sensitive configuration data and secrets in Azure Key Vault: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -// Add Azure Key Vault resource -var keyVault = builder.AddAzureKeyVault("key-vault"); - -// Reference Key Vault in your services -builder.AddProject() - .WithReference(keyVault); -``` - -For more information, see [Aspire Azure Key Vault integration](https://aspire.dev/integrations/cloud/azure/azure-key-vault/). - -### Configure user-assigned managed identities - -For more granular control over permissions, use user-assigned managed identities: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -// Create or reference a user-assigned managed identity -var managedIdentity = builder.AddAzureUserAssignedIdentity("app-identity"); - -// Apply the identity to your container apps -builder.AddProject() - .WithReference(managedIdentity); -``` - -For detailed guidance, see [User-assigned managed identity](https://aspire.dev/integrations/cloud/azure/user-assigned-identity/). - -### Enable comprehensive monitoring - -**Application Insights**: Monitor your applications for security anomalies and performance issues: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -// Add Application Insights -var appInsights = builder.AddAzureApplicationInsights("monitoring"); - -builder.AddProject() - .WithReference(appInsights); -``` - -For more information, see [Use Aspire with Application Insights](application-insights.md). - -**Azure Monitor**: Configure alerts for suspicious activities and resource consumption anomalies. - -## Additional security resources - -For comprehensive guidance on Azure security, see [Azure security best practices and patterns](/azure/security/fundamentals/best-practices-and-patterns). - -## Next steps - -- [Deploy an Aspire project to Azure Container Apps](../azd/aca-deployment.md) -- [Customize Aspire Azure deployments](customize-deployments.md) -- [Aspire Azure Key Vault integration](https://aspire.dev/integrations/cloud/azure/azure-key-vault/) -- [User-assigned managed identity](https://aspire.dev/integrations/cloud/azure/user-assigned-identity/) diff --git a/docs/deployment/aspire-deploy/customize-deployments.md b/docs/deployment/aspire-deploy/customize-deployments.md index 2e057bbcb1..ca2e738736 100644 --- a/docs/deployment/aspire-deploy/customize-deployments.md +++ b/docs/deployment/aspire-deploy/customize-deployments.md @@ -14,7 +14,7 @@ Aspire provides APIs to customize how your applications are deployed. This artic - Aspire 9.5 or later - An existing Aspire project -For information about creating an Aspire project, see [Build your first Aspire app](../../get-started/build-your-first-aspire-app.md). +For information about creating an Aspire project, see [Build your first Aspire app](https://aspire.dev/get-started/first-app/). ## Dynamic container image tagging @@ -101,4 +101,4 @@ serviceBus.ConfigureInfrastructure(infrastructure => ## Related content - [Deploy to Azure Container Apps using aspire deploy](aca-deployment-aspire-cli.md) -- [App host overview](../../fundamentals/app-host-overview.md) +- [App host overview](https://aspire.dev/get-started/app-host/) diff --git a/docs/deployment/azd/aca-deployment-azd-in-depth.md b/docs/deployment/azd/aca-deployment-azd-in-depth.md index d34dc201e8..ac83c0db3f 100644 --- a/docs/deployment/azd/aca-deployment-azd-in-depth.md +++ b/docs/deployment/azd/aca-deployment-azd-in-depth.md @@ -134,7 +134,7 @@ Just like in local development, the configuration of connection strings has been :::image type="content" loc-scope="azure" source="../media/azd-aca-variables.png" lightbox="../media/azd-aca-variables.png" alt-text="A screenshot of environment variables in the webfrontend container app."::: For more information on how Aspire projects handle connection strings and service discovery, see -[Aspire orchestration overview](../../fundamentals/app-host-overview.md). +[Aspire orchestration overview](https://aspire.dev/get-started/app-host/). ### Deploy application updates diff --git a/docs/deployment/azd/aca-deployment-github-actions.md b/docs/deployment/azd/aca-deployment-github-actions.md index b1d6e834e0..e54fe4a2f0 100644 --- a/docs/deployment/azd/aca-deployment-github-actions.md +++ b/docs/deployment/azd/aca-deployment-github-actions.md @@ -57,7 +57,7 @@ curl -fsSL https://aka.ms/install-azd.sh | bash ## Create an Aspire solution -As a starting point, this article assumes that you've created an Aspire solution from the **Aspire Starter Application** template. For more information, see [Quickstart: Build your first Aspire app](../../get-started/build-your-first-aspire-app.md). +As a starting point, this article assumes that you've created an Aspire solution from the **Aspire Starter Application** template. For more information, see [Quickstart: Build your first Aspire app](https://aspire.dev/get-started/first-app/). [!INCLUDE [init workflow](../includes/init-workflow.md)] @@ -110,7 +110,7 @@ When you add GitHub Actions to an existing multi-project Aspire solution where t ### When working-directory configuration is needed -The `azd pipeline config` command generates a GitHub Actions workflow that assumes your Aspire AppHost project is in the root directory of your repository. However, in many real-world scenarios, especially when [adding Aspire to existing applications](../../get-started/add-aspire-existing-app.md), the AppHost project might be in a subdirectory. +The `azd pipeline config` command generates a GitHub Actions workflow that assumes your Aspire AppHost project is in the root directory of your repository. However, in many real-world scenarios, especially when [adding Aspire to existing applications](https://aspire.dev/get-started/add-aspire-existing-app/), the AppHost project might be in a subdirectory. For example, if your repository structure looks like this: diff --git a/docs/deployment/azd/aca-deployment.md b/docs/deployment/azd/aca-deployment.md index 918ac207e1..3c1e295b61 100644 --- a/docs/deployment/azd/aca-deployment.md +++ b/docs/deployment/azd/aca-deployment.md @@ -27,7 +27,7 @@ With Aspire and Azure Container Apps (ACA), you have a great hosting scenario fo ## Create an Aspire project -As a starting point, this article assumes that you've created an Aspire project from the **Aspire Starter Application** template. For more information, see [Quickstart: Build your first Aspire project](../../get-started/build-your-first-aspire-app.md). +As a starting point, this article assumes that you've created an Aspire project from the **Aspire Starter Application** template. For more information, see [Quickstart: Build your first Aspire project](https://aspire.dev/get-started/first-app/). ### Resource naming diff --git a/docs/deployment/deployment-state-caching.md b/docs/deployment/deployment-state-caching.md deleted file mode 100644 index 0f9988d607..0000000000 --- a/docs/deployment/deployment-state-caching.md +++ /dev/null @@ -1,171 +0,0 @@ ---- -title: Deployment state caching -description: Learn how the aspire deploy command manages deployment state through cached configuration files. -ms.date: 10/17/2025 -ai-usage: ai-assisted ---- - -# Deployment state caching - -The `aspire deploy` command manages deployment state through cached configuration files stored locally on your machine. This caching mechanism streamlines repeated deployments by preserving provisioning settings and parameters, making subsequent deployments faster and more efficient. - -## Default behavior - -The `aspire deploy` command automatically manages deployment state based on whether cached configuration exists for your application and target environment. - -### First deployment - -When you run `aspire deploy` for the first time, or for the first time in a target `--environment`, the command: - -1. Prompts for provisioning information (subscription ID, resource group name, location). -1. Prompts for deployment parameters (for example, API keys, connection strings). -1. Initiates the deployment process. -1. Saves all prompted values and deployment state to `~/.aspire/deployments/{AppHostSha}/production.json`. - -### Subsequent deployments - -On subsequent `aspire deploy` executions, the command: - -1. Detects the existing deployment state file at _~/.aspire/deployments/{AppHostSha}/production.json_. -1. Notifies you that settings will be read from the cached file. -1. Prompts for confirmation to load the cached settings. -1. Loads the configuration from the cached file into the configuration provider. -1. Proceeds with deployment using the cached values (no re-prompting). - -## Environment-specific deployments - -Different deployment environments (such as development, staging, and production) typically require different configurations, resource names, and connection strings. The `aspire deploy` command supports environment-specific deployments, ensuring that each environment maintains isolated deployment state. - -### Specify an environment - -Use the `--environment` flag to deploy to different environments: - -```Aspire -aspire deploy --environment staging -``` - -**First deployment to a specific environment:** - -- Prompts for all provisioning and parameter information. -- Saves deployment state to _~/.aspire/deployments/{AppHostSha}/{environment}.json_ (for example, _staging.json_). - -**Subsequent deployments:** - -- Reads the environment-specific cached file. -- Loads configuration from the cached state. -- Uses cached values without prompting. - -### Environment variable support - -The deployment environment can also be specified using the `DOTNET_ENVIRONMENT` environment variable: - -```bash -export DOTNET_ENVIRONMENT=staging && aspire deploy -``` - -This behaves identically to using the `--environment` flag, loading the appropriate cached configuration file. - -## Cache management - -The `aspire deploy` command provides mechanisms to manage cached deployment state, giving you control over when to use cached values and when to start fresh. - -### Clear the cache - -Use the `--clear-cache` flag to reset deployment state: - -```Aspire -aspire deploy --clear-cache -``` - -**Behavior:** - -1. Prompts for confirmation before deleting the cache for the specified environment. -1. Deletes the environment-specific deployment state file (for example, _~/.aspire/deployments/{AppHostSha}/production.json_). -1. Prompts for all provisioning and parameter information as if deploying for the first time. -1. Proceeds with deployment. -1. **Does not save the prompted values** to cache. - -### Environment-specific cache clearing - -The `--clear-cache` flag respects the environment context: - -```Aspire -aspire deploy --environment staging --clear-cache -``` - -This clears only the _staging.json_ cache file while leaving other environment caches (like _production.json_) intact. - -## File storage location - -- **Path pattern:** _~/.aspire/deployments/{AppHostSha}/{environment}.json_. -- **Default environment:** `production`. -- **AppHostSha:** A hash value representing the application host configuration, ensuring deployment states are specific to each application configuration. - -## Use deployment state in CI/CD pipelines - -When using the `aspire deploy` command in continuous integration and deployment (CI/CD) pipelines, you might want to persist deployment state across pipeline runs. This approach can be useful for maintaining consistent deployment configurations without manual intervention. - -### GitHub Actions example - -The following example demonstrates how to cache deployment state in a GitHub Actions workflow using the `actions/cache` action: - -```yaml -name: Deploy to Azure - -on: - push: - branches: [ main ] - -jobs: - deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Cache Aspire deployment state - uses: actions/cache@v4 - with: - path: ~/.aspire/deployments - key: aspire-deploy-${{ hashFiles('**/AppHost.csproj') }}-${{ github.ref }} - restore-keys: | - aspire-deploy-${{ hashFiles('**/AppHost.csproj') }}- - aspire-deploy- - - - name: Deploy with Aspire CLI - run: aspire deploy --environment production - env: - AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} -``` - -This workflow caches the _~/.aspire/deployments_ directory, using the AppHost project file hash and branch reference as cache keys. The `actions/cache` action automatically restores the cache before the deployment step and saves any updates to the cache after the job completes. Subsequent workflow runs restore the cached deployment state, allowing automated deployments without re-prompting for configuration values. - -> [!CAUTION] -> When caching deployment state in CI/CD pipelines, ensure that your pipeline has appropriate access controls and secret management practices in place, as the cached state might contain sensitive configuration values. - -## Security considerations - -The deployment state files are stored locally on your machine in the _~/.aspire/deployments_ directory. These files contain provisioning settings and parameter values, including secrets that might be associated with parameter resources. The `aspire deploy` command follows the same security pattern as .NET's user secrets manager: - -- Files are stored outside of source code to mitigate against accidental secret leaks in version control. -- Secrets are stored in plain text in the local file system. -- Any process running under your user account can access these files. - -Consider these security best practices: - -- Ensure your local machine has appropriate security measures in place. -- Be cautious when sharing or backing up files from the _~/.aspire/deployments_ directory. -- Use the `--clear-cache` flag when you need to change sensitive parameter values. - -## Key points - -- Each environment maintains its own isolated deployment state. -- Cached values persist across deployments unless explicitly cleared. -- The `--clear-cache` flag performs a one-time deployment without persisting new values. -- Environment selection can be specified via flag or environment variable. -- You're prompted for confirmation when loading cached settings. -- Cache files are stored per application (via AppHostSha) and per environment. - -## See also - -- [aspire deploy command reference](../cli-reference/aspire-deploy.md) -- [Deploy to Azure Container Apps using Aspire CLI](aspire-deploy/aca-deployment-aspire-cli.md) diff --git a/docs/deployment/docker-integration.md b/docs/deployment/docker-integration.md index 2025f8d4ca..98136680d1 100644 --- a/docs/deployment/docker-integration.md +++ b/docs/deployment/docker-integration.md @@ -128,8 +128,8 @@ The Docker hosting integration captures environment variables from your app mode ## Next steps -- [Deploy Aspire projects to Azure Container Apps using the Aspire CLI](aspire-deploy/aca-deployment-aspire-cli.md) -- [Building custom deployment pipelines](../fundamentals/custom-deployments.md) +- [Deploy Aspire projects to Azure Container Apps using the Aspire CLI](https://aspire.dev/deployment/azure/aca-deployment-aspire-cli/) +- [Building custom deployment pipelines](https://aspire.dev/deployment/custom-deployments/) - [Docker Compose to AppHost API reference](../get-started/docker-compose-to-apphost-reference.md) -- [Aspire integrations](../fundamentals/integrations-overview.md) +- [Aspire integrations](https://aspire.dev/integrations/overview/) - [Aspire GitHub repo](https://github.com/dotnet/aspire) diff --git a/docs/deployment/kubernetes-integration.md b/docs/deployment/kubernetes-integration.md index cbf8ef5d0d..cb37fbb5b2 100644 --- a/docs/deployment/kubernetes-integration.md +++ b/docs/deployment/kubernetes-integration.md @@ -13,7 +13,7 @@ The Aspire Kubernetes hosting integration enables you to generate Kubernetes dep ## Hosting integration -To get started with the Aspire Kubernetes hosting integration, install the [πŸ“¦ Aspire.Hosting.Kubernetes](https://www.nuget.org/packages/Aspire.Hosting.Kubernetes) NuGet package in the [AppHost](xref:dotnet/aspire/app-host) project. +To get started with the Aspire Kubernetes hosting integration, install the [πŸ“¦ Aspire.Hosting.Kubernetes](https://www.nuget.org/packages/Aspire.Hosting.Kubernetes) NuGet package in the [AppHost](https://aspire.dev/get-started/app-host/) project. ### [.NET CLI](#tab/dotnet-cli) @@ -108,12 +108,12 @@ Resource names in Kubernetes must follow DNS naming conventions. The integration ### Environment-specific configuration -Use [external parameters](../fundamentals/external-parameters.md) to configure environment-specific values that should be different between development and production environments. +Use [external parameters](https://aspire.dev/fundamentals/external-parameters/) to configure environment-specific values that should be different between development and production environments. ## See also - [Deploy to Kubernetes](overview.md#deploy-to-kubernetes) -- [Aspire integrations overview](../fundamentals/integrations-overview.md) +- [Aspire integrations overview](https://aspire.dev/integrations/overview/) - [Aspire GitHub repo](https://github.com/dotnet/aspire) - [Kubernetes documentation](https://kubernetes.io/docs/) - [Helm documentation](https://helm.sh/docs/) diff --git a/docs/deployment/manifest-format.md b/docs/deployment/manifest-format.md deleted file mode 100644 index 06ebefb12f..0000000000 --- a/docs/deployment/manifest-format.md +++ /dev/null @@ -1,923 +0,0 @@ ---- -title: Aspire manifest format for deployment tool builders -description: Learn about the Aspire manifest format in this comprehensive deployment tool builder guide. -ms.date: 09/23/2025 -ms.topic: reference -ms.custom: - - sfi-image-nochange - - sfi-ropc-nochange ---- - -# Aspire manifest format for deployment tool builders - -In this article, you learn about the Aspire manifest format. This article serves as a reference guide for deployment tool builders, aiding in the creation of tooling to deploy Aspire projects on specific hosting platforms, whether on-premises or in the cloud. - -Aspire [simplifies the local development experience](../fundamentals/networking-overview.md) by helping to manage interdependencies between application integrations. To help simplify the deployment of applications, Aspire projects can generate a manifest of all the resources defined as a JSON formatted file. - -## Generate a manifest - -A valid Aspire project is required to generate a manifest. To get started, create -an Aspire project using the `aspire-starter` .NET template: - -```dotnetcli -dotnet new aspire-starter --use-redis-cache ` - -o AspireApp && ` - cd AspireApp -``` - -Manifest generation is achieved by running `dotnet build` with a special target: - -```dotnetcli -dotnet run --project AspireApp.AppHost\AspireApp.AppHost.csproj ` - --publisher manifest ` - --output-path ../aspire-manifest.json -``` - -> [!TIP] -> The `--output-path` supports relative paths. The previous command uses `../aspire-manifest.json` to place the manifest file in the root of the project directory. - -For more information, see [dotnet run](/dotnet/core/tools/dotnet-run). The previous command produces the following output: - -```Output -Building... -info: Aspire.Hosting.Publishing.ManifestPublisher[0] - Published manifest to: .\AspireApp.AppHost\aspire-manifest.json -``` - -The file generated is the Aspire manifest and is used by tools to support deploying into target cloud environments. - -> [!NOTE] -> You can also generate a manifest as part of the launch profile. Consider the following _launchSettings.json_: -> -> ```json -> { -> "$schema": "http://json.schemastore.org/launchsettings.json", -> "profiles": { -> "generate-manifest": { -> "commandName": "Project", -> "launchBrowser": false, -> "dotnetRunMessages": true, -> "commandLineArgs": "--publisher manifest --output-path aspire-manifest.json" -> } -> } -> } -> ``` - -## Basic manifest format - -Publishing the manifest from the default starter template for Aspire produces the following JSON output: - -```json -{ - "resources": { - "cache": { - "type": "container.v0", - "connectionString": "{cache.bindings.tcp.host}:{cache.bindings.tcp.port}", - "image": "redis:7.2.4", - "bindings": { - "tcp": { - "scheme": "tcp", - "protocol": "tcp", - "transport": "tcp", - "containerPort": 6379 - } - } - }, - "apiservice": { - "type": "project.v0", - "path": "../AspireApp.ApiService/AspireApp.ApiService.csproj", - "env": { - "OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES": "true", - "OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES": "true" - }, - "bindings": { - "http": { - "scheme": "http", - "protocol": "tcp", - "transport": "http" - }, - "https": { - "scheme": "https", - "protocol": "tcp", - "transport": "http" - } - } - }, - "webfrontend": { - "type": "project.v0", - "path": "../AspireApp.Web/AspireApp.Web.csproj", - "env": { - "OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES": "true", - "OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES": "true", - "ConnectionStrings__cache": "{cache.connectionString}", - "APISERVICE_HTTP": "{apiservice.bindings.http.url}", - "APISERVICE_HTTPS": "{apiservice.bindings.https.url}", - "services__apiservice__http__0": "{apiservice.bindings.http.url}", - "services__apiservice__https__0": "{apiservice.bindings.https.url}" - }, - "bindings": { - "http": { - "scheme": "http", - "protocol": "tcp", - "transport": "http" - }, - "https": { - "scheme": "https", - "protocol": "tcp", - "transport": "http" - } - } - } - } -} -``` - -The manifest format JSON consists of a single object called `resources`, which contains a property for each resource specified in _:::no-loc text="Program.cs":::_ (the `name` argument for each name is used as the property for each of the child resource objects in JSON). - -### Connection string and binding references - -In the previous example, there are two project resources and one Redis cache resource. The _webfrontend_ depends on both the _apiservice_ (project) and _cache_ (Redis) resources. - -This dependency is known because the environment variables for the _webfrontend_ contain placeholders that reference the two other resources: - -```json -"env": { - // ... other environment variables omitted for clarity - "ConnectionStrings__cache": "{cache.connectionString}", - "APISERVICE_HTTP": "{apiservice.bindings.http.url}", - "APISERVICE_HTTPS": "{apiservice.bindings.https.url}", - "services__apiservice__http__0": "{apiservice.bindings.http.url}", - "services__apiservice__https__0": "{apiservice.bindings.https.url}" -}, -``` - -The `apiservice` resource is referenced by `webfrontend` using the call `WithReference(apiservice)` in the AppHost _:::no-loc text="AppHost.cs":::_ file and `redis` is referenced using the call `WithReference(cache)`: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var cache = builder.AddRedis("cache"); - -var apiService = builder.AddProject("apiservice"); - -builder.AddProject("webfrontend") - .WithReference(cache) - .WithReference(apiService); - -builder.Build().Run(); -``` - -References between project resource types result in [service discovery](https://aspire.dev/fundamentals/service-discovery/) variables being injected into the referencing project. References to well known reference types such as Redis result in connection strings being injected. - -:::image type="content" source="media/manifest-placeholder-strings.png" lightbox="media/manifest-placeholder-strings.png" alt-text="A diagram showing which resources contribute to which corresponding placeholder strings."::: - -For more information on how resources in the app model and references between them work, see, [Aspire orchestration overview](../fundamentals/app-host-overview.md). - -### Placeholder string structure - -Placeholder strings reference the structure of the Aspire manifest: - -:::image type="content" source="media/placeholder-mappings.png" lightbox="media/placeholder-mappings.png" alt-text="A diagram showing how the manifest JSON structure maps to placeholder strings."::: - -The final segment of the placeholder string (`url` in this case) is generated by the tool processing the manifest. There are several suffixes that could be used on the placeholder string: - -- `connectionString`: For well-known resource types such as Redis. Deployment tools translate the resource in the most appropriate infrastructure for the target cloud environment and then produce an Aspire compatible connection string for the consuming application to use. On `container.v0` resources the `connectionString` field may be present and specified explicitly. This is to support scenarios where a container resource type is referenced using the extension but is desired to be hosted explicitly as a container. -- `url`: For service-to-service references where a well-formed URL is required. The deployment tool produces the `url` based on the scheme, protocol, and transport defined in the manifest and the underlying compute/networking topology that was deployed. -- `host`: The host segment of the URL. -- `port`: The port segment of the URL. - -## Resource types - -Each resource has a `type` field. When a deployment tool reads the manifest, it should read the type to verify whether it can correctly process the manifest. During the Aspire preview period, all resource types have a `v0` suffix to indicate that they're subject to change. As Aspire approaches release a `v1` suffix will be used to signify that the structure of the manifest for that resource type should be considered stable (subsequent updates increment the version number accordingly). - -### Common resource fields - -The `type` field is the only field that is common across all resource types, however, the `project.v0`, `container.v0`, and `executable.v0` resource types also share the `env` and `bindings` fields. - -> [!NOTE] -> The `executable.v0` resource type isn't fully implemented in the manifest due to its lack of utility in deployment scenarios. For more information on containerizing executables, see [Dockerfile resource types](#dockerfile-resource-types). - -The `env` field type is a basic key/value mapping where the values might contain [_placeholder strings_](#placeholder-string-structure). - -Bindings are specified in the `bindings` field with each binding contained within its own field under the `bindings` JSON object. The fields omitted by the Aspire manifest in the `bindings` node include: - -- `scheme`: One of the following values `tcp`, `udp`, `http`, or `https`. -- `protocol`: One of the following values `tcp` or `udp` -- `transport`: Same as `scheme`, but used to disambiguate between `http` and `http2`. -- `containerPort`: Optional, if omitted defaults to port 80. - -### The `inputs` field - -Some resources generate an `inputs` field. This field is used to specify input parameters for the resource. The `inputs` field is a JSON object where each property is an input parameter that's used in placeholder structure resolution. Resources that have a `connectionString`, for example, might use the `inputs` field to specify a `password` for the connection string: - -```json -"connectionString": "Host={.bindings.tcp.host};Port={.bindings.tcp.port};Username=admin;Password={.inputs.password};" -``` - -The connection string placeholder references the `password` input parameter from the `inputs` field: - -```json -"inputs": { - "password": { - "type": "string", - "secret": true, - "default": { - "generate": { - "minLength": 10 - } - } - } -} -``` - -The preceding JSON snippet shows the `inputs` field for a resource that has a `connectionString` field. The `password` input parameter is a string type and is marked as a secret. The `default` field is used to specify a default value for the input parameter. In this case, the default value is generated using the `generate` field, with random string of a minimum length. - -## Built-in resources - -The following table is a list of resource types that are explicitly generated by Aspire and -extensions developed by the Aspire team: - -### Cloud-agnostic resource types - -These resources are available in the [πŸ“¦ Aspire.Hosting](https://www.nuget.org/packages/Aspire.Hosting) NuGet package. - -| App model usage | Manifest resource type | Heading link | -|--|--|--| -| | `container.v0` | [Container resource type](#container-resource-type) | -| `PublishAsDockerFile` | `dockerfile.v0` | [Dockerfile resource types](#dockerfile-resource-types) | -| | `value.v0` | [MongoDB Server resource types](#mongodb-resource-types) | -| | `container.v0` | [MongoDB resource types](#mongodb-resource-types) | -| | `value.v0` | [MySQL Server resource types](#mysql-resource-types) | -| | `container.v0` | [MySQL resource types](#mysql-resource-types) | -| | `value.v0` | [Postgres resource types](#postgres-resource-types) | -| | `container.v0` | [Postgres resource types](#postgres-resource-types) | -| | `project.v0` | [Project resource type](#project-resource-type) | -| | `container.v0` | [RabbitMQ resource types](#rabbitmq-resource-types) | -| | `container.v0` | [Redis resource type](#redis-resource-type) | -| | `value.v0` | [SQL Server resource types](#sql-server-resource-types) | -| | `container.v0` | [SQL Server resource types](#sql-server-resource-types) | - -#### Project resource type - -Example code: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); -var apiservice = builder.AddProject("apiservice"); -``` - -Example manifest: - -```json -"apiservice": { - "type": "project.v0", - "path": "../AspireApp.ApiService/AspireApp.ApiService.csproj", - "env": { - "OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES": "true", - "OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES": "true" - }, - "bindings": { - "http": { - "scheme": "http", - "protocol": "tcp", - "transport": "http" - }, - "https": { - "scheme": "https", - "protocol": "tcp", - "transport": "http" - } - } -} -``` - -#### Container resource type - -Example code: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -builder.AddContainer("mycontainer", "myimage") - .WithEnvironment("LOG_LEVEL", "WARN") - .WithHttpEndpoint(3000); -``` - -Example manifest: - -```json -{ - "resources": { - "mycontainer": { - "type": "container.v0", - "image": "myimage:latest", - "env": { - "LOG_LEVEL": "WARN" - }, - "bindings": { - "http": { - "scheme": "http", - "protocol": "tcp", - "transport": "http", - "containerPort": 3000 - } - } - } - } -} -``` - -#### Dockerfile resource types - -Example code: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -builder.AddNodeApp("nodeapp", "../nodeapp/app.js") - .WithHttpEndpoint(hostPort: 5031, env: "PORT") - .PublishAsDockerFile(); -``` - -> [!TIP] -> The `PublishAsDockerFile` call is required to generate the Dockerfile resource type in the manifest, and this extension method is only available on the type. - -Example manifest: - -```json -{ - "resources": { - "nodeapp": { - "type": "dockerfile.v0", - "path": "../nodeapp/Dockerfile", - "context": "../nodeapp", - "env": { - "NODE_ENV": "development", - "PORT": "{nodeapp.bindings.http.port}" - }, - "bindings": { - "http": { - "scheme": "http", - "protocol": "tcp", - "transport": "http", - "containerPort": 5031 - } - } - } - } -} -``` - -#### Postgres resource types - -Example code: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -builder.AddPostgres("postgres1") - .AddDatabase("shipping"); -``` - -Example manifest: - -```json -{ - "resources": { - "postgres1": { - "type": "container.v0", - "connectionString": "Host={postgres1.bindings.tcp.host};Port={postgres1.bindings.tcp.port};Username=postgres;Password={postgres1.inputs.password}", - "image": "postgres:16.2", - "env": { - "POSTGRES_HOST_AUTH_METHOD": "scram-sha-256", - "POSTGRES_INITDB_ARGS": "--auth-host=scram-sha-256 --auth-local=scram-sha-256", - "POSTGRES_PASSWORD": "{postgres1.inputs.password}" - }, - "bindings": { - "tcp": { - "scheme": "tcp", - "protocol": "tcp", - "transport": "tcp", - "containerPort": 5432 - } - }, - "inputs": { - "password": { - "type": "string", - "secret": true, - "default": { - "generate": { - "minLength": 10 - } - } - } - } - }, - "shipping": { - "type": "value.v0", - "connectionString": "{postgres1.connectionString};Database=shipping" - } - } -} -``` - -#### RabbitMQ resource types - -RabbitMQ is modeled as a container resource `container.v0`. The following sample shows how they're added to the app model. - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -builder.AddRabbitMQ("rabbitmq1"); -``` - -The previous code produces the following manifest: - -```json -{ - "resources": { - "rabbitmq1": { - "type": "container.v0", - "connectionString": "amqp://guest:{rabbitmq1.inputs.password}@{rabbitmq1.bindings.tcp.host}:{rabbitmq1.bindings.tcp.port}", - "image": "rabbitmq:3", - "env": { - "RABBITMQ_DEFAULT_USER": "guest", - "RABBITMQ_DEFAULT_PASS": "{rabbitmq1.inputs.password}" - }, - "bindings": { - "tcp": { - "scheme": "tcp", - "protocol": "tcp", - "transport": "tcp", - "containerPort": 5672 - } - }, - "inputs": { - "password": { - "type": "string", - "secret": true, - "default": { - "generate": { - "minLength": 10 - } - } - } - } - } - } -} -``` - -#### Redis resource type - -Example code: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -builder.AddRedis("redis1"); -``` - -Example manifest: - -```json -{ - "resources": { - "redis1": { - "type": "container.v0", - "connectionString": "{redis1.bindings.tcp.host}:{redis1.bindings.tcp.port}", - "image": "redis:7.2.4", - "bindings": { - "tcp": { - "scheme": "tcp", - "protocol": "tcp", - "transport": "tcp", - "containerPort": 6379 - } - } - } - } -} -``` - -#### SQL Server resource types - -Example code: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -builder.AddSqlServer("sql1") - .AddDatabase("shipping"); -``` - -Example manifest: - -```json -{ - "resources": { - "sql1": { - "type": "container.v0", - "connectionString": "Server={sql1.bindings.tcp.host},{sql1.bindings.tcp.port};User ID=sa;Password={sql1.inputs.password};TrustServerCertificate=true", - "image": "mcr.microsoft.com/mssql/server:2022-latest", - "env": { - "ACCEPT_EULA": "Y", - "MSSQL_SA_PASSWORD": "{sql1.inputs.password}" - }, - "bindings": { - "tcp": { - "scheme": "tcp", - "protocol": "tcp", - "transport": "tcp", - "containerPort": 1433 - } - }, - "inputs": { - "password": { - "type": "string", - "secret": true, - "default": { - "generate": { - "minLength": 10 - } - } - } - } - }, - "shipping": { - "type": "value.v0", - "connectionString": "{sql1.connectionString};Database=shipping" - } - } -} -``` - -#### MongoDB resource types - -Example code: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -builder.AddMongoDB("mongodb1") - .AddDatabase("shipping"); -``` - -Example manifest: - -```json -{ - "resources": { - "mongodb1": { - "type": "container.v0", - "connectionString": "mongodb://{mongodb1.bindings.tcp.host}:{mongodb1.bindings.tcp.port}", - "image": "mongo:7.0.5", - "bindings": { - "tcp": { - "scheme": "tcp", - "protocol": "tcp", - "transport": "tcp", - "containerPort": 27017 - } - } - }, - "shipping": { - "type": "value.v0", - "connectionString": "{mongodb1.connectionString}/shipping" - } - } -} -``` - -#### MySQL resource types - -Example code: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -builder.AddMySql("mysql1") - .AddDatabase("shipping"); -``` - -Example manifest: - -```json -{ - "resources": { - "mysql1": { - "type": "container.v0", - "connectionString": "Server={mysql1.bindings.tcp.host};Port={mysql1.bindings.tcp.port};User ID=root;Password={mysql1.inputs.password}", - "image": "mysql:8.3.0", - "env": { - "MYSQL_ROOT_PASSWORD": "{mysql1.inputs.password}" - }, - "bindings": { - "tcp": { - "scheme": "tcp", - "protocol": "tcp", - "transport": "tcp", - "containerPort": 3306 - } - }, - "inputs": { - "password": { - "type": "string", - "secret": true, - "default": { - "generate": { - "minLength": 10 - } - } - } - } - }, - "shipping": { - "type": "value.v0", - "connectionString": "{mysql1.connectionString};Database=shipping" - } - } -} -``` - -### Azure-specific resource types - -The following resources are available in the [πŸ“¦ Aspire.Hosting.Azure](https://www.nuget.org/packages/Aspire.Hosting.Azure) NuGet package. - -| App Model usage | Manifest resource type | Heading link | -|--|--|--| -| | `azure.bicep.v0` | [Azure App Configuration resource types](#azure-app-configuration-resource-type) | -| | `azure.bicep.v0` | [Azure Key Vault resource type](#azure-key-vault-resource-type) | -| `AddAzureRedis` | `azure.bicep.v0` | [Azure Redis resource types](#azure-redis-resource-type) | -| | `azure.bicep.v0` | [Azure Service Bus resource type](#azure-service-bus-resource-type) | -| `AddAzureSqlServer(...)` | `azure.bicep.v0` | [Azure SQL resource types](#azure-sql-resource-types) | -| `AddAzureSqlServer(...).AddDatabase(...)` | `value.v0` | [Azure SQL resource types](#azure-sql-resource-types) | -| `AddAzurePostgresFlexibleServer(...)` | `azure.bicep.v0` | [Azure Postgres resource types](#azure-postgres-resource-types) | -| `AddAzurePostgresFlexibleServer(...).AddDatabase(...)` | `value.v0` | [Azure Postgres resource types](#azure-postgres-resource-types) | -| | `azure.storage.v0` | [Azure Storage resource types](#azure-storage-resource-types) | -| | `value.v0` | [Azure Storage resource types](#azure-storage-resource-types) | -| | `value.v0` | [Azure Storage resource types](#azure-storage-resource-types) | -| | `value.v0` | [Azure Storage resource types](#azure-storage-resource-types) | - -#### Azure Key Vault resource type - -Example code: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -builder.AddAzureKeyVault("keyvault1"); -``` - -Example manifest: - -```json -{ - "resources": { - "keyvault1": { - "type": "azure.bicep.v0", - "connectionString": "{keyvault1.outputs.vaultUri}", - "path": "aspire.hosting.azure.bicep.keyvault.bicep", - "params": { - "principalId": "", - "principalType": "", - "vaultName": "keyvault1" - } - } - } -} -``` - -#### Azure Service Bus resource type - -Example code: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -builder.AddAzureServiceBus("sb1") - .AddTopic("topic1", []) - .AddTopic("topic2", []) - .AddQueue("queue1") - .AddQueue("queue2"); -``` - -Example manifest: - -```json -{ - "resources": { - "sb1": { - "type": "azure.bicep.v0", - "connectionString": "{sb1.outputs.serviceBusEndpoint}", - "path": "aspire.hosting.azure.bicep.servicebus.bicep", - "params": { - "serviceBusNamespaceName": "sb1", - "principalId": "", - "principalType": "", - "queues": [ - "queue1", - "queue2" - ], - "topics": [ - { - "name": "topic1", - "subscriptions": [] - }, - { - "name": "topic2", - "subscriptions": [] - } - ] - } - } - } -} -``` - -#### Azure Storage resource types - -Example code: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var storage = builder.AddAzureStorage("images"); - -storage.AddBlobs("blobs"); -storage.AddQueues("queues"); -storage.AddTables("tables"); -``` - -Example manifest: - -```json -{ - "resources": { - "images": { - "type": "azure.bicep.v0", - "path": "aspire.hosting.azure.bicep.storage.bicep", - "params": { - "principalId": "", - "principalType": "", - "storageName": "images" - } - }, - "blobs": { - "type": "value.v0", - "connectionString": "{images.outputs.blobEndpoint}" - }, - "queues": { - "type": "value.v0", - "connectionString": "{images.outputs.queueEndpoint}" - }, - "tables": { - "type": "value.v0", - "connectionString": "{images.outputs.tableEndpoint}" - } - } -} -``` - -#### Azure Redis resource type - -Example code: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -builder.AddAzureRedis("azredis1"); -``` - -Example manifest: - -```json -{ - "resources": { - "azredis": { - "type": "azure.bicep.v0", - "connectionString": "{azredis.outputs.connectionString}", - "path": "azredis.module.bicep", - "params": { - "principalId": "", - "principalName": "" - } - } - } -} -``` - -#### Azure App Configuration resource type - -Example code: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -builder.AddAzureAppConfiguration("appconfig1"); -``` - -Example manifest: - -```json -{ - "resources": { - "appconfig1": { - "type": "azure.bicep.v0", - "connectionString": "{appconfig1.outputs.appConfigEndpoint}", - "path": "aspire.hosting.azure.bicep.appconfig.bicep", - "params": { - "configName": "appconfig1", - "principalId": "", - "principalType": "" - } - } - } -} -``` - -#### Azure SQL resource types - -Example code: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -builder.AddAzureSqlServer("sql") - .AddDatabase("inventory"); -``` - -Example manifest: - -```json -{ - "resources": { - "sql": { - "type": "azure.bicep.v0", - "connectionString": "Server=tcp:{sql.outputs.sqlServerFqdn},1433;Encrypt=True;Authentication=\u0022Active Directory Default\u0022", - "path": "sql.module.bicep", - "params": { - "principalId": "", - "principalName": "" - } - }, - "inventory": { - "type": "value.v0", - "connectionString": "{sql.connectionString};Database=inventory" - } - } -} -``` - -#### Azure Postgres resource types - -Example code: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -builder.AddAzurePostgresFlexibleServer("postgres") - .AddDatabase("db"); -``` - -Example manifest: - -```json -{ - "resources": { - "postgres": { - "type": "azure.bicep.v0", - "connectionString": "{postgres.outputs.connectionString}", - "path": "postgres.module.bicep", - "params": { - "principalId": "", - "principalType": "", - "principalName": "" - } - }, - "db": { - "type": "value.v0", - "connectionString": "{postgres.connectionString};Database=db" - } - } -} -``` - -### Resource types supported in the Azure Developer CLI - -The [Azure Developer CLI](/azure/developer/azure-developer-cli/) (azd) is a tool that can be used to deploy Aspire projects to Azure Container Apps. With the `azure.bicep.v0` resource type, cloud-agnostic resource container types can be mapped to Azure-specific resources. The following table lists the resource types that are supported in the Azure Developer CLI: - -| Name | Cloud-agnostic API | Azure API | -| ---- | ---------------------------- | ---------------------------------- | -| Redis | | `AddAzureRedis` | -| Postgres | | `AddAzurePostgresFlexibleServer` | -| SQL Server | | `AddAzureSqlServer` | - -When resources as configured as Azure resources, the `azure.bicep.v0` resource type is generated in the manifest. For more information, see [Deploy an Aspire project to Azure Container Apps using the Azure Developer CLI (in-depth guide)](azure/aca-deployment-azd-in-depth.md). - -## See also - -- [Aspire overview](../get-started/aspire-overview.md) -- [Aspire orchestration overview](../fundamentals/app-host-overview.md) -- [Aspire integrations overview](../fundamentals/integrations-overview.md) -- [Service discovery in Aspire](https://aspire.dev/fundamentals/service-discovery/) diff --git a/docs/deployment/overview.md b/docs/deployment/overview.md deleted file mode 100644 index 0761146f3b..0000000000 --- a/docs/deployment/overview.md +++ /dev/null @@ -1,293 +0,0 @@ ---- -title: Aspire publishing and deployment -description: Learn how Aspire solutions are published and deployed. -ms.topic: overview -ms.date: 09/29/2025 ---- - -# Aspire publishing and deployment overview - -Aspire separates the act of _producing deployment assets_ from _executing a deployment_. The Aspire CLI (`aspire`) provides two high‑level entrypoints: - -- `aspire publish`: Generates intermediate, parameterized assets for one or more hosting integrations that implement publish semantics. -- `aspire deploy`: Executes a deployment (when an integration implements deploy semantics) by resolving parameters and applying changes to a target environment. - -These commands provide direct access to publishing and deployment capabilities. The actual behavior (what gets generated, how deployment happens) comes from **hosting integrations** you reference (for example: Docker, Kubernetes, Azure). The system is **extensible**β€”you can build your own publishing or deployment integrations that plug into the same model. - -The `aspire publish` command produces deployment artifacts that contain unresolved parameters (placeholders). The `aspire deploy` command uses these artifacts, resolves the parameters when supported by the target integration, and then executes the deployment. Some integrations don't support the `deploy` command. - -## Aspire CLI commands (conceptual behavior) - -| Command | What it does | Outputs | Parameter state | Requires integration capability | -|---------|--------------|---------|-----------------|---------------------------------| -| `aspire publish` | Transforms the application model into integration-specific assets (Compose files, manifests, specifications, etc.). | Intermediate artifacts (not directly production-final). | Unresolved (placeholders, e.g. `${VAR}` or similar). | Publish support | -| `aspire deploy` | Runs a deployment using one or more integrations (build, parameter resolution, apply). | Real resources / applied changes. | Resolved. | Deploy support | - -If an integration does not implement deploy functionality, `aspire deploy` will not deploy that target (it may warn or no-op for it). - -When you run `aspire publish` without any integrations that support publishing, you'll see: - -```Output -Step 1: Analyzing model. - - βœ— FAILED: Analyzing the distributed application model for publishing and deployment capabilities. 00:00:00 - No resources in the distributed application model support publishing. - -❌ FAILED: Analyzing model. completed with errors -``` - -Similarly, when you run `aspire deploy` without any integrations that support deployment, you'll see this error: - -```Output -Step 1: Analyzing model. - - βœ— FAILED: Analyzing the distributed application model for publishing and deployment capabilities. 00:00:00 - No resources in the distributed application model support deployment. - -❌ FAILED: Analyzing model. completed with errors -``` - -These messages indicate that you need to add hosting integrations to your AppHost project. Hosting integrations are NuGet packages (like `Aspire.Hosting.Docker`, `Aspire.Hosting.Kubernetes`, or `Aspire.Hosting.Azure`) that provide the publishing and deployment capabilities for specific target platforms. - -## Parameter placeholders - -Published assets intentionally contain placeholders instead of concrete values. For Docker Compose–based publish output, parameterization appears as standard environment variable references. For example, a publish artifact might include: - -```yaml -services: - pg: - image: "docker.io/library/postgres:17.6" - environment: - POSTGRES_HOST_AUTH_METHOD: "scram-sha-256" - POSTGRES_INITDB_ARGS: "--auth-host=scram-sha-256 --auth-local=scram-sha-256" - POSTGRES_USER: "postgres" - POSTGRES_PASSWORD: "${PG_PASSWORD}" - ports: - - "8000:5432" - networks: - - "aspire" - dbsetup: - image: "${DBSETUP_IMAGE}" - environment: - OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES: "true" - OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES: "true" - OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY: "in_memory" - ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true" - HTTP_PORTS: "8001" - ConnectionStrings__db: "Host=pg;Port=5432;Username=postgres;Password=${PG_PASSWORD};Database=db" - ports: - - "8002:8001" - - "8004:8003" - depends_on: - pg: - condition: "service_started" - networks: - - "aspire" -``` - -Key points: - -- `${PG_PASSWORD}` and `${DBSETUP_IMAGE}` (and similar) are *placeholders* in the published asset. -- They are not resolved during `aspire publish`. -- A deployment engine (which could be `aspire deploy`, `docker compose` plus a script exporting variables, CI/CD variable injection, etc.) supplies their values later. -- This keeps secrets and environment-specific values decoupled from generated structure. - -Different integrations may use different placeholder conventions (environment variables, tokens, or parameter metadata), but the principle remains: publish preserves *shape*, deploy injects *values*. - -## Publisher model and compute environments - -Aspire uses a flexible publisher model that distributes publishing behavior across your application graph. Resources support publishing and deployment through annotations: - -- [`aspire publish`](../cli-reference/aspire-publish.md) -- [`aspire deploy`](../cli-reference/aspire-deploy.md) - -This design enables hybrid and heterogeneous deployments, where different services within the same app can be deployed to different targets (cloud, edge, local). - -### Compute environments - -A **compute environment** is a core deployment concept in Aspire that represents a target platform where your application resources will be deployed. Compute environments define how resources should be transformed and what deployment artifacts should be generated. Examples of built-in comput environments include the Azure Container Apps environment and the Docker Compose environment. - -**Compute resources** are the runnable parts of your application, such as .NET projects, containers, and executables that need to be deployed to a compute environment. - -When you add a compute environment like Docker Compose or Kubernetes, Aspire applies the correct publishing behavior to all compatible compute resources in your app modelβ€”no extra configuration needed. - -### Multiple environments require disambiguation - -If you add multiple compute environments, Aspire needs to know which resource goes where. Compute environments apply their transformations to all applicable compute resources (projects, containers, executables). If more than one environment matches a given resource, Aspire throws an ambiguous environment exception at publish time. - -You can resolve this by using : - -```csharp -var k8s = builder.AddKubernetesEnvironment("k8s-env"); -var compose = builder.AddDockerComposeEnvironment("docker-env"); - -builder.AddProject("frontend") - .WithComputeEnvironment(k8s); - -builder.AddProject("backend") - .WithComputeEnvironment(compose); -``` - -This example shows how you could explicitly map services to different compute environments. For example, a frontend in Kubernetes and a backend in Docker Compose. - - - -## Hosting integration support matrix - -| Integration package | Target | Publish | Deploy | Notes | -|---------------------|--------|---------|--------|-------| -| [Aspire.Hosting.Docker](https://www.nuget.org/packages/Aspire.Hosting.Docker) | Docker / Docker Compose | βœ… Yes | ❌ No | Use generated Compose with your own scripts or tooling. | -| [Aspire.Hosting.Kubernetes](https://www.nuget.org/packages/Aspire.Hosting.Kubernetes) | Kubernetes | βœ… Yes | ❌ No | Apply with `kubectl`, GitOps, or other controllers. | -| [Aspire.Hosting.Azure.AppContainers](https://www.nuget.org/packages/Aspire.Hosting.Azure.AppContainers) | Azure Container Apps | βœ… Yes | βœ… Yes (Preview) | Deploy capability is in Preview and may change. | -| [Aspire.Hosting.Azure.AppService](https://www.nuget.org/packages/Aspire.Hosting.Azure.AppService) | Azure App Service | βœ… Yes | βœ… Yes (Preview) | Deploy capability is in Preview and may change. | - -> [!TIP] -> Deploy support is integration-specific. Absence of deploy support means you use the published artifacts with external tooling. - -## Typical workflows - -### 1. Generate artifacts (any integration) - -```Aspire -aspire publish -o artifacts/ -``` - -Review the contents of _artifacts/_ (for example: Docker Compose files, Kubernetes manifests, Azure specification documents, etc.). - -### 2. Run locally (Docker example) - -```bash -# Provide or export required environment variables, then: -docker compose -f artifacts/docker-compose.yml up --build -``` - -Missing variables like `PG_PASSWORD` must be set in the shell, an `.env` file, or injected by your chosen runner. - -### 3. Using `aspire deploy` - -If an integration supports deployment, you can run: - -```Aspire -aspire deploy -``` - -This resolves parameters and applies deployment changes for integrations that support deployment. - -## Extensibility - -The `aspire publish` and `aspire deploy` commands support extensible workflows through annotations that you can add to resources. This functionality is in preview and may change in future releases. - -### Custom publishing and deployment callbacks - -Resources support custom publishing and deployment behavior through annotations: - -- : Executes custom logic during `aspire publish` operations. -- : Executes custom logic during `aspire deploy` operations. - -The following example demonstrates using `DeployingCallbackAnnotation` to register custom deployment behavior: - -```csharp -#pragma warning disable ASPIREPUBLISHERS001 -#pragma warning disable ASPIREINTERACTION001 - -using Aspire.Hosting.Publishing; -using Microsoft.Extensions.DependencyInjection; - -var builder = DistributedApplication.CreateBuilder(args); - -// Custom deployment step defined below -builder.AddDataSeedJob("SeedInitialData", seedDataPath: "data/seeds"); - -builder.Build().Run(); - -internal class DataSeedJobResource([ResourceName] string name, string seedDataPath) - : Resource(name) -{ - public string SeedDataPath { get; } = seedDataPath; -} - -internal static class DataSeedJobResourceBuilderExtensions -{ - public static IResourceBuilder AddDataSeedJob( - this IDistributedApplicationBuilder builder, - string name, - string seedDataPath = "data/seeds") - { - var job = new DataSeedJobResource(name, seedDataPath); - var resourceBuilder = builder.AddResource(job); - - // Attach a DeployingCallbackAnnotation that will be invoked on `aspire deploy` - job.Annotations.Add(new DeployingCallbackAnnotation(async ctx => - { - CancellationToken ct = ctx.CancellationToken; - - // Prompt the user for a confirmation using the interaction service - var interactionService = ctx.Services.GetRequiredService(); - - var envResult = await interactionService.PromptInputAsync( - "Environment Configuration", - "Please enter the target environment name:", - new InteractionInput - { - Label = "Environment Name", - InputType = InputType.Text, - Required = true, - Placeholder = "dev, staging, prod" - }, - cancellationToken: ct); - - // Custom deployment logic here - var reporter = ctx.ActivityReporter; - await using (var deployStep = await reporter.CreateStepAsync( - $"Deploying data seed job to {envResult.Value}", ct)) - { - // Simulate deployment work - await Task.Delay(2000, ct); - await deployStep.SucceedAsync("Data seed job deployed successfully", ct); - } - })); - - return resourceBuilder; - } -} -``` - -This custom deployment logic integrates seamlessly with the `aspire deploy` command, providing interactive prompts and progress reporting. For more information, see [Resource annotations in Aspire](../fundamentals/annotations-overview.md). - -## Diagnostics and auditing - -Publishing gives you an immutable snapshot of intended structure before secrets appear. You can: - -- Diff published outputs between commits. -- Scan for disallowed images or configuration. -- Preserve a record for compliance, then separately record the resolved set applied at deployment time. - -## Additional tools - -### Azure Developer CLI (`azd`) - -[Azure Developer CLI (azd)](/azure/developer/azure-developer-cli/) has first-class support for deploying Aspire projects. It can provision infrastructure, manage environments, and coordinate secret/value injection. You can incorporate Aspire publish artifacts into `azd` workflows or use the Azure integration (preview) directly. - -## Deployment manifest - -Starting with Aspire 9.2, the [manifest format](manifest-format.md) is slowly being phased out in favor of Aspire CLI publish and deploy command support and APIs for defining publishing and deploying functionality. Earlier workflows emphasized a single "deployment manifest" generated from specialized AppHost targets. The modern approach centers on `aspire publish` + integration extensibility. The legacy manifest format is **not being evolved further**, but you can still generate it for inspection or debugging: - -```Aspire -aspire publish --publisher manifest -o diagnostics/ -``` - -This: - -- Produces a manifest snapshot useful for understanding resource graphs or troubleshooting. -- Should not be treated as the primary deployment contract. -- Is provided solely for backward compatibility and debugging visibility. - -## Key takeaways - -Publishing comes first, followed by deployment, which separates the structure from the values. The artifacts produced during publishing are parameterized, with resolution occurring later in the process. Specific integrations determine the actual behaviors of publishing and deployment, and the system is designed to be extensible, allowing you to build custom integrations that target new platforms or internal tooling. While the legacy manifest can still be generated, it remains static and is no longer evolving. - -## See also - -- [Hosting integrations overview](../fundamentals/integrations-overview.md) -- [Azure deployment with Container Apps](azure/aca-deployment.md) -- [Aspire CLI reference](../cli/overview.md) diff --git a/docs/extensibility/custom-client-integration.md b/docs/extensibility/custom-client-integration.md deleted file mode 100644 index b7f60bae38..0000000000 --- a/docs/extensibility/custom-client-integration.md +++ /dev/null @@ -1,205 +0,0 @@ ---- -title: Create custom Aspire client integrations -description: Learn how to create a custom Aspire client integration for an existing containerized application. -ms.date: 09/12/2024 -ms.topic: how-to -ms.custom: sfi-ropc-nochange ---- - -# Create custom Aspire client integrations - -This article is a continuation of the [Create custom Aspire hosting integrations](custom-hosting-integration.md) article. It guides you through creating an Aspire client integration that uses [MailKit](https://github.com/jstedfast/MailKit) to send emails. This integration is then added into the Newsletter app you previously built. The previous example omitted the creation of a client integration and instead relied on the existing .NET `SmtpClient`. It's best to use MailKit's `SmtpClient` over the official .NET `SmtpClient` for sending emails, as it's more modern and supports more features/protocols. For more information, see [.NET SmtpClient: Remarks](/dotnet/api/system.net.mail.smtpclient#remarks). - -## Prerequisites - -If you're following along, you should have a Newsletter app from the steps in the [Create custom Aspire hosting integration](custom-hosting-integration.md) article. - -> [!TIP] -> This article is inspired by existing Aspire integrations, and based on the team's official guidance. There are places where said guidance varies, and it's important to understand the reasoning behind the differences. For more information, see [Aspire integration requirements](https://github.com/dotnet/aspire/blob/f38b6cba86942ad1c45fc04fe7170f0fd4ba7c0b/src/Components/Aspire_Components_Progress.md#net-aspire-integration-requirements). - -## Create library for integration - -[Aspire integrations](../fundamentals/integrations-overview.md) are delivered as NuGet packages, but in this example, it's beyond the scope of this article to publish a NuGet package. Instead, you create a class library project that contains the integration and reference it as a project. Aspire integration packages are intended to wrap a client library, such as MailKit, and provide production-ready telemetry, health checks, configurability, and testability. Let's start by creating a new class library project. - -1. Create a new class library project named `MailKit.Client` in the same directory as the _MailDevResource.sln_ from the previous article. - - ```dotnetcli - dotnet new classlib -o MailKit.Client - ``` - -1. Add the project to the solution. - - ```dotnetcli - dotnet sln ./MailDevResource.sln add MailKit.Client/MailKit.Client.csproj - ``` - -The next step is to add all the NuGet packages that the integration relies on. Rather than having you add each package one-by-one from the .NET CLI, it's likely easier to copy and paste the following XML into the _MailKit.Client.csproj_ file. - -:::code language="xml" source="snippets/MailDevResourceAndComponent/MailKit.Client/MailKit.Client.csproj" range="9-16"::: - -## Define integration settings - -Whenever you're creating an Aspire integration, it's best to understand the client library that you're mapping to. With MailKit, you need to understand the configuration settings that are required to connect to a Simple Mail Transfer Protocol (SMTP) server. But it's also important to understand if the library has support for _health checks_, _tracing_ and _metrics_. MailKit supports _tracing_ and _metrics_, through its [`Telemetry.SmtpClient` class](https://github.com/jstedfast/MailKit/blob/master/MailKit/Telemetry.cs#L112-L189). When adding _health checks_, you should use any established or existing health checks where possible. Otherwise, you might consider implementing your own in the integration. Add the following code to the `MailKit.Client` project in a file named _MailKitClientSettings.cs_: - -:::code source="snippets/MailDevResourceAndComponent/MailKit.Client/MailKitClientSettings.cs"::: - -The preceding code defines the `MailKitClientSettings` class with: - -- `Endpoint` property that represents the connection string to the SMTP server. -- `DisableHealthChecks` property that determines whether health checks are enabled. -- `DisableTracing` property that determines whether tracing is enabled. -- `DisableMetrics` property that determines whether metrics are enabled. - -### Parse connection string logic - -The settings class also contains a `ParseConnectionString` method that parses the connection string into a valid `Uri`. The configuration is expected to be provided in the following format: - -- `ConnectionStrings:`: The connection string to the SMTP server. -- `MailKit:Client:ConnectionString`: The connection string to the SMTP server. - -If neither of these values are provided, an exception is thrown. - -## Expose client functionality - -The goal of Aspire integrations is to expose the underlying client library to consumers through dependency injection. With MailKit and for this example, the `SmtpClient` class is what you want to expose. You're not wrapping any functionality, but rather mapping configuration settings to an `SmtpClient` class. It's common to expose both standard and keyed-service registrations for integrations. Standard registrations are used when there's only one instance of a service, and keyed-service registrations are used when there are multiple instances of a service. Sometimes, to achieve multiple registrations of the same type you use a factory pattern. Add the following code to the `MailKit.Client` project in a file named _MailKitClientFactory.cs_: - -:::code source="snippets/MailDevResourceAndComponent/MailKit.Client/MailKitClientFactory.cs"::: - -The `MailKitClientFactory` class is a factory that creates an `ISmtpClient` instance based on the configuration settings. It's responsible for returning an `ISmtpClient` implementation that has an active connection to a configured SMTP server. Next, you need to expose the functionality for the consumers to register this factory with the dependency injection container. Add the following code to the `MailKit.Client` project in a file named _MailKitExtensions.cs_: - -:::code source="snippets/MailDevResourceAndComponent/MailKit.Client/MailKitExtensions.cs"::: - -The preceding code adds two extension methods on the `IHostApplicationBuilder` type, one for the standard registration of MailKit and another for keyed-registration of MailKit. - -> [!TIP] -> Extension methods for Aspire integrations should extend the `IHostApplicationBuilder` type and follow the `Add` naming convention where the `` is the type or functionality you're adding. For this article, the `AddMailKitClient` extension method is used to add the MailKit client. It's likely more in-line with the official guidance to use `AddMailKitSmtpClient` instead of `AddMailKitClient`, since this only registers the `SmtpClient` and not the entire MailKit library. - -Both extensions ultimately rely on the private `AddMailKitClient` method to register the `MailKitClientFactory` with the dependency injection container as a [scoped service](/dotnet/core/extensions/dependency-injection#scoped). The reason for registering the `MailKitClientFactory` as a scoped service is because the connection operations are considered expensive and should be reused within the same scope where possible. In other words, for a single request, the same `ISmtpClient` instance should be used. The factory holds on to the instance of the `SmtpClient` that it creates and disposes of it. - -### Configuration binding - -One of the first things that the private implementation of the `AddMailKitClient` methods does, is to bind the configuration settings to the `MailKitClientSettings` class. The settings class is instantiated and then `Bind` is called with the specific section of configuration. Then the optional `configureSettings` delegate is invoked with the current settings. This allows the consumer to further configure the settings, ensuring that manual code settings are honored over configuration settings. After that, depending on whether the `serviceKey` value was provided, the `MailKitClientFactory` should be registered with the dependency injection container as either a standard or keyed service. - -> [!IMPORTANT] -> It's intentional that the `implementationFactory` overload is called when registering services. The `CreateMailKitClientFactory` method throws when the configuration is invalid. This ensures that creation of the `MailKitClientFactory` is deferred until it's needed and it prevents the app from erroring out before logging is available. - -The registration of health checks, and telemetry are described in a bit more detail in the following sections. - -### Add health checks - -[Health checks](https://aspire.dev/fundamentals/health-checks/) are a way to monitor the health of an integration. With MailKit, you can check if the connection to the SMTP server is healthy. Add the following code to the `MailKit.Client` project in a file named _MailKitHealthCheck.cs_: - -:::code source="snippets/MailDevResourceAndComponent/MailKit.Client/MailKitHealthCheck.cs"::: - -The preceding health check implementation: - -- Implements the `IHealthCheck` interface. -- Accepts the `MailKitClientFactory` as a primary constructor parameter. -- Satisfies the `CheckHealthAsync` method by: - - Attempting to get an `ISmtpClient` instance from the `factory`. If successful, it returns `HealthCheckResult.Healthy`. - - If an exception is thrown, it returns `HealthCheckResult.Unhealthy`. - -As previously shared in the registration of the `MailKitClientFactory`, the `MailKitHealthCheck` is conditionally registered with the `IHeathChecksBuilder`: - -```csharp -if (settings.DisableHealthChecks is false) -{ - builder.Services.AddHealthChecks() - .AddCheck( - name: serviceKey is null ? "MailKit" : $"MailKit_{connectionName}", - failureStatus: default, - tags: []); -} -``` - -The consumer could choose to omit health checks by setting the `DisableHealthChecks` property to `true` in the configuration. A common pattern for integrations is to have optional features and Aspire integrations strongly encourages these types of configurations. For more information on health checks and a working sample that includes a user interface, see [Aspire ASP.NET Core HealthChecksUI sample](/samples/dotnet/aspire-samples/aspire-health-checks-ui/). - -### Wire up telemetry - -As a best practice, the [MailKit client library exposes telemetry](https://github.com/jstedfast/MailKit/blob/master/Telemetry.md). Aspire can take advantage of this telemetry and display it in the [Aspire dashboard](https://aspire.dev/dashboard/overview/). Depending on whether or not tracing and metrics are enabled, telemetry is wired up as shown in the following code snippet: - -```csharp -if (settings.DisableTracing is false) -{ - builder.Services.AddOpenTelemetry() - .WithTracing( - traceBuilder => traceBuilder.AddSource( - Telemetry.SmtpClient.ActivitySourceName)); -} - -if (settings.DisableMetrics is false) -{ - // Required by MailKit to enable metrics - Telemetry.SmtpClient.Configure(); - - builder.Services.AddOpenTelemetry() - .WithMetrics( - metricsBuilder => metricsBuilder.AddMeter( - Telemetry.SmtpClient.MeterName)); -} -``` - -## Update the Newsletter service - -With the integration library created, you can now update the Newsletter service to use the MailKit client. The first step is to add a reference to the `MailKit.Client` project. Add the _MailKit.Client.csproj_ project reference to the `MailDevResource.NewsletterService` project: - -```dotnetcli -dotnet add ./MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj reference MailKit.Client/MailKit.Client.csproj -``` - -Next, add a reference to the `ServiceDefaults` project: - -```dotnetcli -dotnet add ./MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj reference MailDevResource.ServiceDefaults/MailDevResource.ServiceDefaults.csproj -``` - -The final step is to replace the existing _:::no-loc text="Program.cs":::_ file in the `MailDevResource.NewsletterService` project with the following C# code: - -:::code source="snippets/MailDevResourceAndComponent/MailDevResource.NewsletterService/Program.cs"::: - -The most notable changes in the preceding code are: - -- The updated `using` statements that include the `MailKit.Client`, `MailKit.Net.Smtp`, and `MimeKit` namespaces. -- The replacement of the registration for the official .NET `SmtpClient` with the call to the `AddMailKitClient` extension method. -- The replacement of both `/subscribe` and `/unsubscribe` map post calls to instead inject the `MailKitClientFactory` and use the `ISmtpClient` instance to send the email. - -## Run the sample - -Now that you've created the MailKit client integration and updated the Newsletter service to use it, you can run the sample. From your IDE, select F5 or run `dotnet run` from the root directory of the solution to start the applicationβ€”you should see the [Aspire dashboard](https://aspire.dev/dashboard/overview/): - -:::image type="content" source="./media/maildev-with-newsletterservice-dashboard.png" lightbox="./media/maildev-with-newsletterservice-dashboard.png" alt-text="Aspire dashboard: MailDev and Newsletter resources running."::: - -Once the application is running, navigate to the Swagger UI at [https://localhost:7251/swagger](https://localhost:7251/swagger) and test the `/subscribe` and `/unsubscribe` endpoints. Select the down arrow to expand the endpoint: - -:::image type="content" source="./media/swagger-ui.png" lightbox="./media/swagger-ui.png" alt-text="Swagger UI: Subscribe endpoint."::: - -Then select the `Try it out` button. Enter an email address, and then select the `Execute` button. - -:::image type="content" source="./media/swagger-ui-try.png" lightbox="./media/swagger-ui-try.png" alt-text="Swagger UI: Subscribe endpoint with email address."::: - -Repeat this several times, to add multiple email addresses. You should see the email sent to the MailDev inbox: - -:::image type="content" source="./media/maildev-inbox.png" alt-text="MailDev inbox with multiple emails."::: - -Stop the application by selecting Ctrl+C in the terminal window where the application is running, or by selecting the stop button in your IDE. - -### View MailKit telemetry - -The MailKit client library exposes telemetry that can be viewed in the Aspire dashboard. To view the telemetry, navigate to the Aspire dashboard at [https://localhost:7251](https://localhost:7251). Select the `newsletter` resource to view the telemetry on the **Metrics** page: - -:::image type="content" source="./media/mailkit-metrics-dashboard.png" lightbox="./media/mailkit-metrics-dashboard.png" alt-text="Aspire dashboard: MailKit telemetry."::: - -Open up the Swagger UI again, and make some requests to the `/subscribe` and `/unsubscribe` endpoints. Then, navigate back to the Aspire dashboard and select the `newsletter` resource. Select a metric under the **mailkit.net.smtp** node, such as `mailkit.net.smtp.client.operation.count`. You should see the telemetry for the MailKit client: - -:::image type="content" source="./media/mailkit-metrics-graph-dashboard.png" lightbox="./media/mailkit-metrics-graph-dashboard.png" alt-text="Aspire dashboard: MailKit telemetry for operation count."::: - -## Summary - -In this article, you learned how to create an Aspire integration that uses MailKit to send emails. You also learned how to integrate this integration into the Newsletter app you previously built. You learned about the core principles of Aspire integrations, such as exposing the underlying client library to consumers through dependency injection, and how to add health checks and telemetry to the integration. You also learned how to update the Newsletter service to use the MailKit client. - -Go forth and build your own Aspire integrations. If you believe that there's enough community value in the integration you're building, consider publishing it as a [NuGet package](/dotnet/standard/library-guidance/nuget) for others to use. Furthermore, consider submitting a pull request to the [Aspire GitHub repository](https://github.com/dotnet/aspire) for consideration to be included in the official Aspire integrations. - -## Next steps - -> [!div class="nextstepaction"] -> [Secure communication between hosting and client integrations](secure-communication-between-integrations.md) diff --git a/docs/extensibility/custom-hosting-integration.md b/docs/extensibility/custom-hosting-integration.md deleted file mode 100644 index 29bcfdb40a..0000000000 --- a/docs/extensibility/custom-hosting-integration.md +++ /dev/null @@ -1,492 +0,0 @@ ---- -title: Create custom Aspire hosting integrations -description: Learn how to create a custom Aspire hosting integration for an existing containerized application. -ms.date: 11/11/2024 -ms.topic: how-to -ms.custom: sfi-ropc-nochange ---- - -# Create custom Aspire hosting integrations - -Aspire improves the development experience by providing reusable building blocks that can be used to quickly arrange application dependencies and expose them to your own code. One of the key building blocks of an Aspire-based application is the _resource_. Consider the code below: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var redis = builder.AddRedis("cache"); - -var db = builder.AddPostgres("pgserver") - .AddDatabase("inventorydb"); - -builder.AddProject("inventoryservice") - .WithReference(redis) - .WithReference(db); -``` - -In the preceding code there are four resources represented: - -1. `cache`: A Redis container. -1. `pgserver`: A Postgres container. -1. `inventorydb`: A database hosted on `pgserver`. -1. `inventoryservice`: An ASP.NET Core application. - -Most Aspire-related code that the average developer writes, centers around adding resources to the [app model](../fundamentals/app-host-overview.md) and creating references between them. - -## Key elements of an Aspire custom resource - -Building a custom resource in Aspire requires the following: - -1. A custom resource type that implements -2. An extension method for named `Add{CustomResource}` where `{CustomResource}` is the name of the custom resource. - -When custom resource requires optional configuration, developers may wish to implement `With*` suffixed extension methods to make these configuration options discoverable using the _builder pattern_. - -## A practical example: MailDev - -To help understand how to develop custom resources, this article shows an example of how to build a custom resource for [MailDev](https://maildev.github.io/maildev/). MailDev is an open-source tool which provides a local mail server designed to allow developers to test e-mail sending behaviors within their app. For more information, see [the MailDev GitHub repository](https://github.com/maildev/maildev). - -In this example you create a new Aspire project as a test environment for the MailDev resource that you create. While you can create custom resources in existing Aspire projects it's a good idea to consider whether the custom resource might be used across multiple Aspire-based solutions and should be developed as a reusable integration. - -## Set up the starter project - -Create a new Aspire project that is used to test out the new resource that we're developing. - -```dotnetcli -dotnet new aspire -o MailDevResource -cd MailDevResource -dir -``` - -Once the project is created, you should see a listing containing the following: - -- `MailDevResource.AppHost`: The [AppHost](../fundamentals/app-host-overview.md) used to test out the custom resource. -- `MailDevResource.ServiceDefaults`: The [service defaults](https://aspire.dev/fundamentals/service-defaults/) project for use in service-related projects. -- `MailDevResource.sln`: The solution file referencing both projects. - -Verify that the project can build and run successfully by executing the following command: - -```dotnetcli -dotnet run --project MailDevResource.AppHost/MailDevResource.AppHost.csproj -``` - -The console output should look similar to the following: - -```dotnetcli -Building... -info: Aspire.Hosting.DistributedApplication[0] - Aspire version: 9.0.0 -info: Aspire.Hosting.DistributedApplication[0] - Distributed application starting. -info: Aspire.Hosting.DistributedApplication[0] - Application host directory is: - ..\docs-aspire\docs\extensibility\snippets\MailDevResource\MailDevResource.AppHost -info: Aspire.Hosting.DistributedApplication[0] - Now listening on: https://localhost:17251 -info: Aspire.Hosting.DistributedApplication[0] - Login to the dashboard at https://localhost:17251/login?t=928db244c720c5022a7a9bf5cf3a3526 -info: Aspire.Hosting.DistributedApplication[0] - Distributed application started. Press Ctrl+C to shut down. -``` - -Select the [dashboard link in the browser](https://aspire.dev/dashboard/explore/#dashboard-authentication) to see the Aspire dashboard: - -:::image type="content" source="media/maildevresource-empty-dashboard.png" lightbox="media/maildevresource-empty-dashboard.png" alt-text="A screenshot of the empty Aspire dashboard for test project."::: - -Press Ctrl+C to shut down the app (you can close the browser tab). - -## Create library for resource extension - -Aspire resources are just classes and methods contained within a class library that references the Aspire Hosting library (`Aspire.Hosting`). By placing the resource in a separate project, you can more easily share it between Aspire-based apps and potentially package and share it on NuGet. - -1. Create the class library project named _MailDev.Hosting_. - - ```dotnetcli - dotnet new classlib -o MailDev.Hosting - ``` - -1. Add `Aspire.Hosting` to the class library as a package reference. - - ```dotnetcli - dotnet add ./MailDev.Hosting/MailDev.Hosting.csproj package Aspire.Hosting --version 9.0.0 - ``` - - > [!IMPORTANT] - > The version you specify here should match the Aspire SDK version used in your solution. - -1. Add class library reference to the _MailDevResource.AppHost_ project. - - ```dotnetcli - dotnet add ./MailDevResource.AppHost/MailDevResource.AppHost.csproj reference ./MailDev.Hosting/MailDev.Hosting.csproj - ``` - -1. Add class library project to the solution file. - - ```dotnetcli - dotnet sln ./MailDevResource.sln add ./MailDev.Hosting/MailDev.Hosting.csproj - ``` - -Once the following steps are performed, you can launch the project: - -```dotnetcli -dotnet run --project ./MailDevResource.AppHost/MailDevResource.AppHost.csproj -``` - -This results in a warning being displayed to the console: - -```Output -.\.nuget\packages\aspire.hosting.apphost\9.0.0\build\Aspire.Hosting.AppHost.targets(174,5): warning ASPIRE004: '..\MailDev.Hosting\MailDev.Hosting.csproj' is referenced by an A -spire Host project, but it is not an executable. Did you mean to set IsAspireProjectResource="false"? [D:\source\repos\docs-aspire\docs\extensibility\snippets\MailDevResource\MailDevResource.AppHost\MailDevRe -source.AppHost.csproj] -``` - -This is because Aspire treats project references in the AppHost as if they're service projects. To tell Aspire that the project reference should be treated as a nonservice project modify the _:::no-loc text="MailDevResource.AppHost\MailDevResource.AppHost.csproj":::_ files reference to the `MailDev.Hosting` project to be the following: - -```xml - - - - -``` - -Now when you launch the AppHost, there's no warning displayed to the console. - -## Define the resource types - -The _MailDev.Hosting_ class library contains the resource type and extension methods for adding the resource to the AppHost. You should first think about the experience that you want to give developers when using your custom resource. In the case of this custom resource, you would want developers to be able to write code like the following: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var maildev = builder.AddMailDev("maildev"); - -builder.AddProject("newsletterservice") - .WithReference(maildev); -``` - -To achieve this, you need a custom resource named `MailDevResource` which implements so that consumers can use it with extension to inject the connection details for the MailDev server as a connection string. - -MailDev is available as a container resource, so you'll also want to derive from so that we can make use of various pre-existing container-focused extensions in Aspire. - -Replace the contents of the _:::no-loc text="Class1.cs":::_ file in the `MailDev.Hosting` project, and rename the file to _:::no-loc text="MailDevResource.cs":::_ with the following code: - -:::code language="csharp" source="snippets/MailDevResource/MailDev.Hosting/MailDevResource.cs"::: - -In the preceding custom resource, the and are examples of several types which implement a collection of interfaces, such as , , and . For more information about these types and their role in Aspire, see [technical details](#technical-details). - -## Define the resource extensions - -To make it easy for developers to use the custom resource an extension method named `AddMailDev` needs to be added to the _:::no-loc text="MailDev.Hosting":::_ project. The `AddMailDev` extension method is responsible for configuring the resource so it can start successfully as a container. - -Add the following code to a new file named _MailDevResourceBuilderExtensions.cs_ in the _MailDev.Hosting_ project: - -:::code language="csharp" source="snippets/MailDevResource/MailDev.Hosting/MailDevResourceBuilderExtensions.cs"::: - -## Validate custom integration inside the AppHost - -Now that the basic structure for the custom resource is complete it's time to test it in a real AppHost project. Open the _:::no-loc text="AppHost.cs":::_ file in the _:::no-loc text="MailDevResource.AppHost":::_ project and update it with the following code: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var maildev = builder.AddMailDev("maildev"); - -builder.Build().Run(); -``` - -After updating the _:::no-loc text="AppHost.cs":::_ file, launch the AppHost project and open the dashboard: - -```dotnetcli -dotnet run --project ./MailDevResource.AppHost/MailDevResource.AppHost.csproj -``` - -After a few moments the dashboard shows that the `maildev` resource is running and a hyperlink will be available that navigates to the MailDev web app, which shows the content of each e-mail that your app sends. - -_The Aspire dashboard should look similar to the following:_ - -:::image type="content" source="media/maildev-in-aspire-dashboard.png" lightbox="media/maildev-in-aspire-dashboard.png" alt-text="MailDev resource visible in Aspire dashboard."::: - -_The MailDev web app should look similar to the following:_ - -:::image type="content" source="media/maildev-web-ui.png" lightbox="media/maildev-web-ui.png" alt-text="MailDev web-based user interface running as a container managed by Aspire."::: - -## Add a .NET service project to the AppHost for testing - -Once Aspire can successfully launch the MailDev integration, it's time to consume the connection information for MailDev within a .NET project. In Aspire it's common for there to be a _hosting package_ and one or more _component packages_. For example consider: - -- **Hosting package**: Used to represent resources within the app model. - - `Aspire.Hosting.Redis` -- **Component packages**: Used to configure and consume client libraries. - - `Aspire.StackExchange.Redis` - - `Aspire.StackExchange.Redis.DistributedCaching` - - `Aspire.StackExchange.Redis.OutputCaching` - -In the case of the MailDev resource, the .NET platform already has a simple mail transfer protocol (SMTP) client in the form of . In this example you use this existing API for the sake of simplicity, although other resource types may benefit from custom integration libraries to assist developers. - -In order to test the end-to-end scenario, you need a .NET project which we can inject the connection information into for the MailDev resource. Add a Web API project: - -1. Create a new .NET project named _:::no-loc text="MailDevResource.NewsletterService":::_. - - ```dotnetcli - dotnet new webapi --use-minimal-apis -o MailDevResource.NewsletterService - ``` - -1. Add a reference to the _:::no-loc text="MailDev.Hosting":::_ project. - - ```dotnetcli - dotnet add ./MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj reference ./MailDev.Hosting/MailDev.Hosting.csproj - ``` - -1. Add a reference to the _:::no-loc text="MailDevResource.AppHost":::_ project. - - ```dotnetcli - dotnet add ./MailDevResource.AppHost/MailDevResource.AppHost.csproj reference ./MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj - ``` - -1. Add the new project to the solution file. - - ```dotnetcli - dotnet sln ./MailDevResource.sln add ./MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj - ``` - -After the project has been added and references have been updated, open the _:::no-loc text="AppHost.cs":::_ of the _:::no-loc text="MailDevResource.AppHost.csproj":::_ project, and update the source file to look like the following: - -:::code source="snippets/MailDevResource/MailDevResource.AppHost/AppHost.cs"::: - -After updating the _:::no-loc text="AppHost.cs":::_ file, launch the AppHost again. Then verify that the Newsletter Service started and that the environment variable `ConnectionStrings__maildev` was added to the process. From the **Resources** page, find the `newsletterservice` row, and select the **View** link on the **Details** column: - -:::image type="content" source="media/maildev-envvar.png" lightbox="media/maildev-envvar.png" alt-text="Environment variables for Newsletter Service in Aspire Dashboard."::: - -The preceding screenshot shows the environment variables for the `newsletterservice` project. The `ConnectionStrings__maildev` environment variable is the connection string that was injected into the project by the `maildev` resource. - -## Use connection string to send messages - -To use the SMTP connection details that were injected into the newsletter service project, you inject an instance of into the dependency injection container as a singleton. Add the following code to the _:::no-loc text="Program.cs":::_ file in the _:::no-loc text="MailDevResource.NewsletterService":::_ project to set up the singleton service. In the `Program` class, immediately following the `// Add services to the container` comment, add the following code: - -:::code source="snippets/MailDevResource/MailDevResource.NewsletterService/Program.cs" id="smtp"::: - -> [!TIP] -> This code snippet relies on the official `SmtpClient`, however; this type is obsolete on some platforms and not recommended on others. For a more modern approach using [MailKit](https://github.com/jstedfast/MailKit), see [Create custom Aspire client integrations](custom-client-integration.md). - -To test the client, add two simple `subscribe` and `unsubscribe` POST methods to the newsletter service. Add the following code replacing the "weatherforecast" `MapGet` call in the _:::no-loc text="Program.cs":::_ file of the _MailDevResource.NewsletterService_ project to set up the ASP.NET Core routes: - -:::code source="snippets/MailDevResource/MailDevResource.NewsletterService/Program.cs" id="subs"::: - -> [!TIP] -> Remember to reference the `System.Net.Mail` and `Microsoft.AspNetCore.Mvc` namespaces in _:::no-loc text="Program.cs":::_ if your code editor doesn't automatically add them. - -Once the _:::no-loc text="Program.cs":::_ file is updated, launch the AppHost and use your browser, or `curl` to hit the following URLs (alternatively if you're using Visual Studio you can use `.http` files): - -```http -POST /subscribe?email=test@test.com HTTP/1.1 -Host: localhost:7251 -Content-Type: application/json -``` - -To use this API, you can use `curl` to send the request. The following `curl` command sends an HTTP `POST` request to the `subscribe` endpoint, and it expects an `email` query string value to subscribe to the newsletter. The `Content-Type` header is set to `application/json` to indicate that the request body is in JSON format.: - -## [Unix](#tab/unix) - -```bash -curl -H "Content-Type: application/json" --request POST https://localhost:7251/subscribe?email=test@test.com -``` - -## [Windows](#tab/windows) - -```powershell -curl -H @{ ContentType = "application/json" } -Method POST https://localhost:7251/subscribe?email=test@test.com -``` - ---- - -The next API is the `unsubscribe` endpoint. This endpoint is used to unsubscribe from the newsletter. - -```http -POST /unsubscribe?email=test@test.com HTTP/1.1 -Host: localhost:7251 -Content-Type: application/json -``` - -To unsubscribe from the newsletter, you can use the following `curl` command, passing an `email` parameter to the `unsubscribe` endpoint as a query string: - -## [Unix](#tab/unix) - -```bash -curl -H "Content-Type: application/json" --request POST https://localhost:7251/unsubscribe?email=test@test.com -``` - -## [Windows](#tab/windows) - -```powershell -curl -H @{ ContentType = "application/json" } -Method POST https://localhost:7251/unsubscribe?email=test@test.com -``` - ---- - -> [!TIP] -> Make sure that you replace the `https://localhost:7251` with the correct localhost port (the URL of the AppHost that you are running). - -If those API calls return a successful response (HTTP 200, Ok) then you should be able to select on the `maildev` resource the dashboard and the :::no-loc text="MailDev UI"::: will show the emails that have been sent to the SMTP endpoint. - -:::image type="content" source="media/maildev-emails.png" lightbox="media/maildev-emails.png" alt-text="E-mails visible in the MailDev UI"::: - -## Technical details - -In the following sections, various technical details are discussed which are important to understand when developing custom resources for Aspire. - -### Secure networking - -In this example, the MailDev resource is a container resource which is exposed to the host machine over HTTP and SMTP. The MailDev resource is a development tool and isn't intended for production use. To instead use HTTPS, see [MailDev: Configure HTTPS](https://github.com/maildev/maildev/blob/357a20edcd205413d3590aedb8fcd7c97563c40d/docs/https.md). - -When developing custom resources that expose network endpoints, it's important to consider the security implications of the resource. For example, if the resource is a database, it's important to ensure that the database is secure and that the connection string isn't exposed to the public internet. - -### The `ReferenceExpression` and `EndpointReference` type - -In the preceding code, the `MailDevResource` had two properties: - -- `SmtpEndpoint`: type. -- `ConnectionStringExpression`: type. - -These types are among several which are used throughout Aspire to represent configuration data, which isn't finalized until the Aspire project is either run or published to the cloud via a tool such as [Azure Developer CLI (`azd`)](/azure/developer/azure-developer-cli/overview). - -The fundamental problem that these types help to solve, is deferring resolution of concrete configuration information until _all_ the information is available. - -For example, the `MailDevResource` exposes a property called `ConnectionStringExpression` as required by the interface. The type of the property is and is created by passing in an interpolated string to the method. - -```csharp -public ReferenceExpression ConnectionStringExpression => - ReferenceExpression.Create( - $"smtp://{SmtpEndpoint.Property(EndpointProperty.HostAndPort)}" - ); -``` - -The signature for the method is as follows: - -```csharp -public static ReferenceExpression Create( - in ExpressionInterpolatedStringHandler handler) -``` - -This isn't a regular argument. The method makes use of the [interpolated string handler pattern](/dotnet/csharp/whats-new/tutorials/interpolated-string-handler), to capture the interpolated string template and the values referenced within it to allow for custom processing. In the case of Aspire, these details are captured in a which can be evaluated as each value referenced in the interpolated string becomes available. - -Here's how the flow of execution works: - -1. A resource which implements is added to the model (for example, `AddMailDev(...)`). -1. The `IResourceBuilder` is passed to the which has a special overload for handling implementors. -1. The `WithReference` wraps the resource in a instance and the object is captured in a which is evaluated after the Aspire project is built and starts running. -1. As the process that references the connection string starts Aspire starts evaluating the expression. It first gets the and calls . -1. The `GetValueAsync` method gets the value of the property to get the instance. -1. The method then calls to process the previously captured interpolated string. -1. Because the interpolated string contains references to other reference types such as they're also evaluated and real value substituted (which at this time is now available). - -### Manifest publishing - -The interface is designed to solve the problem of sharing connection information between resources at deployment. The solution for this particular problem is described in the [Aspire inner-loop networking overview](../fundamentals/networking-overview.md). Similarly to local development, many of the values are necessary to configure the app, yet they can't be determined until the app is being deployed via a tool, such as `azd` (Azure Developer CLI). - -To solve this problem [Aspire produces a manifest file](../deployment/manifest-format.md) which `azd` and other deployment tools interpret. Rather than specifying concrete values for connection information between resources an expression syntax is used which deployment tools evaluate. Generally the manifest file isn't visible to developers but it's possible to generate one for manual inspection. The command below can be used on the AppHost to produce a manifest. - -```dotnetcli -dotnet run --project MailDevResource.AppHost/MailDevResource.AppHost.csproj -- --publisher manifest --output-path aspire-manifest.json -``` - -This command produces a manifest file like the following: - -```json -{ - "resources": { - "maildev": { - "type": "container.v0", - "connectionString": "smtp://{maildev.bindings.smtp.host}:{maildev.bindings.smtp.port}", - "image": "docker.io/maildev/maildev:2.1.0", - "bindings": { - "http": { - "scheme": "http", - "protocol": "tcp", - "transport": "http", - "targetPort": 1080 - }, - "smtp": { - "scheme": "tcp", - "protocol": "tcp", - "transport": "tcp", - "targetPort": 1025 - } - } - }, - "newsletterservice": { - "type": "project.v0", - "path": "../MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj", - "env": { - "OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES": "true", - "OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES": "true", - "OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY": "in_memory", - "ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true", - "ConnectionStrings__maildev": "{maildev.connectionString}" - }, - "bindings": { - "http": { - "scheme": "http", - "protocol": "tcp", - "transport": "http" - }, - "https": { - "scheme": "https", - "protocol": "tcp", - "transport": "http" - } - } - } - } -} -``` - -Because the `MailDevResource` implements the manifest publishing logic in Aspire knows that even though `MailDevResource` is a container resource, it also needs a `connectionString` field. The `connectionString` field references other parts of the `maildev` resource in the manifest to produce the final string: - -```json -{ - // ... other content omitted. - "connectionString": "smtp://{maildev.bindings.smtp.host}:{maildev.bindings.smtp.port}" -} -``` - -Aspire knows how to form this string because it looks at and builds up the final string via the interface (in much the same way as the interface is used). - -The `MailDevResource` automatically gets included in the manifest because it's derived from . Resource authors can choose to suppress outputting content to the manifest by using the extension method on the resource builder. - -```csharp -public static IResourceBuilder AddMailDev( - this IDistributedApplicationBuilder builder, - string name, - int? httpPort = null, - int? smtpPort = null) -{ - var resource = new MailDevResource(name); - - return builder.AddResource(resource) - .WithImage(MailDevContainerImageTags.Image) - .WithImageRegistry(MailDevContainerImageTags.Registry) - .WithImageTag(MailDevContainerImageTags.Tag) - .WithHttpEndpoint( - targetPort: 1080, - port: httpPort, - name: MailDevResource.HttpEndpointName) - .WithEndpoint( - targetPort: 1025, - port: smtpPort, - name: MailDevResource.SmtpEndpointName) - .ExcludeFromManifest(); // This line was added -} -``` - -Careful consideration should be given as to whether the resource should be present in the manifest, or whether it should be suppressed. If the resource is being added to the manifest, it should be configured in such a way that it's safe and secure to use. - -## Summary - -In the custom resource tutorial, you learned how to create a custom Aspire resource which uses an existing containerized application (MailDev). You then used that to improve the local development experience by making it easy to test e-mail capabilities that might be used within an app. These learnings can be applied to building out other custom resources that can be used in Aspire-based applications. This specific example didn't include any custom integrations, but it's possible to build out custom integrations to make it easier for developers to use the resource. In this scenario you were able to rely on the existing `SmtpClient` class in the .NET platform to send e-mails. - -## Next steps - -> [!div class="nextstepaction"] -> [Create custom Aspire client integrations](custom-client-integration.md) diff --git a/docs/extensibility/dev-tunnels-integration.md b/docs/extensibility/dev-tunnels-integration.md index 995a0a4f6f..37b110d5c3 100644 --- a/docs/extensibility/dev-tunnels-integration.md +++ b/docs/extensibility/dev-tunnels-integration.md @@ -181,4 +181,4 @@ Verify that: - [Dev tunnels service documentation](/azure/developer/dev-tunnels/overview) - [Dev tunnels FAQ](/azure/developer/dev-tunnels/faq) - [Aspire service discovery](https://aspire.dev/fundamentals/service-discovery/) -- [Aspire networking overview](../fundamentals/networking-overview.md) +- [Aspire networking overview](https://aspire.dev/fundamentals/networking-overview/) diff --git a/docs/extensibility/interaction-service.md b/docs/extensibility/interaction-service.md deleted file mode 100644 index ea94045fa6..0000000000 --- a/docs/extensibility/interaction-service.md +++ /dev/null @@ -1,349 +0,0 @@ ---- -title: Interaction Service (Preview) -description: Use the interaction service API to prompt users for input, request confirmation, and display messages in the Aspire dashboard or CLI during publish and deploy. -ms.date: 09/24/2025 ---- - -# Interaction Service (Preview) - -The interaction service (`Aspire.Hosting.IInteractionService`) allows you to prompt users for input, request confirmation, and display messages. The interaction service works in two different contexts: - -- **Aspire dashboard**: When running `aspire run` or launching the AppHost directly, interactions appear as dialogs and notifications in the dashboard UI. -- **Aspire CLI**: When running `aspire publish` or `aspire deploy`, interactions are prompted through the command-line interface. - -This is useful for scenarios where you need to gather information from the user or provide feedback on the status of operations, regardless of how the application is being launched or deployed. - -## The `IInteractionService` API - -The `IInteractionService` interface is retrieved from the dependency injection container. `IInteractionService` can be injected into types created from DI or resolved from , which is usually available on a context argument passed to events. - -When you request `IInteractionService`, be sure to check if it's available for usage. If you attempt to use the interaction service when it's not available (`IInteractionService.IsAvailable` returns `false`), an exception is thrown. - -```csharp -var interactionService = serviceProvider.GetRequiredService(); -if (interactionService.IsAvailable) -{ - var result = await interactionService.PromptConfirmationAsync( - title: "Delete confirmation", - message: "Are you sure you want to delete the data?"); - - if (result.Data) - { - // Run your resource/command logic. - } -} -``` - -The interaction service has several methods that you use to interact with users or display messages. The behavior of these methods depends on the execution context: - -- **Dashboard context** (`aspire run` or direct AppHost launch): Interactions appear as modal dialogs, notifications, and form inputs in the [Aspire dashboard web interface](https://aspire.dev/dashboard/overview/). -- **CLI context** (`aspire publish` or `aspire deploy`): Interactions are prompted through the command-line interface with text-based prompts and responses. - -The following sections describe how to use these APIs effectively in both contexts: - -| Method | Description | Contexts supported | -|--|--|--| -| `PromptMessageBoxAsync` | Displays a modal dialog box with a message and buttons for user interaction. | Dashboard only | -| `PromptNotificationAsync` | Displays a non-modal notification in the dashboard as a message bar. | Dashboard only | -| `PromptConfirmationAsync` | Displays a confirmation dialog with options for the user to confirm or cancel an action. | Dashboard only | -| `PromptInputAsync` | Prompts the user for a single input value, such as text or secret. | Dashboard, CLI | -| `PromptInputsAsync` | Prompts the user for multiple input values in a single dialog (dashboard) or sequentially (CLI). | Dashboard, CLI | - -> [!IMPORTANT] -> During `aspire publish` and `aspire deploy` operations, only `PromptInputAsync` and `PromptInputsAsync` are available. Other interaction methods (`PromptMessageBoxAsync`, `PromptNotificationAsync`, and `PromptConfirmationAsync`) will throw an exception if called in CLI contexts. - -## Where to use the interaction service - -Any of the available callback-based extension methods of `IResourceBuilder` can use the interaction service to prompt users for input or confirmation. Use the interaction service in these scenarios: - -- **Custom resource types**: Gather input from users or confirm actions when you create custom resource types. - - Resource types are free to define dashboard interactions, such as prompting for user input or displaying messages. The interaction service allows you to create a more interactive experience for users when they manage resources in the Aspire dashboard or CLI. For more information, see [Create custom Aspire hosting integrations](custom-hosting-integration.md). - -- **Custom resource commands**: Add commands to resources in the Aspire dashboard or CLI. Use the interaction service to prompt users for input or confirmation when these commands run. - - When you chain a call to on a target `IResourceBuilder`, for example, your callback can use the interaction service to gather input or confirm actions. For more information, see [Custom resource commands in Aspire](../fundamentals/custom-resource-commands.md). - -- **Publish and deploy workflows**: During `aspire publish` or `aspire deploy` operations, use the interaction service to gather deployment-specific configuration and confirm destructive operations through the CLI. - -These approaches help you create interactive, user-friendly experiences for local development, dashboard interactions, and deployment workflows. - -> [!IMPORTANT] -> This article demonstrates the interaction service in the context of a `WithCommand` callback with a `FakeResource` type, but the same principles apply to other extension methods that support user interactions. -> -> For example: -> -> ```csharp -> var builder = DistributedApplication.CreateBuilder(args); -> -> builder.AddFakeResource("fake-resource") -> .WithCommand("msg-dialog", "Example Message Dialog", async context => -> { -> var interactionService = context.ServiceProvider.GetRequiredService(); -> -> // Use interaction service... -> -> return CommandResults.Success(); -> }); -> ``` -> -> For CLI specific contexts, the interaction service is retrieved from either the `PublishingContext` or `PipelineStepContext` depending on the operation being performed. - -## Display messages - -There are several ways to display messages to the user: - -- **Dialog messages**: Show important information in a dialog box. -- **Notification messages**: Display less critical information in a notification. - -> [!NOTE] -> Message display methods (`PromptMessageBoxAsync` and `PromptNotificationAsync`) are only available in dashboard contexts. These methods throw an exception if called during `aspire publish` or `aspire deploy` operations. - -### Display a dialog message box - -Dialog messages provide important information that requires user attention. - - - -The `IInteractionService.PromptMessageBoxAsync` method displays a message with customizable response options. - -:::code source="snippets/InteractionService/AppHost.MessageBoxExample.cs" id="example"::: - -**Dashboard view:** - -:::image type="content" source="media/interaction-service-message-dialog.png" lightbox="media/interaction-service-message-dialog.png" alt-text="Aspire dashboard interface showing a message dialog with a title, message, and buttons."::: - -**CLI view:** - -The `PromptMessageBoxAsync` method only works in the dashboard context. If you call it during `aspire publish` or `aspire deploy`, the method throws an exception and doesn't display a message in the CLI. - -### Display a notification message - -Notification messages provide non-modal notifications. - -> [!TIP] -> In the dashboard, notification messages appear stacked at the top, so you can show several messages at once. You can display notifications one after another by awaiting each dismissal before showing the next. Or, you can display multiple notifications at the same time without waiting for each to be dismissed. - -The method displays informational messages with optional action links in the dashboard context. You don't have to await the result of a notification message if you don't need to. This is especially useful for notifications, since you might want to display a notification and continue without waiting for user to dismiss it. - -:::code source="snippets/InteractionService/AppHost.NotificationExample.cs" id="example"::: - -The previous example demonstrates several ways to use the notification API. Each approach displays different types of notifications, all of which are invoked in parallel and displayed in the dashboard around the same time. - -**Dashboard view:** - -:::image type="content" source="media/interaction-service-message-bar.png" lightbox="media/interaction-service-message-bar.png" alt-text="Aspire dashboard interface showing multiple notification messages stacked near the top of the page. There are five notifications displayed, each with a different type of notification."::: - -**CLI view:** - -The `PromptNotificationAsync` method isn't available in CLI contexts. If you call it during `aspire publish` or `aspire deploy`, it throws an exception. - -## Prompt for user confirmation - -Use the interaction service when you need the user to confirm an action before proceeding. The method displays a confirmation prompt in the dashboard context. Confirmation prompts are essential for destructive operations or actions that have significant consequences. They help prevent accidental actions and give users a chance to reconsider their decisions. - -### Prompt for confirmation before destructive operations - -For operations that can't be undone, such as deleting resources, always prompt for confirmation: - -:::code source="snippets/InteractionService/AppHost.ConfirmationExample.cs" id="example"::: - -**Dashboard view:** - -:::image type="content" source="media/interaction-service-confirmation.png" lightbox="media/interaction-service-confirmation.png" alt-text="Aspire dashboard interface showing a confirmation dialog with a title, message, and buttons for confirming or canceling the operation."::: - -**CLI view:** - -The `PromptConfirmationAsync` method isn't available in CLI contexts. If you call it during `aspire publish` or `aspire deploy`, the method throws an exception. - -## Prompt for user input - -The interaction service API allows you to prompt users for input in various ways. You can collect single values or multiple values, with support for different input types including text, secrets, choices, booleans, and numbers. The presentation adapts automatically to the execution context. - -| Type | Dashboard | CLI prompt | -|--------------|---------------------------|-----------------------| -| `Text` | Textbox | Text prompt | -| `SecretText` | Textbox with masked input | Masked text prompt | -| `Choice` | Dropdown box of options | Choice prompt | -| `Boolean` | Checkbox | Boolean choice prompt | -| `Number` | Number textbox | Text prompt | - -### Prompt the user for input values - -You can prompt for a single value using the method, or collect multiple pieces of information with `IInteractionService.PromptInputsAsync`. In the dashboard, multiple inputs appear together in a single dialog. In the CLI, each input is requested one after another. - -> [!IMPORTANT] -> It's possible to create wizard-like flows using the interaction service. By chaining multiple prompts togetherβ€”handling the results from one prompt before moving to the nextβ€”you can guide users through a series of related questions, making it easier to collect all the necessary information. - -Consider the following example, which prompts the user for multiple input values: - -:::code source="snippets/InteractionService/AppHost.MultipleInputExample.cs" id="example"::: - -**Dashboard view:** - -This renders on the dashboard as shown in the following image: - -:::image type="content" source="media/interaction-service-multiple-input.png" lightbox="media/interaction-service-multiple-input.png" alt-text="Aspire dashboard interface showing a multiple input dialog with labels, input fields, and buttons for confirming or canceling the input."::: - -Imagine you fill out the dialog with the following values: - -:::image type="content" source="media/interaction-service-multiple-input-filled.png" lightbox="media/interaction-service-multiple-input-filled.png" alt-text="Aspire dashboard interface showing a multiple input dialog with filled input fields and buttons for confirming or canceling the input."::: - -After you select the **Ok** button, the resource logs display the following output: - -:::image type="content" source="media/interaction-service-multiple-input-logs.png" lightbox="media/interaction-service-multiple-input-logs.png" alt-text="Aspire dashboard interface showing logs with the input values entered in the multiple input dialog."::: - -**CLI view:** - -In the CLI context, the same inputs are requested sequentially: - -```Aspire -aspire deploy - -Step 1: Analyzing model. - - βœ“ DONE: Analyzing the distributed application model for publishing and deployment capabilities. 00:00:00 - Found 1 resources that support deployment. (FakeResource) - -βœ… COMPLETED: Analyzing model. completed successfully - -═══════════════════════════════════════════════════════════════════════════════════════════════════════════════ - -Configure your application deployment settings: -Application Name: example-app -Environment: Staging -Instance Count: 3 -Enable Monitoring: [y/n] (n): y -βœ“ DEPLOY COMPLETED: Deploying completed successfully -``` - -Depending on the input type, the CLI might display additional prompts. For example, the `Enable Monitoring` input is a boolean choice, so the CLI prompts for a yes/no response. If you enter `y`, it enables monitoring; if you enter `n`, it disables monitoring. For the environment input, the CLI displays a list of available environments for selection: - -```Aspire -Configure your application deployment settings: -Application Name: example-app -Environment: - -> Development - Staging - Testing - -(Type to search) -``` - -#### Input validation - -Basic input validation is available by configuring . It provides options for requiring a value, or the maximum text length of `Text` or `SecretText` fields. - -For complex scenarios, you can provide custom validation logic using the property: - -```csharp -// Multiple inputs with custom validation -var databaseInputs = new List -{ - new() - { - Name = "Database Name", - InputType = InputType.Text, - Required = true, - Placeholder = "myapp-db" - }, - new() - { - Name = "Username", - InputType = InputType.Text, - Required = true, - Placeholder = "admin" - }, - new() - { - Name = "Password", - InputType = InputType.SecretText, - Required = true, - Placeholder = "Enter a strong password" - }, - new() - { - Name = "Confirm password", - InputType = InputType.SecretText, - Required = true, - Placeholder = "Confirm your password" - } -}; - -var validationOptions = new InputsDialogInteractionOptions -{ - ValidationCallback = async context => - { - var passwordInput = context.Inputs.FirstOrDefault(i => i.Label == "Password"); - var confirmPasswordInput = context.Inputs.FirstOrDefault(i => i.Label == "Confirm password"); - - // Validate password strength - if (passwordInput?.Value is { Length: < 8 }) - { - context.AddValidationError(passwordInput, "Password must be at least 8 characters long"); - } - - // Validate password confirmation - if (passwordInput?.Value != confirmPasswordInput?.Value) - { - context.AddValidationError(confirmPasswordInput!, "Passwords do not match"); - } - - await Task.CompletedTask; - } -}; - -var dbResult = await interactionService.PromptInputsAsync( - title: "Database configuration", - message: "Configure your PostgreSQL database connection:", - inputs: databaseInputs, - options: validationOptions); - -if (!dbResult.Canceled && dbResult.Data != null) -{ - // Use the validated configuration -} -``` - -Prompting the user for a password and confirming they match is referred to as "dual independent verification" input. This approach is common in scenarios where you want to ensure the user enters the same password twice to avoid typos or mismatches. - -### Best practices for user input - -When prompting for user input, consider these best practices: - -1. **Group related inputs**: Use multiple input prompts to collect related configuration values. In the dashboard, these appear in a single dialog; in the CLI, they're requested sequentially but grouped conceptually. -1. **Provide clear labels and placeholders**: Help users understand what information is expected, regardless of context. -1. **Use appropriate input types**: Choose the right input type for the data you're collecting (secret for passwords, choice for predefined options, etc.). Both contexts support these input types appropriately. -1. **Implement validation**: Validate user input and provide clear error messages when validation fails. Both contexts support validation feedback. -1. **Make required fields clear**: Mark required fields and provide appropriate defaults for optional ones. -1. **Handle cancellation**: Always check if the user canceled the input prompt and handle it gracefully. Users can cancel in both dashboard and CLI contexts. - -## Interaction contexts - -The interaction service behaves differently depending on how your Aspire solution is launched: - -### Dashboard context - -When you run your application using `aspire run` or by directly launching the AppHost project, interactions appear in the Aspire dashboard web interface: - -- **Modal dialogs**: Message boxes and input prompts appear as overlay dialogs that require user interaction. -- **Notification messages**: Informational messages appear as dismissible banners at the top of the dashboard. -- **Rich UI**: Full support for interactive form elements, validation, and visual feedback. -- **All methods available**: All interaction service methods are supported in dashboard contexts. - -### CLI context - -When you run `aspire publish` or `aspire deploy`, interactions are prompted through the command-line interface: - -- **Text prompts**: Only input prompts (`PromptInputAsync` and `PromptInputsAsync`) are available and appear as text-based prompts in the terminal. -- **Sequential input**: Multiple inputs are requested one at a time rather than in a single dialog. -- **Limited functionality**: Message boxes, notifications, and confirmation dialogs aren't available and throws exceptions if called. - -> [!IMPORTANT] -> The interaction service adapts automatically to dashboard and CLI contexts. In CLI mode, only input-related methodsβ€”`PromptInputAsync` and `PromptInputsAsync`β€”are supported. Calling `PromptMessageBoxAsync`, `PromptNotificationAsync`, or `PromptConfirmationAsync` in CLI operations like `aspire publish` or `aspire deploy` results in an exception. - -## See also - -- -- [Aspire extensibility overview](../extensibility/custom-hosting-integration.md) diff --git a/docs/extensibility/secure-communication-between-integrations.md b/docs/extensibility/secure-communication-between-integrations.md deleted file mode 100644 index 6511d8275f..0000000000 --- a/docs/extensibility/secure-communication-between-integrations.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: Secure communication between hosting and client integrations -description: Learn how to Secure communication between hosting and client integrations. -ms.date: 09/12/2024 -ms.topic: how-to -ms.custom: sfi-ropc-nochange ---- - -# Secure communication between hosting and client integrations - -This article is a continuation of two previous articles demonstrating the creation of [custom hosting integrations](custom-hosting-integration.md) and [custom client integrations](custom-client-integration.md). - -One of the primary benefits to Aspire is how it simplifies the configurability of resources and consuming clients (or integrations). This article demonstrates how to share authentication credentials from a custom resource in a hosting integration, to the consuming client in a custom client integration. The custom resource is a MailDev container that allows for either incoming or outgoing credentials. The custom client integration is a MailKit client that sends emails. - -## Prerequisites - -Since this article continues from previous content, you should have already created the resulting solution as a starting point for this article. If you haven't already, complete the following articles: - -- [Create custom Aspire hosting integrations](custom-hosting-integration.md) -- [Create custom Aspire client integrations](custom-client-integration.md) - -The resulting solution from these previous articles contains the following projects: - -- _MailDev.Hosting_: Contains the custom resource type for the MailDev container. -- _MailDevResource.AppHost_: The [AppHost](../fundamentals/app-host-overview.md) that uses the custom resource and defines it as a dependency for a Newsletter service. -- _MailDevResource.NewsletterService_: An ASP.NET Core Web API project that sends emails using the MailDev container. -- _MailDevResource.ServiceDefaults_: Contains the [default service configurations](https://aspire.dev/fundamentals/service-defaults/) intended for sharing. -- _MailKit.Client_: Contains the custom client integration that exposes the MailKit `SmtpClient` through a factory. - -## Update the MailDev resource - -To flow authentication credentials from the MailDev resource to the MailKit integration, you need to update the MailDev resource to include the username and password parameters. - -The MailDev container supports basic authentication for both incoming and outgoing simple mail transfer protocol (SMTP). To configure the credentials for incoming, you need to set the `MAILDEV_INCOMING_USER` and `MAILDEV_INCOMING_PASS` environment variables. For more information, see [MailDev: Usage](https://maildev.github.io/maildev/#usage). Update the _MailDevResource.cs_ file in the `MailDev.Hosting` project, by replacing its contents with the following C# code: - -:::code source="snippets/MailDevResourceWithCredentials/MailDev.Hosting/MailDevResource.cs" highlight="9-10"::: - -These updates add a `UsernameParameter` and `PasswordParameter` property. These properties are used to store the parameters for the MailDev username and password. The `ConnectionStringExpression` property is updated to include the username and password parameters in the connection string. Next, update the _MailDevResourceBuilderExtensions.cs_ file in the `MailDev.Hosting` project with the following C# code: - -:::code source="snippets/MailDevResourceWithCredentials/MailDev.Hosting/MailDevResourceBuilderExtensions.cs" highlight="9-10,29-30,32-34,40-41,55-59"::: - -The preceding code updates the `AddMailDev` extension method to include the `userName` and `password` parameters. The `WithEnvironment` method is updated to include the `UserEnvVarName` and `PasswordEnvVarName` environment variables. These environment variables are used to set the MailDev username and password. - -## Update the AppHost - -Now that the resource is updated to include the username and password parameters, you need to update the AppHost to include these parameters. Update the _:::no-loc text="AppHost.cs":::_ file in the `MailDevResource.AppHost` project with the following C# code: - -:::code source="snippets/MailDevResourceWithCredentials/MailDevResource.AppHost/AppHost.cs" highlight="3-4,6-9"::: - -The preceding code adds two parameters for the MailDev username and password. It assigns these parameters to the `MAILDEV_INCOMING_USER` and `MAILDEV_INCOMING_PASS` environment variables. The `AddMailDev` method has two chained calls to `WithEnvironment` which includes these environment variables. For more information on parameters, see [External parameters](../fundamentals/external-parameters.md). - -Next, configure the secrets for these parameters. Right-click on the `MailDevResource.AppHost` project and select `Manage User Secrets`. Add the following JSON to the _secrets.json_ file: - -```json -{ - "Parameters:maildev-username": "@admin", - "Parameters:maildev-password": "t3st1ng" -} -``` - -> [!WARNING] -> These credentials are for demonstration purposes only and MailDev is intended for local development. These credentials are fictitious and shouldn't be used in a production environment. - -## Update the MailKit integration - -It's good practice for client integrations to expect connection strings to contain various key/value pairs, and to parse these pairs into the appropriate properties. Update the _MailKitClientSettings.cs_ file in the `MailKit.Client` project with the following C# code: - -:::code source="snippets/MailDevResourceWithCredentials/MailKit.Client/MailKitClientSettings.cs" highlight="21-28,95-100"::: - -The preceding settings class, now includes a `Credentials` property of type `NetworkCredential`. The `ParseConnectionString` method is updated to parse the `Username` and `Password` keys from the connection string. If the `Username` and `Password` keys are present, a `NetworkCredential` is created and assigned to the `Credentials` property. - -With the settings class updated to understand and populate the credentials, update the factory to conditionally use the credentials if they're configured. Update the _MailKitClientFactory.cs_ file in the `MailKit.Client` project with the following C# code: - -:::code source="snippets/MailDevResourceWithCredentials/MailKit.Client/MailKitClientFactory.cs" highlight="44-48"::: - -When the factory determines that credentials have been configured, it authenticates with the SMTP server after connecting before returning the `SmtpClient`. - -## Run the sample - -Now that you've updated the resource, corresponding integration projects, and the AppHost, you're ready to run the sample app. To run the sample from your IDE, select F5 or use `dotnet run` from the root directory of the solution to start the applicationβ€”you should see the [Aspire dashboard](https://aspire.dev/dashboard/overview/). Navigate to the `maildev` container resource and view the details. You should see the username and password parameters in the resource details, under the **Environment Variables** section: - -:::image type="content" source="media/maildev-details.png" lightbox="media/maildev-details.png" alt-text="Aspire Dashboard: MailDev container resource details."::: - -Likewise, you should see the connection string in the `newsletterservice` resource details, under the **Environment Variables** section: - -:::image type="content" source="media/newsletter-details.png" lightbox="media/newsletter-details.png" alt-text="Aspire Dashboard: Newsletter service resource details."::: - -Validate that everything is working as expected. - -## Summary - -This article demonstrated how to flow authentication credentials from a custom resource to a custom client integration. The custom resource is a MailDev container that allows for either incoming or outgoing credentials. The custom client integration is a MailKit client that sends emails. By updating the resource to include the `username` and `password` parameters, and updating the integration to parse and use these parameters, authentication flows credentials from the hosting integration to the client integration. diff --git a/docs/fundamentals/annotations-overview.md b/docs/fundamentals/annotations-overview.md deleted file mode 100644 index aa8a08682f..0000000000 --- a/docs/fundamentals/annotations-overview.md +++ /dev/null @@ -1,266 +0,0 @@ ---- -title: Resource annotations -description: Learn about annotations in Aspire, how they work, and how to create custom annotations for extending resource behavior. -ms.date: 07/25/2025 ---- - -# Resource annotations in Aspire - -Annotations are a key extensibility mechanism in Aspire that allow you to attach metadata and behavior to resources. They provide a way to customize how resources are configured, deployed, and managed throughout the application lifecycle. This article explains how annotations work and how to use them effectively in your Aspire applications. - -## What are annotations - -Annotations in Aspire are objects that implement the interface. They're attached to resources to provide additional metadata, configuration, or behavior. Annotations are consumed by various parts of the Aspire stack, including: - -- The dashboard for displaying custom URLs and commands. -- Deployment tools for generating infrastructure as code. -- The hosting layer for configuring runtime behavior. -- Testing infrastructure for resource inspection. - -Every annotation is associated with a specific resource and can contain any data or behavior needed to extend that resource's functionality. - -## How annotations work - -When you add a resource to your app model, you can attach annotations using various extension methods. These annotations are stored with the resource and can be retrieved and processed by different components of the system. - -Here's a simple example of how annotations are used: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var redis = builder.AddRedis("cache") - .WithCommand("clear-cache", "Clear Cache", - async context => new ExecuteCommandResult { Success = true }) - .WithUrl("admin", "http://localhost:8080/admin"); - -builder.Build().Run(); -``` - -In this example: - -- adds a that defines a custom command. -- adds a that defines a custom URL. - -## Built-in annotation types - -Aspire includes many built-in annotation types for common scenarios. This section covers _some_ of the more commonly used annotations, but there are [_many more_](xref:Aspire.Hosting.ApplicationModel.IResourceAnnotation) available for specific use cases. - -### `EndpointAnnotation` - -The defines network endpoints for resources. It contains information about ports, protocols, and endpoint configuration. - -```csharp -var api = builder.AddProject("api") - .WithEndpoint(callback: endpoint => - { - endpoint.Port = 5000; - endpoint.IsExternal = true; - endpoint.Protocol = Protocol.Tcp; - endpoint.Transport = "http"; - }); -``` - -### `ResourceUrlAnnotation` - -The defines custom URLs that appear in the dashboard, often pointing to management interfaces or documentation. - -```csharp -var database = builder.AddPostgres("postgres") - .WithUrl("admin", "https://localhost:5050"); -``` - -### `EnvironmentCallbackAnnotation` - -The allows you to modify environment variables at runtime based on the state of other resources. - -```csharp -// This is typically used internally by WithReference -var app = builder.AddProject("app") - .WithReference(database); -``` - -### `ContainerMountAnnotation` - -The `ContainerMountAnnotation` defines volume mounts for containerized resources. - -```csharp -var postgres = builder.AddPostgres("postgres") - .WithDataVolume(); // Adds a ContainerMountAnnotation -``` - -### `PublishingCallbackAnnotation` - -The allows you to register callbacks that execute during the publishing process. This is useful for performing custom operations when resources are being published. - -```csharp -var api = builder.AddProject("api") - .WithPublishingCallback(async context => - { - // Custom logic during publishing - await CustomPublishLogicAsync(context); - }); -``` - -For more information, see . - -### `DeployingCallbackAnnotation` - - - -The `DeployingCallbackAnnotation` allows you to register callbacks that execute during the deployment process. This annotation is used internally by deployment tools to customize resource deployment behavior. - -```csharp -var api = builder.AddProject("api"); - -api.Resource.Annotations.Add( - new DeployingCallbackAnnotation(async context => - { - // Custom deployment logic - await ConfigureDeploymentAsync(context); - }); -); -``` - -For more information about publishing and deploying Aspire apps, see [publishing and deploying](../deployment/overview.md). - -## Creating custom annotations - -Custom annotations in Aspire are designed to capture resource-specific metadata and behavior that can be leveraged throughout the application lifecycle. They're commonly used by: - -- **Extension methods** to infer user intent and configure resource behavior. -- **Deployment tools** to generate deployment-specific configuration. -- **Lifecycle hooks** to query the app model and make runtime decisions. -- **Development tools** like the dashboard to display resource information. - -Custom annotations should focus on a single concern and provide clear value to consumers of the resource metadata. - -### 1. Define the annotation class - -Start by creating a class that implements `IResourceAnnotation`. Focus on capturing specific metadata that other components need to reason about your resource: - -:::code source="snippets/annotations-overview/Program.cs" id="ServiceMetricsAnnotation"::: - -### 2. Create extension methods - -Create fluent extension methods that follow Aspire's builder pattern. These methods should make it easy for AppHost authors to configure your annotation: - -:::code source="snippets/annotations-overview/Program.cs" id="ServiceMetricsExtensions"::: - -The extension methods serve as the primary API surface for your annotation. They should: - -- Follow naming conventions (start with `With` for additive operations). -- Provide sensible defaults. -- Return the builder for method chaining. -- Include comprehensive XML documentation. - -### 3. Use the custom annotation - -Once defined, annotations integrate seamlessly into the AppHost model: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var api = builder.AddProject("api") - .WithMetrics("/api/metrics", 9090, "environment:production", "service:api"); -``` - -## Testing with annotations - -When writing tests, you can inspect annotations to verify resource configuration: - -```csharp -[Fact] -public async Task Resource_Should_Have_Expected_Annotations() -{ - var appHost = await DistributedApplicationTestingBuilder - .CreateAsync(); - - await using var app = await appHost.BuildAsync(); - - var resource = app.Resources.GetResource("my-resource"); - - // Assert that specific annotations exist - Assert.NotEmpty(resource.Annotations.OfType()); - - // Assert annotation properties - var metricsConfig = resource.Annotations - .OfType() - .First(); - - Assert.True(metricsConfig.Enabled); - Assert.Equal("/metrics", metricsConfig.MetricsPath); -} -``` - -For more information, see [Testing with Aspire](https://aspire.dev/testing/overview/). - -## Best practices - -When working with annotations, consider these best practices: - -### Use meaningful names - -Choose descriptive names for your annotation classes and properties: - -```csharp -// Good -public sealed class DatabaseConnectionPoolAnnotation : IResourceAnnotation - -// Avoid -public sealed class DbAnnotation : IResourceAnnotation -``` - -### Follow the builder pattern - -Create fluent extension methods that follow Aspire's builder pattern: - -```csharp -var resource = builder.AddMyResource("name") - .WithCustomBehavior() - .WithAnotherFeature(); -``` - -### Document your annotations - -Provide XML documentation for custom annotations and extension methods: - -```csharp -/// -/// Configures custom caching behavior for the resource. -/// -/// The resource builder. -/// The time-to-live for cached items. -/// The resource builder for chaining. -public static IResourceBuilder WithCaching( - this IResourceBuilder builder, - TimeSpan ttl) - where T : class, IResource { /*...*/ } -``` - -### Keep annotations simple - -Annotations should be focused on a single responsibility: - -```csharp -// Good - single responsibility -public sealed class RetryPolicyAnnotation : IResourceAnnotation -{ - public int MaxRetries { get; set; } - public TimeSpan Delay { get; set; } -} - -// Avoid - multiple responsibilities -public sealed class ConfigAnnotation : IResourceAnnotation -{ - public RetryPolicy RetryPolicy { get; set; } - public LoggingSettings Logging { get; set; } - public SecuritySettings Security { get; set; } -} -``` - -## Next steps - -- Learn about [custom resource commands](custom-resource-commands.md) -- Explore [custom resource URLs](custom-resource-urls.md) -- See [create custom hosting integrations](../extensibility/custom-hosting-integration.md) -- Review the [Aspire app model API reference](/dotnet/api/aspire.hosting.applicationmodel) diff --git a/docs/fundamentals/app-host-overview.md b/docs/fundamentals/app-host-overview.md deleted file mode 100644 index 5b06d29395..0000000000 --- a/docs/fundamentals/app-host-overview.md +++ /dev/null @@ -1,383 +0,0 @@ ---- -title: Aspire orchestration overview -description: Learn the fundamental concepts of Aspire orchestration and explore the various APIs for adding resources and expressing dependencies. -ms.date: 10/01/2025 -ms.topic: overview -uid: dotnet/aspire/app-host -ms.custom: - - sfi-image-nochange - - sfi-ropc-nochange ---- - -# Aspire orchestration overview - -Aspire provides APIs for expressing resources and dependencies within your distributed application. In addition to these APIs, [there's tooling](setup-tooling.md#install-aspire-prerequisites) that enables several compelling scenarios. The orchestrator is intended for _local development_ purposes and isn't supported in production environments. - - - -Before continuing, consider some common terminology used in Aspire: - -- **App model**: A collection of resources that make up your distributed application (), defined within the namespace. For a more formal definition, see [Define the app model](#define-the-app-model). -- **AppHost/Orchestrator project**: The .NET project that orchestrates the _app model_, named with the _*.AppHost_ suffix (by convention). -- **Resource**: A [resource](#built-in-resource-types) is a dependent part of an application, such as a .NET project, container, executable, database, cache, or cloud service. It represents any part of the application that can be managed or referenced. -- **Integration**: An integration is a NuGet package for either the _AppHost_ that models a _resource_ or a package that configures a client for use in a consuming app. For more information, see [Aspire integrations overview](integrations-overview.md). -- **Reference**: A reference defines a connection between resources, expressed as a dependency using the API. For more information, see [Reference resources](#reference-resources) or [Reference existing resources](#reference-existing-resources). - -> [!NOTE] -> Aspire's orchestration is designed to enhance your _local development_ experience by simplifying the management of your cloud-native app's configuration and interconnections. While it's an invaluable tool for development, it's not intended to replace production environment systems like [Kubernetes](../deployment/overview.md#deploy-to-kubernetes), which are specifically designed to excel in that context. - -## Define the app model - -Aspire enables you to efficiently build, provision, deploy, configure, test, run, and monitor your distributed applications. These capabilities are powered by an _app model_, which defines the resources in your Aspire solution and their interconnections. - -The app model is more than just a list of resourcesβ€”it represents the complete topology of your application. This includes the relationships between resources, their dependencies, and their configurations. Resources can include projects, executables, containers, external services, and cloud resources that your application relies on. - -In your [Aspire AppHost project](#apphost-project), your `Program` file defines your app model: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -// Add resources to the app model - -builder.Build().Run(); -``` - -When you call , you get an instance of , which is used to configure your app model. This builder provides methods to add resources, define dependencies, and set up the overall structure of your application. After you've added resources, call `Build` to create the app model. The [templates](../fundamentals/aspire-sdk-templates.md) include code that chains a call to β€”which returns an instance, and then calls . - -## AppHost project - -The AppHost project handles running all of the projects that are part of the Aspire project. In other words, it's responsible for orchestrating all apps within the app model. The project itself is a .NET executable project that uses the [Aspire SDK](dotnet-aspire-sdk.md). Starting with Aspire 13.0, the `Aspire.AppHost.Sdk` can be set as the sole project SDK, which implicitly adds a package reference to the [πŸ“¦ Aspire.Hosting.AppHost](https://www.nuget.org/packages/Aspire.Hosting.AppHost) NuGet package: - -```xml - - - - Exe - net10.0 - - - - - - -``` - -> [!NOTE] -> The alternative approach of explicitly listing the SDK and package reference still works and isn't a requirement to change existing projects: -> -> ```xml -> -> -> -> -> -> Exe -> net10.0 -> -> -> -> -> -> -> -> -> -> -> ``` - -The following code describes an AppHost `Program` with two project references and a Redis cache: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var cache = builder.AddRedis("cache"); - -var apiservice = builder.AddProject("apiservice"); - -builder.AddProject("webfrontend") - .WithExternalHttpEndpoints() - .WithReference(cache) - .WaitFor(cache) - .WithReference(apiService) - .WaitFor(apiService); - -builder.Build().Run(); -``` - -The preceding code: - -- Creates a new app model builder using the method. -- Adds a Redis `cache` resource named "cache" using the method. -- Adds a project resource named "apiservice" using the method. -- Adds a project resource named "webfrontend" using the method. - - Specifies that the project has external HTTP endpoints using the method. - - Adds a reference to the `cache` resource and waits for it to be ready using the and methods. - - Adds a reference to the `apiservice` resource and waits for it to be ready using the and methods. -- Builds and runs the app model using the and methods. - -The example code uses the [Aspire Redis hosting integration](https://aspire.dev/integrations/caching/redis/#hosting-integration). - -To help visualize the relationship between the AppHost project and the resources it describes, consider the following diagram: - -:::image type="content" source="../media/app-host-resource-diagram.png" lightbox="../media/app-host-resource-diagram.png" alt-text="The relationship between the projects in the Aspire Starter Application template."::: - -Each resource must be uniquely named. This diagram shows each resource and the relationships between them. The container resource is named "cache" and the project resources are named "apiservice" and "webfrontend". The web frontend project references the cache and API service projects. When you're expressing references in this way, the web frontend project is saying that it depends on these two resources, the "cache" and "apiservice" respectively. - -## Built-in resource types - -Aspire projects are made up of a set of resources. The primary base resource types in the [πŸ“¦ Aspire.Hosting.AppHost](https://www.nuget.org/packages/Aspire.Hosting.AppHost) NuGet package are described in the following table: - -| Method | Resource type | Description | -|--|--|--| -| | | A .NET project, for example, an ASP.NET Core web app. | -| `AddCSharpApp` | `CSharpAppResource` | A C# project or file-based app, for example, a _*.cs_ file, _*.csproj_ file, or project directory. | -| | | A container image, such as a Docker image. | -| | | An executable file, such as a [Node.js app](../get-started/build-aspire-apps-with-nodejs.md). | -| | | A parameter resource that can be used to [express external parameters](external-parameters.md). | - - - -Project resources represent .NET projects that are part of the app model. When you add a project reference to the AppHost project, the Aspire SDK generates a type in the `Projects` namespace for each referenced project. For more information, see [Aspire SDK: Project references](dotnet-aspire-sdk.md#project-references). Alternatively, you can add C# projects or file-based apps without a project reference using the `AddCSharpApp` method. - -To add a project to the app model, use the method: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -// Adds the project "apiservice" of type "Projects.AspireApp_ApiService". -var apiservice = builder.AddProject("apiservice"); -``` - -Projects can be replicated and scaled out by adding multiple instances of the same project to the app model. To configure replicas, use the method: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -// Adds the project "apiservice" of type "Projects.AspireApp_ApiService". -var apiservice = builder.AddProject("apiservice") - .WithReplicas(3); -``` - -The preceding code adds three replicas of the "apiservice" project resource to the app model. For more information, see [Aspire dashboard: Resource replicas](https://aspire.dev/dashboard/explore/#resource-replicas). - -C# app resources represent C# projects or file-based apps that are part of the app model. Unlike , which requires a project reference, the `AddCSharpApp` method can add C# projects or file-based apps using a path to a _*.cs_ file, _*.csproj_ file, or project directory. This is useful for adding file-based apps introduced in .NET 10 or for including projects without adding a project reference to the AppHost. - -To add a C# app to the app model, use the `AddCSharpApp` method: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -// Adds a file-based C# app "inventoryservice" from a .cs file. -var inventoryService = builder.AddCSharpApp("inventoryservice", @"..\InventoryService.cs"); - -// Adds a C# project "catalogservice" from a project directory. -var catalogService = builder.AddCSharpApp("catalogservice", @"..\CatalogService"); -``` - -The `AddCSharpApp` method supports the same configuration options as , including replicas, environment variables, and resource dependencies. - -> [!NOTE] -> The `AddCSharpApp` method is marked as experimental and requires .NET 10 SDK for file-based C# app support. For more information on file-based apps, see the [What's new in Aspire 9.5](../whats-new/dotnet-aspire-9.5.md#file-based-apphost-support-preview) documentation. - -## Reference resources - -A reference represents a dependency between resources. For example, you can probably imagine a scenario where a web frontend depends on a Redis cache. Consider the following example AppHost `Program` C# code: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var cache = builder.AddRedis("cache"); - -builder.AddProject("webfrontend") - .WithReference(cache); -``` - -The "webfrontend" project resource uses to add a dependency on the "cache" container resource. These dependencies can represent connection strings or [service discovery](https://aspire.dev/fundamentals/service-discovery/) information. In the preceding example, an environment variable is _injected_ into the "webfrontend" resource with the name `ConnectionStrings__cache`. This environment variable contains a connection string that the `webfrontend` uses to connect to Redis via the [Aspire Redis integration](https://aspire.dev/integrations/caching/redis/), for example, `ConnectionStrings__cache="localhost:62354"`. - -### Connection string and endpoint references - -It's common to express dependencies between project resources. Consider the following example code: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var cache = builder.AddRedis("cache"); - -var apiservice = builder.AddProject("apiservice"); - -builder.AddProject("webfrontend") - .WithReference(cache) - .WithReference(apiservice); -``` - -Project-to-project references are handled differently than resources that have well-defined connection strings. Instead of connection string being injected into the "webfrontend" resource, environment variables to support service discovery are injected. - -| Method | Environment variable | -|--|--| -| `WithReference(cache)` | `ConnectionStrings__cache="localhost:62354"` | -| `WithReference(apiservice)` | `APISERVICE_HTTP="http://localhost:5455"`
`APISERVICE_HTTPS="https://localhost:7356"`
`services__apiservice__http__0="http://localhost:5455"`
`services__apiservice__https__0="https://localhost:7356"` | - -Adding a reference to the "apiservice" project results in service discovery environment variables being added to the frontend. This is because typically, project-to-project communication occurs over HTTP/gRPC. - -Aspire injects two types of environment variables for service references: - -- **Simplified format** (e.g., `APISERVICE_HTTP`): Uses the pattern `{RESOURCENAME}_{ENDPOINTNAME}` in uppercase. This format is simpler and more suitable for non-.NET languages and polyglot scenarios. -- **.NET service discovery format** (e.g., `services__apiservice__http__0`): Uses the pattern `services__{servicename}__{endpointname}__{index}` in lowercase. This format is used by .NET's configuration-based service discovery. - -For more information, see [Aspire service discovery](https://aspire.dev/fundamentals/service-discovery/). - -To get specific endpoints from a or an , use one of the following endpoint APIs: - -- -- -- - -Then call the API to get the endpoint which can be used to reference the endpoint in the method: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var customContainer = builder.AddContainer("myapp", "mycustomcontainer") - .WithHttpEndpoint(port: 9043, name: "endpoint"); - -var endpoint = customContainer.GetEndpoint("endpoint"); - -var apiservice = builder.AddProject("apiservice") - .WithReference(endpoint); -``` - -| Method | Environment variable | -|---------------------------|-------------------------------------------------------| -| `WithReference(endpoint)` | `MYAPP_ENDPOINT="https://localhost:9043"`
`services__myapp__endpoint__0="https://localhost:9043"` | - -The `port` parameter is the port that the container is listening on. For more information on container ports, see [Container ports](networking-overview.md#container-ports). For more information on service discovery, see [Aspire service discovery](https://aspire.dev/fundamentals/service-discovery/). - -### Service endpoint environment variable format - -In the preceding section, the method is used to express dependencies between resources. When service endpoints result in environment variables being injected into the dependent resource, the format might not be obvious. This section provides details on the available formats. - -When one resource depends on another resource, the AppHost injects environment variables into the dependent resource. These environment variables configure the dependent resource to connect to the resource it depends on. Aspire provides two environment variable formats to support different scenarios: - -#### Simplified format (polyglot-friendly) - -The simplified format uses the pattern `{RESOURCENAME}_{ENDPOINTNAME}` in uppercase. This format is easier to use from non-.NET languages and is recommended for polyglot scenarios. - -Consider the following environment variable examples: - -```Environment -APISERVICE_HTTP -APISERVICE_HTTPS -``` - -The preceding environment variables express HTTP and HTTPS endpoints for the `apiservice` service. A named endpoint might be expressed as follows: - -```Environment -APISERVICE_MYENDPOINT -``` - -In the preceding example, the `apiservice` service has a named endpoint called `myendpoint`. - -> [!NOTE] -> The environment variable name is based on the resource name, not the optional connection name parameter. Even when using `WithReference(resource, "customname")` to specify a custom connection name, the generated environment variables still use the resource's name (e.g., `APISERVICE_HTTP`), not the custom name. - -#### .NET service discovery format - -The .NET service discovery format is used by .NET's configuration-based service discovery. Service endpoint environment variable names are prefixed with `services__` (double underscore), then the service name, the endpoint name, and finally the index. The index supports multiple endpoints for a single service, starting with `0` for the first endpoint and incrementing for each endpoint. - -Consider the following environment variable examples: - -```Environment -services__apiservice__http__0 -services__apiservice__https__0 -``` - -The preceding environment variables express the first HTTP and HTTPS endpoints for the `apiservice` service. A named endpoint might be expressed as follows: - -```Environment -APISERVICE_MYENDPOINT -``` - -In the preceding example, the `apiservice` service has a named endpoint called `myendpoint`. - -#### Using a specific endpoint with WithEnvironment - -To specify a custom environment variable name for a specific endpoint, use the method combined with : - -```csharp -var projectA = builder.AddProject("projecta"); -var projectB = builder.AddProject("projectb") - .WithEnvironment("PROJECTA_URL", projectA.GetEndpoint("https")); -``` - -This generates a single environment variable `PROJECTA_URL` with the HTTPS endpoint URL of the `projecta` service. - -## Reference existing resources - -Some situations warrant that you reference an existing resource, perhaps one that is deployed to a cloud provider. For example, you might want to reference an Azure database. In this case, you'd rely on the [Execution context](#execution-context) to dynamically determine whether the AppHost is running in "run" mode or "publish" mode. If you're running locally and want to rely on a cloud resource, you can use the `IsRunMode` property to conditionally add the reference. You might choose to instead create the resource in publish mode. Some [hosting integrations](integrations-overview.md#hosting-integrations) support providing a connection string directly, which can be used to reference an existing resource. - -Likewise, there might be use cases where you want to integrate Aspire into an existing solution. One common approach is to add the Aspire AppHost project to an existing solution. Within your AppHost, you express dependencies by adding project references to the AppHost and [building out the app model](#define-the-app-model). For example, one project might depend on another. These dependencies are expressed using the method. For more information, see [Add Aspire to an existing .NET app](../get-started/add-aspire-existing-app.md). - -## Execution context - -The exposes an execution context (), which provides information about the current execution of the AppHost. This context can be used to evaluate whether or not the AppHost is executing as "run" mode, or as part of a publish operation. Consider the following properties: - -- : Returns `true` if the current operation is running. -- : Returns `true` if the current operation is publishing. - -This information can be useful when you want to conditionally execute code based on the current operation. Consider the following example that demonstrates using the `IsRunMode` property. In this case, an extension method is used to generate a stable node name for RabbitMQ for local development runs. - -```csharp -private static IResourceBuilder RunWithStableNodeName( - this IResourceBuilder builder) -{ - if (builder.ApplicationBuilder.ExecutionContext.IsRunMode) - { - builder.WithEnvironment(context => - { - // Set a stable node name so queue storage is consistent between sessions - var nodeName = $"{builder.Resource.Name}@localhost"; - context.EnvironmentVariables["RABBITMQ_NODENAME"] = nodeName; - }); - } - - return builder; -} -``` - -The execution context is often used to conditionally add resources or connection strings that point to existing resources. Consider the following example that demonstrates conditionally adding Redis or a connection string based on the execution context: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var redis = builder.ExecutionContext.IsRunMode - ? builder.AddRedis("redis") - : builder.AddConnectionString("redis"); - -builder.AddProject("api") - .WithReference(redis); - -builder.Build().Run(); -``` - -In the preceding code: - -- If the AppHost is in "run" mode, a Redis container resource is added. -- If the AppHost is in "publish" mode, a connection string is added. - -This logic can easily be inverted to connect to an existing Redis resource when you're running locally, and create a new Redis resource when you're publishing. - -> [!IMPORTANT] -> Aspire provides common APIs to control the modality of resource builders, allowing resources to behave differently based on the execution mode. The fluent APIs are prefixed with `RunAs*` and `PublishAs*`. The `RunAs*` APIs influence the local development (or run mode) behavior, whereas the `PublishAs*` APIs influence the publishing of the resource. For more information on how the Azure resources use these APIs, see [Use existing Azure resources](https://aspire.dev/integrations/cloud/azure/#use-existing-azure-resources). - -## See also - -- [Orchestrate resources in Aspire](orchestrate-resources.md) -- [Aspire integrations overview](integrations-overview.md) -- [Aspire SDK](dotnet-aspire-sdk.md) -- [Eventing in Aspire](../app-host/eventing.md) -- [Service discovery in Aspire](https://aspire.dev/fundamentals/service-discovery/) -- [Aspire service defaults](https://aspire.dev/fundamentals/service-defaults/) -- [Expressing external parameters](external-parameters.md) -- [Aspire inner-loop networking overview](networking-overview.md) diff --git a/docs/fundamentals/aspire-sdk-templates.md b/docs/fundamentals/aspire-sdk-templates.md index 096be70ccf..db1e26bb5a 100644 --- a/docs/fundamentals/aspire-sdk-templates.md +++ b/docs/fundamentals/aspire-sdk-templates.md @@ -94,7 +94,7 @@ Select the desired location, enter a name, and select **Create**. To create an Aspire solution or project using the .NET CLI, use the [dotnet new](/dotnet/core/tools/dotnet-new) command and specify which template you would like to create. Consider the following examples: -To create a basic [Aspire AppHost](app-host-overview.md) project targeting the latest .NET version: +To create a basic [Aspire AppHost](https://aspire.dev/get-started/app-host/) project targeting the latest .NET version: ```dotnetcli dotnet new aspire-apphost @@ -107,7 +107,7 @@ dotnet new aspire-starter ``` > [!TIP] -> Aspire templates default to using the latest .NET version, even when using an earlier version of the .NET CLI. To manually specify the .NET version, use the `--framework ` option, e.g. to create a basic [Aspire AppHost](app-host-overview.md) project targeting .NET 8: +> Aspire templates default to using the latest .NET version, even when using an earlier version of the .NET CLI. To manually specify the .NET version, use the `--framework ` option, e.g. to create a basic [Aspire AppHost](https://aspire.dev/get-started/app-host/) project targeting .NET 8: > > ```dotnetcli > dotnet new aspire-apphost --framework net8.0 diff --git a/docs/fundamentals/aspire-vscode-extension.md b/docs/fundamentals/aspire-vscode-extension.md index 2229e7fdf8..2528d19064 100644 --- a/docs/fundamentals/aspire-vscode-extension.md +++ b/docs/fundamentals/aspire-vscode-extension.md @@ -13,7 +13,7 @@ The Aspire Visual Studio Code extension provides a set of commands and tools to [!INCLUDE [aspire-prereqs](../includes/aspire-prereqs.md)] -In addition, before you can use the Aspire Visual Studio Code extension, you must have the [Aspire CLI](../cli/install.md) installed and available on your PATH. +In addition, before you can use the Aspire Visual Studio Code extension, you must have the [Aspire CLI](https://aspire.dev/reference/cli/overview/) installed and available on your PATH. ## Install the Aspire extension @@ -155,7 +155,7 @@ The command invokes registered publishing callback annotations to generate artif - Docker Compose YAML files. - Kubernetes Helm charts. -For more information about Aspire publishing, see [Aspire publishing and deployment overview](../deployment/overview.md). +For more information about Aspire publishing, see [Aspire publishing and deployment overview](https://aspire.dev/deployment/overview/). ## Deploy an Aspire solution @@ -172,7 +172,7 @@ To deploy an Aspire solution: The command publishes deployment artifacts and then invokes deployment callback annotations to deploy resources to the specified targets. -For more information about Aspire deployment, see [Aspire publishing and deployment overview](../deployment/overview.md). +For more information about Aspire deployment, see [Aspire publishing and deployment overview](https://aspire.dev/deployment/overview/). ## Open Aspire terminal @@ -188,6 +188,6 @@ To report issues or request features for the Aspire VS Code extension: ## See also - [Aspire setup and tooling](setup-tooling.md) -- [Aspire CLI Overview](../cli/overview.md) +- [Aspire CLI Overview](https://aspire.dev/reference/cli/overview/) - [Aspire templates](aspire-sdk-templates.md) - [Aspire VS Code extension on the marketplace](https://marketplace.visualstudio.com/items?itemName=microsoft-aspire.aspire-vscode) diff --git a/docs/fundamentals/custom-deployments.md b/docs/fundamentals/custom-deployments.md deleted file mode 100644 index f7dc2dc494..0000000000 --- a/docs/fundamentals/custom-deployments.md +++ /dev/null @@ -1,182 +0,0 @@ ---- -title: Building custom deployment pipelines -description: Learn how to build container images from your Aspire resources and create custom deployment pipelines. -ms.date: 09/22/2025 -ai-usage: ai-assisted ---- - -# Building custom deployment pipelines (Preview) - -Aspire provides powerful APIs for building container images from your resources during publishing and deployment operations. This article covers the key components that enable programmatic container image creation and progress reporting. - -## Overview - -During publishing and deployment, the container image builder is available to create images for resources that need them. Aspire uses this builder when a resource requires a container image, such as when publishing with Docker Compose. The process involves two main components: - -- : The service that turns resource definitions into runnable container images. -- `IPipelineActivityReporter`: The API that provides structured progress reporting during long-running operations. - -These APIs give you fine-grained control over the image building process and provide real-time feedback to users during lengthy build operations. - -> [!IMPORTANT] -> These APIs are currently in preview and subject to change. They are designed for advanced scenarios where you need custom control over container image building and progress reporting. To suppress warnings for these APIs, see [Compiler Error ASPIREPUBLISHERS001](https://aspire.dev/diagnostics/aspirepublishers001/). - -## When to use these APIs - -Consider using the container image building and progress reporting APIs in these scenarios: - -- **Custom deployment targets**: When you need to deploy to platforms that require specific image formats or build configurations. -- **Complex build pipelines**: When your publishing process involves multiple steps that users should see. -- **Enterprise scenarios**: When you need custom progress reporting for integration with CI/CD systems or dashboards. -- **Custom resource types**: When implementing custom resources that need to participate in the publishing and deployment process. - -> [!NOTE] -> For most standard Aspire applications, the built-in publishing process builds container images automatically without requiring these APIs. - -## Resource container image builder API - -The `IResourceContainerImageBuilder` is the core service in the layer that converts resource definitions into container images. It analyzes each resource in your distributed application model and determines whether to: - -- Reuse an existing image. -- Build from a .NET project using `dotnet publish /t:PublishContainer`. -- Build from a Dockerfile using the local container runtime. - -### Container build options - -The class provides strongly typed configuration for container builds. This class allows you to specify: - -- **Image format**: Docker or Open Container Initiative (OCI) format. -- **Target platform**: Linux x64, Windows, ARM64, etc. -- **Output path**: Where to save the built images. - -### Container runtime health checks - -The builder performs container runtime health checks (Docker/Podman) only when at least one resource requires a Dockerfile build. This change eliminates false-positive errors in projects that publish directly from .NET assemblies. If the container runtime is required but unhealthy, the builder throws an explicit `InvalidOperationException` to surface the problem early. - -## Pipeline activity reporter API - -The `PipelineActivityReporter` API enables structured progress reporting during [`aspire publish`](../cli-reference/aspire-publish.md) and [`aspire deploy`](../cli-reference/aspire-deploy.md) commands. This reduces uncertainty during long-running operations and surfaces failures early. - -### API overview and behavior - -The progress reporter uses a hierarchical model with guaranteed ordering and thread-safe operations: - -| Concept | Description | CLI Rendering | Behavior | -|---------|-------------|---------------|----------| -| **Step** | Top-level phase, such as "Build images" or "Deploy workloads". | Step message with status glyph and elapsed time. | Forms a strict tree structure; nested steps are unsupported. Steps are created automatically during pipeline execution. | -| **Task** | Discrete unit of work nested under a step. | Task message with indentation. | Belongs to a single step; supports parallel creation with deterministic completion ordering. | -| **Completion state** | Final status: `Completed`, `Warning`, or `Error`. | βœ… (Completed), ⚠️ (Warning), ❌ (Error) | Each step/task transitions exactly once to a final state. | - -### API structure and usage - -The reporter API provides structured access to progress reporting with the following characteristics: - -- **Acquisition**: Retrieved from `PublishingContext.ActivityReporter` or through the `PipelineStepContext.ReportingStep` property in pipeline steps. -- **Step creation**: Steps are now created automatically during pipeline execution. The `CreateStepAsync(title, ct)` method returns an `IReportingStep`. -- **Task creation**: `IReportingStep.CreateTaskAsync(title, ct)` returns an `IReportingTask`. -- **State transitions**: `SucceedAsync`, `WarnAsync`, `FailAsync` methods accept a summary message. -- **Completion**: `CompletePublishAsync(message, state, isDeploy, ct)` marks the entire operation. -- **Ordering**: Creation and completion events preserve call order; updates are serialized. -- **Cancellation**: All APIs accept and propagate cancellation to the CLI. -- **Disposal contract**: Disposing steps automatically completes them if unfinished, preventing orphaned phases. - -## Example: Build container images and report progress - -To use these APIs, add a `PublishingCallbackAnnotation`, a `DeployingCallbackAnnotation`, or both to a resource in your app model. You can annotate custom (or built-in) resources by adding annotations to the collection. - -As a developer, you can choose to: - -- Use both annotations if your resource needs to do work in both publishing and deployment. For example, build images and generate manifests during publishing, then push images or configure deployment targets during deployment. Publishing always happens before deployment, so you can keep logic for each phase separate. - -- Use only `PublishingCallbackAnnotation` if your resource only needs to do something during publishing. This is common when you just need to build artifacts or images, but don't need to do anything during deployment. - -- Use only `DeployingCallbackAnnotation` if your resource only needs to do something during deployment. This fits cases where you use prebuilt images and just need to deploy or configure them. - -Choose one or more annotations that match your resource's responsibilities to keep your application model clear and maintainable. This separation lets you clearly define logic for each phase, but you can use both the activity reporter and the resource container image builder in either callback as needed. - -### Example resource with annotations - -For example, consider the `ComputeEnvironmentResource` constructor: - -:::code source="snippets/build-container-images/apphost/ComputeEnvironmentResource.cs" id="ctor"::: - -When instantiated, it defines both a publishing and deploying callback annotation. - -Given the example `ComputeEnvironmentResource` () type, imagine you have an extension method that you expose so consumers are able to add the compute environment: - -:::code source="snippets/build-container-images/apphost/ComputeEnvironmentResourceExtensions.cs"::: - -The preceding code: - -- Defines an extension method on the . -- Accepts a `name` for the compute environment resource, protected by the . -- Instantiates a `ComputeEnvironmentResource` given the `name` and adds it to the `builder`. - -### Example AppHost - -In your AppHost, you can add the `ComputeEnvironmentResource` to the application model like this: - -:::code source="snippets/build-container-images/apphost/AppHost.cs"::: - -The preceding code uses the `AddComputeEnvironment` extension method to add the `ComputeEnvironmentResource` to the application model. - -### Publishing callback annotation - -When you add the `ComputeEnvironmentResource`, it registers a `PublishingCallbackAnnotation`. The callback uses the `PublishAsync` method: - -:::code source="snippets/build-container-images/apphost/ComputeEnvironmentResource.cs" id="publish"::: - -The preceding code: - -- Implements a publishing pipeline that builds container images and generates deployment manifests. -- Uses the `IResourceContainerImageBuilder` API to build container images. -- Reports progress and completion status using the `PipelineActivityReporter` API. - -Your publishing callback might use `IResourceContainerImageBuilder` to build container images, while your deployment callback might use the built images and push them to a registry or deployment target. - -### Deploying callback annotation - -Like the publishing callback, the deploying callback is registered using the `DeployingCallbackAnnotation` and calls the `DeployAsync` method: - -:::code source="snippets/build-container-images/apphost/ComputeEnvironmentResource.cs" id="deploy"::: - -The preceding code: - -- Simulates deploying workloads to a Kubernetes cluster. -- Uses the `PipelineActivityReporter` API to create and manage deployment steps and tasks. -- Reports progress and marks each deployment phase as completed. -- Completes the deployment operation with a final status update. -- Handles cancellation through the provided `CancellationToken`. - -## Best practices - -When using these APIs, follow these guidelines: - -### Image building - -- Always specify explicit `ContainerBuildOptions` for production scenarios. -- Consider target platform requirements when building for deployment. -- Use OCI format for maximum compatibility with container registries. -- Handle `InvalidOperationException` when container runtime health checks fail. - -### Progress reporting - -- Encapsulate long-running logical phases in steps rather than emitting raw tasks. -- Keep titles concise (under 60 characters) as the CLI truncates longer strings. -- Call `CompletePublishAsync` exactly once per publishing or deployment operation. -- Treat warnings as recoverable and allow subsequent steps to proceed. -- Treat errors as fatal and fail fast with clear diagnostics. -- Use asynchronous, cancellation-aware operations to avoid blocking event processing. - -### State management - -- Each step and task starts in *Running* state and transitions exactly once to *Completed*, *Warning*, or *Error*. -- Throw an exception when attempting multiple state transitions. -- Leverage the reporter to guarantee ordered events and prevent interleaving. -- Dispose of `IPublishingActivityStep` to automatically complete unfinished steps. - -## See also - -- [Publishing and deployment overview](../deployment/overview.md) -- [Container configuration](../app-host/configuration.md) -- [Dockerfile integration](../app-host/withdockerfile.md) diff --git a/docs/fundamentals/custom-resource-commands.md b/docs/fundamentals/custom-resource-commands.md deleted file mode 100644 index 0ae3b67f86..0000000000 --- a/docs/fundamentals/custom-resource-commands.md +++ /dev/null @@ -1,130 +0,0 @@ ---- -title: Custom resource commands -description: Learn how to create custom resource commands in Aspire. -ms.date: 08/07/2025 -ms.topic: how-to -ms.custom: sfi-ropc-nochange ---- - -# Custom resource commands in Aspire - -Each resource in the Aspire [app model](app-host-overview.md#define-the-app-model) is represented as an and when added to the [distributed application builder](xref:Aspire.Hosting.IDistributedApplicationBuilder), it's the generic-type parameter of the interface. You use the _resource builder_ API to chain calls, configuring the underlying resource, and in some situations, you might want to add custom commands to the resource. Some common scenario for creating a custom command might be running database migrations or seeding/resetting a database. In this article, you learn how to add a custom command to a Redis resource that clears the cache. - -> [!IMPORTANT] -> These [Aspire dashboard](https://aspire.dev/dashboard/overview/) commands are only available when running the dashboard locally. They're not available when running the dashboard in Azure Container Apps. - -## Add custom commands to a resource - -Start by creating a new Aspire Starter App from the [available templates](aspire-sdk-templates.md). To create the solution from this template, follow the [Quickstart: Build your first Aspire solution](../get-started/build-your-first-aspire-app.md). After creating this solution, add a new class named _RedisResourceBuilderExtensions.cs_ to the [AppHost project](app-host-overview.md#apphost-project). Replace the contents of the file with the following code: - -:::code source="snippets/custom-commands/AspireApp/AspireApp.AppHost/RedisResourceBuilderExtensions.cs"::: - -The preceding code: - -- Shares the namespace so that it's visible to the AppHost project. -- Is a `static class` so that it can contain extension methods. -- It defines a single extension method named `WithClearCommand`, extending the `IResourceBuilder` interface. -- The `WithClearCommand` method registers a command named `clear-cache` that clears the cache of the Redis resource. -- The `WithClearCommand` method returns the `IResourceBuilder` instance to allow chaining. - -The `WithCommand` API adds the appropriate annotations to the resource, which are consumed in the [Aspire dashboard](https://aspire.dev/dashboard/overview/). The dashboard uses these annotations to render the command in the UI. Before getting too far into those details, let's ensure that you first understand the parameters of the `WithCommand` method: - -- `name`: The name of the command to invoke. -- `displayName`: The name of the command to display in the dashboard. -- `executeCommand`: The `Func>` to run when the command is invoked, which is where the command logic is implemented. -- `updateState`: The `Func` callback is invoked to determine the "enabled" state of the command, which is used to enable or disable the command in the dashboard. -- `iconName`: The name of the icon to display in the dashboard. The icon is optional, but when you do provide it, it should be a valid [Fluent UI Blazor icon name](https://www.fluentui-blazor.net/Icon#explorer). -- `iconVariant`: The variant of the icon to display in the dashboard, valid options are `Regular` (default) or `Filled`. - -## Execute command logic - -The `executeCommand` delegate is where the command logic is implemented. This parameter is defined as a `Func>`. The `ExecuteCommandContext` provides the following properties: - -- `ExecuteCommandContext.ServiceProvider`: The `IServiceProvider` instance that's used to resolve services. -- `ExecuteCommandContext.ResourceName`: The name of the resource instance that the command is being executed on. -- `ExecuteCommandContext.CancellationToken`: The that's used to cancel the command execution. - -In the preceding example, the `executeCommand` delegate is implemented as an `async` method that clears the cache of the Redis resource. It delegates out to a private class-scoped function named `OnRunClearCacheCommandAsync` to perform the actual cache clearing. Consider the following code: - -```csharp -private static async Task OnRunClearCacheCommandAsync( - IResourceBuilder builder, - ExecuteCommandContext context) -{ - var connectionString = await builder.Resource.GetConnectionStringAsync() ?? - throw new InvalidOperationException( - $"Unable to get the '{context.ResourceName}' connection string."); - - await using var connection = ConnectionMultiplexer.Connect(connectionString); - - var database = connection.GetDatabase(); - - await database.ExecuteAsync("FLUSHALL"); - - return CommandResults.Success(); -} -``` - -The preceding code: - -- Retrieves the connection string from the Redis resource. -- Connects to the Redis instance. -- Gets the database instance. -- Executes the `FLUSHALL` command to clear the cache. -- Returns a `CommandResults.Success()` instance to indicate that the command was successful. - -## Update command state logic - -The `updateState` delegate is where the command state is determined. This parameter is defined as a `Func`. The `UpdateCommandStateContext` provides the following properties: - -- `UpdateCommandStateContext.ServiceProvider`: The `IServiceProvider` instance that's used to resolve services. -- `UpdateCommandStateContext.ResourceSnapshot`: The snapshot of the resource instance that the command is being executed on. - -The immutable snapshot is an instance of `CustomResourceSnapshot`, which exposes all sorts of valuable details about the resource instance. Consider the following code: - -```csharp -private static ResourceCommandState OnUpdateResourceState( - UpdateCommandStateContext context) -{ - var logger = context.ServiceProvider.GetRequiredService>(); - - if (logger.IsEnabled(LogLevel.Information)) - { - logger.LogInformation( - "Updating resource state: {ResourceSnapshot}", - context.ResourceSnapshot); - } - - return context.ResourceSnapshot.HealthStatus is HealthStatus.Healthy - ? ResourceCommandState.Enabled - : ResourceCommandState.Disabled; -} -``` - -The preceding code: - -- Retrieves the logger instance from the service provider. -- Logs the resource snapshot details. -- Returns `ResourceCommandState.Enabled` if the resource is healthy; otherwise, it returns `ResourceCommandState.Disabled`. - -## Test the custom command - -To test the custom command, update your AppHost project's _AppHost.cs_ file to include the following code: - -:::code source="snippets/custom-commands/AspireApp/AspireApp.AppHost/AppHost.cs" highlight="4"::: - -The preceding code calls the `WithClearCommand` extension method to add the custom command to the Redis resource. Run the app and navigate to the Aspire dashboard. You should see the custom command listed under the Redis resource. On the **Resources** page of the dashboard, select the ellipsis button under the **Actions** column: - -:::image source="media/custom-clear-cache-command.png" lightbox="media/custom-clear-cache-command.png" alt-text="Aspire dashboard: Redis cache resource with custom command displayed."::: - -The preceding image shows the **Clear cache** command that was added to the Redis resource. The icon displays as a rabbit crosses out to indicate that the speed of the dependant resource is being cleared. - -Select the **Clear cache** command to clear the cache of the Redis resource. The command should execute successfully, and the cache should be cleared: - -:::image source="media/custom-clear-cache-command-succeeded.png" lightbox="media/custom-clear-cache-command-succeeded.png" alt-text="Aspire dashboard: Redis cache resource with custom command executed."::: - -## See also - -- [Custom HTTP commands in Aspire](http-commands.md) -- [Aspire dashboard: Resource submenu actions](https://aspire.dev/dashboard/explore/#resource-submenu-actions) -- [Aspire orchestration overview](app-host-overview.md) diff --git a/docs/fundamentals/custom-resource-urls.md b/docs/fundamentals/custom-resource-urls.md deleted file mode 100644 index 713a28ce3b..0000000000 --- a/docs/fundamentals/custom-resource-urls.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -title: Define custom resource URLs -description: Learn how to create custom URLs for Aspire resources. -ms.date: 11/13/2025 -ms.topic: how-to ---- - -# Define custom resource URLs - -In Aspire, resources that expose endpoints only configure host and port, which aren't known until run time. If you need to access a specific path on one of these endpointsβ€”especially from the [dashboard](https://aspire.dev/dashboard/overview/)β€”you can define custom resource URLs. You can also add custom URLs that aren't tied to any endpoint. All custom URLs are only available in "run" mode, since they're meant for dashboard use. This article demonstrates how to define custom URLs. - -## Default endpoint behavior - -By default, Aspire project resources rely on existing configurations such as Kestrel or launch profiles to determine the host and port of a resource for a configured endpointβ€”and the endpoints are always displayed on the dashboard. - -Likewise, you can explicitly expose endpoints using the API. This API allows you to specify the host and port for a resource, which is then used to create the default URL for that resource. The default URL is typically in the format `://:`. To omit the host port, use one of the following methods: - -- -- - -For more information, see [Endpoint extension methods](networking-overview.md#endpoint-extension-methods). - -## Supported resource types - -Custom resource URLs are supported for the following resource types: - -- -- -- - -## Customize resource URLs - -Use the appropriate `WithUrl` overload, `WithUrls`, or `WithUrlForEndpoint` APIs on any supported resource builder to define custom URLs for a resource. The following example demonstrates how to set a custom URL for a project resource: - -:::code source="snippets/custom-urls/AspireApp.AppHost/Program.WithUrl.cs" id="withurl"::: - -> [!TIP] -> There's an overload that accepts a `string` allowing you to pass any URL. This is useful for defining custom URLs that aren't directly related to the resource's endpoint. - -The preceding code assigns a project reference to the `api` variable, which is then used to create a custom URL for the `Admin Portal` route. The `WithUrl` method takes a and a display name as parameters. The resulting URL is available in the dashboard as shown in the following screenshot. - -### Customize endpoint URL - -Both [Scalar](https://scalar.com/) and [Swagger](https://swagger.io/tools/swagger-ui/) are common API services that enhance the usability of endpoints. These services are accessed via URLs tied to declared endpoints. - -To customize the URL for the first associated resource endpoint, use the method. - -If you want to add a separate URL (even for the same endpoint) you need to call the `WithUrl` overload that takes a or interpolated string, or call `WithUrls` and add the URL to the `Urls` list on the context. - -:::code source="snippets/custom-urls/AspireApp.AppHost/Program.WithUrlForEndpoint.cs" id="withurlforendpoint"::: - -The preceding example assumes that the `api` project resource has an `https` endpoint configured. The `WithUrlForEndpoint` method updates the associated with the endpoint. In this case, it assigns the display text to `Scalar (HTTPS)` and assigns the relative `/scalar` path to the URL. - -When the resource is started, the URL is available in the dashboard as shown in the following screenshot. - -Alternatively, you could use the overload that accepts a `Func` as a callback. This allows you to specify deep-links on target instances. - -### Customize multiple resource URLs - -To customize multiple URLs for a resource, use the method. This method allows you to specify multiple URLs for a resource, each with its own display text. The following example demonstrates how to set multiple URLs for a project resource: - -:::code source="snippets/custom-urls/AspireApp.AppHost/Program.WithUrls.cs" id="withurls"::: - -The preceding code iterates through the URLs defined for the `api` project resource and assigns a display text with scheme. - -> [!TIP] -> The exposes an extension method that enables you to easily access the underlying resource named endpoints. Call the `GetEndpoint` API on a context instance to achieve this. - -## URL customization lifecycle - -URL customization callbacks run during the application model lifecycle, specifically during the event processing. URLs associated with endpoints become active and appear on the dashboard once the endpoint itself becomes active. URLs not associated with endpoints become active only when the resource enters the "Running" state. This ensures that all custom URLs are accurately represented and available when the application resources are fully operational. - -## See also - -- [Aspire dashboard overview](https://aspire.dev/dashboard/overview/) -- [Aspire AppHost](app-host-overview.md) diff --git a/docs/fundamentals/dotnet-aspire-sdk.md b/docs/fundamentals/dotnet-aspire-sdk.md index c5894aad8e..1d7a72dd93 100644 --- a/docs/fundamentals/dotnet-aspire-sdk.md +++ b/docs/fundamentals/dotnet-aspire-sdk.md @@ -7,7 +7,7 @@ uid: dotnet/aspire/sdk # Aspire SDK -The Aspire SDK is intended for [_*.AppHost_ projects](app-host-overview.md#apphost-project), which serve as the Aspire orchestrator. These projects are designated by their usage of the `Aspire.AppHost.Sdk` in the project file. The SDK provides a set of features that simplify the development of Aspire apps. +The Aspire SDK is intended for [_*.AppHost_ projects](https://aspire.dev/get-started/app-host/#apphost-project), which serve as the Aspire orchestrator. These projects are designated by their usage of the `Aspire.AppHost.Sdk` in the project file. The SDK provides a set of features that simplify the development of Aspire apps. ## Overview @@ -57,4 +57,4 @@ The Aspire SDK dynamically adds references to the [Aspire dashboard](https://asp When the AppHost project runs, the orchestrator relies on these dependencies to provide the necessary functionality to the AppHost. For more information, see [Aspire orchestration overview][app-host]. -[app-host]: xref:dotnet/aspire/app-host +[app-host]: https://aspire.dev/get-started/app-host/ diff --git a/docs/fundamentals/external-parameters.md b/docs/fundamentals/external-parameters.md deleted file mode 100644 index b0501d201e..0000000000 --- a/docs/fundamentals/external-parameters.md +++ /dev/null @@ -1,221 +0,0 @@ ---- -title: External parameters -description: Learn how to express parameters such as secrets, connection strings, and other configuration values that might vary between environments. -ms.topic: how-to -ms.date: 09/24/2025 -ms.custom: sfi-ropc-nochange ---- - -# External parameters - -Environments provide context for the application to run in. Parameters express the ability to ask for an external value when running the app. Parameters can be used to provide values to the app when running locally, or to prompt for values when deploying. They can be used to model a wide range of scenarios including secrets, connection strings, and other configuration values that might vary between environments. - -## Parameter values - -Parameter values are read from the `Parameters` section of the AppHost's configuration and are used to provide values to the app while running locally. When you run or publish the app, if the value isn't configured you're prompted to provide it. - -Consider the following example AppHost _:::no-loc text="AppHost.cs":::_ file: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -// Add a parameter named "example-parameter-name" -var parameter = builder.AddParameter("example-parameter-name"); - -builder.AddProject("api") - .WithEnvironment("ENVIRONMENT_VARIABLE_NAME", parameter); -``` - -The preceding code adds a parameter named `example-parameter-name` to the AppHost. The parameter is then passed to the `Projects.ApiService` project as an environment variable named `ENVIRONMENT_VARIABLE_NAME`. - -### Configure parameter values - -Adding parameters to the builder is only one aspect of the configuration. You must also provide the value for the parameter. The value can be provided in the AppHost configuration file, set as a user secret, or configured in any [other standard configuration](/dotnet/core/extensions/configuration). When parameter values aren't found, they're prompted for when you run or publish the app. - -Consider the following AppHost configuration file _:::no-loc text="appsettings.json":::_: - -```json -{ - "Parameters": { - "example-parameter-name": "local-value" - } -} -``` - -The preceding JSON configures a parameter in the `Parameters` section of the AppHost configuration. In other words, that AppHost is able to find the parameter as it's configured. For example, you could walk up to the and access the value using the `Parameters:example-parameter-name` key: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var key = $"Parameters:example-parameter-name"; -var value = builder.Configuration[key]; // value = "local-value" -``` - -> [!IMPORTANT] -> However, you don't need to access this configuration value yourself in the AppHost. Instead, the is used to pass the parameter value to dependent resources. Most often as an environment variable. - -### Prompt for parameter values in the dashboard - -If your code adds parameters but doesn't set them, you'll see a prompt to configure their values in the Aspire dashboard. The **Unresolved parameters** message appears, and you can select **Enter values** to resolve the problem: - -:::image type="content" source="./media/dashboard-unresolved-parameters-message.png" lightbox="./media/dashboard-unresolved-parameters-message.png" alt-text="Screenshot of the Aspire dashboard warning that appears when there are unresolved parameters."::: - -When you select **Enter values**, Aspire displays a form that you can use to configure values for each of the missing parameters. - -You can also control how the dashboard displays these parameters, by using these methods: - -- `WithDescription`: Use this method to provide a text description that helps users understand the purpose of the parameter. To provide a formatted description in [Markdown](https://www.markdownguide.org/basic-syntax/), use the `enableMarkdown: true` parameter. -- `WithCustomInput`: Use this method to provide a callback method that customizes the parameter dialog. For example, in this callback you can customize the default value, input type, label, and placeholder text. - -This code shows how to set a description and use the callback: - -:::code language="csharp" source="snippets/unresolvedparameters/AppHost.cs" id="unresolvedparameters"::: - -The code renders this control in the dashboard: - -:::image type="content" source="./media/customized-parameter-ui.png" lightbox="./media/customized-parameter-ui.png" alt-text="Screenshot of the Aspire dashboard parameter completion dialog with customizations."::: - -> [!NOTE] -> The dashboard parameter dialog includes a **Save to user secret** checkbox. Select this option to store sensitive values in your AppHost's user secrets for extra protection. For more information about secret parameter values, see [Secret values](#secret-values). - -### Parameter representation in the manifest - -Aspire uses a [deployment manifest](../deployment/manifest-format.md) to represent the app's resources and their relationships. Parameters are represented in the manifest as a new primitive called `parameter.v0`: - -```json -{ - "resources": { - "example-parameter-name": { - "type": "parameter.v0", - "value": "{value.inputs.value}", - "inputs": { - "value": { - "type": "string" - } - } - } - } -} -``` - -## Secret values - -Parameters can be used to model secrets. When a parameter is marked as a secret, it serves as a hint to the manifest that the value should be treated as a secret. When you publish the app, the value is prompted for and stored in a secure location. When you run the app locally, the value is read from the `Parameters` section of the AppHost configuration. - -Consider the following example AppHost _:::no-loc text="AppHost.cs":::_ file: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -// Add a secret parameter named "secret" -var secret = builder.AddParameter("secret", secret: true); - -builder.AddProject("api") - .WithEnvironment("SECRET", secret); - -builder.Build().Run(); -``` - -Now consider the following AppHost configuration file _:::no-loc text="appsettings.json":::_: - -```json -{ - "Parameters": { - "secret": "local-secret" - } -} -``` - -The manifest representation is as follows: - -```json -{ - "resources": { - "value": { - "type": "parameter.v0", - "value": "{value.inputs.value}", - "inputs": { - "value": { - "type": "string", - "secret": true - } - } - } - } -} -``` - -## Connection string values - -Parameters can be used to model connection strings. When you publish the app, the value is prompted for and stored in a secure location. When you run the app locally, the value is read from the `ConnectionStrings` section of the AppHost configuration. - -[!INCLUDE [connection-strings-alert](../includes/connection-strings-alert.md)] - -Consider the following example AppHost _:::no-loc text="AppHost.cs":::_ file: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var redis = builder.AddConnectionString("redis"); - -builder.AddProject("api") - .WithReference(redis) - .WaitFor(redis); - -builder.Build().Run(); -``` - -> [!NOTE] -> Using with a connection string will implicitly wait for the resource that the connection string connects to. - -Now consider the following AppHost configuration file _:::no-loc text="appsettings.json":::_: - -```json -{ - "ConnectionStrings": { - "redis": "local-connection-string" - } -} -``` - -For more information pertaining to connection strings and their representation in the deployment manifest, see [Connection string and binding references](../deployment/manifest-format.md#connection-string-and-binding-references). - -### Build connection strings with reference expressions - -If you want to construct a connection string from parameters and ensure that it's handled correctly in both development and production, use with a . - -For example, if you have a secret parameter that stores a small part of a connection string, use this code to insert it: - -:::code language="csharp" source="snippets/referenceexpressions/AspireReferenceExpressions.AppHost/AppHost.cs" id="secretkey"::: - -You can also use reference expressions to append text to connection strings created by Aspire resources. For example, when you add a PostgreSQL resource to your Aspire solution, the database server runs in a container and a connection string is formulated for it. In the following code, the extra property `Include Error Details` is appended to that connection string before it's passed to consuming projects: - -:::code language="csharp" source="snippets/referenceexpressions/AspireReferenceExpressions.AppHost/AppHost.cs" id="postgresappend"::: - -## Parameter example - -To express a parameter, consider the following example code: - -:::code source="snippets/params/Parameters.AppHost/AppHost.cs"::: - -The following steps are performed: - -- Adds a SQL Server resource named `sql` and publishes it as a connection string. -- Adds a database named `db`. -- Adds a parameter named `insertionRows`. -- Adds a project named `api` and associates it with the `Projects.Parameters_ApiService` project resource type-parameter. -- Passes the `insertionRows` parameter to the `api` project. -- References the `db` database. - -The value for the `insertionRows` parameter is read from the `Parameters` section of the AppHost configuration file _:::no-loc text="appsettings.json":::_: - -:::code language="json" source="snippets/params/Parameters.AppHost/appsettings.json"::: - -The `Parameters_ApiService` project consumes the `insertionRows` parameter. Consider the _:::no-loc text="Program.cs":::_ example file: - -:::code source="snippets/params/Parameters.ApiService/Program.cs"::: - -## See also - -- [Aspire manifest format for deployment tool builders](../deployment/manifest-format.md) -- [Tutorial: Connect an ASP.NET Core app to SQL Server using Aspire and Entity Framework Core](https://aspire.dev/integrations/databases/sql-server/) diff --git a/docs/fundamentals/http-commands.md b/docs/fundamentals/http-commands.md deleted file mode 100644 index 61c9550ced..0000000000 --- a/docs/fundamentals/http-commands.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -title: Custom HTTP commands in Aspire -description: Learn how to create custom HTTP commands in Aspire. -ms.date: 09/23/2025 -ms.topic: how-to ---- - -# Custom HTTP commands in Aspire - -In Aspire, you can add custom HTTP commands to resources using the `WithHttpCommand` API. This API extends existing functionality, where you provide [custom commands on resources](custom-resource-commands.md). This feature enables a command on a resource that sends an HTTP request to a specified endpoint and path. This is useful for scenarios such as triggering database migrations, clearing caches, or performing custom actions on resources through HTTP requests. - -To implement custom HTTP commands, you define a command on a resource and a corresponding HTTP endpoint that handles the request. This article provides an overview of how to create and configure custom HTTP commands in Aspire. - -## HTTP command APIs - -The available APIs provide extensive capabilities with numerous parameters to customize the HTTP command. To add an HTTP command to a resource, use the `WithHttpCommand` extension method on the resource builder. There are two overloads available: - -The API provides two overloads to add custom HTTP commands to resources in Aspire. These APIs are designed to offer flexibility and cater to different use cases when defining HTTP commands. - -1. **Overload with `endpointName`:** - - This version is ideal when you have a predefined endpoint name that the HTTP command should target. It simplifies the configuration by directly associating the command with a specific endpoint. This is useful in scenarios where the endpoint is static and well-known during development. - -1. **Overload with `endpointSelector`:** - - This version provides more dynamic behavior by allowing you to specify a callback (`endpointSelector`) to determine the endpoint at runtime. This is useful when the endpoint might vary based on the resource's state or other contextual factors. It offers greater flexibility for advanced scenarios where the endpoint can't be hardcoded. - -Both overloads allow you to customize the HTTP command extensively, providing an subclass of the type, including specifying the HTTP method, configure the request, handling the response, and define UI-related properties like display name, description, and icons. The choice between the two depends on whether the endpoint is static or dynamic in your use case. - -These APIs are designed to integrate seamlessly with the Aspire ecosystem, enabling developers to extend resource functionality with minimal effort while maintaining control over the behavior and presentation of the commands. - -## Considerations when registering HTTP commands - -Since HTTP commands are exposed via HTTP endpoints, consider potential security risks. Limit these endpoints to development or staging environments when possible. Always validate incoming requests to ensure they originate from trusted sources. For more information, see [ASP.NET Core security](/aspnet/core/security). - -Use the `HttpCommandOptions.PrepareRequest` callback to enhance security by adding authentication headers or other measures. A common approach is to use a shared secret, [external parameter](external-parameters.md), or token known only to the AppHost and resource. This shared value can be used to validate requests and prevent unauthorized access. - -## Add a custom HTTP command - -In your _AppHost.cs_ file, you add a custom HTTP command using the `WithHttpCommand` API on an where `T` is an . Here's an example of how to do this: - -:::code source="snippets/http-commands/AspireApp/AspireApp.AppHost/AppHost.cs"::: - -The preceding code: - -- Creates a new distributed application builder. -- Adds a [Redis cache](https://aspire.dev/integrations/caching/redis/) named `cache` to the application. -- Adds a parameter named `ApiCacheInvalidationKey` to the application. This parameter is marked as a secret, meaning its value is treated securely. -- Adds a project named `AspireApp_Api` to the application. -- Adds a reference to the Redis cache and [waits for it to be ready before proceeding](orchestrate-resources.md#waiting-for-resources). -- Configures an HTTP command for the project with the following: - - `path`: Specifies the URL path for the HTTP command (`/cache/invalidate`). - - `displayName`: Sets the name of the command as it appears in the UI (`Invalidate cache`). - - `commandOptions`: An optional instance of `HttpCommandOptions` that configures the command's behavior and appearance in the UI: - - `Description`: Provides a description of the command that's shown in the UI. - - `PrepareRequest`: A callback function that configures the HTTP request before sending it. In this case, it adds a custom (`X-CacheInvalidation-Key`) header with the value of the `ApiCacheInvalidationKey` parameter. - - `IconName`: Specifies the icon to be used for the command in the UI (`DocumentLightningFilled`). - - `IsHighlighted`: Indicates whether the command should be highlighted in the UI. -- Finally, the application is built and run. - -The HTTP endpoint is responsible for invalidating the cache. When the command is executed, it sends an HTTP request to the specified path (`/cache/invalidate`) with the configured parameters. Since there's an added security measure, the request includes the `X-CacheInvalidation-Key` header with the value of the `ApiCacheInvalidationKey` parameter. This ensures that only authorized requests can trigger the cache invalidation process. - -### Example HTTP endpoint - -The preceding AppHost code snippet defined a custom HTTP command that sends a request to the `/cache/invalidate` endpoint. The ASP.NET Core minimal API project defines an HTTP endpoint that handles the cache invalidation request. Consider the following code snippet from the project's _Program.cs_ file: - -:::code source="snippets/http-commands/AspireApp/AspireApp.Api/Program.cs" id="post"::: - -The preceding code: - -- Assumes that the `app` variable is an instance of and is set up to handle HTTP requests. -- Maps an HTTP POST endpoint at the path `/cache/invalidate`. -- The endpoint expects a header named `X-CacheInvalidation-Key` to be present in the request. -- It retrieves the value of the `ApiCacheInvalidationKey` parameter from the configuration. -- If the header value doesn't match the expected key, it returns an unauthorized response. -- If the header is valid, it calls the `ClearAllAsync` method on the `ICacheService` to clear all cached items. -- Finally, it returns an HTTP OK response. - -### Example dashboard experiences - -The sample AppHost and corresponding ASP.NET Core minimal API projects demonstrate both sides of the HTTP command implementation. When you run the AppHost, the dashboard's **Resources** page displays the custom HTTP command as a button. When you specify that the command should be highlighted (`isHighlighted: true`), the button appears on the **Actions** column of the **Resources** page. This allows users to easily trigger the command from the dashboard, as shown in the following screenshot: - -:::image type="content" source="media/custom-http-command-highlighted.png" lightbox="media/custom-http-command-highlighted.png" alt-text="Aspire dashboard: Resources page showing a highlighted custom HTTP command."::: - -If you're to omit the `isHighlighted` parameter, or set it to `false`, the command appears nested under the horizontal ellipsis menu (three dots) in the **Actions** column of the **Resources** page. This allows users to access the command without cluttering the UI with too many buttons. The following screenshot shows the same command appearing in the ellipsis menu: - -:::image type="content" source="media/custom-http-command.png" lightbox="media/custom-http-command.png" alt-text="Aspire dashboard: Resources page showing a custom HTTP command in the ellipsis menu."::: - -When the user selects the button, the command is executed, and the HTTP request is sent to the specified endpoint. The dashboard provides feedback on the command's execution status, allowing users to monitor the results. When it's starting, a toast notification appears: - -:::image type="content" source="media/custom-http-command-starting.png" lightbox="media/custom-http-command-starting.png" alt-text="Aspire dashboard: Toast notification showing the custom HTTP command is starting."::: - -When the command completes, the dashboard updates the status and provides feedback on whether it was successful or failed. The following screenshot shows a successful execution of the command: - -:::image type="content" source="media/custom-http-command-succeeded.png" lightbox="media/custom-http-command-succeeded.png" alt-text="Aspire dashboard: Toast notification showing the custom HTTP command succeeded."::: - -## See also - -- [Aspire orchestration overview](app-host-overview.md) -- [Custom resource commands in Aspire](custom-resource-commands.md) -- [Aspire GitHub repository: Playground sample](https://github.com/dotnet/aspire/tree/4fdfdbf57d35265913a3bbac38b92d98ed255a5d/playground/TestShop) diff --git a/docs/fundamentals/integrations-overview.md b/docs/fundamentals/integrations-overview.md deleted file mode 100644 index f7128650dd..0000000000 --- a/docs/fundamentals/integrations-overview.md +++ /dev/null @@ -1,219 +0,0 @@ ---- -title: Aspire integrations overview -description: Explore the fundamental concepts of Aspire integrations and learn how to integrate them into your apps. -ms.date: 09/23/2025 -ms.topic: conceptual -uid: dotnet/aspire/integrations ---- - -# Aspire integrations overview - -Aspire integrations are a curated suite of NuGet packages selected to facilitate the integration of cloud-native applications with prominent services and platforms, such as Redis and PostgreSQL. Each integration furnishes essential cloud-native functionalities through either automatic provisioning or standardized configuration patterns. - -> [!TIP] -> Always strive to use the latest version of Aspire integrations to take advantage of the latest features, improvements, and security updates. - -> [!WARNING] -> Integrations execute code in your development environment. Ensure that third-party integrations are trusted before use. For more information, see [Best practices for a secure software supply chain](/nuget/concepts/security-best-practices). - -## Integration responsibilities - -Most Aspire integrations are made up of two separate libraries, each with a different responsibility. One type represents resources within the [_AppHost_](app-host-overview.md) projectβ€”known as [hosting integrations](#hosting-integrations). The other type of integration represents client libraries that connect to the resources modeled by hosting integrations, and they're known as [client integrations](#client-integrations). - -### Hosting integrations - -Hosting integrations configure applications by provisioning resources (like containers or cloud resources) or pointing to existing instances (such as a local SQL server). These packages model various services, platforms, or capabilities, including caches, databases, logging, storage, and messaging systems. - -Hosting integrations extend the interface, enabling the _AppHost_ project to express resources within its [_app model_](app-host-overview.md#terminology). **Hosting integrations work with any type of application**, not just .NET applications. They provide infrastructure and inject configuration details (such as connection strings, endpoints, and credentials) as environment variables into any project, executable, or container that references them. - -The official [hosting integration NuGet packages](https://www.nuget.org/packages?q=owner%3A+aspire+tags%3A+aspire+hosting+integration&includeComputedFrameworks=true&prerel=true&sortby=relevance) are tagged with `aspire`, `integration`, and `hosting`. In addition to the official hosting integrations, the [community has created hosting integrations](https://aspire.dev/integrations/) for various services and platforms as part of the Community Toolkit. - -For information on creating a custom _hosting integration_, see [Create custom Aspire hosting integration](../extensibility/custom-hosting-integration.md). - -### Client integrations - -Client integrations wire up client libraries to [dependency injection (DI)](/dotnet/core/extensions/dependency-injection), define configuration schema, and add [health checks](https://aspire.dev/fundamentals/health-checks/), [resiliency](/dotnet/core/resilience), and [telemetry](telemetry.md) where applicable. Aspire client integration libraries are prefixed with `Aspire.` and then include the full package name that they integrate with, such as `Aspire.StackExchange.Redis`. - -These packages configure existing client libraries to connect to hosting integrations. They extend the interface allowing client-consuming projects, such as your web app or API, to use the connected resource. The official [client integration NuGet packages](https://www.nuget.org/packages?q=owner%3A+aspire+tags%3A+aspire+client+integration&includeComputedFrameworks=true&prerel=true&sortby=relevance) are tagged with `aspire`, `integration`, and `client`. In addition to the official client integrations, the [community has created client integrations](https://aspire.dev/integrations/) for various services and platforms as part of the Community Toolkit. - -> [!IMPORTANT] -> Aspire integrations require and are **not compatible** with `HostingStartup` implementations, which only provide access to . If you're using `HostingStartup` for modular configuration, see [HostingStartup is not supported with Aspire integrations](../troubleshooting/hosting-startup-not-supported.md) for migration guidance. - -For more information on creating a custom client integration, see [Create custom Aspire client integrations](../extensibility/custom-client-integration.md). - -### Relationship between hosting and client integrations - -Hosting and client integrations are best when used together, but are **not** coupled and can be used separately. Some hosting integrations don't have a corresponding client integration. Configuration is what makes the hosting integration work with the client integration. - -**Client integrations are .NET-specific** and provide convenient, opinionated ways to configure .NET applications. However, **you can use hosting integrations without client integrations** for non-.NET applications or when you prefer to configure connections manually. In these scenarios, the hosting integration still provides the infrastructure and exposes connection information through environment variables that any application technology can consume. - -Consider the following diagram that depicts the relationship between hosting and client integrations: - -:::image type="content" source="media/integrations-thumb.png" lightbox="media/integrations.png" alt-text="A diagram "::: - -The AppHost project is where hosting integrations are used. Configuration, specifically environment variables, is injected into projects, executables, and containers, allowing client integrations to connect to the hosting integrations. - -## Integration features - -When you add a client integration to a project within your Aspire solution, [service defaults](https://aspire.dev/fundamentals/service-defaults/) are automatically applied to that project; meaning the Service Defaults project is referenced and the `AddServiceDefaults` extension method is called. These defaults are designed to work well in most scenarios and can be customized as needed. The following service defaults are applied: - -- **Observability and telemetry**: Automatically sets up logging, tracing, and metrics configurations: - - - **[Logging](/dotnet/core/diagnostics/logging-tracing)**: A technique where code is instrumented to produce logs of interesting events that occurred while the program was running. - - **[Tracing](/dotnet/core/diagnostics/distributed-tracing)**: A specialized form of logging that helps you localize failures and performance issues within applications distributed across multiple machines or processes. - - **[Metrics](/dotnet/core/diagnostics/metrics)**: Numerical measurements recorded over time to monitor application performance and health. Metrics are often used to generate alerts when potential problems are detected. - -- **[Health checks](https://aspire.dev/fundamentals/health-checks/)**: Exposes HTTP endpoints to provide basic availability and state information about an app. Health checks are used to influence decisions made by container orchestrators, load balancers, API gateways, and other management services. -- **[Resiliency](/dotnet/core/resilience/http-resilience)**: The ability of your system to react to failure and still remain functional. Resiliency extends beyond preventing failures to include recovering and reconstructing your cloud-native environment back to a healthy state. - -## Understand host integration extension methods - -Aspire hosting integrations provide extension methods that start with either `Add` or `With`. These methods conform to the following pattern: - -- **`Add*` methods**: `Add*` methods create and register new resources within the AppHost and return an `IResourceBuilder` where `TResource` is the concrete resource type added. This lets you continue fluent configuration on the returned builder. For example, calling returns an `IResourceBuilder`, and then calling on that namespace builder returns an `IResourceBuilder`. This pattern models parent-child relationships (for example, a Service Bus namespace and its queues or topics) while preserving a consistent fluent builder API. -- **`With*` methods**: Use `With*` methods to configure or enhance an existing resource. These methods typically return the same object type as the parent, allowing you to chain additional configuration calls. - -> [!IMPORTANT] -> When using `Add` methods, make sure to pass the correct resource object to your client integration. Passing the wrong object can result in misconfigured connections or runtime errors. - -Consider this code: - -```csharp -var serviceBus = builder.AddAzureServiceBus(name: "serviceBus") - .AddServiceBusTopic(name: "messagetopic"); - -var apiService = builder.AddProject("apiservice") - .WithHttpHealthCheck("/health") - .WithReference(serviceBus); - -// The serviceBus is an IResourceBuilder type -``` - -You may expect `serviceBus` to represent the Azure Service Bus resource but in fact, because you called on the same line, `serviceBus` is an Azure Service Bus topic resource. To avoid this result, call `AddServiceBusTopic` on a separate line: - -```csharp -var serviceBus = builder.AddAzureServiceBus(name: "serviceBus"); -var topic = serviceBus.AddServiceBusTopic(name: "messagetopic"); - -var apiService = builder.AddProject("apiservice") - .WithHttpHealthCheck("/health") - .WithReference(serviceBus); - -// The serviceBus is an IResourceBuilder type -``` - -Now, you can choose to pass the resource that consuming project needs. Either, as in the example, the Service Bus resource or the topic resource. - -This distinction helps you model your application's infrastructure accurately and ensures that client integrations receive the correct connection information. - -## Versioning considerations - -Hosting and client integrations are updated each release to target the latest stable versions of dependent resources. When container images are updated with new image versions, the hosting integrations update to these new versions. Similarly, when a new NuGet version is available for a dependent client library, the corresponding client integration updates to the new version. This ensures the latest features and security updates are available to applications. The Aspire update type (major, minor, patch) doesn't necessarily indicate the type of update in dependent resources. For example, a new major version of a dependent resource may be updated in an Aspire patch release, if necessary. - -When major breaking changes happen in dependent resources, integrations may temporarily split into version-dependent packages to ease updating across the breaking change. For more information, see the [first example of such a breaking change](https://github.com/dotnet/aspire/issues/3956). - -## Official integrations - -Aspire provides many integrations to help you build cloud-native applications. These integrations are designed to work seamlessly with the Aspire AppHost and client libraries. The following sections detail cloud-agnostic, Azure-specific, Amazon Web Services (AWS), and Community Toolkit integrations. - -### Cloud-agnostic integrations - -The following section details cloud-agnostic Aspire integrations with links to their respective docs and NuGet packages, and provides a brief description of each integration. - - -| Integration docs and NuGet packages | Description | -|--|--| -| - **Learn more**: [πŸ“„ Apache Kafka](https://aspire.dev/integrations/messaging/apache-kafka/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Kafka](https://www.nuget.org/packages/Aspire.Hosting.Kafka)
- **Client**: [πŸ“¦ Aspire.Confluent.Kafka](https://www.nuget.org/packages/Aspire.Confluent.Kafka) | A library for producing and consuming messages from an [Apache Kafka](https://kafka.apache.org/) broker. | -| - **Learn more**: [πŸ“„ Dapr](https://aspire.dev/integrations/cloud/azure/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Dapr](https://www.nuget.org/packages/Aspire.Hosting.Dapr)
- **Client**: N/A | A library for modeling [Dapr](https://dapr.io/) as an Aspire resource. | -| - **Learn more**: [πŸ“„ Docker](../deployment/docker-integration.md)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Docker](https://www.nuget.org/packages/Aspire.Hosting.Docker)
- **Client**: N/A | A library for deploying Aspire applications using Docker Compose. | -| - **Learn more**: [πŸ“„ Elasticsearch](https://aspire.dev/integrations/databases/elasticsearch/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Elasticsearch](https://www.nuget.org/packages/Aspire.Hosting.Elasticsearch)
- **Client**: [πŸ“¦ Aspire.Elastic.Clients.Elasticsearch](https://www.nuget.org/packages/Aspire.Elastic.Clients.Elasticsearch) | A library for accessing [Elasticsearch](https://www.elastic.co/guide/en/elasticsearch/client/index.html) databases. | -| - **Learn more**: [πŸ“„ Keycloak](https://aspire.dev/integrations/security/keycloak/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Keycloak](https://www.nuget.org/packages/Aspire.Hosting.Keycloak)
- **Client**: [πŸ“¦ Aspire.Keycloak.Authentication](https://www.nuget.org/packages/Aspire.Keycloak.Authentication) | A library for accessing [Keycloak](https://www.keycloak.org/docs/latest/server_admin/index.html) authentication. | -| - **Learn more**: [πŸ“„ Milvus](https://aspire.dev/integrations/databases/milvus/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Milvus](https://www.nuget.org/packages/Aspire.Hosting.Milvus)
- **Client**: [πŸ“¦ Aspire.Milvus.Client](https://www.nuget.org/packages/Aspire.Milvus.Client) | A library for accessing [Milvus](https://milvus.io/) databases. | -| - **Learn more**: [πŸ“„ MongoDB Driver](https://aspire.dev/integrations/databases/mongodb/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.MongoDB](https://www.nuget.org/packages/Aspire.Hosting.MongoDB)
- **Client**: [πŸ“¦ Aspire.MongoDB.Driver](https://www.nuget.org/packages/Aspire.MongoDB.Driver) | A library for accessing [MongoDB](https://www.mongodb.com/docs) databases. | -| - **Learn more**: [πŸ“„ MySqlConnector](https://aspire.dev/integrations/mysql/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.MySql](https://www.nuget.org/packages/Aspire.Hosting.MySql)
- **Client**: [πŸ“¦ Aspire.MySqlConnector](https://www.nuget.org/packages/Aspire.MySqlConnector) | A library for accessing [MySqlConnector](https://mysqlconnector.net/) databases. | -| - **Learn more**: [πŸ“„ NATS](https://aspire.dev/integrations/messaging/nats/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Nats](https://www.nuget.org/packages/Aspire.Hosting.Nats)
- **Client**: [πŸ“¦ Aspire.NATS.Net](https://www.nuget.org/packages/Aspire.NATS.Net) | A library for accessing [NATS](https://nats.io/) messaging. | -| - **Learn more**: [πŸ“„ Oracle - EF Core](https://aspire.dev/integrations/databases/oracle/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Oracle](https://www.nuget.org/packages/Aspire.Hosting.Oracle)
- **Client**: [πŸ“¦ Aspire.Oracle.EntityFrameworkCore](https://www.nuget.org/packages/Aspire.Oracle.EntityFrameworkCore) | A library for accessing Oracle databases with [Entity Framework Core](/ef/core). | -| - **Learn more**: [πŸ“„ OpenAI](https://aspire.dev/integrations/ai/openai/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.OpenAI](https://www.nuget.org/packages/Aspire.Hosting.OpenAI)
- **Client**: [πŸ“¦ Aspire.OpenAI](https://www.nuget.org/packages/Aspire.OpenAI) | A library for accessing [OpenAI](https://platform.openai.com/docs) APIs. | -| - **Learn more**: [πŸ“„ Orleans](https://aspire.dev/integrations/frameworks/orleans/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Orleans](https://www.nuget.org/packages/Aspire.Hosting.Orleans)
- **Client**: N/A | A library for modeling [Orleans](/dotnet/Orleans) as an Aspire resource. | -| - **Learn more**: [πŸ“„ Pomelo MySQL - EF Core](https://aspire.dev/integrations/databases/mysql/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.MySql](https://www.nuget.org/packages/Aspire.Hosting.MySql)
- **Client**: [πŸ“¦ Aspire.Pomelo.EntityFrameworkCore.MySql](https://www.nuget.org/packages/Aspire.Pomelo.EntityFrameworkCore.MySql) | A library for accessing MySql databases with [Entity Framework Core](/ef/core). | -| - **Learn more**: [πŸ“„ PostgreSQL - EF Core](https://aspire.dev/integrations/databases/postgres/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.PostgreSQL](https://www.nuget.org/packages/Aspire.Hosting.PostgreSQL)
- **Client**: [πŸ“¦ Aspire.Npgsql.EntityFrameworkCore.PostgreSQL](https://www.nuget.org/packages/Aspire.Npgsql.EntityFrameworkCore.PostgreSQL) | A library for accessing PostgreSQL databases using [Entity Framework Core](https://www.npgsql.org/efcore/index.html). | -| - **Learn more**: [πŸ“„ PostgreSQL](https://aspire.dev/integrations/databases/postgres/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.PostgreSQL](https://www.nuget.org/packages/Aspire.Hosting.PostgreSQL)
- **Client**: [πŸ“¦ Aspire.Npgsql](https://www.nuget.org/packages/Aspire.Npgsql) | A library for accessing [PostgreSQL](https://www.npgsql.org/doc/index.html) databases. | -| - **Learn more**: [πŸ“„ Qdrant](https://aspire.dev/integrations/databases/qdrant/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Qdrant](https://www.nuget.org/packages/Aspire.Hosting.Qdrant)
- **Client**: [πŸ“¦ Aspire.Qdrant.Client](https://www.nuget.org/packages/Aspire.Qdrant.Client) | A library for accessing [Qdrant](https://qdrant.tech/) databases. | -| - **Learn more**: [πŸ“„ RabbitMQ](https://aspire.dev/integrations/messaging/rabbitmq/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.RabbitMQ](https://www.nuget.org/packages/Aspire.Hosting.RabbitMQ)
- **Client**: [πŸ“¦ Aspire.RabbitMQ.Client](https://www.nuget.org/packages/Aspire.RabbitMQ.Client) | A library for accessing [RabbitMQ](https://www.rabbitmq.com/dotnet.html). | -| - **Learn more**: [πŸ“„ Redis Distributed Caching](https://aspire.dev/integrations/caching/redis-distributed/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Redis](https://www.nuget.org/packages/Aspire.Hosting.Redis), [πŸ“¦ Aspire.Hosting.Garnet](https://www.nuget.org/packages/Aspire.Hosting.Garnet), or [πŸ“¦ Aspire.Hosting.Valkey](https://www.nuget.org/packages/Aspire.Hosting.Valkey)
- **Client**: [πŸ“¦ Aspire.StackExchange.Redis.DistributedCaching](https://www.nuget.org/packages/Aspire.StackExchange.Redis.DistributedCaching) | A library for accessing [Redis](https://stackexchange.github.io/StackExchange.Redis/) caches for [distributed caching](/aspnet/core/performance/caching/distributed). | -| - **Learn more**: [πŸ“„ Redis Output Caching](https://aspire.dev/integrations/caching/redis-output/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Redis](https://www.nuget.org/packages/Aspire.Hosting.Redis), [πŸ“¦ Aspire.Hosting.Garnet](https://www.nuget.org/packages/Aspire.Hosting.Garnet), or [πŸ“¦ Aspire.Hosting.Valkey](https://www.nuget.org/packages/Aspire.Hosting.Valkey)
- **Client**: [πŸ“¦ Aspire.StackExchange.Redis.OutputCaching](https://www.nuget.org/packages/Aspire.StackExchange.Redis.OutputCaching) | A library for accessing [Redis](https://stackexchange.github.io/StackExchange.Redis/) caches for [output caching](/aspnet/core/performance/caching/output). | -| - **Learn more**: [πŸ“„ Redis](https://aspire.dev/integrations/caching/redis/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Redis](https://www.nuget.org/packages/Aspire.Hosting.Redis), [πŸ“¦ Aspire.Hosting.Garnet](https://www.nuget.org/packages/Aspire.Hosting.Garnet), or [πŸ“¦ Aspire.Hosting.Valkey](https://www.nuget.org/packages/Aspire.Hosting.Valkey)
- **Client**: [πŸ“¦ Aspire.StackExchange.Redis](https://www.nuget.org/packages/Aspire.StackExchange.Redis) | A library for accessing [Redis](https://stackexchange.github.io/StackExchange.Redis/) caches. | -| - **Learn more**: [πŸ“„ Seq](https://aspire.dev/integrations/observability/seq/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Seq](https://www.nuget.org/packages/Aspire.Hosting.Seq)
- **Client**: [πŸ“¦ Aspire.Seq](https://www.nuget.org/packages/Aspire.Seq) | A library for logging to [Seq](https://datalust.co/seq). | -| - **Learn more**: [πŸ“„ SQL Server - EF Core](https://aspire.dev/integrations/databases/sql-server/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.SqlServer](https://www.nuget.org/packages/Aspire.Hosting.SqlServer)
- **Client**: [πŸ“¦ Aspire.Microsoft.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Aspire.Microsoft.EntityFrameworkCore.SqlServer) | A library for accessing [SQL Server databases using EF Core](/ef/core/providers/sql-server/). | -| - **Learn more**: [πŸ“„ SQL Server](https://aspire.dev/integrations/databases/sql-server/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.SqlServer](https://www.nuget.org/packages/Aspire.Hosting.SqlServer)
- **Client**: [πŸ“¦ Aspire.Microsoft.Data.SqlClient](https://www.nuget.org/packages/Aspire.Microsoft.Data.SqlClient) | A library for accessing [SQL Server](/sql/sql-server/) databases. | - - -For more information on working with Aspire integrations in Visual Studio, see [Visual Studio tooling](setup-tooling.md#visual-studio-tooling). - -### Azure integrations - -Azure integrations configure applications to use Azure resources. These hosting integrations are available in the `Aspire.Hosting.Azure.*` NuGet packages, while their client integrations are available in the `Aspire.*` NuGet packages: - - -| Integration | Docs and NuGet packages | Description | -|--|--|--| -| Azure App Configuration logo. | - **Learn more**: [πŸ“„ Azure App Configuration](https://github.com/dotnet/aspire/blob/main/src/Aspire.Hosting.Azure.AppConfiguration/README.md)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Azure.AppConfiguration](https://www.nuget.org/packages/Aspire.Hosting.Azure.AppConfiguration)
- **Client**: N/A | A library for interacting with [Azure App Configuration](/azure/azure-app-configuration/). | -| Azure App Service logo. | - **Learn more**: [πŸ“„ Azure App Service](https://aspire.dev/integrations/azure-app-service/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Azure.AppService](https://www.nuget.org/packages/Aspire.Hosting.Azure.AppService)
- **Client**: N/A | A library for hosting web applications on [Azure App Service](/azure/app-service/). | -| Azure Application Insights logo. | - **Learn more**: [πŸ“„ Azure Application Insights](https://github.com/dotnet/aspire/blob/main/src/Aspire.Hosting.Azure.ApplicationInsights/README.md)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Azure.ApplicationInsights](https://www.nuget.org/packages/Aspire.Hosting.Azure.ApplicationInsights)
- **Client**: N/A | A library for interacting with [Azure Application Insights](/azure/azure-monitor/app/app-insights-overview). | -| Azure Cache for Redis logo | - **Learn more**: [πŸ“„ Azure Cache for Redis](https://aspire.dev/integrations/azure-redis/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Azure.Redis](https://www.nuget.org/packages/Aspire.Hosting.Azure.Redis)
- **Client**: [πŸ“¦ Aspire.StackExchange.Redis](https://www.nuget.org/packages/Aspire.StackExchange.Redis) or [πŸ“¦ Aspire.StackExchange.Redis.DistributedCaching](https://www.nuget.org/packages/Aspire.StackExchange.Redis.DistributedCaching) or [πŸ“¦ Aspire.StackExchange.Redis.OutputCaching](https://www.nuget.org/packages/Aspire.StackExchange.Redis.OutputCaching) | A library for accessing [Azure Cache for Redis](/azure/azure-cache-for-redis/). | -| Azure Cosmos DB EF logo. | - **Learn more**: [πŸ“„ Azure Cosmos DB - EF Core](https://aspire.dev/integrations/cloud/azure/azure-cosmos-db/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Azure.CosmosDB](https://www.nuget.org/packages/Aspire.Hosting.Azure.CosmosDB)
- **Client**: [πŸ“¦ Aspire.Microsoft.EntityFrameworkCore.Cosmos](https://www.nuget.org/packages/Aspire.Microsoft.EntityFrameworkCore.Cosmos) | A library for accessing Azure Cosmos DB databases with [Entity Framework Core](/ef/core/providers/cosmos/). | -| Azure Cosmos DB logo.| - **Learn more**: [πŸ“„ Azure Cosmos DB](https://aspire.dev/integrations/cloud/azure/azure-cosmos-db/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Azure.CosmosDB](https://www.nuget.org/packages/Aspire.Hosting.Azure.CosmosDB)
- **Client**: [πŸ“¦ Aspire.Microsoft.Azure.Cosmos](https://www.nuget.org/packages/Aspire.Microsoft.Azure.Cosmos) | A library for accessing [Azure Cosmos DB](/azure/cosmos-db/introduction) databases. | -| Azure Event Hubs logo. | - **Learn more**: [πŸ“„ Azure Event Hubs](https://aspire.dev/integrations/cloud/azure/azure-event-hubs/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Azure.EventHubs](https://www.nuget.org/packages/Aspire.Hosting.Azure.EventHubs)
- **Client**: [πŸ“¦ Aspire.Azure.Messaging.EventHubs](https://www.nuget.org/packages/Aspire.Azure.Messaging.EventHubs) | A library for accessing [Azure Event Hubs](/azure/event-hubs/event-hubs-about). | -| Azure Functions logo. | - **Learn more**: [πŸ“„ Azure Functions](https://aspire.dev/integrations/compute/azure-functions/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Azure.Functions](https://www.nuget.org/packages/Aspire.Hosting.Azure.Functions)
- **Client**: N/A | A library for integrating with [Azure Functions](/azure/azure-functions/). | -| Azure Key Vault logo. | - **Learn more**: [πŸ“„ Azure Key Vault](https://aspire.dev/integrations/azure-key-vault/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Azure.KeyVault](https://www.nuget.org/packages/Aspire.Hosting.Azure.KeyVault)
- **Client**: [πŸ“¦ Aspire.Azure.Security.KeyVault](https://www.nuget.org/packages/Aspire.Azure.Security.KeyVault) | A library for accessing [Azure Key Vault](/azure/key-vault/general/overview). | -| Azure Operational Insights logo. | - **Learn more**: [πŸ“„ Azure Operational Insights](https://github.com/dotnet/aspire/blob/main/src/Aspire.Hosting.Azure.OperationalInsights/README.md)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Azure.OperationalInsights](https://www.nuget.org/packages/Aspire.Hosting.Azure.OperationalInsights)
- **Client**: N/A | A library for interacting with [Azure Operational Insights](/azure/azure-monitor/logs/log-analytics-workspace-overview). | -| Azure OpenAI logo. | - **Learn more**: [πŸ“„ Azure AI OpenAI](https://aspire.dev/integrations/cloud/azure/azure-openai/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Azure.CognitiveServices](https://www.nuget.org/packages/Aspire.Hosting.Azure.CognitiveServices)
- **Client**: [πŸ“¦ Aspire.Azure.AI.OpenAI](https://www.nuget.org/packages/Aspire.Azure.AI.OpenAI) | A library for accessing [Azure AI OpenAI](/azure/ai-services/openai/overview) or OpenAI functionality. | -| Azure PostgreSQL logo. | - **Learn more**: [πŸ“„ Azure PostgreSQL](https://github.com/dotnet/aspire/blob/main/src/Aspire.Hosting.Azure.PostgreSQL/README.md)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Azure.PostgreSQL](https://www.nuget.org/packages/Aspire.Hosting.Azure.PostgreSQL)
- **Client**: N/A | A library for interacting with [Azure Database for PostgreSQL](/azure/postgresql/). | -| Azure AI Search logo. | - **Learn more**: [πŸ“„ Azure AI Search](https://aspire.dev/integrations/azure-ai-search/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Azure.Search](https://www.nuget.org/packages/Aspire.Hosting.Azure.Search)
- **Client**: [πŸ“¦ Aspire.Azure.Search.Documents](https://www.nuget.org/packages/Aspire.Azure.Search.Documents) | A library for accessing [Azure AI Search](/azure/search/search-what-is-azure-search) functionality. | -| Azure Service Bus logo. | - **Learn more**: [πŸ“„ Azure Service Bus](https://aspire.dev/integrations/cloud/azure/azure-service-bus/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Azure.ServiceBus](https://www.nuget.org/packages/Aspire.Hosting.Azure.ServiceBus)
- **Client**: [πŸ“¦ Aspire.Azure.Messaging.ServiceBus](https://www.nuget.org/packages/Aspire.Azure.Messaging.ServiceBus) | A library for accessing [Azure Service Bus](/azure/service-bus-messaging/service-bus-messaging-overview). | -| Azure SignalR Service logo. | - **Learn more**: [πŸ“„ Azure SignalR Service](https://aspire.dev/integrations/azure-signalr/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Azure.SignalR](https://www.nuget.org/packages/Aspire.Hosting.Azure.SignalR)
- **Client**: [Microsoft.Azure.SignalR](https://www.nuget.org/packages/Microsoft.Azure.SignalR) | A library for accessing [Azure SignalR Service](/azure/azure-signalr/signalr-overview). | -| Azure Blob Storage logo. | - **Learn more**: [πŸ“„ Azure Blob Storage](https://aspire.dev/integrations/azure-blob-storage/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Azure.Storage](https://www.nuget.org/packages/Aspire.Hosting.Azure.Storage)
- **Client**: [πŸ“¦ Aspire.Azure.Storage.Blobs](https://www.nuget.org/packages/Aspire.Azure.Storage.Blobs) | A library for accessing [Azure Blob Storage](/azure/storage/blobs/storage-blobs-introduction). | -| Azure Storage Queues logo. | - **Learn more**: [πŸ“„ Azure Storage Queues](https://aspire.dev/integrations/azure-queue-storage/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Azure.Storage](https://www.nuget.org/packages/Aspire.Hosting.Azure.Storage)
- **Client**: [πŸ“¦ Aspire.Azure.Storage.Queues](https://www.nuget.org/packages/Aspire.Azure.Storage.Queues) | A library for accessing [Azure Storage Queues](/azure/storage/queues/storage-queues-introduction). | -| Azure Table Storage logo. | - **Learn more**: [πŸ“„ Azure Table Storage](https://aspire.dev/integrations/azure-table-storage/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Azure.Storage](https://www.nuget.org/packages/Aspire.Hosting.Azure.Storage)
- **Client**: [πŸ“¦ Aspire.Azure.Data.Tables](https://www.nuget.org/packages/Aspire.Azure.Data.Tables) | A library for accessing the [Azure Table](/azure/storage/tables/table-storage-overview) service. | -| Azure Web PubSub logo. | - **Learn more**: [πŸ“„ Azure Web PubSub](https://aspire.dev/integrations/azure-web-pubsub/)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Azure.WebPubSub](https://www.nuget.org/packages/Aspire.Hosting.Azure.WebPubSub)
- **Client**: [πŸ“¦ Aspire.Azure.Messaging.WebPubSub](https://www.nuget.org/packages/Aspire.Azure.Messaging.WebPubSub) | A library for accessing the [Azure Web PubSub](/azure/azure-web-pubsub/) service. | - - -### Amazon Web Services (AWS) hosting integrations - - -| Integration docs and NuGet packages | Description | -|--|--| -| - **Learn more**: [πŸ“„ AWS Hosting](https://github.com/aws/integrations-on-dotnet-aspire-for-aws/blob/main/src/Aspire.Hosting.AWS/README.md)
- **Hosting**: [πŸ“¦ Aspire.Hosting.AWS](https://www.nuget.org/packages/Aspire.Hosting.AWS)
- **Client**: N/A | A library for modeling [AWS resources](https://aws.amazon.com/cdk/). | - - -For more information, see [GitHub: Aspire.Hosting.AWS library](https://github.com/aws/integrations-on-dotnet-aspire-for-aws/tree/main/src/Aspire.Hosting.AWS). - -### Kubernetes hosting integrations - - -| Integration docs and NuGet packages | Description | -|--|--| -| - **Learn more**: [πŸ“„ Kubernetes hosting](../deployment/kubernetes-integration.md)
- **Hosting**: [πŸ“¦ Aspire.Hosting.Kubernetes](https://www.nuget.org/packages/Aspire.Hosting.Kubernetes)
- **Client**: N/A | A library for generating Kubernetes deployment manifests from your .NET Aspire application model. | - - -### Community Toolkit integrations - -> [!NOTE] -> The Community Toolkit integrations are community-driven and maintained by the Aspire community. These integrations are not officially supported by the Aspire team. - - -| Integration docs and NuGet packages | Description | -|--|--| -| - **Learn More**: [πŸ“„ Bun hosting](https://aspire.dev/integrations/frameworks/bun-apps/)
- **Hosting**: [πŸ“¦ CommunityToolkit.Aspire.Hosting.Bun](https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Bun)
- **Client**: N/A | A hosting integration for Bun apps. | -| - **Learn More**: [πŸ“„ Deno hosting](https://aspire.dev/integrations/frameworks/deno-apps/)
- **Hosting**: [πŸ“¦ CommunityToolkit.Aspire.Hosting.Deno](https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Deno)
- **Client**: N/A | A hosting integration for Deno apps. | -| - **Learn More**: [πŸ“„ Go hosting](https://aspire.dev/integrations/frameworks/go-apps/)
- **Hosting**: [πŸ“¦ CommunityToolkit.Aspire.Hosting.Golang](https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Golang)
- **Client**: N/A | A hosting integration for Go apps. | -| - **Learn More**: [πŸ“„ Java/Spring hosting](https://aspire.dev/integrations/frameworks/java/)
- **Hosting**: [πŸ“¦ CommunityToolkit.Aspire.Hosting.Java](https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Java)
- **Client**: N/A | A integration for running Java code in Aspire either using the local JDK or using a container. | -| - **Learn More**: [πŸ“„ Node.js hosting extensions](https://aspire.dev/integrations/frameworks/nodejs-extensions/)
- **Hosting**: [πŸ“¦ CommunityToolkit.Aspire.Hosting.NodeJs.Extensions](https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.NodeJS.Extensions)
- **Client**: N/A | An integration that contains some additional extensions for running Node.js applications | -| - **Learn More**: [πŸ“„ Ollama](https://aspire.dev/integrations/ai/ollama/)
- **Hosting**: [πŸ“¦ CommunityToolkit.Aspire.Hosting.Ollama](https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Ollama)
- **Client**: [πŸ“¦ Aspire.CommunitToolkit.OllamaSharp](https://nuget.org/packages/CommunityToolkit.Aspire.OllamaSharp) | An Aspire component leveraging the [Ollama](https://ollama.com) container with support for downloading a model on startup. | -| - **Learn More**: [πŸ“„ Meilisearch hosting](https://aspire.dev/integrations/databases/meilisearch/)
- **Hosting**: [πŸ“¦ CommunityToolkit.Aspire.Hosting.Meilisearch](https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Meilisearch)
- **Client**: [πŸ“¦ Aspire.CommunitToolkit.Meilisearch](https://nuget.org/packages/CommunityToolkit.Aspire.Meilisearch) | An Aspire component leveraging the [Meilisearch](https://meilisearch.com) container. | -| - **Learn More**: [πŸ“„ Rust hosting](https://aspire.dev/integrations/frameworks/rust/)
- **Hosting**: [πŸ“¦ CommunityToolkit.Aspire.Hosting.Rust](https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Rust)
- **Client**: N/A | A hosting integration for Rust apps. | -| - **Learn More**: [πŸ“„ SQL Database projects hosting](https://aspire.dev/integrations/devtools/sql-projects/)
- **Hosting**: [πŸ“¦ CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects](https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects)
- **Client**: N/A | An Aspire hosting integration for SQL Database Projects. | -| - **Learn More**: [πŸ“„ RavenDB](https://aspire.dev/integrations/databases/ravendb/)
- **Hosting**: [πŸ“¦ CommunityToolkit.Aspire.Hosting.RavenDB](https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.RavenDB)
- **Client**: [πŸ“¦ Aspire.CommunityToolkit.RavenDB.Client](https://nuget.org/packages/CommunityToolkit.Aspire.RavenDB.Client) | An Aspire component leveraging the [RavenDB](https://ravendb.net/) container. | - - -For more information, see [Aspire Community Toolkit](https://aspire.dev/integrations/). diff --git a/docs/fundamentals/networking-overview.md b/docs/fundamentals/networking-overview.md deleted file mode 100644 index 7cc59efebc..0000000000 --- a/docs/fundamentals/networking-overview.md +++ /dev/null @@ -1,228 +0,0 @@ ---- -title: Aspire inner loop networking overview -description: Learn how Aspire handles networking and endpoints, and how you can use them in your app code. -ms.date: 07/11/2025 -ms.topic: overview ---- - -# Aspire inner-loop networking overview - -One of the advantages of developing with Aspire is that it enables you to develop, test, and debug cloud-native apps locally. Inner-loop networking is a key aspect of Aspire that allows your apps to communicate with each other in your development environment. In this article, you learn how Aspire handles various networking scenarios with proxies, endpoints, endpoint configurations, and launch profiles. - -## Networking in the inner loop - -The inner loop is the process of developing and testing your app locally before deploying it to a target environment. Aspire provides several tools and features to simplify and enhance the networking experience in the inner loop, such as: - -- **Launch profiles**: Launch profiles are configuration files that specify how to run your app locally. You can use launch profiles (such as the _launchSettings.json_ file) to define the endpoints, environment variables, and launch settings for your app. -- **Kestrel configuration**: Kestrel configuration allows you to specify the endpoints that the Kestrel web server listens on. You can configure Kestrel endpoints in your app settings, and Aspire automatically uses these settings to create endpoints. -- **Endpoints/Endpoint configurations**: Endpoints are the connections between your app and the services it depends on, such as databases, message queues, or APIs. Endpoints provide information such as the service name, host port, scheme, and environment variable. You can add endpoints to your app either implicitly (via launch profiles) or explicitly by calling . -- **Proxies**: Aspire automatically launches a proxy for each service binding you add to your app, and assigns a port for the proxy to listen on. The proxy then forwards the requests to the port that your app listens on, which might be different from the proxy port. This way, you can avoid port conflicts and access your app and services using consistent and predictable URLs. - -## How endpoints work - -A service binding in Aspire involves two integrations: a **service** representing an external resource your app requires (for example, a database, message queue, or API), and a **binding** that establishes a connection between your app and the service and provides necessary information. - -Aspire supports two service binding types: **implicit**, automatically created based on specified launch profiles defining app behavior in different environments, and **explicit**, manually created using . - -Upon creating a binding, whether implicit or explicit, Aspire launches a lightweight reverse proxy on a specified port, handling routing and load balancing for requests from your app to the service. The proxy is an Aspire implementation detail, requiring no configuration or management concern. - -To help visualize how endpoints work, consider the Aspire starter templates inner-loop networking diagram: - -:::image type="content" source="media/networking/networking-proxies-1x.png" lightbox="media/networking/networking-proxies.png" alt-text="Aspire Starter Application template inner loop networking diagram."::: - -## How container networks are managed - -When you add one or more container resources, Aspire creates a dedicated container bridge network to enable service discovery between containers. This bridge network is a virtual network that lets containers communicate with each other and provides a DNS server for container-to-container service discovery using DNS names. - -The network's lifetime depends on the container resources: - -- If all containers have a session lifetime, the network is also session-based and is cleaned up when the AppHost process ends. -- If any container has a persistent lifetime, the network is persistent and remains running after the AppHost process terminates. Aspire reuses this network on subsequent runs, allowing persistent containers to keep communicating even when the AppHost isn't running. - -For more information on container lifetimes, see [Container resource lifetime](orchestrate-resources.md#container-resource-lifetime). - -Here are the naming conventions for container networks: - -- **Session networks**: `aspire-session-network--` -- **Persistent networks**: `aspire-persistent-network--` - -Each AppHost instance gets its own network resources. The only differences are the network's lifetime and name; service discovery works the same way for both. - -Containers register themselves on the network using their resource name. Aspire uses this name for service discovery between containers. For example, a `pgadmin` container can connect to a database resource named `postgres` using `postgres:5432`. - -> [!NOTE] -> Host services, such as projects or other executables, don't use container networks. They rely on exposed container ports for service discovery and communication with containers. For more details on service discovery, see [service discovery overview](https://aspire.dev/fundamentals/service-discovery/). - -## Launch profiles - -When you call , the AppHost looks for _Properties/launchSettings.json_ to determine the default set of endpoints. The AppHost selects a specific launch profile using the following rules: - -1. An explicit `launchProfileName` argument passed when calling `AddProject`. -1. The `DOTNET_LAUNCH_PROFILE` environment variable. For more information, see [.NET environment variables](/dotnet/core/tools/dotnet-environment-variables). -1. The first launch profile defined in _launchSettings.json_. - -Consider the following _launchSettings.json_ file: - -:::code language="json" source="snippets/networking/Networking.Frontend/Networking.Frontend/Properties/launchSettings.json"::: - -For the remainder of this article, imagine that you've created an assigned to a variable named `builder` with the API: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); -``` - -To specify the **http** and **https** launch profiles, configure the `applicationUrl` values for both in the _launchSettings.json_ file. These URLs are used to create endpoints for this project. This is the equivalent of: - -:::code source="snippets/networking/Networking.AppHost/Program.WithLaunchProfile.cs" id="verbose"::: - -> [!IMPORTANT] -> If there's no _launchSettings.json_ (or launch profile), there are no bindings by default. - -For more information, see [Aspire and launch profiles](https://aspire.dev/fundamentals/launch-profiles/). - -## Kestrel configured endpoints - -Aspire supports Kestrel endpoint configuration. For example, consider an _appsettings.json_ file for a project that defines a Kestrel endpoint with the HTTPS scheme and port 5271: - -:::code language="json" source="snippets/networking/Networking.Frontend/Networking.Frontend/appsettings.Development.json" highlight="8-14"::: - -The preceding configuration specifies an `Https` endpoint. The `Url` property is set to `https://*:5271`, which means the endpoint listens on all interfaces on port 5271. For more information, see [Configure endpoints for the ASP.NET Core Kestrel web server](/aspnet/core/fundamentals/servers/kestrel/endpoints). - -With the Kestrel endpoint configured, the project should remove any configured `applicationUrl` from the _launchSettings.json_ file. - -> [!NOTE] -> If the `applicationUrl` is present in the _launchSettings.json_ file and the Kestrel endpoint is configured, the AppHost will throw an exception. - -When you add a project resource, there's an overload that lets you specify that the Kestrel endpoint should be used instead of the _launchSettings.json_ file: - -:::code source="snippets/networking/Networking.AppHost/Program.KestrelConfiguration.cs" id="kestrel"::: - -For more information, see . - -## Ports and proxies - -When defining a service binding, the host port is *always* given to the proxy that sits in front of the service. This allows single or multiple replicas of a service to behave similarly. Additionally, all resource dependencies that use the API rely of the proxy endpoint from the environment variable. - -Consider the following method chain that calls , , and then : - -:::code source="snippets/networking/Networking.AppHost/Program.WithReplicas.cs" id="withreplicas"::: - -The preceding code results in the following networking diagram: - -:::image type="content" source="media/networking/proxy-with-replicas-1x.png" lightbox="media/networking/proxy-with-replicas.png" alt-text="Aspire frontend app networking diagram with specific host port and two replicas."::: - -The preceding diagram depicts the following: - -- A web browser as an entry point to the app. -- A host port of 5066. -- The frontend proxy sitting between the web browser and the frontend service replicas, listening on port 5066. -- The `frontend_0` frontend service replica listening on the randomly assigned port 65001. -- The `frontend_1` frontend service replica listening on the randomly assigned port 65002. - -Without the call to `WithReplicas`, there's only one frontend service. The proxy still listens on port 5066, but the frontend service listens on a random port: - -:::code source="snippets/networking/Networking.AppHost/Program.HostPortAndRandomPort.cs" id="hostport"::: - -There are two ports defined: - -- A host port of 5066. -- A random proxy port that the underlying service will be bound to. - -:::image type="content" source="media/networking/proxy-host-port-and-random-port-1x.png" lightbox="media/networking/proxy-host-port-and-random-port.png" alt-text="Aspire frontend app networking diagram with specific host port and random port."::: - -The preceding diagram depicts the following: - -- A web browser as an entry point to the app. -- A host port of 5066. -- The frontend proxy sitting between the web browser and the frontend service, listening on port 5066. -- The frontend service listening on random port of 65001. - -The underlying service is fed this port via `ASPNETCORE_URLS` for project resources. Other resources access to this port by specifying an environment variable on the service binding: - -:::code source="snippets/networking/Networking.AppHost/Program.EnvVarPort.cs" id="envvarport"::: - -The previous code makes the random port available in the `PORT` environment variable. The app uses this port to listen to incoming connections from the proxy. Consider the following diagram: - -:::image type="content" source="media/networking/proxy-with-env-var-port-1x.png" lightbox="media/networking/proxy-with-env-var-port.png" alt-text="Aspire frontend app networking diagram with specific host port and environment variable port."::: - -The preceding diagram depicts the following: - -- A web browser as an entry point to the app. -- A host port of 5067. -- The frontend proxy sitting between the web browser and the frontend service, listening on port 5067. -- The frontend service listening on an environment 65001. - -> [!TIP] -> To avoid an endpoint being proxied, set the `IsProxied` property to `false` when calling the `WithEndpoint` extension method. For more information, see [Endpoint extensions: additional considerations](#additional-considerations). - -## Omit the host port - -When you omit the host port, Aspire generates a random port for both host and service port. This is useful when you want to avoid port conflicts and don't care about the host or service port. Consider the following code: - -:::code source="snippets/networking/Networking.AppHost/Program.OmitHostPort.cs" id="omithostport"::: - -In this scenario, both the host and service ports are random, as shown in the following diagram: - -:::image type="content" source="media/networking/proxy-with-random-ports-1x.png" lightbox="media/networking/proxy-with-random-ports.png" alt-text="Aspire frontend app networking diagram with random host port and proxy port."::: - -The preceding diagram depicts the following: - -- A web browser as an entry point to the app. -- A random host port of 65000. -- The frontend proxy sitting between the web browser and the frontend service, listening on port 65000. -- The frontend service listening on a random port of 65001. - -## Container ports - -When you add a container resource, Aspire automatically assigns a random port to the container. To specify a container port, configure the container resource with the desired port: - -:::code source="snippets/networking/Networking.AppHost/Program.ContainerPort.cs" id="containerport"::: - -The preceding code: - -- Creates a container resource named `frontend`, from the `mcr.microsoft.com/dotnet/samples:aspnetapp` image. -- Exposes an `http` endpoint by binding the host to port 8000 and mapping it to the container's port 8080. - -Consider the following diagram: - -:::image type="content" source="media/networking/proxy-with-docker-port-mapping-1x.png" alt-text="Aspire frontend app networking diagram with a docker host."::: - -## Endpoint extension methods - -Any resource that implements the interface can use the `WithEndpoint` extension methods. There are several overloads of this extension, allowing you to specify the scheme, container port, host port, environment variable name, and whether the endpoint is proxied. - -There's also an overload that allows you to specify a delegate to configure the endpoint. This is useful when you need to configure the endpoint based on the environment or other factors. Consider the following code: - -:::code source="snippets/networking/Networking.AppHost/Program.WithEndpoint.cs" id="withendpoint"::: - -The preceding code provides a callback delegate to configure the endpoint. The endpoint is named `admin` and configured to use the `http` scheme and transport, as well as the 17003 host port. The consumer references this endpoint by name, consider the following `AddHttpClient` call: - -```csharp -builder.Services.AddHttpClient( - client => client.BaseAddress = new Uri("http://_admin.apiservice")); -``` - -The `Uri` is constructed using the `admin` endpoint name prefixed with the `_` sentinel. This is a convention to indicate that the `admin` segment is the endpoint name belonging to the `apiservice` service. For more information, see [Aspire service discovery](https://aspire.dev/fundamentals/service-discovery/). - -### Additional considerations - -When calling the `WithEndpoint` extension method, the `callback` overload exposes the raw , which allows the consumer to customize many aspects of the endpoint. - -The `AllocatedEndpoint` property allows you to get or set the endpoint for a service. The `IsExternal` and `IsProxied` properties determine how the endpoint is managed and exposed: `IsExternal` decides if it should be publicly accessible, while `IsProxied` ensures DCP manages it, allowing for internal port differences and replication. - -> [!TIP] -> If you're hosting an external executable that runs its own proxy and encounters port binding issues due to DCP already binding the port, try setting the `IsProxied` property to `false`. This prevents DCP from managing the proxy, allowing your executable to bind the port successfully. - -The `Name` property identifies the service, whereas the `Port` and `TargetPort` properties specify the desired and listening ports, respectively. - -For network communication, the `Protocol` property supports **TCP** and **UDP**, with potential for more in the future, and the `Transport` property indicates the transport protocol (**HTTP**, **HTTP2**, **HTTP3**). Lastly, if the service is URI-addressable, the `UriScheme` property provides the URI scheme for constructing the service URI. - -For more information, see the available properties of the [EndpointAnnotation properties](/dotnet/api/aspire.hosting.applicationmodel.endpointannotation#properties). - -## Endpoint filtering - -All Aspire project resource endpoints follow a set of default heuristics. Some endpoints are included in `ASPNETCORE_URLS` at runtime, some are published as `HTTP/HTTPS_PORTS`, and some configurations are resolved from Kestrel configuration. Regardless of the default behavior, you can filter the endpoints that are included in environment variables by using the extension method: - -:::code source="snippets/networking/Networking.AppHost/Program.EndpointFilter.cs" id="filter"::: - -The preceding code adds a default HTTPS endpoint, as well as an `admin` endpoint on port 19227. However, the `admin` endpoint is excluded from the environment variables. This is useful when you want to expose an endpoint for internal use only. diff --git a/docs/fundamentals/orchestrate-resources.md b/docs/fundamentals/orchestrate-resources.md index 104cc563b9..54b2a0d41d 100644 --- a/docs/fundamentals/orchestrate-resources.md +++ b/docs/fundamentals/orchestrate-resources.md @@ -15,7 +15,7 @@ In this article, you learn how to customize the behavior of resources further by - **Integration resources**: Integrations often add resources such as databases, caches, and messaging services to your application. - **External service**: Represents a third-party API or service that your application depends on but isn't managed by Aspire. Use this for resources like public APIs or SaaS endpoints. -For the fundamentals of Aspire orchestration and how it manages resources, see [Aspire orchestration overview](app-host-overview.md). +For the fundamentals of Aspire orchestration and how it manages resources, see [Aspire orchestration overview](https://aspire.dev/get-started/app-host/). ## Resource naming conventions @@ -63,7 +63,7 @@ builder.AddProject("apiservice") .WaitFor(postgresdb); ``` -In the preceding code, the "apiservice" project resource waits for the "postgresdb" database resource to enter the state. The example code shows the [Aspire PostgreSQL integration](https://aspire.dev/integrations/databases/postgres/), but the same pattern can be applied to other resources. +In the preceding code, the "apiservice" project resource waits for the "postgresdb" database resource to enter the state. The example code shows the [Aspire PostgreSQL integration](https://aspire.dev/integrations/databases/postgres/postgres-get-started/), but the same pattern can be applied to other resources. Other cases might warrant waiting for a resource to run to completion, either or before the dependent resource starts. To wait for a resource to run to completion, use the method: @@ -90,7 +90,7 @@ Waiting for a resource can be bypassed using the **Start** command in the dashbo ## APIs for adding and expressing resources -Aspire [hosting integrations](integrations-overview.md#hosting-integrations) and [client integrations](integrations-overview.md#client-integrations) are both delivered as NuGet packages, but they serve different purposes. While _client integrations_ provide client library configuration for consuming apps outside the scope of the AppHost, _hosting integrations_ provide APIs for expressing resources and dependencies within the AppHost. For more information, see [Aspire integrations overview: Integration responsibilities](integrations-overview.md#integration-responsibilities). +Aspire [hosting integrations](https://aspire.dev/integrations/overview/#hosting-integrations) and [client integrations](https://aspire.dev/integrations/overview/#client-integrations) are both delivered as NuGet packages, but they serve different purposes. While _client integrations_ provide client library configuration for consuming apps outside the scope of the AppHost, _hosting integrations_ provide APIs for expressing resources and dependencies within the AppHost. For more information, see [Aspire integrations overview: Integration responsibilities](https://aspire.dev/integrations/overview/#integration-responsibilities). ## Express container resources @@ -132,7 +132,7 @@ The preceding code adds a container resource named "ollama" with the image `olla ### Customize container resources -All subclasses can be customized to meet your specific requirements. This can be useful when using a [hosting integration](integrations-overview.md#hosting-integrations) that models a container resource, but requires modifications. When you have an `IResourceBuilder` you can chain calls to any of the available APIs to modify the container resource. Aspire container resources typically point to pinned tags, but you might want to use the `latest` tag instead. +All subclasses can be customized to meet your specific requirements. This can be useful when using a [hosting integration](https://aspire.dev/integrations/overview/#hosting-integrations) that models a container resource, but requires modifications. When you have an `IResourceBuilder` you can chain calls to any of the available APIs to modify the container resource. Aspire container resources typically point to pinned tags, but you might want to use the `latest` tag instead. To help exemplify this, imagine a scenario where you're using the [Aspire Redis integration](https://aspire.dev/integrations/caching/redis/). If the Redis integration relies on the `7.4` tag and you want to use the `latest` tag instead, you can chain a call to the API: @@ -172,7 +172,7 @@ These commands are used instead of `podman run` to manage attached container net --- -Beyond the base resource types, , , and , Aspire provides extension methods to add common resources to your app model. For more information, see [Hosting integrations](integrations-overview.md#hosting-integrations). +Beyond the base resource types, , , and , Aspire provides extension methods to add common resources to your app model. For more information, see [Hosting integrations](https://aspire.dev/integrations/overview/#hosting-integrations). ### Container resource lifetime @@ -234,7 +234,7 @@ var frontend = builder.AddProject("frontend") .WithReference(externalService); ``` -When using parameter-based configuration, the URL value can be set through configuration, environment variables, or user secrets. During development, Aspire might prompt you to provide the URL value. For more information, see [External parameters](external-parameters.md). +When using parameter-based configuration, the URL value can be set through configuration, environment variables, or user secrets. During development, Aspire might prompt you to provide the URL value. For more information, see [External parameters](https://aspire.dev/fundamentals/external-parameters/). ### External service URL requirements @@ -324,5 +324,5 @@ The preceding example uses [!NOTE] -> Volumes and bind mounts are features of your container runtime: Docker or Podman. Aspire includes methods that make it easy to work with those features. - -## Compare volumes and bind mounts - -Both volumes and bind mounts store data in a directory on the container host. Because this directory is outside the container, data isn't destroyed when the container stops. Volumes and bind mounts, however behave differently: - -- **Volumes**: The container runtime creates and controls volumes. Volumes are isolated from the core functionality of the container host. -- **Bind mounts**: The container runtime mounts a file or directory on the host machine. Both the container and the host machine can access the contents of the bind mount. - -Volumes are more secure and portable than bind mounts. They also perform better and you should use them wherever possible. Use bind mounts only if you need to access or modify the data from your host machine. - -## Use volumes - -Volumes are the recommended way to persist data generated by containers and they're supported on both Windows and Linux. Volumes can store data from multiple containers at a time, offer high performance, and are easy to back up or migrate. With Aspire, you configure a volume for each resource container using the method, which accepts three parameters: - -- **`name`**: An optional name for the volume. -- **`target`**: The target path in the container of the data you want to persist. -- **`isReadOnly`**: A Boolean flag that indicates whether the data in the volume can be changed. The default value is `false`. - -For the remainder of this article, imagine that you're exploring a `Program` class in an Aspire [AppHost project](app-host-overview.md) that's already defined the distributed app builder bits: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -// TODO: -// Consider various code snippets for configuring -// volumes here and persistent passwords. - -builder.Build().Run(); -``` - -The first code snippet to consider uses the API to configure a volume for a SQL Server resource. The following code demonstrates how to configure a volume for a SQL Server resource in an Aspire AppHost project: - -:::code language="csharp" source="snippets/volumes/VolumeMounts.AppHost/Program.WithVolume.cs" id="volume"::: - -In this example `/var/opt/mssql` sets the path to the database files in the container. - -All Aspire container resources can utilize volumes, and some provide convenient APIs for adding named volumes derived from resources. Using the method as an example, the following code is functionally equivalent to the previous example but more succinct: - -:::code language="csharp" source="snippets/volumes/VolumeMounts.AppHost/Program.ImplicitVolume.cs" id="implicitvolume"::: - -With the AppHost project being named `VolumeMount.AppHost`, the `WithDataVolume` method automatically creates a named volume as `VolumeMount.AppHost-sql-data` and is mounted to the `/var/opt/mssql` path in the SQL Server container. The naming convention is as follows: - -- `{appHostProjectName}-{resourceName}-data`: The volume name is derived from the AppHost project name and the resource name. - -## Use bind mounts - -Bind mounts enable access to the data from both within the container and from processes on the host machine. For example, once a bind mount is established, you can copy a file into it on your host computer. The file is then available at the bound path within the container for your resource. With Aspire, you configure a bind mount for each resource container using the method, which accepts three parameters: - -- **`source`**: The path to the folder on the host machine to mount in the container. -- **`target`**: The target path in the container for the folder. -- **`isReadOnly`**: A Boolean flag that indicates whether the data in the bind mount can be changed. The default value is `false`. - -Consider this code snippet, which uses the API to configure a bind mount for a SQL Server resource: - -:::code language="csharp" source="snippets/volumes/VolumeMounts.AppHost/Program.WithBindMount.cs" id="bindmount"::: - -In this example: - -- `source: @"C:\SqlServer\Data"` sets the folder on the host computer that will be bound. -- `target: "/var/opt/mssql"` sets the path to the database files in the container. - -As for volumes, some Aspire container resources provide convenient APIs for adding bind mounts. Using the method as an example, the following code is functionally equivalent to the previous example but more succinct: - -:::code language="csharp" source="snippets/volumes/VolumeMounts.AppHost/Program.ImplicitBindMount.cs" id="implicitbindmount"::: - -## Create persistent passwords - -Named volumes require a consistent password between app launches. Aspire conveniently provides random password generation functionality. Consider the previous example once more, where a password is generated automatically: - -:::code language="csharp" source="snippets/volumes/VolumeMounts.AppHost/Program.ImplicitVolume.cs" id="implicitvolume"::: - -Since the `password` parameter isn't provided when calling `AddSqlServer`, Aspire automatically generates a password for the SQL Server resource. - -> [!IMPORTANT] -> This isn't a persistent password! Instead, it changes every time the AppHost runs. - -To create a _persistent_ password, you must override the generated password. To do this, run the following command in your AppHost project directory to set a local password in your .NET user secrets: - -```dotnetcli -dotnet user-secrets set Parameters:sql-password -``` - -The naming convention for these secrets is important to understand. The password is stored in configuration with the `Parameters:sql-password` key. The naming convention follows this pattern: - -- `Parameters:{resourceName}-password`: In the case of the SQL Server resource (which was named `"sql"`), the password is stored in the configuration with the key `Parameters:sql-password`. - -The same pattern applies to the other server-based resource types, such as those shown in the following table: - -| Resource type | Hosting package | Example resource name | Override key | -|--|--|--| -| MySQL | [πŸ“¦ Aspire.Hosting.MySql](https://www.nuget.org/packages/Aspire.Hosting.MySql) | `mysql` | `Parameters:mysql-password` | -| Oracle | [πŸ“¦ Aspire.Hosting.Oracle](https://www.nuget.org/packages/Aspire.Hosting.Oracle) | `oracle` | `Parameters:oracle-password` | -| PostgreSQL | [πŸ“¦ Aspire.Hosting.PostgreSQL](https://www.nuget.org/packages/Aspire.Hosting.PostgreSQL) | `postgresql` | `Parameters:postgresql-password` | -| RabbitMQ | [πŸ“¦ Aspire.Hosting.RabbitMq](https://www.nuget.org/packages/Aspire.Hosting.RabbitMq) | `rabbitmq` | `Parameters:rabbitmq-password` | -| SQL Server | [πŸ“¦ Aspire.Hosting.SqlServer](https://www.nuget.org/packages/Aspire.Hosting.SqlServer) | `sql` | `Parameters:sql-password` | - -By overriding the generated password, you can ensure that the password remains consistent between app launches. An alternative approach is to use the method to create a parameter that can be used as a password. The following code demonstrates how to create a persistent password for a SQL Server resource: - -:::code language="csharp" source="snippets/volumes/VolumeMounts.AppHost/Program.ExplicitStable.cs" id="explicit"::: - -The `AddParameter` method is used to create a parameter named `sql-password` that's considered a secret. The `AddSqlServer` method is then called with the `password` parameter to set the password for the SQL Server resource. For more information, see [External parameters](external-parameters.md). - -## Next steps - -You can apply the volume concepts in the preceding code to a variety of services, including seeding a database with data that will persist across app launches. Try combining these techniques with the resource implementations demonstrated in the following tutorials: - -- [Tutorial: Connect an ASP.NET Core app to Aspire storage integrations](https://aspire.dev/integrations/cloud/azure/azure-storage/) -- [Tutorial: Connect an ASP.NET Core app to SQL Server using Aspire and Entity Framework Core](https://aspire.dev/integrations/databases/sql-server/) -- [Aspire orchestration overview](../fundamentals/app-host-overview.md) diff --git a/docs/fundamentals/setup-tooling.md b/docs/fundamentals/setup-tooling.md index 9d756a4aab..8e44d7f247 100644 --- a/docs/fundamentals/setup-tooling.md +++ b/docs/fundamentals/setup-tooling.md @@ -160,7 +160,7 @@ Both commands should succeed and return valid results before running your Aspire ## Aspire dashboard -Aspire templates that expose the [AppHost](app-host-overview.md) project also include a useful developer [dashboard](https://aspire.dev/dashboard/overview/) that's used to monitor and inspect various aspects of your app, such as logs, traces, and environment configurations. This dashboard is designed to improve the local development experience and provides an overview of the overall state and structure of your app. +Aspire templates that expose the [AppHost](https://aspire.dev/get-started/app-host/) project also include a useful developer [dashboard](https://aspire.dev/dashboard/overview/) that's used to monitor and inspect various aspects of your app, such as logs, traces, and environment configurations. This dashboard is designed to improve the local development experience and provides an overview of the overall state and structure of your app. The Aspire dashboard is only visible while the app is running and starts automatically when you start the _*.AppHost_ project. Visual Studio and Visual Studio Code launch both your app and the Aspire dashboard for you automatically in your browser. If you start the app using the .NET CLI, copy and paste the dashboard URL from the output into your browser, or hold Ctrl and select the link (if your terminal supports hyperlinks). @@ -188,7 +188,7 @@ You add Aspire integrations to your app like any other NuGet package using Visua :::image type="content" loc-scope="visual-studio" source="../media/visual-studio-add-aspire-comp-nuget.png" lightbox="../media/visual-studio-add-aspire-comp-nuget.png" alt-text="The Visual Studio context menu displaying the Add Aspire integration options."::: -For more information on Aspire integrations, see [Aspire integrations overview](integrations-overview.md). +For more information on Aspire integrations, see [Aspire integrations overview](https://aspire.dev/integrations/overview/). ### Add hosting packages @@ -220,7 +220,7 @@ You can add Aspire orchestration projects to an existing app using the following - A call to `builder.AddServiceDefaults` will be added to the _:::no-loc text="Program.cs":::_ file of your original project. - A reference to your original project will be added to the _:::no-loc text="AppHost.cs":::_ file of the _*.AppHost_ project. -For more information on Aspire orchestration, see [Aspire orchestration overview](app-host-overview.md). +For more information on Aspire orchestration, see [Aspire orchestration overview](https://aspire.dev/get-started/app-host/). ### Enlist in orchestration @@ -257,9 +257,9 @@ The [Aspire Visual Studio Code extension](aspire-vscode-extension.md) provides a The Aspire CLI (`aspire` command) is a cross-platform tool that provides command-line functionality to create, manage, run, and publish polyglot Aspire projects. Use the Aspire CLI to streamline development workflows and coordinate services for distributed applications. -For more information, see [Aspire CLI Overview](../cli/overview.md) and [Install Aspire CLI](../cli/install.md). +For more information, see [Aspire CLI Overview](https://aspire.dev/reference/cli/overview/) and [Install Aspire CLI](https://aspire.dev/reference/cli/overview/). ## See also - [Use Dev Proxy with Aspire project](/microsoft-cloud/dev/dev-proxy/how-to/use-dev-proxy-with-dotnet-aspire) -- [Aspire CLI Overview](../cli/overview.md) +- [Aspire CLI Overview](https://aspire.dev/reference/cli/overview/) diff --git a/docs/fundamentals/telemetry.md b/docs/fundamentals/telemetry.md index fda6f31653..b5b871f8e0 100644 --- a/docs/fundamentals/telemetry.md +++ b/docs/fundamentals/telemetry.md @@ -61,4 +61,4 @@ Aspire deployment environments should configure OpenTelemetry environment variab Aspire telemetry works best in environments that support OTLP. OTLP exporting is disabled if `OTEL_EXPORTER_OTLP_ENDPOINT` isn't configured. -For more information, see [Aspire deployments](../deployment/overview.md). +For more information, see [Aspire deployments](https://aspire.dev/deployment/overview/). diff --git a/docs/get-started/add-aspire-existing-app.md b/docs/get-started/add-aspire-existing-app.md deleted file mode 100644 index 1b24ce992f..0000000000 --- a/docs/get-started/add-aspire-existing-app.md +++ /dev/null @@ -1,495 +0,0 @@ ---- -title: Add Aspire to an existing .NET app -description: Learn how to add Aspire integrations, orchestration, and tooling to a microservices app that already exists. -ms.date: 10/01/2025 -ms.topic: how-to -zone_pivot_groups: dev-environment ---- - -# Tutorial: Add Aspire to an existing .NET app - -If you have existing microservices and .NET web app, you can add Aspire to it and get all the included features and benefits. In this article, you add Aspire orchestration to a simple, preexisting .NET 9 project. You learn how to: - -> [!div class="checklist"] -> -> - Understand the structure of the existing microservices app. -> - Enroll existing projects in Aspire orchestration. -> - Understand the changes enrollment makes in the projects. -> - Start the Aspire project. - -[!INCLUDE [aspire-prereqs](../includes/aspire-prereqs.md)] - -## Get started - -Let's start by obtaining the code for the solution: - -1. Open a command prompt and change directories to where you want to store the code. -1. To clone to .NET 9 example solution, use the following `git clone` command: - - ```bash - git clone https://github.com/MicrosoftDocs/mslearn-dotnet-cloudnative-devops.git eShopLite - ``` - -## Explore the sample app - -This article uses a .NET 9 solution with three projects: - -- **Data Entities**: This project is an example class library. It defines the `Product` class used in the Web App and Web API. -- **Products**: This example Web API returns a list of products in the catalog and their properties. -- **Store**: This example Blazor Web App displays the product catalog to website visitors. - -### Sample app architecture - -To better understand the structure of the sample app, consider the following diagram, which illustrates its simple three-tier architecture: - -:::image type="content" source="media/product-store-architecture-thumb.png" alt-text="Simple three-tier architecture diagram showing a product database, product API, and store web app." lightbox="media/product-store-architecture.png"::: - -This layered design ensures a clear separation of concerns, making the app easier to maintain and scale. - -### Run the sample app - -Open and start debugging the project to examine its default behavior: - -:::zone pivot="visual-studio" - -1. Start Visual Studio and then select **File** > **Open** > **Project/Solution**. -1. Navigate to the top level folder of the solution you cloned, select **eShopLite.sln**, and then select **Open**. -1. In the **Solution Explorer**, right-click the **eShopLite** solution, and then select **Configure Startup Projects**. -1. Select **Multiple startup projects**. -1. In the **Action** column, select **Start** for both the **Products** and **Store** projects. -1. Select **OK**. -1. To start debugging the solution, press F5 or select **Start**. -1. Two pages open in the browser: - - - A page displays products in JSON format from a call to the Products Web API. - - A page displays the homepage of the website. In the menu on the left, select **Products** to see the catalog obtained from the Web API. - -1. To stop debugging, close the browser. - -:::zone-end -:::zone pivot="vscode" - -1. Start Visual Studio Code and open the folder that you cloned. From the terminal where you cloned the repo, run the following command: - - ```bash - code . - ``` - -1. Select the **Run and Debug** menu item, or press Ctrl+Shift+D. -1. Select the **create a launch.json file** link. - - :::image type="content" source="media/vscode-launch.json.png" lightbox="media/vscode-launch.json.png" alt-text="Visual Studio Code: Run and Debug create launch.json file."::: - -1. Copy and paste the following JSON into this file and **Save**: - - ## [Unix](#tab/unix) - - ```json - { - "version": "0.2.0", - "compounds": [ - { - "name": "Run all", - "configurations": [ - "Run products", - "Run store", - ] - } - ], - "configurations": [ - { - "name": "Run products", - "type": "dotnet", - "request": "launch", - "projectPath": "${workspaceFolder}/Products/Products.csproj" - }, - { - "name": "Run store", - "type": "dotnet", - "request": "launch", - "projectPath": "${workspaceFolder}/Store/Store.csproj" - } - ] - } - ``` - - ## [Windows](#tab/windows) - - ```json - { - "version": "0.2.0", - "compounds": [ - { - "name": "Run all", - "configurations": [ - "Run products", - "Run store", - ] - } - ], - "configurations": [ - { - "name": "Run products", - "type": "dotnet", - "request": "launch", - "projectPath": "${workspaceFolder}\\Products\\Products.csproj" - }, - { - "name": "Run store", - "type": "dotnet", - "request": "launch", - "projectPath": "${workspaceFolder}\\Store\\Store.csproj" - } - ] - } - ``` - - --- - -1. To start debugging the solution, press F5 or select **Start**. -1. Two pages open in the browser: - - - A page displays products in JSON format from a call to the Products Web API. - - A page displays the homepage of the website. In the menu on the left, select **Products** to see the catalog obtained from the Web API. - -1. To stop debugging, close the browser, and then select the **Stop** button twice (once for each running debug instance). - -:::zone-end -:::zone pivot="dotnet-cli" - -1. Open a terminal window and change directories into the newly cloned repository. -1. To start the _Products_ app, run the following command: - - ```dotnetcli - dotnet run --project ./Products/Products.csproj - ``` - -1. A browser page opens, displaying the JSON for the products. -1. In a separate terminal window, again change directories to cloned repository. -1. Start the _Store_ app by running the following command: - - ```dotnetcli - dotnet run --project ./Store/Store.csproj - ``` - -1. The browser opens a page that displays the homepage of the website. In the menu on the left, select **Products** to see the catalog obtained from the Web API. - -1. To stop debugging, close the browser, and press Ctrl+C in both terminals. - -:::zone-end - -No matter which tool you useβ€”starting multiple projects manually or configuring connections between them is tedious. Additionally, the **Store** project requires explicit endpoint configuration for the **Products** API, which is both cumbersome and prone to errors. This is where Aspire simplifies and streamlines the process! - -## Ensure Aspire templates are installed - -If you've worked with Aspire on your current computer before, you likely have the necessary .NET project templates already installed. You can check by using the following command: - -```dotnetcli -dotnet new list aspire -``` - -If the Aspire templates are installed, the output resembles: - -```dotnetcli -These templates matched your input: 'Aspire' - -Template Name Short Name Language Tags ------------------- ---------------------- -------- ------------------------------------------------------------------------------- -Aspire App... aspire-apphost [C#] Common/Aspire/Cloud -Aspire Emp... aspire [C#] Common/Aspire/Cloud/Web/Web API/API/Service -Aspire Ser... aspire-servicedefaults [C#] Common/Aspire/Cloud/Web/Web API/API/Service -Aspire Sta... aspire-starter [C#] Common/Aspire/Blazor/Web/Web API/API/Service/Cloud/Test/MSTest/NUnit/xUnit -Aspire Tes... aspire-mstest [C#] Common/Aspire/Cloud/Web/Web API/API/Service/Test/MSTest -Aspire Tes... aspire-nunit [C#] Common/Aspire/Cloud/Web/Web API/API/Service/Test/NUnit -Aspire Tes... aspire-xunit [C#] Common/Aspire/Cloud/Web/Web API/API/Service/Test/xUnit -``` - -In this tutorial, you'll add a AppHost project and a Service Defaults project. - -If the previous command didn't find any templates you must install them. Execute this command: - -```dotnetcli -dotnet new install Aspire.ProjectTemplates -``` - -For more information about the Aspire templates, see [Aspire templates](../fundamentals/setup-tooling.md#aspire-templates) - -## Add Aspire to the Store web app - -Now, let's enroll the **Store** project, which implements the web user interface, in Aspire orchestration: - -:::zone pivot="visual-studio" - -1. In Visual Studio, in the **Solution Explorer**, right-click the **Store** project, select **Add**, and then select **Aspire Orchestrator Support**. -1. In the **Add Aspire Orchestrator Support** dialog, select **OK**. - - :::image type="content" loc-scope="visual-studio" source="media/add-aspire-orchestrator-support.png" alt-text="Screenshot of the Add Aspire Orchestrator Support dialog."::: - -You should now have two new projects, both added to the solution: - -- **eShopLite.AppHost**: An orchestrator project designed to connect and configure the different projects and services of your app. The orchestrator is set as the _Startup project_, and it depends on the **eShopLite.Store** project. -- **eShopLite.ServiceDefaults**: A Aspire shared project to manage configurations that are reused across the projects in your solution related to [resilience](/dotnet/core/resilience/http-resilience), [service discovery](https://aspire.dev/fundamentals/service-discovery/), and [telemetry](../fundamentals/telemetry.md). - -In the **eShopLite.AppHost** project, open the _:::no-loc text="AppHost.cs":::_ file. Notice this line of code, which registers the **Store** project in the Aspire orchestration: - -```csharp -builder.AddProject("store"); -``` - -For more information, see . - -To add the **Products** project to Aspire: - -1. In Visual Studio, in the **Solution Explorer**, right-click the **Products** project, select **Add**, and then select **Aspire Orchestrator Support**. -1. A dialog indicating that Aspire Orchestrator project already exists, select **OK**. - - :::image type="content" loc-scope="visual-studio" source="media/orchestrator-already-added.png" alt-text="Screenshot indicating that theAspire Orchestrator was already added."::: - -In the **eShopLite.AppHost** project, open the _:::no-loc text="AppHost.cs":::_ file. Notice this line of code, which registers the **Products** project in the Aspire orchestration: - -```csharp -builder.AddProject("products"); -``` - -Also notice that the **eShopLite.AppHost** project, now depends on both the **Store** and **Products** projects. - -:::zone-end -:::zone pivot="vscode,dotnet-cli" - -### Create an AppHost project - -In order to orchestrate the existing projects, you need to create a new _AppHost_ project. To create a new [_AppHost_ project](../fundamentals/app-host-overview.md) from the available Aspire templates, use the following .NET CLI command: - -```dotnetcli -dotnet new aspire-apphost -o eShopLite.AppHost -``` - -Add the _AppHost_ project to existing solution: - -## [Unix](#tab/unix) - -```dotnetcli -dotnet sln ./eShopLite.sln add ./eShopLite.AppHost/eShopLite.AppHost.csproj -``` - -## [Windows](#tab/windows) - -```dotnetcli -dotnet sln .\eShopLite.sln add .\eShopLite.AppHost\eShopLite.AppHost.csproj -``` - ---- - -Add the **Store** project as a project reference to the _AppHost_ project using the following .NET CLI command: - -## [Unix](#tab/unix) - -```dotnetcli -dotnet add ./eShopLite.AppHost/eShopLite.AppHost.csproj reference ./Store/Store.csproj -``` - -## [Windows](#tab/windows) - -```dotnetcli -dotnet add .\eShopLite.AppHost\eShopLite.AppHost.csproj reference .\Store\Store.csproj -``` - ---- - -For more information on the available templates, see [Aspire templates](../fundamentals/aspire-sdk-templates.md). - -### Create a service defaults project - -After the AppHost project is created, you need to create a new _service defaults_ project. To create a new [_service defaults_ project](https://aspire.dev/fundamentals/service-defaults/) from the available Aspire templates, use the following .NET CLI command: - -```dotnetcli -dotnet new aspire-servicedefaults -o eShopLite.ServiceDefaults -``` - -To add the project to the solution, use the following .NET CLI command: - -## [Unix](#tab/unix) - -```dotnetcli -dotnet sln ./eShopLite.sln add ./eShopLite.ServiceDefaults/eShopLite.ServiceDefaults.csproj -``` - -## [Windows](#tab/windows) - -```dotnetcli -dotnet sln .\eShopLite.sln add .\eShopLite.ServiceDefaults\eShopLite.ServiceDefaults.csproj -``` - ---- - -Update the _AppHost_ project to add a project reference to the **Products** project: - -## [Unix](#tab/unix) - -```dotnetcli -dotnet add ./eShopLite.AppHost/eShopLite.AppHost.csproj reference ./Products/Products.csproj -``` - -## [Windows](#tab/windows) - -```dotnetcli -dotnet add .\eShopLite.AppHost\eShopLite.AppHost.csproj reference .\Products\Products.csproj -``` - ---- - -Both the **Store** and **Products** projects need to reference the _service defaults_ project so that they can easily include [service discovery](https://aspire.dev/fundamentals/service-discovery/). To add a reference to the _service defaults_ project in the **Store** project, use the following .NET CLI command: - -## [Unix](#tab/unix) - -```dotnetcli -dotnet add ./Store/Store.csproj reference ./eShopLite.ServiceDefaults/eShopLite.ServiceDefaults.csproj -``` - -## [Windows](#tab/windows) - -```dotnetcli -dotnet add .\Store\Store.csproj reference .\eShopLite.ServiceDefaults\eShopLite.ServiceDefaults.csproj -``` - ---- - -The same command with slightly different paths should be used to add a reference to the _service defaults_ project in the **Products** project: - -## [Unix](#tab/unix) - -```dotnetcli -dotnet add ./Products/Products.csproj reference ./eShopLite.ServiceDefaults/eShopLite.ServiceDefaults.csproj -``` - -## [Windows](#tab/windows) - -```dotnetcli -dotnet add .\Products\Products.csproj reference .\eShopLite.ServiceDefaults\eShopLite.ServiceDefaults.csproj -``` - ---- - -In both the **Store** and **Products** projects, update their _:::no-loc text="Program.cs":::_ files, adding the following line immediately after their `var builder = WebApplication.CreateBuilder(args);` line: - -```csharp -builder.AddServiceDefaults(); -``` - -### Update the AppHost project - -Open the _:::no-loc text="AppHost.cs":::_ file of the _AppHost_ project, and replace its contents with the following C# code: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -builder.AddProject("store"); - -builder.AddProject("products"); - -builder.Build().Run(); -``` - -The preceding code: - -- Creates a new instance. -- Adds the **Store** project to the orchestrator. -- Adds the **Products** project to the orchestrator. -- Builds and runs the orchestrator. - -:::zone-end - -## Service Discovery - -At this point, both projects are part of Aspire orchestration, but the **Store** project needs to rely on the **Products** backend address through [Aspire's service discovery](https://aspire.dev/fundamentals/service-discovery/). To enable service discovery, open the _:::no-loc text="AppHost.cs":::_ file in **eShopLite.AppHost** project and update the code so that the `builder` adds a reference to the _Products_ project: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var products = builder.AddProject("products"); - -builder.AddProject("store") - .WithExternalHttpEndpoints() - .WithReference(products) - .WaitFor(products); - -builder.Build().Run(); -``` - -The preceding code expresses that the _Store_ project depends on the _Products_ project. For more information, see [Aspire AppHost: Reference resources](../fundamentals/app-host-overview.md#reference-resources). This reference is used to discover the address of the _Products_ project at run time. Additionally, the _Store_ project is configured to use external HTTP endpoints. If you later choose to deploy this app, you'd need the call to to ensure that it's public to the outside world. Finally, the API ensures that _Store_ app waits for the _Products_ app to be ready to serve requests. - -Next, update the _:::no-loc text="appsettings.json":::_ in the _Store_ project with the following JSON: - -```json -{ - "DetailedErrors": true, - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - }, - "AllowedHosts": "*", - "ProductEndpoint": "http://products", - "ProductEndpointHttps": "https://products" -} -``` - -The addresses for both the endpoints now uses the "products" name that was added to the orchestrator in the _AppHost_. These names are used to discover the address of the _Products_ project. - -## Explore the enrolled app - -Let's start the solution and examine the new behavior that Aspire provides. - -:::zone pivot="visual-studio" - -> [!NOTE] -> Notice that the **eShopLite.AppHost** project is the new startup project. - -1. In Visual Studio, to start debugging, press F5 Visual Studio builds the projects. -1. If the **Start Docker Desktop** dialog appears, select **Yes**. Visual Studio starts the Docker engine and creates the necessary containers. When the deployment is complete, the Aspire dashboard is displayed. -1. In the dashboard, select the endpoint for the **products** project. A new browser tab appears and displays the product catalog in JSON format. -1. In the dashboard, select the endpoint for the **store** project. A new browser tab appears and displays the home page for the web app. -1. In the menu on the left, select **Products**. The product catalog is displayed. -1. To stop debugging, close the browser. - -:::zone-end -:::zone pivot="vscode" - -Delete the _launch.json_ file that you created earlier, it no longer serves a purpose. Instead, start the _AppHost_ project, which orchestrates the other projects: - -1. Start the _AppHost_ project by right-clicking the **eShopLite.AppHost** project in the **Solution Explorer** and selecting **Debug** > **Start New Instance**: - - :::image type="content" source="media/vscode-run-app-host.png" lightbox="media/vscode-run-app-host.png" alt-text="Visual Studio Code: Solution Explorer selecting Debug > Start New Instance." ::: - - > [!NOTE] - > If Docker Desktop (or Podman) isn't running, you experience an error. Start the container runtime and try again. - -:::zone-end -:::zone pivot="dotnet-cli" - -1. Start the _AppHost_ project by running the following command: - - ```dotnetcli - dotnet run --project ./eShopLite.AppHost/eShopLite.AppHost.csproj - ``` - - > [!NOTE] - > If Docker Desktop (or Podman) isn't running, you experience an error. Start the container runtime and try again. - -:::zone-end -:::zone pivot="vscode,dotnet-cli" - - - - -2. In the dashboard, select the endpoint for the **products** project. A new browser tab appears and displays the product catalog in JSON format. -3. In the dashboard, select the endpoint for the **store** project. A new browser tab appears and displays the home page for the web app. -4. In the menu on the left, select **Products**. The product catalog is displayed. -5. To stop debugging, close the browser. - - - -:::zone-end - -Congratulations, you added Aspire orchestration to your preexisting web app. You can now add Aspire integrations and use the Aspire tooling to streamline your cloud-native web app development. diff --git a/docs/get-started/aspire-overview.md b/docs/get-started/aspire-overview.md deleted file mode 100644 index 295fb6e26a..0000000000 --- a/docs/get-started/aspire-overview.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -title: Aspire overview -description: Learn about Aspire, an application stack designed to improve the experience of building distributed applications. -ms.date: 07/21/2025 -ms.custom: sfi-ropc-nochange ---- - -# Aspire overview - -**Aspire** provides tools, templates, and packages for building **observable, production-ready distributed apps**. At the center is the **app model**β€”a **code-first, single source of truth** that defines your app's services, resources, and connections. - -Aspire gives you a **unified toolchain**: launch and debug your entire app locally with one command, then deploy anywhereβ€”**Kubernetes, the cloud, or your own servers**β€”using the same composition. - -Extensibility is a core focus. Aspire's APIs are designed so you can adapt the platform to your infrastructure, services, and workflows. - -### Key capabilities - -- **AppHost orchestration:** Define services, dependencies, and configuration in code. -- **Rich integrations:** NuGet packages for popular services with standardized interfaces. -- **Consistent tooling:** Project templates and experiences for **Visual Studio, VS Code, and the CLI.** - -For the official support information, see the [Aspire Support Policy](https://dotnet.microsoft.com/platform/support/policy/aspire). - -## The AppHost - -Aspire's AppHost is where you define your app's services and dependencies in codeβ€”no complex configuration files required. The AppHost provides orchestration for your local development environment by simplifying the management of service discovery, environment variables, and container configurations. - -Picture a common three-tier architecture: a frontend, which depends on an API, which connects to a database. In Aspire, this topology is represented in the AppHost as shown in the following code: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -// Add database service -var postgres = builder.AddPostgres("db") - .AddDatabase("appdata") - .WithDataVolume(); - -// Add API service and reference dependencies -var api = builder.AddProject("api") - .WithReference(postgres) - .WaitFor(postgres); - -// Add frontend service and reference the API -var frontend = builder.AddProject("frontend") - .WithReference(api); - -builder.Build().Run(); -``` - -The AppHost assists with the following concerns: - -- **App composition**: Specify the projects, containers, executables, and cloud resources that make up your application. -- **Service discovery and connection string management**: Automatically inject the right connection strings and network configurations. - -It's important to note that Aspire's orchestration focuses on enhancing the _local development_ experience. It's not intended to replace production systems like Kubernetes, but rather provides abstractions that eliminate low-level implementation details during development. - -For more information, see [Aspire orchestration overview](../fundamentals/app-host-overview.md). - -## Aspire integrations - -Aspire makes it easy to define everything your app needs using integrationsβ€”NuGet packages designed to simplify connections to popular services and platforms. Each integration handles cloud resource setup and provides standardized patterns for health checks, telemetry, and configuration. - -Resources you can integrate include: - -- **AI Services**: Large Language Models, AI endpoints, and cognitive services. -- **Caches**: Redis, in-memory caches, and distributed caching solutions. -- **Containers**: Docker containers for databases, message brokers, and other services. -- **Databases**: SQL Server, PostgreSQL, MySQL, MongoDB, and other data stores. -- **Executables**: Console applications, scripts, and background services. -- **Frameworks**: Web applications, APIs, and microservices built with various frameworks. -- **Messaging Services**: Azure Service Bus, RabbitMQ, Kafka, and other messaging systems. -- **Projects**: .NET projects, Node.js applications, Python services, and more. -- **Storage**: Blob storage, file systems, and cloud storage services. - -Integrations are two-fold: "hosting" integrations represent the service you're connecting to, while "client" integrations represent the consumer of that service. - -> [!TIP] -> Under the hood, a _hosting_ [integration](../fundamentals/integrations-overview.md) can represent a container, an executable, or even just C# code that configures resources without running a separate process. You can add any container image, codebase, script, or cloud resource to your AppHost. Creating reusable Aspire integrations is similar to building reusable components for your apps. - -## Monitor and troubleshoot with the Aspire dashboard - -Aspire includes a powerful developer dashboard that gives you real-time visibility into your distributed app. The dashboard lets you inspect resources, view logs, traces, and metrics, and manage your app's servicesβ€”all from a single UI. - -When you run your Aspire app, the dashboard launches automatically. You can: - -- See all your app's resources and their status. -- Drill into logs, traces, and metrics for any service. -- Start, stop, or restart resources directly from the dashboard. -- Visualize dependencies and troubleshoot issues faster. - -The dashboard is available both as part of an Aspire solution or as a [standalone tool](https://aspire.dev/dashboard/standalone/) for any app that emits OpenTelemetry data. - -Learn more in the [dashboard overview](https://aspire.dev/dashboard/overview/), or dive deeper into [dashboard features and usage](https://aspire.dev/dashboard/explore/). - -## From development to deployment - -When you compose your distributed app in Aspire's AppHost, you're not just defining services for local developmentβ€”you're setting up the foundation for deployment. The same composition you use to run and debug locally becomes the blueprint for production deployment, ensuring consistency from development through to production. - -Aspire provides project templates and tooling experiences for your favorite development environments. These [templates include opinionated defaults](../fundamentals/aspire-sdk-templates.md) with boilerplate code for health checks, logging, and telemetry. The templates also include service defaults that handle common configurations: - -```csharp -builder.AddServiceDefaults(); -``` - -When added to your C# code, this method configures: - -- **OpenTelemetry**: Formatted logging, runtime metrics, and tracing for ASPCore, gRPC, and HTTP. -- **Health checks**: Default endpoints that tools can query to monitor your app. -- **Service discovery**: Enables service discovery and configures accordingly. - -For more information, see [Aspire service defaults](https://aspire.dev/fundamentals/service-defaults/). - -Consider how the three-tier architecture example can be deployed across different environments: - -| **Resource** | **Local development** | **Azure** | **AWS** | -|----------|-------------------|-------|-----|---------| -| Frontend | `npm run` | Azure Container Apps | Amazon Elastic Container Service | -| API service | `dotnet run` | Azure Container Apps | AWS Lambda | -| Database | `docker.io/library/postgres` | Azure Database for PostgreSQL | Amazon Relational Database Service | - -> [!TIP] -> These are just a few examples of how you can deploy Aspire apps. - -Aspire's deployment capabilities are flexible and don't interfere with your existing workflows. You can continue using your preferred tools and services while benefiting from the consistent app topology defined in your AppHost. - -For more information, see [Deploy Aspire apps](../deployment/overview.md). - -## Next steps - -> [!div class="nextstepaction"] -> [Build your first Aspire solution](build-your-first-aspire-app.md) diff --git a/docs/get-started/build-aspire-apps-with-nodejs.md b/docs/get-started/build-aspire-apps-with-nodejs.md deleted file mode 100644 index 7111379d20..0000000000 --- a/docs/get-started/build-aspire-apps-with-nodejs.md +++ /dev/null @@ -1,264 +0,0 @@ ---- -title: Orchestrate Node.js apps in Aspire -description: Learn how to integrate Node.js and npm apps into an Aspire AppHost project. -ms.date: 05/27/2025 -ms.custom: sfi-image-nochange ---- - -# Orchestrate Node.js apps in Aspire - -In this article, you learn how to use Node.js and Node Package Manager (`npm`) apps in an Aspire project. The sample app in this article demonstrates [Angular](https://angular.io), [React](https://react.dev/), and [Vue](https://vuejs.org/) client experiences. The following Aspire APIs exist to support these scenariosβ€”and they're part of the [Aspire.Hosting.NodeJS](https://nuget.org/packages/Aspire.Hosting.NodeJS) NuGet package: - -- [Node.js](https://nodejs.org/): . -- [`npm` apps](https://docs.npmjs.com/cli/using-npm/scripts): . - -The difference between these two APIs is that the former is used to host Node.js apps, while the latter is used to host apps that execute from a _package.json_ file's `scripts` sectionβ€”and the corresponding `npm run ` command. - -> [!TIP] -> The sample source code for this article is available on [GitHub](https://github.com/dotnet/aspire-samples/tree/main/samples/AspireWithJavaScript), and there are details available on the [Code Samples: Aspire with Angular, React and Vue](/samples/dotnet/aspire-samples/aspire-angular-react-vue) page. - -> [!IMPORTANT] -> While this article is focused on Single-Page App (SPA) frontend bits, there's an additional Node.js sample available on the [Code Samples: Aspire Node.js sample](/samples/dotnet/aspire-samples/aspire-nodejs) page, that demonstrates how to use Node.js as a server app with [express](https://expressjs.com/). - -[!INCLUDE [aspire-prereqs](../includes/aspire-prereqs.md)] - -Additionally, you need to install [Node.js](https://nodejs.org/en/download/package-manager) on your machine. The sample app in this article was built with Node.js version 20.12.2 and npm version 10.5.1. To verify your Node.js and npm versions, run the following commands: - -```nodejs -node --version -``` - -```nodejs -npm --version -``` - -To download Node.js (including `npm`), see the [Node.js download page](https://nodejs.org/en/download/package-manager). - -## Clone sample source code - -To clone the sample source code from [GitHub](https://github.com/dotnet/aspire-samples/tree/main/samples/AspireWithJavaScript), run the following command: - -```bash -git clone https://github.com/dotnet/aspire-samples.git -``` - -After cloning the repository, navigate to the _samples/AspireWithJavaScript_ folder: - -```bash -cd samples/AspireWithJavaScript -``` - -From this directory, there are six child directories described in the following list: - -- **AspireJavaScript.Angular**: An Angular app that consumes the weather forecast API and displays the data in a table. -- **AspireJavaScript.AppHost**: A Aspire project that orchestrates the other apps in this sample. For more information, see [Aspire orchestration overview](../fundamentals/app-host-overview.md). -- **AspireJavaScript.MinimalApi**: An HTTP API that returns randomly generated weather forecast data. -- **AspireJavaScript.React**: A React app that consumes the weather forecast API and displays the data in a table. -- **AspireJavaScript.ServiceDefaults**: The default shared project for Aspire projects. For more information, see [Aspire service defaults](https://aspire.dev/fundamentals/service-defaults/). -- **AspireJavaScript.Vue**: A Vue app that consumes the weather forecast API and displays the data in a table. - -## Install client dependencies - -The sample app demonstrates how to use JavaScript client apps that are built on top of Node.js. Each client app was written either using a `npm create` template command or manually. The following table lists the template commands used to create each client app, along with the default port: - -| App type | Create template command | Default port | -|--------------------------------|-------------------------------|--------------| -| [Angular](https://angular.dev) | `npm create @angular@latest` | 4200 | -| [React](https://react.dev) | Didn't use a template. | PORT env var | -| [Vue](https://vuejs.org) | `npm create vue@latest` | 5173 | - -> [!TIP] -> You don't need to run any of these commands, since the sample app already includes the clients. Instead, this is a point of reference from which the clients were created. For more information, see [npm-init](https://docs.npmjs.com/cli/commands/npm-init). - -To run the app, you first need to install the dependencies for each client. To do so, navigate to each client folder and run [`npm install` (or the install alias `npm i`) commands](https://docs.npmjs.com/cli/v10/commands/npm-install). - -### Install Angular dependencies - -```nodejs -npm i ./AspireJavaScript.Angular/ -``` - -For more information on the Angular app, see [explore the Angular client](#explore-the-angular-client). - -### Install React dependencies - -```nodejs -npm i ./AspireJavaScript.React/ -``` - -For more information on the React app, see [explore the React client](#explore-the-react-client). - -### Install Vue dependencies - -```nodejs -npm i ./AspireJavaScript.Vue/ -``` - -For more information on the Vue app, see [explore the Vue client](#explore-the-vue-client). - -## Run the sample app - -To run the sample app, call the [dotnet run](/dotnet/core/tools/dotnet-run) command given the orchestrator AppHost _AspireJavaScript.AppHost.csproj_ as the `--project` switch: - -```dotnetcli -dotnet run --project ./AspireJavaScript.AppHost/AspireJavaScript.AppHost.csproj -``` - -The [Aspire dashboard](https://aspire.dev/dashboard/overview/) launches in your default browser, and each client app endpoint displays under the **Endpoints** column of the **Resources** page. The following image depicts the dashboard for this sample app: - -:::image type="content" source="media/aspire-dashboard-with-nodejs.png" lightbox="media/aspire-dashboard-with-nodejs.png" alt-text="Aspire dashboard with multiple JavaScript client apps."::: - -The `weatherapi` service endpoint resolves to a Swagger UI page that documents the HTTP API. Each client app consumes this service to display the weather forecast data. You can view each client app by navigating to the corresponding endpoint in the Aspire dashboard. Their screenshots and the modifications made from the template starting point are detailed in the following sections. - -In the same terminal session that you used to run the app, press Ctrl + C to stop the app. - -## Explore the AppHost - -To help understand how each client app resource is orchestrated, look to the AppHost project. The AppHost requires the [Aspire.Hosting.NodeJS](https://nuget.org/packages/Aspire.Hosting.NodeJS) NuGet package to host Node.js apps: - -:::code language="xml" highlight="15,22-30" source="~/aspire-samples/samples/AspireWithJavaScript/AspireJavaScript.AppHost/AspireJavaScript.AppHost.csproj"::: - -The project file also defines a build target that ensures that the npm dependencies are installed before the AppHost is built. The AppHost code (AppHost.cs_) declares the client app resources using the API. - -:::code source="~/aspire-samples/samples/AspireWithJavaScript/AspireJavaScript.AppHost/AppHost.cs"::: - -The preceding code: - -- Creates a . -- Adds the "weatherapi" service as a project to the AppHost. - - Marks the HTTP endpoints as external. -- With a reference to the "weatherapi" service, adds the "angular", "react", and "vue" client apps as npm apps. - - Each client app is configured to run on a different container port, and uses the `PORT` environment variable to determine the port. - - All client apps also rely on a _Dockerfile_ to build their container image and are configured to express themselves in the publishing manifest as a container from the API. - -For more information on inner-loop networking, see [Aspire inner-loop networking overview](../fundamentals/networking-overview.md). For more information on deploying apps, see [Aspire manifest format for deployment tool builders](../deployment/manifest-format.md). - -When the AppHost orchestrates the launch of each client app, it uses the `npm run start` command. This command is defined in the `scripts` section of the _package.json_ file for each client app. The `start` script is used to start the client app on the specified port. Each client app relies on a proxy to request the "weatherapi" service. - -The proxy is configured in: - -- The _proxy.conf.js_ file for the Angular client. -- The _webpack.config.js_ file for the React client. -- The _vite.config.ts_ file for the Vue client. - -## Explore the Angular client - -There are several key modifications from the original Angular template. The first is the addition of a _proxy.conf.js_ file. This file is used to proxy requests from the Angular client to the "weatherapi" service. - -:::code language="javascript" source="~/aspire-samples/samples/AspireWithJavaScript/AspireJavaScript.Angular/proxy.conf.js"::: - -The Aspire AppHost sets the `WEATHERAPI_HTTPS` and `WEATHERAPI_HTTP` environment variables, which are used to resolve the "weatherapi" service endpoints. The preceding configuration proxies HTTP requests that start with `/api` to the target URL specified in the environment variable. - -Then include the proxy file in the _angular.json_ file. -Update the `serve` target to include the `proxyConfig` option, referencing the created _proxy.conf.js_ file. -The Angular CLI will now use the proxy configuration while serving the Angular client app. - -:::code language="javascript" source="~/aspire-samples/samples/AspireWithJavaScript/AspireJavaScript.Angular/angular.json" range="59-73" highlight="13"::: - -The third update is to the _package.json_ file. This file is used to configure the Angular client to run on a different port than the default port. This is achieved by using the `PORT` environment variable, and the `run-script-os` npm package to set the port. - -:::code language="json" source="~/aspire-samples/samples/AspireWithJavaScript/AspireJavaScript.Angular/package.json"::: - -The `scripts` section of the _package.json_ file is used to define the `start` script. This script is used by the `npm start` command to start the Angular client app. The `start` script is configured to use the `run-script-os` package to set the port, which delegates to the `ng serve` command passing the appropriate `--port` switch based on the OS-appropriate syntax. - -In order to make HTTP calls to the "weatherapi" service, the Angular client app needs to be configured to provide the Angular `HttpClient` for dependency injection. This is achieved by using the `provideHttpClient` helper function while configuring the application in the _app.config.ts_ file. - -:::code language="typescript" source="~/aspire-samples/samples/AspireWithJavaScript/AspireJavaScript.Angular/src/app/app.config.ts"::: - -Finally, the Angular client app needs to call the `/api/WeatherForecast` endpoint to retrieve the weather forecast data. There are several HTML, CSS, and TypeScript updates, all of which are made to the following files: - -- _app.component.css_: [Update the CSS to style the table.](https://github.com/dotnet/aspire-samples/blob/ef6868b0999c6eea3d42a10f2b20433c5ea93720/samples/AspireWithJavaScript/AspireJavaScript.Angular/src/app/app.component.css) -- _app.component.html_: [Update the HTML to display the weather forecast data in a table.](https://github.com/dotnet/aspire-samples/blob/ef6868b0999c6eea3d42a10f2b20433c5ea93720/samples/AspireWithJavaScript/AspireJavaScript.Angular/src/app/app.component.html) -- _app.component.ts_: [Update the TypeScript to call the `/api/WeatherForecast` endpoint and display the data in the table.](https://github.com/dotnet/aspire-samples/blob/ef6868b0999c6eea3d42a10f2b20433c5ea93720/samples/AspireWithJavaScript/AspireJavaScript.Angular/src/app/app.component.ts) - -:::code language="typescript" source="~/aspire-samples/samples/AspireWithJavaScript/AspireJavaScript.Angular/src/app/app.component.ts"::: - -### Angular app running - -To visualize the Angular client app, navigate to the "angular" endpoint in the Aspire dashboard. The following image depicts the Angular client app: - -:::image type="content" source="media/angular-app.png" lightbox="media/angular-app.png" alt-text="Angular client app with fake forecast weather data displayed as a table."::: - -## Explore the React client - -The React app wasn't written using a template, and instead was written manually. The complete source code can be found in the [dotnet/aspire-samples repository](https://github.com/dotnet/aspire-samples/tree/main/samples/AspireWithJavaScript/AspireJavaScript.React). Some of the key points of interest are found in the _src/App.js_ file: - -:::code language="javascript" source="~/aspire-samples/samples/AspireWithJavaScript/AspireJavaScript.React/src/components/App.js"::: - -The `App` function is the entry point for the React client app. It uses the `useState` and `useEffect` hooks to manage the state of the weather forecast data. The `fetch` API is used to make an HTTP request to the `/api/WeatherForecast` endpoint. The response is then converted to JSON and set as the state of the weather forecast data. - -:::code language="javascript" source="~/aspire-samples/samples/AspireWithJavaScript/AspireJavaScript.React/webpack.config.js"::: - -The preceding code defines the `module.exports` as follows: - -- The `entry` property is set to the _src/index.js_ file. -- The `devServer` relies on a proxy to forward requests to the "weatherapi" service, sets the port to the `PORT` environment variable, and allows all hosts. -- The `output` results in a _dist_ folder with a _bundle.js_ file. -- The `plugins` set the _src/index.html_ file as the template, and expose the _favicon.ico_ file. - -The final updates are to the following files: - -- _App.css_: [Update the CSS to style the table.](https://github.com/dotnet/aspire-samples/blob/ef6868b0999c6eea3d42a10f2b20433c5ea93720/samples/AspireWithJavaScript/AspireJavaScript.React/src/App.css) -- _App.js_: [Update the JavaScript to call the `/api/WeatherForecast` endpoint and display the data in the table.](https://github.com/dotnet/aspire-samples/blob/ef6868b0999c6eea3d42a10f2b20433c5ea93720/samples/AspireWithJavaScript/AspireJavaScript.React/src/App.js) - -### React app running - -To visualize the React client app, navigate to the "react" endpoint in the Aspire dashboard. The following image depicts the React client app: - -:::image type="content" source="media/react-app.png" lightbox="media/react-app.png" alt-text="React client app with fake forecast weather data displayed as a table."::: - -## Explore the Vue client - -There are several key modifications from the original Vue template. The primary updates were the addition of the `fetch` call in the _TheWelcome.vue_ file to retrieve the weather forecast data from the `/api/WeatherForecast` endpoint. The following code snippet demonstrates the `fetch` call: - -:::code language="html" source="~/aspire-samples/samples/AspireWithJavaScript/AspireJavaScript.Vue/src/components/TheWelcome.vue"::: - -As the `TheWelcome` integration is `mounted`, it calls the `/api/weatherforecast` endpoint to retrieve the weather forecast data. The response is then set as the `forecasts` data property. To set the server port, the Vue client app uses the `PORT` environment variable. This is achieved by updating the _vite.config.ts_ file: - -:::code language="typescript" source="~/aspire-samples/samples/AspireWithJavaScript/AspireJavaScript.Vue/vite.config.ts"::: - -Additionally, the Vite config specifies the `server.proxy` property to forward requests to the "weatherapi" service. This is achieved by using the `WEATHERAPI_HTTPS` and `WEATHERAPI_HTTP` environment variables, which are set by the Aspire AppHost. - -The final update from the template is made to the _TheWelcome.vue_ file. This file calls the `/api/WeatherForecast` endpoint to retrieve the weather forecast data, and displays the data in a table. It includes [CSS, HTML, and TypeScript updates](https://github.com/dotnet/aspire-samples/blob/ef6868b0999c6eea3d42a10f2b20433c5ea93720/samples/AspireWithJavaScript/AspireJavaScript.Vue/src/components/TheWelcome.vue). - -### Vue app running - -To visualize the Vue client app, navigate to the "vue" endpoint in the Aspire dashboard. The following image depicts the Vue client app: - -:::image type="content" source="media/vue-app.png" lightbox="media/vue-app.png" alt-text="Vue client app with fake forecast weather data displayed as a table."::: - -## Deployment considerations - -The sample source code for this article is designed to run locally. Each client app deploys as a container image. The _Dockerfile_ for each client app is used to build the container image. Each _Dockerfile_ is identical, using a multistage build to create a production-ready container image. - -:::code language="dockerfile" source="~/aspire-samples/samples/AspireWithJavaScript/AspireJavaScript.Angular/Dockerfile"::: - -The client apps are currently configured to run as true SPA apps, and aren't configured to run in a server-side rendered (SSR) mode. They sit behind **nginx**, which is used to serve the static files. They use a _default.conf.template_ file to configure **nginx** to proxy requests to the client app. - -:::code language="nginx" source="~/aspire-samples/samples/AspireWithJavaScript/AspireJavaScript.Angular/default.conf.template"::: - -## Node.js server app considerations - -While this article focuses on client apps, you might have scenarios where you need to host a Node.js server app. The same semantics are required to host a Node.js server app as a SPA client app. The Aspire AppHost requires a package reference to the [Aspire.Hosting.NodeJS](https://nuget.org/packages/Aspire.Hosting.NodeJS) NuGet package and the code needs to call either `AddNodeApp` or `AddNpmApp`. These APIs are useful for adding existing JavaScript apps to the Aspire AppHost. - -When configuring secrets and passing environment variables to JavaScript-based apps, whether they are client or server apps, use parameters. For more information, see [Aspire: External parametersβ€”secrets](../fundamentals/external-parameters.md#secret-values). - -### Use the OpenTelemetry JavaScript SDK - -To export OpenTelemetry logs, traces, and metrics from a Node.js server app, you use the [OpenTelemetry JavaScript SDK](https://opentelemetry.io/docs/languages/js/). - -For a complete example of a Node.js server app using the OpenTelemetry JavaScript SDK, you can refer to the [Code Samples: Aspire Node.js sample](/samples/dotnet/aspire-samples/aspire-nodejs) page. Consider the sample's _instrumentation.js_ file, which demonstrates how to configure the OpenTelemetry JavaScript SDK to export logs, traces, and metrics: - -:::code language="javascript" source="~/aspire-samples/samples/AspireWithNode/NodeFrontend/instrumentation.js"::: - -> [!TIP] -> To configure the Aspire dashboard OTEL CORS settings, see the [Aspire dashboard OTEL CORS settings](https://aspire.dev/dashboard/configuration/#otlp-cors) page. - -## Summary - -While there are several considerations that are beyond the scope of this article, you learned how to build Aspire projects that use Node.js and Node Package Manager (`npm`). You also learned how to use the APIs to host Node.js apps and apps that execute from a _package.json_ file, respectively. Finally, you learned how to use the `npm` CLI to create Angular, React, and Vue client apps, and how to configure them to run on different ports. - -## See also - -- [Code Samples: Aspire with Angular, React, and Vue](/samples/dotnet/aspire-samples/aspire-angular-react-vue) -- [Code Samples: Aspire Node.js App](/samples/dotnet/aspire-samples/aspire-nodejs) diff --git a/docs/get-started/build-aspire-apps-with-python.md b/docs/get-started/build-aspire-apps-with-python.md deleted file mode 100644 index a07d93f1cb..0000000000 --- a/docs/get-started/build-aspire-apps-with-python.md +++ /dev/null @@ -1,203 +0,0 @@ ---- -title: Orchestrate Python apps in Aspire -description: Learn how to integrate Python apps into an Aspire AppHost project. -ms.date: 04/15/2025 -ms.custom: sfi-image-nochange ---- - -# Orchestrate Python apps in Aspire - -In this article, you learn how to use Python apps in an Aspire AppHost. The sample app in this article demonstrates launching a Python application. The Python extension for Aspire requires the use of virtual environments. - -[!INCLUDE [aspire-prereqs](../includes/aspire-prereqs.md)] - -Additionally, you need to install [Python](https://www.python.org/downloads) on your machine. The sample app in this article was built with Python version 3.12.4 and pip version 24.1.2. To verify your Python and pip versions, run the following commands: - -```console -python --version -``` - -```console -pip --version -``` - -To download Python (including `pip`), see the [Python download page](https://www.python.org/downloads). - -## Create an Aspire project using the template - -To get started launching a Python project in Aspire, use the starter template to first create an Aspire application host: - -```dotnetcli -dotnet new aspire -o PythonSample -``` - -In the same terminal session, change directories into the newly created project: - -```console -cd PythonSample -``` - -After the template is created, launch the AppHost with the following command to ensure that the AppHost and the [Aspire dashboard](https://aspire.dev/dashboard/overview/) run successfully: - -```dotnetcli -dotnet run --project ./PythonSample.AppHost/PythonSample.AppHost.csproj -``` - -If the Aspire Dashboard doesn't open, open it with the link in the console output. At this point the dashboard won't show any resources. Stop the AppHost by pressing Ctrl + C in the terminal. - -## Prepare a Python app - -From your previous terminal session where you created the Aspire solution, create a new directory to contain the Python source code. - -```console -mkdir hello-python -``` - -Change directories into the newly created _hello-python_ directory: - -```console -cd hello-python -``` - -### Initialize the Python virtual environment - -To work with Python apps, they need to be within a virtual environment. To create a virtual environment, run the following command: - -```console -python -m venv .venv -``` - -For more information on virtual environments, see the [Python: Install packages in a virtual environment using pip and venv](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/). - -To activate the virtual environment, enabling installation and usage of packages, run the following command: - -### [Unix/macOS](#tab/bash) - -```bash -source .venv/bin/activate -``` - -### [Windows](#tab/powershell) - -```powershell -.venv\Scripts\Activate.ps1 -``` - ---- - -Ensure that pip within the virtual environment is up-to-date by running the following command: - -```console -python -m pip install --upgrade pip -``` - -## Install Python packages - -Install the Flask package by creating a _requirements.txt_ file in the _hello-python_ directory and adding the following line: - -```text -Flask==3.0.3 -``` - -Then, install the Flask package by running the following command: - -```console -python -m pip install -r requirements.txt -``` - -After Flask is installed, create a new file named _main.py_ in the _hello-python_ directory and add the following code: - -```python -import os -import flask - -app = flask.Flask(__name__) - -@app.route('/', methods=['GET']) -def hello_world(): - return 'Hello, World!' - -if __name__ == '__main__': - port = int(os.environ.get('PORT', 8111)) - app.run(host='0.0.0.0', port=port) -``` - -The preceding code creates a simple Flask app that listens on port 8111 and returns the message `"Hello, World!"` when the root endpoint is accessed. - -## Update the AppHost project - -Install the Python hosting package by running the following command: - -```dotnetcli -dotnet add ../PythonSample.AppHost/PythonSample.AppHost.csproj package Aspire.Hosting.Python --version 9.0.0 -``` - -After the package is installed, the project XML should have a new package reference similar to the following example: - -:::code language="xml" source="snippets/PythonSample/PythonSample.AppHost/PythonSample.AppHost.csproj" highlight="15"::: - -Replace the _AppHost.cs_ code with the following snippet. This code adds the Python project to Aspire by calling the `AddPythonApp` API and specifying the project name, project path, and the entry point file: - -:::code source="snippets/PythonSample/PythonSample.AppHost/AppHost.cs" highlight="6"::: - -> [!IMPORTANT] -> The preceding code suppresses the `ASPIREHOSTINGPYTHON001` diagnostic error. This error is generated because the `AddPythonApp` API is experimental and might change in future release. For more information, see [Compiler Error ASPIREHOSTINGPYTHON001](https://aspire.dev/diagnostics/aspirehostingpython001/). - -## Run the app - -Now that you've added the Python hosting package, updated the _AppHost.cs_ file, and created a Python project, you can run the AppHost: - -```dotnetcli -dotnet run --project ../PythonSample.AppHost/PythonSample.AppHost.csproj -``` - -Launch the dashboard by clicking the link in the console output. The dashboard should display the Python project as a resource. - -:::image source="media/python-dashboard.png" lightbox="media/python-dashboard.png" alt-text="Aspire dashboard: Python sample app."::: - -Select the **Endpoints** link to open the `hello-python` endpoint in a new browser tab. The browser should display the message "Hello, World!": - -:::image source="media/python-hello-world.png" lightbox="media/python-hello-world.png" alt-text="Aspire dashboard: Python sample app endpoint."::: - -Stop the AppHost by pressing Ctrl + C in the terminal. - -## Add telemetry support - -To add a bit of observability, add telemetry to help monitor the dependant Python app. In the Python project, add the following **OpenTelemetry** packages as a dependency in the _requirements.txt_ file: - -:::code language="text" source="snippets/PythonSample/hello-python/requirements.txt" highlight="2-5"::: - -Next, reinstall the Python app requirements into the virtual environment by running the following command: - -```console -python -m pip install -r requirements.txt -``` - -The preceding command installs the **OpenTelemetry** package and the **OTLP** exporter, in the virtual environment. Update the Python app to include the **OpenTelemetry** code, by replacing the existing _main.py_ code with the following: - -:::code language="python" source="snippets/PythonSample/hello-python/main.py"::: - -Update the AppHost project's _launchSettings.json_ file to include the `ASPIRE_ALLOW_UNSECURED_TRANSPORT` environment variable under the `http` profile: - -:::code language="json" source="snippets/PythonSample/PythonSample.AppHost/Properties/launchSettings.json" highlight="26"::: - -The `ASPIRE_ALLOW_UNSECURED_TRANSPORT` variable is required because when running locally the OpenTelemetry client in Python rejects the local development certificate. Launch the _AppHost_ again: - -```dotnetcli -dotnet run --project ../PythonSample.AppHost/PythonSample.AppHost.csproj --launch-profile http -``` - -> [!IMPORTANT] -> The Aspire AppHost must be run using HTTP instead of HTTPS. The **OpenTelemetry** library requires HTTP when running in a local dev environment. - -Once the AppHost is running, navigate to the dashboard and select the **Structured** logging tab. Notice that it now contains logging events. - -:::image source="media/python-telemetry-in-dashboard.png" lightbox="media/python-telemetry-in-dashboard.png" alt-text="Aspire dashboard: Structured logging from Python process."::: - -## Summary - -While there are several considerations that are beyond the scope of this article, you learned how to build Aspire solution that integrates with Python. You also learned how to use the `AddPythonApp` API to host Python apps. - -## See also - -- [GitHub: Aspire Samplesβ€”Python hosting integration](https://github.com/dotnet/aspire-samples/tree/main/samples/AspireWithPython) diff --git a/docs/get-started/build-your-first-aspire-app.md b/docs/get-started/build-your-first-aspire-app.md deleted file mode 100644 index 9db5d23de3..0000000000 --- a/docs/get-started/build-your-first-aspire-app.md +++ /dev/null @@ -1,243 +0,0 @@ ---- -title: Build your first Aspire solution -description: Learn how to build your first Aspire solution using the Aspire Started Application template. -ms.date: 11/07/2024 -ms.topic: quickstart -zone_pivot_groups: dev-environment -ms.custom: sfi-ropc-nochange ---- - -# Quickstart: Build your first Aspire solution - -Cloud-native apps often require connections to various services such as databases, storage and caching solutions, messaging providers, or other web services. Aspire is designed to streamline connections and configurations between these types of services. This quickstart shows how to create an Aspire Starter Application template solution. - -In this quickstart, you explore the following tasks: - -> [!div class="checklist"] -> -> - Create a basic .NET app that is set up to use Aspire. -> - Add and configure an Aspire integration to implement caching at project creation time. -> - Create an API and use service discovery to connect to it. -> - Orchestrate communication between a front end UI, a back end API, and a local Redis cache. - -[!INCLUDE [aspire-prereqs](../includes/aspire-prereqs.md)] - -## Create the Aspire template - -To create a new Aspire Starter Application, you can use either Visual Studio, Visual Studio Code, or the .NET CLI. - -:::zone pivot="visual-studio" - -[!INCLUDE [visual-studio-file-new](../includes/visual-studio-file-new.md)] - -:::zone-end -:::zone pivot="vscode" - -[!INCLUDE [vscode-file-new](../includes/vscode-file-new.md)] - -:::zone-end -:::zone pivot="dotnet-cli" - -[!INCLUDE [dotnet-cli-file-new](../includes/dotnet-cli-file-new.md)] - -:::zone-end - -For more information on the available templates, see [Aspire templates](../fundamentals/aspire-sdk-templates.md). - -## Test the app locally - -The sample app includes a frontend Blazor app that communicates with a Minimal API project. The API project is used to provide _fake_ weather data to the frontend. The frontend app is configured to use service discovery to connect to the API project. The API project is configured to use output caching with Redis. The sample app is now ready for testing. You want to verify the following conditions: - -- Weather data is retrieved from the API project using service discovery and displayed on the weather page. -- Subsequent requests are handled via the output caching configured by the Aspire Redis integration. - -:::zone pivot="visual-studio" - -In Visual Studio, set the **AspireSample.AppHost** project as the startup project by right-clicking on the project in the **Solution Explorer** and selecting **Set as Startup Project**. It might already have been automatically set as the startup project. Once set, press F5 or (Ctrl + F5 to run without debugging) to run the app. - -:::zone-end -:::zone pivot="dotnet-cli" - -You need to trust the ASP.NET Core localhost certificate before running the app. Run the following command: - -```dotnetcli -dotnet dev-certs https --trust -``` - -For more information, see [Troubleshoot untrusted localhost certificate in Aspire](../troubleshooting/untrusted-localhost-certificate.md). For in-depth details about troubleshooting localhost certificates on Linux, see [ASP.NET Core: GitHub repository issue #32842](https://github.com/dotnet/aspnetcore/issues/32842). - -:::zone-end -:::zone pivot="vscode" - -In Visual Studio Code, press F5 to launch the app. You're prompted to select which language, and C# is suggested. Select **C#** and then select the **AspireSample.AppHost** project with the **Default Configuration**: - -:::image type="content" loc-scope="vs-code" source="media/vscode-run.png" lightbox="media/vscode-run.png" alt-text="A screenshot of the Visual Studio Code launch configuration for the AspireSample.AppHost project."::: - -If this is the first time you're running Aspire, or it's a new machine with a new .NET installation, you're prompted to install a self-signed localhost certificateβ€”and the project will fail to launch: - -:::image type="content" loc-scope="vs-code" source="media/vscode-run-accept-cert.png" lightbox="media/vscode-run-accept-cert.png" alt-text="A screenshot of the Visual Studio Code breaking on an exception and prompting to create a trusted self-signed certificate."::: - -Select **Yes**, and you see an informational message indicating that the **Self-signed certificate successfully created**: - -:::image type="content" loc-scope="vs-code" source="media/vscode-run-cert-created.png" lightbox="media/vscode-run-cert-created.png" alt-text="A screenshot of the Visual Studio Code success message for creating a self-signed certificate."::: - -If you're still having an issue, close all browser windows and try again. For more information, see [Troubleshoot untrusted localhost certificate in Aspire](../troubleshooting/untrusted-localhost-certificate.md). - -> [!TIP] -> If you're on MacOS and using Safari, when your browser opens if the page is blank, you might need to manually refresh the page. - -:::zone-end -:::zone pivot="dotnet-cli" - -```dotnetcli -dotnet run --project AspireSample/AspireSample.AppHost -``` - -For more information, see [dotnet run](/dotnet/core/tools/dotnet-run). - -:::zone-end - -1. The app displays the Aspire dashboard in the browser. You look at the dashboard in more detail later. For now, find the **webfrontend** project in the list of resources and select the project's **localhost** endpoint. - - :::image type="content" source="media/aspire-dashboard-webfrontend.png" lightbox="media/aspire-dashboard-webfrontend.png" alt-text="A screenshot of the Aspire Dashboard, highlighting the webfrontend project's localhost endpoint."::: - - The home page of the **webfrontend** app displays "Hello, world!" - -1. Navigate from the home page to the weather page in the using the left side navigation. The weather page displays weather data. Make a mental note of some of the values represented in the forecast table. -1. Continue occasionally refreshing the page for 10 seconds. Within 10 seconds, the cached data is returned. Eventually, a different set of weather data appears, since the data is randomly generated and the cache is updated. - -:::image type="content" source="media/weather-page.png" lightbox="media/weather-page.png" alt-text="The Weather page of the webfrontend app showing the weather data retrieved from the API."::: - -πŸ€“ Congratulations! You created and ran your first Aspire solution! To stop the app, close the browser window. - -:::zone pivot="visual-studio" - -To stop the app in Visual Studio, select the **Stop Debugging** from the **Debug** menu. - -:::zone-end -:::zone pivot="vscode" - -To stop the app in Visual Studio Code, press Shift + F5, or select the **Stop** button at the top center of the window: - -:::image type="content" loc-scope="vs-code" source="media/vscode-stop.png" lightbox="media/vscode-stop.png" alt-text="A screenshot of the Visual Studio Code stop button."::: - -:::zone-end -:::zone pivot="dotnet-cli" - -To stop the app, press Ctrl + C in the terminal window. - -:::zone-end - -Next, investigate the structure and other features of your new Aspire solution. - -## Explore the Aspire dashboard - -When you run an Aspire project, a [dashboard](https://aspire.dev/dashboard/overview/) launches that you use to monitor various parts of your app. The dashboard resembles the following screenshot: - -:::image type="content" source="media/aspire-dashboard.png" lightbox="media/aspire-dashboard.png" alt-text="A screenshot of the Aspire Dashboard, depicting the Projects tab."::: - -Visit each page using the left navigation to view different information about the Aspire resources: - -- **Resources**: Lists basic information for all of the individual .NET projects in your Aspire project, such as the app state, endpoint addresses, and the environment variables that were loaded in. -- **Console**: Displays the console output from each of the projects in your app. -- **Structured**: Displays structured logs in table format. These logs support basic filtering, free-form search, and log level filtering as well. You should see logs from the `apiservice` and the `webfrontend`. You can expand the details of each log entry by selecting the **View** button on the right end of the row. -- **Traces**: Displays the traces for your application, which can track request paths through your apps. Locate a request for **/weather** and select **View** on the right side of the page. The dashboard should display the request in stages as it travels through the different parts of your app. - - :::image type="content" source="media/aspire-dashboard-trace.png" lightbox="media/aspire-dashboard-trace.png" alt-text="A screenshot showing an Aspire dashboard trace for the webfrontend /weather route."::: - -- **Metrics**: Displays various instruments and meters that are exposed and their corresponding dimensions for your app. Metrics conditionally expose filters based on their available dimensions. - - :::image type="content" source="media/aspire-dashboard-metrics.png" lightbox="media/aspire-dashboard-metrics.png" alt-text="A screenshot showing an Aspire dashboard metrics page for the webfrontend."::: - -For more information, see [Aspire dashboard overview](https://aspire.dev/dashboard/overview/). - -## Understand the Aspire solution structure - -The solution consists of the following projects: - -- **AspireSample.ApiService**: An ASP.NET Core Minimal API project is used to provide data to the front end. This project depends on the shared **AspireSample.ServiceDefaults** project. -- **AspireSample.AppHost**: An orchestrator project designed to connect and configure the different projects and services of your app. The orchestrator should be set as the _Startup project_, and it depends on the **AspireSample.ApiService** and **AspireSample.Web** projects. -- **AspireSample.ServiceDefaults**: A Aspire shared project to manage configurations that are reused across the projects in your solution related to [resilience](/dotnet/core/resilience/http-resilience), [service discovery](https://aspire.dev/fundamentals/service-discovery/), and [telemetry](../fundamentals/telemetry.md). -- **AspireSample.Web**: An ASP.NET Core Blazor App project with default Aspire service configurations, this project depends on the **AspireSample.ServiceDefaults** project. For more information, see [Aspire service defaults](https://aspire.dev/fundamentals/service-defaults/). - -Your _AspireSample_ directory should resemble the following structure: - -[!INCLUDE [template-directory-structure](../includes/template-directory-structure.md)] - -## Explore the starter projects - -Each project in an Aspire solution plays a role in the composition of your app. The _*.Web_ project is a standard ASP.NET Core Blazor App that provides a front end UI. For more information, see [What's new in ASP.NET Core 9.0: Blazor](/aspnet/core/release-notes/aspnetcore-9.0?view=aspnetcore-9.0&preserve-view=true#blazor). The _*.ApiService_ project is a standard ASP.NET Core Minimal API template project. Both of these projects depend on the _*.ServiceDefaults_ project, which is a shared project that's used to manage configurations that are reused across projects in your solution. - -The two projects of interest in this quickstart are the _*.AppHost_ and _*.ServiceDefaults_ projects detailed in the following sections. - -### Aspire host project - -The _*.AppHost_ project is responsible for acting as a local dev-orchestrator: - -:::code language="xml" source="snippets/quickstart/AspireSample/AspireSample.AppHost/AspireSample.AppHost.csproj" highlight="10"::: - -For more information, see [Aspire orchestration overview](../fundamentals/app-host-overview.md) and [Aspire SDK](../fundamentals/dotnet-aspire-sdk.md). - -Consider the _:::no-loc text="AppHost.cs":::_ file of the _AspireSample.AppHost_ project: - -:::code source="snippets/quickstart/AspireSample/AspireSample.AppHost/AppHost.cs"::: - -If you've used either the [.NET Generic Host](/dotnet/core/extensions/generic-host) or the [ASP.NET Core Web Host](/aspnet/core/fundamentals/host/web-host) before, the AppHost programming model and builder pattern should be familiar to you. The preceding code: - -- Creates an instance from calling . -- Calls with the name `"cache"` to add a Redis server to the app, assigning the returned value to a variable named `cache`, which is of type `IResourceBuilder`. -- Calls given the generic-type parameter with the project's details, adding the `AspireSample.ApiService` project to the application model. This is one of the fundamental building blocks of Aspire, and it's used to configure service discovery and communication between the projects in your app. The name argument `"apiservice"` is used to identify the project in the application model, and used later by projects that want to communicate with it. -- Calls `AddProject` again, this time adding the `AspireSample.Web` project to the application model. It also chains multiple calls to passing the `cache` and `apiService` variables. The `WithReference` API is another fundamental API of Aspire, which injects either service discovery information or connection string configuration into the project being added to the application model. Additionally, calls to the `WaitFor` API are used to ensure that the `cache` and `apiService` resources are available before the `AspireSample.Web` project is started. For more information, see [Aspire orchestration: Waiting for resources](../fundamentals/orchestrate-resources.md#waiting-for-resources). - -Finally, the app is built and run. The method is responsible for starting the app and all of its dependencies. For more information, see [Aspire orchestration overview](../fundamentals/app-host-overview.md). - -> [!TIP] -> The call to creates a local Redis container for the app to use. If you'd rather simply point to an existing Redis instance, you can use the `AddConnectionString` method to reference an existing connection string. For more information, see [Reference existing resources](../fundamentals/app-host-overview.md#reference-existing-resources). - -### Aspire service defaults project - -The _*.ServiceDefaults_ project is a shared project that's used to manage configurations that are reused across the projects in your solution. This project ensures that all dependent services share the same resilience, service discovery, and OpenTelemetry configuration. A shared Aspire project file contains the `IsAspireSharedProject` property set as `true`: - -:::code language="xml" source="snippets/quickstart/AspireSample/AspireSample.ServiceDefaults/AspireSample.ServiceDefaults.csproj" highlight="7"::: - -The service defaults project exposes an extension method on the type, named `AddServiceDefaults`. The service defaults project from the template is a starting point, and you can customize it to meet your needs. For more information, see [Aspire service defaults](https://aspire.dev/fundamentals/service-defaults/). - -## Orchestrate service communication - -Aspire provides orchestration features to assist with configuring connections and communication between the different parts of your app. The _AspireSample.AppHost_ project added the _AspireSample.ApiService_ and _AspireSample.Web_ projects to the application model. It also declared their names as `"webfrontend"` for Blazor front end, `"apiservice"` for the API project reference. Additionally, a Redis server resource labeled `"cache"` was added. These names are used to configure service discovery and communication between the projects in your app. - -The front end app defines a typed that's used to communicate with the API project. - -:::code source="snippets/quickstart/AspireSample/AspireSample.Web/WeatherApiClient.cs"::: - -The `HttpClient` is configured to use service discovery. Consider the following code from the _:::no-loc text="Program.cs":::_ file of the _AspireSample.Web_ project: - -:::code source="snippets/quickstart/AspireSample/AspireSample.Web/Program.cs" highlight="7-8,14-19"::: - -The preceding code: - -- Calls `AddServiceDefaults`, configuring the shared defaults for the app. -- Calls with the same `connectionName` that was used when adding the Redis container `"cache"` to the application model. This configures the app to use Redis for output caching. -- Calls and configures the to be `"https+http://apiservice"`. This is the name that was used when adding the API project to the application model, and with service discovery configured, it automatically resolves to the correct address to the API project. - -For more information, see [Make HTTP requests with the `HttpClient`](/dotnet/fundamentals/networking/http/httpclient) class. - -## Aspire CLI - -The Aspire CLI (`aspire` command) is a cross-platform tool that provides command-line functionality to create, manage, run, and publish polyglot Aspire projects. Use the Aspire CLI to streamline development workflows and coordinate services for distributed applications. - -For more information, see [Aspire CLI Overview](../cli/overview.md) and [Install Aspire CLI](../cli/install.md). - -## See also - -- [Aspire integrations overview](../fundamentals/integrations-overview.md) -- [Service discovery in Aspire](https://aspire.dev/fundamentals/service-discovery/) -- [Aspire service defaults](https://aspire.dev/fundamentals/service-defaults/) -- [Health checks in Aspire](https://aspire.dev/fundamentals/health-checks/) -- [Aspire telemetry](../fundamentals/telemetry.md) -- [Troubleshoot untrusted localhost certificate in Aspire](../troubleshooting/untrusted-localhost-certificate.md) - -## Next steps - -> [!div class="nextstepaction"] -> [Tutorial: Add Aspire to an existing .NET app](add-aspire-existing-app.md) diff --git a/docs/get-started/dev-containers.md b/docs/get-started/dev-containers.md index 06a619e02c..14776c7b9e 100644 --- a/docs/get-started/dev-containers.md +++ b/docs/get-started/dev-containers.md @@ -311,5 +311,5 @@ When using Dev Containers with Aspire, keep the following considerations in mind - [Aspire and GitHub Codespaces](github-codespaces.md) - [Aspire Dapr integration](https://aspire.dev/integrations/frameworks/dapr/) - [Visual Studio Dev Containers](https://aka.ms/vs/devcontainers) -- [Add Dockerfiles to your .NET app model](../app-host/withdockerfile.md) +- [Add Dockerfiles to your .NET app model](https://aspire.dev/app-host/withdockerfile/) - [Dev Containers specification](https://containers.dev/implementors/spec/) diff --git a/docs/get-started/docker-compose-to-apphost-reference.md b/docs/get-started/docker-compose-to-apphost-reference.md index 78e6047b1e..4efec3d9f1 100644 --- a/docs/get-started/docker-compose-to-apphost-reference.md +++ b/docs/get-started/docker-compose-to-apphost-reference.md @@ -185,5 +185,5 @@ This reference provides systematic mappings from Docker Compose YAML syntax to e ## See also - [Migrate from Docker Compose to Aspire](migrate-from-docker-compose.md) -- [Aspire orchestration overview](../fundamentals/app-host-overview.md) -- [Add Dockerfiles to your .NET app model](../app-host/withdockerfile.md) +- [Aspire orchestration overview](https://aspire.dev/get-started/app-host/) +- [Add Dockerfiles to your .NET app model](https://aspire.dev/app-host/withdockerfile/) diff --git a/docs/get-started/media/angular-app.png b/docs/get-started/media/angular-app.png deleted file mode 100644 index 39266ccb20..0000000000 Binary files a/docs/get-started/media/angular-app.png and /dev/null differ diff --git a/docs/get-started/media/aspire-dashboard-with-nodejs.png b/docs/get-started/media/aspire-dashboard-with-nodejs.png deleted file mode 100644 index fb3dd46738..0000000000 Binary files a/docs/get-started/media/aspire-dashboard-with-nodejs.png and /dev/null differ diff --git a/docs/get-started/media/python-dashboard.png b/docs/get-started/media/python-dashboard.png deleted file mode 100644 index 5d68a57f24..0000000000 Binary files a/docs/get-started/media/python-dashboard.png and /dev/null differ diff --git a/docs/get-started/media/python-hello-world.png b/docs/get-started/media/python-hello-world.png deleted file mode 100644 index 25f562030c..0000000000 Binary files a/docs/get-started/media/python-hello-world.png and /dev/null differ diff --git a/docs/get-started/media/python-telemetry-in-dashboard.png b/docs/get-started/media/python-telemetry-in-dashboard.png deleted file mode 100644 index b846244173..0000000000 Binary files a/docs/get-started/media/python-telemetry-in-dashboard.png and /dev/null differ diff --git a/docs/get-started/media/react-app.png b/docs/get-started/media/react-app.png deleted file mode 100644 index a5559a8d8d..0000000000 Binary files a/docs/get-started/media/react-app.png and /dev/null differ diff --git a/docs/get-started/media/vue-app.png b/docs/get-started/media/vue-app.png deleted file mode 100644 index 6d10009ee4..0000000000 Binary files a/docs/get-started/media/vue-app.png and /dev/null differ diff --git a/docs/get-started/migrate-from-docker-compose.md b/docs/get-started/migrate-from-docker-compose.md index b7caaab68d..06feb2ec7b 100644 --- a/docs/get-started/migrate-from-docker-compose.md +++ b/docs/get-started/migrate-from-docker-compose.md @@ -41,8 +41,8 @@ For a comprehensive reference mapping Docker Compose YAML syntax to Aspire C# AP **Related links:** - [Docker Compose overview](https://docs.docker.com/compose/) -- [Aspire overview](aspire-overview.md) -- [Aspire orchestration overview](../fundamentals/app-host-overview.md) +- [Aspire overview](https://aspire.dev/get-started/what-is-aspire/) +- [Aspire orchestration overview](https://aspire.dev/get-started/app-host/) ## Common migration patterns @@ -272,8 +272,8 @@ builder.Build().Run(); **Related links:** - [Docker Compose specification](https://docs.docker.com/compose/compose-file/) -- [Aspire AppHost overview](../fundamentals/app-host-overview.md) -- [Add Dockerfiles to your .NET app model](../app-host/withdockerfile.md) +- [Aspire AppHost overview](https://aspire.dev/get-started/app-host/) +- [Add Dockerfiles to your .NET app model](https://aspire.dev/app-host/withdockerfile/) ## Migration strategy @@ -325,7 +325,7 @@ For persistent data: **Related links:** - [Docker Compose migration checklist](https://docs.docker.com/compose/migrate/) -- [Build your first Aspire app](build-your-first-aspire-app.md) +- [Build your first Aspire app](https://aspire.dev/get-started/first-app/) - [Aspire testing overview](https://aspire.dev/testing/overview/) ## Migration troubleshooting @@ -374,16 +374,16 @@ When migrating from Docker Compose to Aspire, you might encounter some common ch After migrating to Aspire: -- Explore [Aspire integrations](../fundamentals/integrations-overview.md) to replace custom container configurations. +- Explore [Aspire integrations](https://aspire.dev/integrations/overview/) to replace custom container configurations. - Set up [health checks](https://aspire.dev/fundamentals/health-checks/) for better monitoring. - Configure [telemetry](../fundamentals/telemetry.md) for observability. -- Learn about [deployment options](../deployment/overview.md) for production environments. +- Learn about [deployment options](https://aspire.dev/deployment/overview/) for production environments. - Consider [testing](https://aspire.dev/testing/overview/) your distributed application. ## See also -- [Aspire overview](aspire-overview.md) +- [Aspire overview](https://aspire.dev/get-started/what-is-aspire/) - [AspiriFridays stream](https://www.youtube.com/@aspiredotdev) -- [Aspire orchestration overview](../fundamentals/app-host-overview.md) +- [Aspire orchestration overview](https://aspire.dev/get-started/app-host/) - [Docker Compose enhancements in Aspire 9.3](../whats-new/dotnet-aspire-9.3.md#-docker-compose-enhancements) -- [Add Dockerfiles to your .NET app model](../app-host/withdockerfile.md) +- [Add Dockerfiles to your .NET app model](https://aspire.dev/app-host/withdockerfile/) diff --git a/docs/get-started/snippets/PythonSample/PythonSample.AppHost/AppHost.cs b/docs/get-started/snippets/PythonSample/PythonSample.AppHost/AppHost.cs deleted file mode 100644 index b2aa8ee3b9..0000000000 --- a/docs/get-started/snippets/PythonSample/PythonSample.AppHost/AppHost.cs +++ /dev/null @@ -1,17 +0,0 @@ -ο»Ώusing Microsoft.Extensions.Hosting; - -var builder = DistributedApplication.CreateBuilder(args); - -#pragma warning disable ASPIREHOSTINGPYTHON001 -var pythonapp = builder.AddPythonApp("hello-python", "../hello-python", "main.py") - .WithHttpEndpoint(env: "PORT") - .WithExternalHttpEndpoints() - .WithOtlpExporter(); -#pragma warning restore ASPIREHOSTINGPYTHON001 - -if (builder.ExecutionContext.IsRunMode && builder.Environment.IsDevelopment()) -{ - pythonapp.WithEnvironment("DEBUG", "True"); -} - -builder.Build().Run(); diff --git a/docs/get-started/snippets/PythonSample/PythonSample.AppHost/Properties/launchSettings.json b/docs/get-started/snippets/PythonSample/PythonSample.AppHost/Properties/launchSettings.json deleted file mode 100644 index f0081b1bec..0000000000 --- a/docs/get-started/snippets/PythonSample/PythonSample.AppHost/Properties/launchSettings.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/launchsettings.json", - "profiles": { - "https": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "applicationUrl": "https://localhost:17171;http://localhost:15209", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development", - "DOTNET_ENVIRONMENT": "Development", - "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21171", - "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22122" - } - }, - "http": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "applicationUrl": "http://localhost:15209", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development", - "DOTNET_ENVIRONMENT": "Development", - "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19171", - "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20208", - "ASPIRE_ALLOW_UNSECURED_TRANSPORT": "true" - } - } - } -} \ No newline at end of file diff --git a/docs/get-started/snippets/PythonSample/PythonSample.AppHost/PythonSample.AppHost.csproj b/docs/get-started/snippets/PythonSample/PythonSample.AppHost/PythonSample.AppHost.csproj deleted file mode 100644 index a49354db72..0000000000 --- a/docs/get-started/snippets/PythonSample/PythonSample.AppHost/PythonSample.AppHost.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - Exe - net9.0 - enable - enable - 5fd92a87-fff8-4a09-9f6e-2c0d656e25ba - - - - - - - - \ No newline at end of file diff --git a/docs/get-started/snippets/PythonSample/PythonSample.AppHost/appsettings.Development.json b/docs/get-started/snippets/PythonSample/PythonSample.AppHost/appsettings.Development.json deleted file mode 100644 index 0c208ae918..0000000000 --- a/docs/get-started/snippets/PythonSample/PythonSample.AppHost/appsettings.Development.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - } -} diff --git a/docs/get-started/snippets/PythonSample/PythonSample.AppHost/appsettings.json b/docs/get-started/snippets/PythonSample/PythonSample.AppHost/appsettings.json deleted file mode 100644 index 31c092aa45..0000000000 --- a/docs/get-started/snippets/PythonSample/PythonSample.AppHost/appsettings.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning", - "Aspire.Hosting.Dcp": "Warning" - } - } -} diff --git a/docs/get-started/snippets/PythonSample/PythonSample.ServiceDefaults/Extensions.cs b/docs/get-started/snippets/PythonSample/PythonSample.ServiceDefaults/Extensions.cs deleted file mode 100644 index 1edfbf67b7..0000000000 --- a/docs/get-started/snippets/PythonSample/PythonSample.ServiceDefaults/Extensions.cs +++ /dev/null @@ -1,111 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Diagnostics.HealthChecks; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Diagnostics.HealthChecks; -using Microsoft.Extensions.Logging; -using OpenTelemetry; -using OpenTelemetry.Metrics; -using OpenTelemetry.Trace; - -namespace Microsoft.Extensions.Hosting; - -// Adds common Aspire services: service discovery, resilience, health checks, and OpenTelemetry. -// This project should be referenced by each service project in your solution. -// To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults -public static class Extensions -{ - public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder) - { - builder.ConfigureOpenTelemetry(); - - builder.AddDefaultHealthChecks(); - - builder.Services.AddServiceDiscovery(); - - builder.Services.ConfigureHttpClientDefaults(http => - { - // Turn on resilience by default - http.AddStandardResilienceHandler(); - - // Turn on service discovery by default - http.AddServiceDiscovery(); - }); - - return builder; - } - - public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicationBuilder builder) - { - builder.Logging.AddOpenTelemetry(logging => - { - logging.IncludeFormattedMessage = true; - logging.IncludeScopes = true; - }); - - builder.Services.AddOpenTelemetry() - .WithMetrics(metrics => - { - metrics.AddAspNetCoreInstrumentation() - .AddHttpClientInstrumentation() - .AddRuntimeInstrumentation(); - }) - .WithTracing(tracing => - { - tracing.AddAspNetCoreInstrumentation() - // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package) - //.AddGrpcClientInstrumentation() - .AddHttpClientInstrumentation(); - }); - - builder.AddOpenTelemetryExporters(); - - return builder; - } - - private static IHostApplicationBuilder AddOpenTelemetryExporters(this IHostApplicationBuilder builder) - { - var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]); - - if (useOtlpExporter) - { - builder.Services.AddOpenTelemetry().UseOtlpExporter(); - } - - // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package) - //if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"])) - //{ - // builder.Services.AddOpenTelemetry() - // .UseAzureMonitor(); - //} - - return builder; - } - - public static IHostApplicationBuilder AddDefaultHealthChecks(this IHostApplicationBuilder builder) - { - builder.Services.AddHealthChecks() - // Add a default liveness check to ensure app is responsive - .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]); - - return builder; - } - - public static WebApplication MapDefaultEndpoints(this WebApplication app) - { - // Adding health checks endpoints to applications in non-development environments has security implications. - // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments. - if (app.Environment.IsDevelopment()) - { - // All health checks must pass for app to be considered ready to accept traffic after starting - app.MapHealthChecks("/health"); - - // Only health checks tagged with the "live" tag must pass for app to be considered alive - app.MapHealthChecks("/alive", new HealthCheckOptions - { - Predicate = r => r.Tags.Contains("live") - }); - } - - return app; - } -} diff --git a/docs/get-started/snippets/PythonSample/PythonSample.ServiceDefaults/PythonSample.ServiceDefaults.csproj b/docs/get-started/snippets/PythonSample/PythonSample.ServiceDefaults/PythonSample.ServiceDefaults.csproj deleted file mode 100644 index 8fd483346a..0000000000 --- a/docs/get-started/snippets/PythonSample/PythonSample.ServiceDefaults/PythonSample.ServiceDefaults.csproj +++ /dev/null @@ -1,22 +0,0 @@ - - - - net9.0 - enable - enable - true - - - - - - - - - - - - - - - diff --git a/docs/get-started/snippets/PythonSample/PythonSample.sln b/docs/get-started/snippets/PythonSample/PythonSample.sln deleted file mode 100644 index a80fd19c03..0000000000 --- a/docs/get-started/snippets/PythonSample/PythonSample.sln +++ /dev/null @@ -1,30 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.8.0.0 -MinimumVisualStudioVersion = 17.8.0.0 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PythonSample.AppHost", "PythonSample.AppHost\PythonSample.AppHost.csproj", "{A80C6371-75DE-47A1-8738-385C54E4B590}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PythonSample.ServiceDefaults", "PythonSample.ServiceDefaults\PythonSample.ServiceDefaults.csproj", "{687DF80B-3F67-49D7-8A94-B67EA5BD9150}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A80C6371-75DE-47A1-8738-385C54E4B590}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A80C6371-75DE-47A1-8738-385C54E4B590}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A80C6371-75DE-47A1-8738-385C54E4B590}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A80C6371-75DE-47A1-8738-385C54E4B590}.Release|Any CPU.Build.0 = Release|Any CPU - {687DF80B-3F67-49D7-8A94-B67EA5BD9150}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {687DF80B-3F67-49D7-8A94-B67EA5BD9150}.Debug|Any CPU.Build.0 = Debug|Any CPU - {687DF80B-3F67-49D7-8A94-B67EA5BD9150}.Release|Any CPU.ActiveCfg = Release|Any CPU - {687DF80B-3F67-49D7-8A94-B67EA5BD9150}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {31663D15-365E-4029-A40F-C4095F36802A} - EndGlobalSection -EndGlobal diff --git a/docs/get-started/snippets/PythonSample/hello-python/gunicorn_config.py b/docs/get-started/snippets/PythonSample/hello-python/gunicorn_config.py deleted file mode 100644 index fee4552a53..0000000000 --- a/docs/get-started/snippets/PythonSample/hello-python/gunicorn_config.py +++ /dev/null @@ -1,12 +0,0 @@ -import os - -workers = int(os.environ.get('GUNICORN_PROCESSES', '1')) -threads = int(os.environ.get('GUNICORN_THREADS', '2')) -timeout = int(os.environ.get('GUNICORN_TIMEOUT', '120')) -host = os.environ.get('HOST', '127.0.0.1') -port = os.environ.get('PORT', '8000') -bind = f'{host}:{port}' - -forwarded_allow_ips = '*' - -secure_scheme_headers = { 'X-Forwarded-Proto': 'https' } \ No newline at end of file diff --git a/docs/get-started/snippets/PythonSample/hello-python/main.py b/docs/get-started/snippets/PythonSample/hello-python/main.py deleted file mode 100644 index 7012fed8d8..0000000000 --- a/docs/get-started/snippets/PythonSample/hello-python/main.py +++ /dev/null @@ -1,31 +0,0 @@ -import os -import logging -import flask -from opentelemetry import trace -from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter -from opentelemetry.sdk.trace import TracerProvider -from opentelemetry.sdk.trace.export import BatchSpanProcessor -from opentelemetry.instrumentation.flask import FlaskInstrumentor - -app = flask.Flask(__name__) - -trace.set_tracer_provider(TracerProvider()) -otlpExporter = OTLPSpanExporter() -processor = BatchSpanProcessor(otlpExporter) -trace.get_tracer_provider().add_span_processor(processor) - -FlaskInstrumentor().instrument_app(app) - -logging.basicConfig(level=logging.INFO) -logger = logging.getLogger(__name__) - -@app.route('/', methods=['GET']) -def hello_world(): - logger.info("request received!") - return 'Hello, World!' - -if __name__ == '__main__': - port = int(os.environ.get('PORT', 8111)) - debug = bool(os.environ.get('DEBUG', False)) - host = os.environ.get('HOST', '127.0.0.1') - app.run(port=port, debug=debug, host=host) \ No newline at end of file diff --git a/docs/get-started/snippets/PythonSample/hello-python/requirements.txt b/docs/get-started/snippets/PythonSample/hello-python/requirements.txt deleted file mode 100644 index 8d5657aa54..0000000000 --- a/docs/get-started/snippets/PythonSample/hello-python/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -Flask==3.0.3 -opentelemetry-distro -opentelemetry-exporter-otlp-proto-grpc -opentelemetry-instrumentation-flask -gunicorn \ No newline at end of file diff --git a/docs/get-started/upgrade-to-aspire-13.md b/docs/get-started/upgrade-to-aspire-13.md index 37bd8b0728..9b4fee6284 100644 --- a/docs/get-started/upgrade-to-aspire-13.md +++ b/docs/get-started/upgrade-to-aspire-13.md @@ -171,7 +171,7 @@ No project file needed - just a single _.cs_ file with package references declar If you prefer to manually upgrade your projects, you can update your project files directly. The following steps guide you through the process: -- Edit your [AppHost](xref:dotnet/aspire/app-host) project file to use the new Aspire 13.0 SDK (`Aspire.AppHost.Sdk`). +- Edit your [AppHost](https://aspire.dev/get-started/app-host/) project file to use the new Aspire 13.0 SDK (`Aspire.AppHost.Sdk`). - Update the NuGet packages in your project files to the latest versions. - Adjust your code to address any breaking changes. diff --git a/docs/includes/integration-observability-and-telemetry.md b/docs/includes/integration-observability-and-telemetry.md index 314b5decfb..2b6e462c7a 100644 --- a/docs/includes/integration-observability-and-telemetry.md +++ b/docs/includes/integration-observability-and-telemetry.md @@ -6,4 +6,4 @@ ms.topic: include ### Observability and telemetry -Aspire integrations automatically set up Logging, Tracing, and Metrics configurations, which are sometimes known as *the pillars of observability*. For more information about integration observability and telemetry, see [Aspire integrations overview](../fundamentals/integrations-overview.md). Depending on the backing service, some integrations may only support some of these features. For example, some integrations support logging and tracing, but not metrics. Telemetry features can also be disabled using the techniques presented in the [Configuration](#configuration) section. +Aspire integrations automatically set up Logging, Tracing, and Metrics configurations, which are sometimes known as *the pillars of observability*. For more information about integration observability and telemetry, see [Aspire integrations overview](https://aspire.dev/integrations/overview/). Depending on the backing service, some integrations may only support some of these features. For example, some integrations support logging and tracing, but not metrics. Telemetry features can also be disabled using the techniques presented in the [Configuration](#configuration) section. diff --git a/docs/index.yml b/docs/index.yml index 1ff48ef53d..3998beb792 100644 --- a/docs/index.yml +++ b/docs/index.yml @@ -15,24 +15,15 @@ metadata: highlightedContent: items: - - itemType: overview - title: Aspire overview - url: get-started/aspire-overview.md - - itemType: quickstart - title: Build your first Aspire solution - url: get-started/build-your-first-aspire-app.md - - itemType: concept - title: AppHost orchestration - url: fundamentals/app-host-overview.md - itemType: concept title: Aspire integrations - url: fundamentals/integrations-overview.md + url: https://aspire.dev/integrations/overview/ - itemType: concept title: Service discovery url: https://aspire.dev/fundamentals/service-discovery/ - itemType: deploy title: Deploy a Aspire projects - url: deployment/overview.md + url: https://aspire.dev/deployment/overview/ - itemType: overview title: Aspire dashboard url: https://aspire.dev/dashboard/overview/ @@ -46,15 +37,9 @@ conceptualContent: items: - title: Get Started links: - - itemType: concept - text: Aspire overview - url: get-started/aspire-overview.md - - itemType: quickstart - text: Build your first Aspire solution - url: get-started/build-your-first-aspire-app.md - itemType: sample text: Add a Node.js app to a Aspire project - url: get-started/build-aspire-apps-with-nodejs.md + url: https://aspire.dev/integrations/frameworks/javascript/ - itemType: how-to-guide text: Aspire setup and tooling url: fundamentals/setup-tooling.md @@ -75,13 +60,10 @@ conceptualContent: url: https://aspire.dev/dashboard/copilot/ - itemType: overview text: Aspire local networking - url: fundamentals/networking-overview.md + url: https://aspire.dev/fundamentals/networking-overview/ - title: Storage integrations links: - - itemType: tutorial - text: Connect to storage with Aspire - url: https://aspire.dev/integrations/cloud/azure/azure-storage/ - itemType: how-to-guide text: Azure Blob Storage url: https://aspire.dev/integrations/cloud/azure/azure-storage-blobs/ @@ -93,7 +75,7 @@ conceptualContent: url: https://aspire.dev/integrations/cloud/azure/azure-storage-tables/ - itemType: sample text: Persist volume mount sample - url: /samples/dotnet/aspire-samples/aspire-volume-mount/ + url: https://aspire.dev/fundamentals/persist-data-volumes/ - title: Database integrations links: @@ -102,25 +84,25 @@ conceptualContent: url: https://aspire.dev/integrations/databases/sql-server/ - itemType: how-to-guide text: PostgreSQL database - url: https://aspire.dev/integrations/databases/postgres/ + url: https://aspire.dev/integrations/databases/postgres/postgres-get-started/ - itemType: how-to-guide text: PostgreSQL with EF Core - url: https://aspire.dev/integrations/databases/postgres-ef/ + url: https://aspire.dev/integrations/databases/efcore/postgresql/ - itemType: how-to-guide text: Azure Cosmos DB url: https://aspire.dev/integrations/cloud/azure/azure-cosmos-db/ - itemType: how-to-guide text: Azure Cosmos DB with EF Core - url: https://aspire.dev/integrations/cloud/azure/azure-cosmos-db/ + url: https://aspire.dev/integrations/databases/efcore/azure-cosmos-db/ - itemType: how-to-guide text: SQL Database url: https://aspire.dev/integrations/databases/sql-server/ - itemType: how-to-guide text: SQL Database with EF Core - url: https://aspire.dev/integrations/databases/sql-server/ + url: https://aspire.dev/integrations/databases/efcore/sql-server/ - itemType: how-to-guide text: Entity Framework Core migrations - url: https://aspire.dev/integrations/databases/ef-core-migrations/ + url: https://aspire.dev/integrations/databases/efcore/migrations/ - itemType: how-to-guide text: MySqlConnector Database url: https://aspire.dev/integrations/databases/mysql/ @@ -130,9 +112,6 @@ conceptualContent: - title: Messaging integrations links: - - itemType: tutorial - text: Implement Messaging with Aspire - url: https://aspire.dev/integrations/messaging/ - itemType: overview text: Azure Event Hubs url: https://aspire.dev/integrations/cloud/azure/azure-event-hubs/ @@ -154,12 +133,6 @@ conceptualContent: - title: Caching integrations links: - - itemType: tutorial - text: Improve app caching with Aspire - url: https://aspire.dev/integrations/caching/ - - itemType: overview - text: Stack Exchange Redis caching overview - url: https://aspire.dev/integrations/caching/redis/ - itemType: how-to-guide text: Redis caching url: https://aspire.dev/integrations/caching/redis/ @@ -175,9 +148,6 @@ conceptualContent: - itemType: overview text: Use Orleans with Aspire url: https://aspire.dev/integrations/frameworks/orleans/ - - itemType: sample - text: Orleans voting sample - url: /samples/dotnet/aspire-samples/orleans-voting-sample-app-on-aspire/ - itemType: overview text: Use Dapr with Aspire url: https://aspire.dev/integrations/frameworks/dapr/ @@ -189,26 +159,25 @@ conceptualContent: links: - itemType: overview text: Overview - url: deployment/overview.md + url: https://aspire.dev/deployment/overview/ - itemType: deploy text: Deploy to Azure Container Apps - url: deployment/azure/aca-deployment.md + url: https://aspire.dev/deployment/azure/aca-deployment-aspire-cli/ - itemType: deploy - text: Deploy using the Azure Developer CLI - url: deployment/azure/aca-deployment-azd-in-depth.md + text: Building custom deployment pipelines + url: https://aspire.dev/deployment/custom-deployments/ - itemType: how-to-guide - text: Integrate with Application Insights - url: deployment/azure/application-insights.md + text: Deployment state caching + url: https://aspire.dev/deployment/deployment-state-caching/ - itemType: reference text: Aspire deployment manifest format - url: deployment/manifest-format.md + url: https://aspire.dev/deployment/manifest-format/ - title: Troubleshooting links: - itemType: how-to-guide text: Allow unsecure transport url: troubleshooting/allow-unsecure-transport.md - - itemType: how-to-guide text: Untrusted localhost certificate url: troubleshooting/untrusted-localhost-certificate.md @@ -228,27 +197,6 @@ conceptualContent: text: Stack Overflow β€” Aspire url: https://stackoverflow.com/questions/tagged/dotnet-aspire - - title: Training - links: - - itemType: training - text: Introduction to Aspire - url: /training/modules/introduction-dotnet-aspire - - itemType: training - text: Create a Aspire project - url: /training/modules/create-aspire-applications - - itemType: training - text: Use telemetry in a Aspire project - url: /training/modules/use-telemetry-dotnet-aspire - - itemType: training - text: Use databases in a Aspire project - url: /training/modules/use-databases-dotnet-aspire-app/ - - itemType: training - text: Improve performance with a cache in a Aspire project - url: /training/modules/improve-performance-cache-aspire/ - - itemType: training - text: Send messages with RabbitMQ in a Aspire project - url: /training/modules/send-messages-rabbitmq-dotnet-aspire-app/ - additionalContent: sections: - title: .NET extensions diff --git a/docs/reference/aspire-faq.yml b/docs/reference/aspire-faq.yml deleted file mode 100644 index 275fabd1d0..0000000000 --- a/docs/reference/aspire-faq.yml +++ /dev/null @@ -1,160 +0,0 @@ -### YamlMime:FAQ -metadata: - title: Frequently asked questions about Aspire - description: Answers to some of the most common questions and scenarios for Aspire. - ms.topic: faq - ms.date: 03/03/2025 -title: Frequently asked questions about Aspire -summary: | - This article lists frequently asked questions about Aspire. For a more comprehensive overview, see [Aspire overview](../get-started/aspire-overview.md). - -sections: - - name: Frequently asked questions - questions: - - question: | - Why choose Aspire over Docker Compose for orchestration? - answer: | - Docker Compose is excellent but is unproductive when all you want to do is run several projects or executables. Docker Compose requires developers to build container images and to run apps inside of containers. That's a barrier when you just want to run your front end, back end, workers, and a database. With Aspire, you don't need to learn anything beyond what you already know. - - Configuration through declarative code is better than through YAML. Docker Compose gets complex once you attempt to do any form of abstraction or composition (for example, see the old [eshopOnContainers app](https://github.com/dotnet-architecture/eShopOnContainers/tree/dev/src)). In addition, there are environment variable replacements (and includes) and no types or IntelliSense, and it's hard to reason about what exactly is running. Debugging is also difficult. Aspire produces a better experience that's easy to get started and scales up to an orchestrator like Compose using a real programming language. - - - question: | - How to add projects to Aspire? - answer: | - You can manually add projects to your Aspire solution by using the `builder.AddProject("", "")` API. - - - question: | - How to deploy Aspire without target cloud-provider tooling? - answer: | - Aspire doesn't constrain deployment of any existing project or solution. Aspire exposes a [deployment manifest](../deployment/manifest-format.md) that's used by tool authors to produce artifacts for deployment to any cloud provider. However, unfortunately, not all cloud providers offer tooling for deployments based on this manifest. The manifest is a simple JSON file that describes the resources of your app and the dependencies between them. The manifest is used by the Azure Developer CLI to deploy to Azure. Likewise, Aspir8 uses the manifest to deploy to Kubernetes. You can use the manifest to deploy to any cloud provider that supports the resources you're using. - - - question: | - If Aspire is mainly for local development, why are client integrations in my project? - answer: | - Aspire's client integrations simplify your development process. They're lightweight wrappers around popular libraries like StackExchange.Redis and Npgsql, adding features such as telemetry, health checks, and resilience. - - Even if you use Aspire only for local development, these integrations provide reasonable defaults, seamless dependency injection, and consistent APIs. - - You're not locked into Aspire's ecosystem. These integrations are just libraries, and you can configure them as you would with the underlying libraries, using environment variables or your preferred methods. - - - question: | - Can Aspire apps be built without Azure dependencies and deployed elsewhere? - answer: | - Yes, you can build Aspire apps without using any Azure-proprietary dependencies. While Aspire does offer a first-party solution to deploying to Azure, it's not a requirement. Aspire is a cloud-native stack that can be used to build applications that run anywhere. All Azure-specific offerings are explicitly called out as such. - - - question: | - Why use Aspire service discovery over Docker Compose with Kubernetes? - answer: | - Aspire service discovery APIs are an abstraction that works with various providers (like Kubernetes and Consul). One of the big advantages is that it works locally and is backed by .NET's `IConfiguration` abstraction. This means you can implement service discovery across your compute fabric in a way that doesn't result in code changes. If you have multiple Kubernetes clusters or services on Azure App Service or Azure Functions, you don't have to fundamentally change your application code to make it work locally, either in a single cluster or across multiple clusters. That's the benefit of the abstraction. - - - question: | - Why use Aspire if OpenTelemetry is available in .NET? - answer: | - Aspire takes a big bet on .NET's integration with OpenTelemetry. The Aspire dashboard is a standard OTLP server that visualizes various telemetry data. Leaning on these open standards makes it easy to build these things without breaking compatibility with the broader ecosystem. - - - question: | - Why use Aspire if Grafana, Jaeger, and Prometheus work with .NET? - answer: | - Aspire isn't a replacement for these tools, but rather a complementary technology. Aspire is a set of libraries and tools that make it easy to build applications that are observable. For more information, see the [Metrics example in the Aspire sample repository](https://github.com/dotnet/aspire-samples/tree/main/samples/Metrics) that shows Grafana and Prometheus. - - - question: | - Why create another framework when existing ones work well? - answer: | - Aspire isn't a framework, it's an [opinionated stack](../get-started/aspire-overview.md). Perhaps the most controversial parts of it are the `DistributedApplication` APIs that you can use to build up the orchestration model in any .NET-based language. While everything is possible today, it's not easy. Using the Unix philosophy, the entire cloud-native ecosystem is built around tying various pieces of CNCF software together to build a stack. Aspire tries to do the same thing using learnings from the cloud-native space and picks some opinions (in ways that use the same building blocks). One novel thing about how Aspire builds various pieces of the stack is that it doesn't restrict the access or compatibility of other applications, frameworks, or services. As people play with it more, they realize how composable and extensible it is. - - - question: | - How does Aspire differ from Microsoft Orleans? - answer: | - Microsoft Orleans and Aspire are complementary technologies. - - [Orleans](/dotnet/orleans) is a distributed actor-based framework. Aspire is a cloud-ready stack for building observable, production-ready, distributed applications. It includes local orchestration capabilities to simplify the developer inner loop and reusable opinionated components for integrating with commonly used application dependencies. An Orleans-based solution will still have external dependencies such as data stores and caches for which Aspire can be used for orchestration purposes. - - For more information, see [Use Orleans with Aspire](https://aspire.dev/integrations/frameworks/orleans/) and the corresponding [Orleans voting app sample](/samples/dotnet/aspire-samples/orleans-voting-sample-app-on-aspire/). - - - question: | - How does Aspire differ from Dapr? - answer: | - Dapr and Aspire are complementary technologies. - - Where Dapr abstracts some of the underlying cloud platform, Aspire provides opinionated configuration around the underlying cloud technologies without abstracting them. A .NET-based application that uses Dapr can use Aspire to orchestrate the local developer inner loop and streamline deployment. Aspire includes extensions that support the launching of Dapr side-car processes during the inner loop. - - For more information, see [Use Dapr with Aspire](https://aspire.dev/integrations/frameworks/dapr/). - - - question: | - How does Aspire differ from Project Tye? - answer: | - Project Tye was an experiment which explored the launching and orchestration of micro-services and support - deployment into orchestrators such as Kubernetes. Aspire is a superset of Tye which includes the - orchestration and deployment capabilities along with opinionated components for integrating common - cloud-native dependencies. Aspire can be considered the evolution of the Project Tye experiment. - - - question: | - How are Aspire and Azure SDK for .NET related? - answer: | - Aspire provides components that rely on the [Azure SDK for .NET](/dotnet/azure/intro), to expose common functionality for storage ([Azure Blob Storage](https://aspire.dev/integrations/azure-blob-storage/), [Azure Storage Queues](https://aspire.dev/integrations/azure-queue-storage/), and [Azure Table Storage](https://aspire.dev/integrations/azure-table-storage/)), databases ([Azure Cosmos DB](https://aspire.dev/integrations/cloud/azure/azure-cosmos-db/) and [Azure Cosmos DB with Entity Framework Core](https://aspire.dev/integrations/cloud/azure/azure-cosmos-db/)), [messaging](https://aspire.dev/integrations/cloud/azure/azure-service-bus/), and [security](https://aspire.dev/integrations/azure-key-vault/). - - - question: | - How are Aspire and Kubernetes related? - answer: | - Aspire makes it easy to develop distributed applications that can be orchestrated on your local development environment as executables and containers. Kubernetes is a technology that orchestrates and manages containers across multiple machines. Aspire projects can produce a [manifest](../deployment/manifest-format.md) that tool authors can use to produce artifacts for deployment to Kubernetes. In essence, Kubernetes is a deployment target for Aspire projects. - - - question: | - Are worker services supported in Aspire? - answer: | - Yes, worker services are fully supported and there are docs and samples available to help you get started. Worker services are a great way to run background tasks, scheduled tasks, or long-running tasks in Aspire. For more information, see [Database migrations with Entity Framework Core sample app](/samples/dotnet/aspire-samples/aspire-efcore-migrations/). - - - question: | - Are Azure Functions supported in Aspire? - answer: | - Yes, Aspire has [preview support for integrating Azure Functions into your app](https://aspire.dev/integrations/compute/azure-functions/). - - - question: | - Does Aspire support running web apps locally on IIS or IIS Express? - answer: | - No. Aspire doesn't support running web apps on IIS or IIS Express. - - - question: | - Does Aspire support deploying apps to IIS? - answer: | - No. Aspire doesn't support deploying apps to IIS. However, it doesn't prevent you from deploying your apps to IIS in the same way that you always have. - - - question: | - How to fix integrations and Service Discovery issues when deploying Aspire apps to IIS? - answer: | - Aspire integrations require specific configuration that must be provided manually. The same is true for [Service Discovery](https://aspire.dev/fundamentals/service-discovery/), ideally, you should deploy to something other than IIS. - - - question: | - What is the purpose of the Community Toolkit project? - answer: | - The goal of the project is to be a centralized home for extensions and integrations for [Aspire](/dotnet/aspire), helping to provide consistency in the way that integrations are built and maintained, as well as easier discoverability for users. - - - question: | - How is the Community Toolkit project different from the official Aspire project? - answer: | - The Aspire Community Toolkit is a community-driven project that's maintained by the community and isn't officially supported by the Aspire team. The toolkit is a collection of integrations and extensions that are built on top of the Aspire project. - - - question: | - How can I contribute to the Community Toolkit project? - answer: | - Anyone can contribute to the Aspire Community Toolkit and before you get started, be sure to read the [Contributing Guide](https://github.com/CommunityToolkit/Aspire/blob/main/CONTRIBUTING.md) to learn how to contribute to the project. - - - question: | - Should I propose a new integration on the Community Toolkit or the `dotnet/aspire` repo? - answer: | - If you have an idea for a new integration, you should propose it on the [Aspire Community Toolkit repository](https://github.com/CommunityToolkit/Aspire), rather than [`dotnet/aspire`](https://github.com/dotnet/aspire), as the official Aspire project is focused on the core functionality of the Aspire project. - - If you've proposed an integration on the `dotnet/aspire` repository, you can still propose it in the Community Toolkit, but link to the existing issue on the `dotnet/aspire` repository to provide context. - - - question: | - How can I find Community Toolkit integrations? - answer: | - Integrations from the Aspire Community Toolkit appear in the **Add Aspire Integration** dialog in Visual Studio under the namespace `CommunityToolkit.Aspire.*`. - -additionalContent: | - - ## Next steps - To learn more about networking and functions: - - * [Aspire overview](../get-started/aspire-overview.md) - * [Build your first Aspire project](../get-started/build-your-first-aspire-app.md) - * [Aspire components](../fundamentals/components-overview.md) diff --git a/docs/toc.yml b/docs/toc.yml index d96a961195..ba50d573a8 100644 --- a/docs/toc.yml +++ b/docs/toc.yml @@ -4,14 +4,6 @@ items: - name: Get Started items: - - name: Aspire overview - displayName: aspire overview,architecture,key concepts,Kubernetes,k8s - href: get-started/aspire-overview.md - - name: Build your first Aspire solution - displayName: quickstart,first app,aspire app - href: get-started/build-your-first-aspire-app.md - - name: Add Aspire to an existing solution - href: get-started/add-aspire-existing-app.md - name: Migrate to Aspire items: - name: From Docker Compose @@ -41,9 +33,6 @@ items: - name: AppHost items: - - name: Overview - displayName: orchestration,aspire apphost,aspire app,dev-time,inner-loop - href: fundamentals/app-host-overview.md - name: Architecture overview displayName: aspire architecture,aspire app,aspire apphost,aspire app model href: architecture/overview.md @@ -52,92 +41,16 @@ items: - name: Resources in Aspire displayName: orchestration,aspire apphost,aspire app href: fundamentals/orchestrate-resources.md - - name: Node.js apps in Aspire - href: get-started/build-aspire-apps-with-nodejs.md - displayName: node.js,node,express,typescript,javascript,spa,client-side,server-side - - name: Python apps in Aspire - displayName: python,flask,fastapi - href: get-started/build-aspire-apps-with-python.md - - name: AppHost configuration - href: app-host/configuration.md - - name: Certificate trust customization - href: app-host/certificate-trust.md - displayName: certificate trust,TLS,HTTPS,development certificate,certificate authority - name: Customize resources - items: - - name: Persistent container services - href: app-host/persistent-containers.md - displayName: persistent containers,container lifetime,withlifetime - - name: Custom resource commands - href: fundamentals/custom-resource-commands.md - displayName: withcommand - - name: Custom HTTP commands - href: fundamentals/http-commands.md - displayName: withhttpcommand, - - name: Custom resource URLs - displayName: withurl,withurlforendpoint,withurls - href: fundamentals/custom-resource-urls.md - - name: Host external executables - href: app-host/executable-resources.md - displayName: executable,addexecutable,external apps,cli tools - - name: Add Dockerfiles to the app model - href: app-host/withdockerfile.md - displayName: dockerfile,docker + href: https://aspire.dev/fundamentals/custom-resource-commands/ - name: Networking overview - displayName: inner loop,local networking,networking - href: fundamentals/networking-overview.md - - name: Eventing in Aspire - href: app-host/eventing.md + href: https://aspire.dev/fundamentals/networking-overview/ - name: Prompt user from CLI or Dashboard - href: extensibility/interaction-service.md + href: https://aspire.dev/extensibility/interaction-service/ - name: Use external parameters - displayName: external parameters,configuration - href: fundamentals/external-parameters.md + href: https://aspire.dev/fundamentals/external-parameters/ - name: Persist data using volumes - displayName: volumes,persist data - href: fundamentals/persist-data-volumes.md - -- name: Aspire CLI - displayName: aspire cli,aspire command line interface,aspire commands,cli - items: - - name: Overview - href: cli/overview.md - - name: Install - href: cli/install.md - - name: Configuration - href: cli/config-settings.md - - name: aspire-install script reference - href: cli/install-script-reference.md - - name: aspire command reference - items: - - name: aspire - href: cli-reference/aspire.md - - name: aspire add - href: cli-reference/aspire-add.md - - name: aspire config [command] - items: - - name: aspire config - href: cli-reference/aspire-config.md - - name: aspire config list - href: cli-reference/aspire-config-list.md - - name: aspire config get - href: cli-reference/aspire-config-get.md - - name: aspire config set - href: cli-reference/aspire-config-set.md - - name: aspire config delete - href: cli-reference/aspire-config-delete.md - - name: aspire deploy (Preview) - href: cli-reference/aspire-deploy.md - - name: aspire exec (Preview) - href: cli-reference/aspire-exec.md - - name: aspire new - href: cli-reference/aspire-new.md - - name: aspire publish (Preview) - href: cli-reference/aspire-publish.md - - name: aspire run - href: cli-reference/aspire-run.md - - name: aspire update (Preview) - href: cli-reference/aspire-update.md + href: https://aspire.dev/fundamentals/persist-data-volumes/ - name: Testing href: https://aspire.dev/testing/overview/ @@ -149,9 +62,6 @@ items: href: https://aspire.dev/fundamentals/service-discovery/ - name: Service defaults href: https://aspire.dev/fundamentals/service-defaults/ - - name: Resource annotations - displayName: annotations,metadata,custom annotations,resource annotations - href: fundamentals/annotations-overview.md - name: Launch profiles href: https://aspire.dev/fundamentals/launch-profiles/ - name: Telemetry @@ -164,7 +74,7 @@ items: items: - name: Overview displayName: aspire integrations,integrations,nuget packages,packages - href: fundamentals/integrations-overview.md + href: https://aspire.dev/integrations/overview/ - name: Tutorials items: - name: Caching using Redis integrations @@ -445,37 +355,14 @@ items: - name: Aspire.Hosting API reference href: /dotnet/api/?term=Aspire.Hosting&view=dotnet-aspire-9.0&preserve-view=true -- name: Custom integrations - items: - - name: Create hosting integrations - displayName: resources,extensibility,hosting,integrations - href: extensibility/custom-hosting-integration.md - - name: Create client integrations - displayName: custom,extensibility,client,library,integrations - href: extensibility/custom-client-integration.md - - name: Secure communication between integrations - href: extensibility/secure-communication-between-integrations.md - - name: Publish and Deploy + href: https://aspire.dev/deployment/overview/ items: - - name: Overview - displayName: azure deployment,deployment,Kubernetes,k8s - href: deployment/overview.md - - name: Building custom deployment pipelines - href: fundamentals/custom-deployments.md - - name: Deployment state caching - href: deployment/deployment-state-caching.md - displayName: deployment state,deployment cache,clear-cache,deployment settings,aspire deploy - name: Azure deployment with Aspire items: - - name: Deploy to Azure Container Apps using Aspire CLI - href: deployment/aspire-deploy/aca-deployment-aspire-cli.md - name: Deploy to Azure Container Apps using Visual Studio href: deployment/aspire-deploy/aca-deployment-visual-studio.md displayName: azure container apps,vs - - name: Azure security best practices - href: deployment/aspire-deploy/azure-security-best-practices.md - displayName: azure security,security best practices,container security,managed identity - name: Use Aspire with Application Insights href: deployment/aspire-deploy/application-insights.md displayName: app insights @@ -499,8 +386,6 @@ items: - name: Customize Aspire Azure deployments using azd href: deployment/azd/customize-deployments.md displayName: azd infra synth,azd infra gen,bicep,infrastructure,production - - name: Tool-builder manifest schemas - href: deployment/manifest-format.md - name: Troubleshoot displayName: troubleshooting @@ -537,9 +422,6 @@ items: href: https://aspire.dev/diagnostics/overview/ - name: Aspire API reference href: /dotnet/api?view=dotnet-aspire-13.0&preserve-view=true - - name: Aspire FAQ - displayName: iis,functions,deploy,azure,kubernetes - href: reference/aspire-faq.yml - name: Aspire NuGet profile href: https://www.nuget.org/profiles/aspire diff --git a/docs/troubleshooting/hosting-startup-not-supported.md b/docs/troubleshooting/hosting-startup-not-supported.md index 2577081517..6f7029ffbc 100644 --- a/docs/troubleshooting/hosting-startup-not-supported.md +++ b/docs/troubleshooting/hosting-startup-not-supported.md @@ -73,4 +73,4 @@ For detailed migration guidance, see: - **Testing**: Aspire provides [testing capabilities](https://aspire.dev/testing/overview/) that work with the new hosting model. -For more information about Aspire integrations and the hosting model, see [Aspire integrations overview](../fundamentals/integrations-overview.md). +For more information about Aspire integrations and the hosting model, see [Aspire integrations overview](https://aspire.dev/integrations/overview/). diff --git a/docs/troubleshooting/name-is-already-in-use.md b/docs/troubleshooting/name-is-already-in-use.md index a68dff9a6d..85420567d5 100644 --- a/docs/troubleshooting/name-is-already-in-use.md +++ b/docs/troubleshooting/name-is-already-in-use.md @@ -14,7 +14,7 @@ This article describes several techniques to avoid this problem. ## Symptoms -When deploying an Aspire project to Azure, the resources in the [app model](../fundamentals/app-host-overview.md#define-the-app-model) are transformed into Azure resources. Some Azure resources have globally scoped names, such as Azure App Configuration, where all instances are in the `[name].azconfig.io` global namespace. +When deploying an Aspire project to Azure, the resources in the [app model](https://aspire.dev/get-started/app-host/#define-the-app-model) are transformed into Azure resources. Some Azure resources have globally scoped names, such as Azure App Configuration, where all instances are in the `[name].azconfig.io` global namespace. The value of `[name]` is derived from the Aspire resource name, along with random characters based on the resource group name. However, the generated string may exceed the allowable length for the resource name in App Configuration. As a result, some characters are truncated to ensure compliance. diff --git a/docs/whats-new/dotnet-aspire-9.1.md b/docs/whats-new/dotnet-aspire-9.1.md index 2eaa8038bc..bf16ce850d 100644 --- a/docs/whats-new/dotnet-aspire-9.1.md +++ b/docs/whats-new/dotnet-aspire-9.1.md @@ -109,7 +109,7 @@ For more information, see [Aspire dashboard: Resources page](https://aspire.dev/ You can now set the `ASPIRE_DASHBOARD_CORS_ALLOWED_ORIGINS` environment variable to allow the dashboard to receive telemetry from other browser apps, such as if you have resources running on custom localhost domains. -For more information, see [Aspire AppHost: Dashboard configuration](../app-host/configuration.md#dashboard). +For more information, see [Aspire AppHost: Dashboard configuration](https://aspire.dev/app-host/configuration/#dashboard). ### πŸͺ΅ Flexibility with console logs @@ -159,11 +159,11 @@ This release introduces a more robust approach to managing socket addresses, ens ## πŸ”Œ Integration updates -Aspire continues to excel through its [integrations](../fundamentals/integrations-overview.md) with various platforms. This release includes numerous updates to existing integrations and details about ownership migrations, enhancing the overall functionality and user experience. +Aspire continues to excel through its [integrations](https://aspire.dev/integrations/overview/) with various platforms. This release includes numerous updates to existing integrations and details about ownership migrations, enhancing the overall functionality and user experience. ### ☁️ Azure updates -This release also focused on improving various [Azure integrations](https://aspire.dev/integrations/cloud/azure/): +This release also focused on improving various [Azure integrations](https://aspire.dev/integrations/cloud/azure/overview/): #### πŸ†• New emulators @@ -171,7 +171,7 @@ We're excited to bring new emulators for making local development easier. The fo - [Azure Service Bus](https://aspire.dev/integrations/cloud/azure/azure-service-bus/#add-azure-service-bus-emulator-resource) - [Azure Cosmos DB Linux-based (preview)](https://aspire.dev/integrations/cloud/azure/azure-cosmos-db/#use-linux-based-emulator-preview) -- [Azure SignalR](/azure/azure-signalr/signalr-howto-emulator) +- [Azure SignalR](https://aspire.dev/integrations/cloud/azure/azure-signalr/#add-an-azure-signalr-service-emulator-resource) ```csharp var serviceBus = builder.AddAzureServiceBus("servicebus") @@ -187,7 +187,7 @@ var signalr = builder.AddAzureSignalR("signalr", AzureSignalRServiceMode.Serverl These new emulators work side-by-side with the existing emulators for: -- [Azure Storage](https://aspire.dev/integrations/cloud/azure/azure-storage/) +- [Azure Storage](https://aspire.dev/integrations/cloud/azure/azure-storage-blobs/) - [Azure Event Hubs](https://aspire.dev/integrations/cloud/azure/azure-event-hubs/#add-azure-event-hubs-emulator-resource) - [Azure Cosmos DB](https://aspire.dev/integrations/cloud/azure/azure-cosmos-db/#add-azure-cosmos-db-emulator-resource) @@ -242,7 +242,7 @@ public class MyCosmosDbTrigger(ILogger logger) } ``` -For more information using Azure Functions with Aspire, see [Aspire Azure Functions integration (Preview)](https://aspire.dev/integrations/compute/azure-functions/). +For more information using Azure Functions with Aspire, see [Aspire Azure Functions integration (Preview)](https://aspire.dev/integrations/cloud/azure/azure-functions/). #### 🚚 Service Bus and Event Hubs @@ -255,7 +255,7 @@ For more information, see the following updated articles: #### ♻️ Working with existing resources -There's consistent feedback about making it easier to connect to existing Azure resources in Aspire. With 9.1, you can now easily connect to an existing Azure resource either directly by `string` name, or with [app model parameters](../fundamentals/external-parameters.md) which can be changed at deployment time. For example to connect to an Azure Service Bus account, we can use the following code: +There's consistent feedback about making it easier to connect to existing Azure resources in Aspire. With 9.1, you can now easily connect to an existing Azure resource either directly by `string` name, or with [app model parameters](https://aspire.dev/fundamentals/external-parameters/) which can be changed at deployment time. For example to connect to an Azure Service Bus account, we can use the following code: ```csharp var existingServiceBusName = builder.AddParameter("serviceBusName"); @@ -265,7 +265,7 @@ var serviceBus = builder.AddAzureServiceBus("messaging") .AsExisting(existingServiceBusName, existingServiceBusResourceGroup); ``` -The preceding code reads the name and resource group from the parameters, and connects to the existing resource when the application is run or deployed. For more information, see [use existing Azure resources](https://aspire.dev/integrations/cloud/azure/#use-existing-azure-resources). +The preceding code reads the name and resource group from the parameters, and connects to the existing resource when the application is run or deployed. For more information, see [use existing Azure resources](https://aspire.dev/integrations/cloud/azure/overview/#use-existing-azure-resources). #### 🌍 Azure Container Apps diff --git a/docs/whats-new/dotnet-aspire-9.2.md b/docs/whats-new/dotnet-aspire-9.2.md index efccc96d3d..ae8df554db 100644 --- a/docs/whats-new/dotnet-aspire-9.2.md +++ b/docs/whats-new/dotnet-aspire-9.2.md @@ -66,7 +66,7 @@ If your AppHost project file doesn't have the `Aspire.AppHost.Sdk` reference, yo ## πŸ–₯️ AppHost enhancements -The [AppHost](../fundamentals/app-host-overview.md) is the core of Aspire, providing the local hosting environment for your distributed applications. In Aspire 9.2, we've made several improvements to the AppHost: +The [AppHost](https://aspire.dev/get-started/app-host/) is the core of Aspire, providing the local hosting environment for your distributed applications. In Aspire 9.2, we've made several improvements to the AppHost: ### 🚧 Project file changes @@ -92,7 +92,7 @@ var catalogDb = builder.AddPostgres("postgres") The preceding code sets the display text for the `PG Admin` URL to `PG Admin`. This makes it easier to access the management console directly from the dashboard. -For more information, see [Define custom resource URLs](../fundamentals/custom-resource-urls.md). +For more information, see [Define custom resource URLs](https://aspire.dev/fundamentals/custom-resource-urls/). ## πŸ”§ Dashboard user experience improvements @@ -136,7 +136,7 @@ We've added a search text box to trace details. Now you can quickly filter large ### 🌐 HTTP-based resource command functionality -[Custom resource commands](../fundamentals/custom-resource-commands.md) now support HTTP-based functionality with the addition of the `WithHttpCommand` API, enabling you to define endpoints for tasks like database migrations or resets. These commands can be run directly from the Aspire dashboard. +[Custom resource commands](https://aspire.dev/fundamentals/custom-resource-commands/) now support HTTP-based functionality with the addition of the `WithHttpCommand` API, enabling you to define endpoints for tasks like database migrations or resets. These commands can be run directly from the Aspire dashboard. Adds WithHttpCommand(), which lets you define a resource command that sends an HTTP request to your app during development. Useful for triggering endpoints like seed or reset from the dashboard. @@ -161,7 +161,7 @@ if (builder.Environment.IsDevelopment()) } ``` -For more information, see [Custom HTTP commands in Aspire](../fundamentals/http-commands.md). +For more information, see [Custom HTTP commands in Aspire](https://aspire.dev/fundamentals/http-commands/). ### πŸ—‚οΈ Connection string resource type @@ -218,7 +218,7 @@ There's [plenty of feedback and confusion](https://github.com/dotnet/aspire/issu | [πŸ“¦ Aspire.Hosting.SqlServer](https://www.nuget.org/packages/Aspire.Hosting.SqlServer) | | | [πŸ“¦ Aspire.Hosting.PostgreSql](https://www.nuget.org/packages/Aspire.Hosting.PostgreSql) | | -The Azure SQL and Azure PostgreSQL hosting integrations also expose `AddDatabase` APIs which work with their respective `RunAsContainer` methods. For more information, see [Understand Azure integration APIs](https://aspire.dev/integrations/cloud/azure/#understand-azure-integration-apis). +The Azure SQL and Azure PostgreSQL hosting integrations also expose `AddDatabase` APIs which work with their respective `RunAsContainer` methods. For more information, see [Understand Azure integration APIs](https://aspire.dev/integrations/cloud/azure/overview/#understand-azure-integration-apis). By default, Aspire will create an empty database if it doesn't exist. You can also optionally provide a custom script to run during creation for advanced setup or seeding. @@ -238,7 +238,7 @@ postgres.AddDatabase("todoapp") For more information and examples of using the `AddDatabase` API, see: -- [Add PostgreSQL resource with database scripts](https://aspire.dev/integrations/databases/postgres/#add-postgresql-resource-with-database-scripts) +- [Add PostgreSQL resource with database scripts](https://aspire.dev/integrations/databases/postgres/postgres-host/#add-postgresql-resource-with-database-scripts) - [Add SQL Server resource with database scripts](https://aspire.dev/integrations/databases/sql-server/#add-sql-server-resource-with-database-scripts) The following hosting integrations don't currently support database creation: @@ -265,7 +265,7 @@ builder.AddAzureContainerAppEnvironment("my-env") .WithAzdResourceNaming(); ``` -For more information, see [Configure Azure Container Apps environments](https://aspire.dev/integrations/azure-container-apps/). +For more information, see [Configure Azure Container Apps environments](https://aspire.dev/integrations/cloud/azure/configure-container-apps/). ### πŸ†• New Client integrations: Azure PostgreSQL (Npgsql & EF Core) @@ -433,7 +433,7 @@ We're excited to announce several new deployment features in Aspire 9.2, includi ### πŸ“¦ Publishers (Preview) -Publishers are a new extensibility point in Aspire that allow you to define how your distributed application gets transformed into deployable assets. Rather than relying on an [intermediate manifest format](../deployment/manifest-format.md), publishers can now plug directly into the application model to generate Docker Compose files, Kubernetes manifests, Azure resources, or whatever else your environment needs. +Publishers are a new extensibility point in Aspire that allow you to define how your distributed application gets transformed into deployable assets. Rather than relying on an [intermediate manifest format](https://aspire.dev/deployment/manifest-format/), publishers can now plug directly into the application model to generate Docker Compose files, Kubernetes manifests, Azure resources, or whatever else your environment needs. When Aspire launched, it introduced a deployment manifest formatβ€”a serialized snapshot of the application model. While useful it burdened deployment tools with interpreting the manifest and resource authors with ensuring accurate serialization. This approach also complicated schema evolution and target-specific behaviors. diff --git a/docs/whats-new/dotnet-aspire-9.4.md b/docs/whats-new/dotnet-aspire-9.4.md index d698fd99a0..863b16c72d 100644 --- a/docs/whats-new/dotnet-aspire-9.4.md +++ b/docs/whats-new/dotnet-aspire-9.4.md @@ -60,7 +60,7 @@ This will install the CLI and put it on your PATH (the binaries are placed in th dotnet tool install -g Aspire.Cli ``` -For more information, see [Install Aspire CLI](../cli/install.md) and [aspire-install script reference](../cli/install-script-reference.md). +For more information, see [Install Aspire CLI](https://aspire.dev/reference/cli/overview/) and [aspire-install script reference](https://aspire.dev/reference/cli/overview/). > [!NOTE] > ⚠️ **The Aspire 9.4 CLI is not compatible with Aspire 9.3 projects.** @@ -106,7 +106,7 @@ aspire exec --start-resource my-worker -- npm run build #### `aspire deploy` -The `aspire deploy` command supports extensible deployment workflows through the new [`DeployingCallbackAnnotation`](../fundamentals/annotations-overview.md), enabling custom pre/post-deploy logic and richer integration with external systems during deployment operations. +The `aspire deploy` command supports extensible deployment workflows through the new [`DeployingCallbackAnnotation`](https://aspire.dev/fundamentals/annotations-overview/), enabling custom pre/post-deploy logic and richer integration with external systems during deployment operations. **Key capabilities:** @@ -233,7 +233,7 @@ For more information about publishing and deploying Aspire apps, see [aspire dep ### πŸŽ›οΈ Interaction service -Aspire 9.4 introduces the [interaction service](../extensibility/interaction-service.md), a general service that allows developers to build rich experiences at runtime by extending the dashboard UX and at publish and deploy time using the Aspire CLI. It allows you to build complex interactions where input is required from the user. +Aspire 9.4 introduces the [interaction service](https://aspire.dev/extensibility/interaction-service/), a general service that allows developers to build rich experiences at runtime by extending the dashboard UX and at publish and deploy time using the Aspire CLI. It allows you to build complex interactions where input is required from the user. > [!IMPORTANT] > πŸ§ͺ This feature is experimental and may change in future releases. @@ -440,7 +440,7 @@ var api = builder.AddProject("api") builder.Build().Run(); ``` -For more information, including supported input types, see the [Interaction Service section](#-interaction-service) below or the full [interaction service docs](../extensibility/interaction-service.md). +For more information, including supported input types, see the [Interaction Service section](#-interaction-service) below or the full [interaction service docs](https://aspire.dev/extensibility/interaction-service/). ### 🌐 External service modeling @@ -468,7 +468,7 @@ External services appear in the Aspire dashboard with health status, can be refe ### πŸ”— Enhanced endpoint URL support -Aspire 9.4 introduces support for [non-localhost URLs](../fundamentals/networking-overview.md), making it easier to work with custom domains and network configurations. This includes support for `*.localhost` subdomains and automatic generation of multiple URL variants for endpoints listening on multiple addresses. +Aspire 9.4 introduces support for [non-localhost URLs](https://aspire.dev/fundamentals/networking-overview/), making it easier to work with custom domains and network configurations. This includes support for `*.localhost` subdomains and automatic generation of multiple URL variants for endpoints listening on multiple addresses. ```csharp var builder = DistributedApplication.CreateBuilder(args); @@ -512,7 +512,7 @@ This simplifies development workflows where custom domains or external network a ### 🐳 Enhanced persistent container support -Aspire 9.4 improves support for [persistent containers](../app-host/persistent-containers.md) with better lifecycle management and networking capabilities, ensuring containers can persist across application restarts while maintaining proper connectivity. +Aspire 9.4 improves support for [persistent containers](https://aspire.dev/app-host/persistent-containers/) with better lifecycle management and networking capabilities, ensuring containers can persist across application restarts while maintaining proper connectivity. ```csharp var builder = DistributedApplication.CreateBuilder(args); @@ -640,7 +640,7 @@ public async Task Should_ResetCache_WhenTestStarts() ### πŸ”„ Resource lifecycle events -Aspire 9.4 introduces convenient extension methods on that make it much easier to subscribe to [lifecycle events](../app-host/eventing.md#apphost-life-cycle-events) directly on resources, providing a cleaner and more intuitive API. +Aspire 9.4 introduces convenient extension methods on that make it much easier to subscribe to [lifecycle events](https://aspire.dev/app-host/eventing/#apphost-life-cycle-events) directly on resources, providing a cleaner and more intuitive API. ```csharp var builder = DistributedApplication.CreateBuilder(args); @@ -768,7 +768,7 @@ var dynamicContainer = builder.AddContainer("worker", "worker:latest") builder.Build().Run(); ``` -The [enhanced APIs](../fundamentals/persist-data-volumes.md) handle file permissions, ownership, and provide both static and dynamic file mounting capabilities while maintaining the flexibility to customize when needed. +The [enhanced APIs](https://aspire.dev/fundamentals/persist-data-volumes/) handle file permissions, ownership, and provide both static and dynamic file mounting capabilities while maintaining the flexibility to customize when needed. ### ✨ Advanced YARP routing with transform APIs (Preview) @@ -870,7 +870,7 @@ This eliminates the need for complex YARP configuration files while providing co ### πŸ”’ Enhanced Docker Compose deployment security -Aspire 9.4 improves [Docker Compose publish](../deployment/overview.md) security with smart port mapping - only external endpoints are exposed to the host while internal services use Docker's internal networking. +Aspire 9.4 improves [Docker Compose publish](https://aspire.dev/deployment/overview/) security with smart port mapping - only external endpoints are exposed to the host while internal services use Docker's internal networking. ```csharp var builder = DistributedApplication.CreateBuilder(args); @@ -914,7 +914,7 @@ When a newer version is detected, a friendly notification appears in the Aspire :::image type="content" source="media/dashboard-update-notification.png" lightbox="media/dashboard-update-notification.png" alt-text="Screenshot of dashboard showing an update notification."::: -Aspire only shows notifications when a newer version is available, and the checks happen in the background without impacting application startup or performance. The upgrade check system can be disabled by setting the `ASPIRE_VERSION_CHECK_DISABLED` environment variable to `true`. For more information, see [Aspire version update notifications](/dotnet/aspire/app-host/configuration#aspire-version-update-notifications). +Aspire only shows notifications when a newer version is available, and the checks happen in the background without impacting application startup or performance. The upgrade check system can be disabled by setting the `ASPIRE_VERSION_CHECK_DISABLED` environment variable to `true`. For more information, see [Aspire version update notifications](https://aspire.dev/app-host/configuration/#aspire-version-update-notifications). ### πŸ“‹ Parameters and connection strings visible in dashboard @@ -1010,7 +1010,7 @@ var chatService = builder.AddProject("chat") builder.Build().Run(); ``` -The [GitHub Models integration](https://aspire.dev/integrations/github-models/) provides: +The [GitHub Models integration](https://aspire.dev/integrations/ai/github-models/) provides: - **Simple model integration** with GitHub's hosted AI models - **Automatic API key parameter creation** with the pattern `{name}-gh-apikey` @@ -1063,7 +1063,7 @@ builder.Build().Run(); #### Client integration -Once you've configured the [Azure AI Foundry resource](https://aspire.dev/integrations/azure-ai-foundry/) in your AppHost, consume it in your services using the [Azure AI Inference SDK](https://aspire.dev/integrations/azure-ai-inference/) or [OpenAI SDK](https://aspire.dev/integrations/cloud/azure/azure-openai/) for compatible models: +Once you've configured the [Azure AI Foundry resource](https://aspire.dev/integrations/cloud/azure/azure-ai-foundry/) in your AppHost, consume it in your services using the [Azure AI Inference SDK](https://aspire.dev/integrations/cloud/azure/azure-ai-inference/) or [OpenAI SDK](https://aspire.dev/integrations/cloud/azure/azure-openai/) for compatible models: **Using Azure AI Inference SDK:** @@ -1244,7 +1244,7 @@ This approach provides: #### πŸ” Disabled local authentication to enforce managed identity -Aspire 9.4 automatically disables local authentication for [Azure EventHubs](https://aspire.dev/integrations/cloud/azure/azure-event-hubs/) and [Azure Web PubSub](https://aspire.dev/integrations/azure-web-pubsub/) resources, enforcing managed identity authentication by default. +Aspire 9.4 automatically disables local authentication for [Azure EventHubs](https://aspire.dev/integrations/cloud/azure/azure-event-hubs/) and [Azure Web PubSub](https://aspire.dev/integrations/cloud/azure/azure-web-pubsub/) resources, enforcing managed identity authentication by default. ```csharp var builder = DistributedApplication.CreateBuilder(args); @@ -1268,7 +1268,7 @@ This change automatically applies to all Azure EventHubs and Web PubSub resource ### πŸ” Azure Key Vault enhancements -Aspire 9.4 introduces significant improvements to the [Azure Key Vault integration](https://aspire.dev/integrations/azure-key-vault/) with new secret management APIs that provide strongly typed access to secrets: +Aspire 9.4 introduces significant improvements to the [Azure Key Vault integration](https://aspire.dev/integrations/cloud/azure/azure-key-vault/) with new secret management APIs that provide strongly typed access to secrets: ```csharp var builder = DistributedApplication.CreateBuilder(args); @@ -1356,7 +1356,7 @@ This approach provides clean separation of concerns, secure container scoping, a ### πŸ“‘ OpenTelemetry tracing support for Azure App Configuration -Aspire 9.4 introduces **OpenTelemetry tracing support** for [Azure App Configuration](https://aspire.dev/integrations/azure-app-configuration/), completing the observability story for this integration. The Azure App Configuration integration now automatically instruments configuration retrieval operations and refresh operations with distributed tracing. +Aspire 9.4 introduces **OpenTelemetry tracing support** for [Azure App Configuration](https://aspire.dev/integrations/cloud/azure/azure-app-configuration/), completing the observability story for this integration. The Azure App Configuration integration now automatically instruments configuration retrieval operations and refresh operations with distributed tracing. ```csharp var builder = WebApplication.CreateBuilder(args); @@ -1425,7 +1425,7 @@ This feature bridges the gap between container development and Azure App Service ### πŸ—οΈ Improvements to the Azure Container Apps integration -Managing complex Azure Container Apps environments often requires integrating with existing Azure resources like Log Analytics workspaces. Aspire 9.4 enhances the [Container Apps integration](https://aspire.dev/integrations/azure-container-apps/) with support for existing Azure resources and improved configuration. +Managing complex Azure Container Apps environments often requires integrating with existing Azure resources like Log Analytics workspaces. Aspire 9.4 enhances the [Container Apps integration](https://aspire.dev/integrations/cloud/azure/configure-container-apps/) with support for existing Azure resources and improved configuration. ```csharp var builder = DistributedApplication.CreateBuilder(args); diff --git a/docs/whats-new/dotnet-aspire-9.5.md b/docs/whats-new/dotnet-aspire-9.5.md index 3efb38ebc7..a753b27012 100644 --- a/docs/whats-new/dotnet-aspire-9.5.md +++ b/docs/whats-new/dotnet-aspire-9.5.md @@ -332,8 +332,8 @@ var embeddingModel = builder.AddGitHubModel("embeddings", GitHubModel.OpenAI.Ope For more information, see: -- [Aspire GitHub Models integration (Preview)](https://aspire.dev/integrations/github-models/). -- [Aspire Azure AI Foundry integration (Preview)](https://aspire.dev/integrations/azure-ai-foundry/). +- [Aspire GitHub Models integration (Preview)](https://aspire.dev/integrations/ai/github-models/). +- [Aspire Azure AI Foundry integration (Preview)](https://aspire.dev/integrations/cloud/azure/azure-ai-foundry/). ### Dev Tunnels hosting integration @@ -537,7 +537,7 @@ var redisEnterprise = builder.AddAzureRedisEnterprise("redis-enterprise") .WithAccessKeyAuthentication(keyVault); ``` -For more information, see [Aspire Azure Managed Redis integration](https://aspire.dev/integrations/azure-redis-enterprise/). +For more information, see [Aspire Azure Managed Redis integration](https://aspire.dev/integrations/cloud/azure/azure-cache-redis/). ### Azure App Configuration emulator (preview) @@ -856,7 +856,7 @@ These resources no longer implement `IResourceWithoutLifetime`; they surface as ### Azure Container App Jobs support -Aspire 9.5 introduces comprehensive support for Azure Container App Jobs, allowing you to deploy both project and container resources as background job workloads that can run on schedules, in response to events, or be triggered manually. For more information, see [Azure Container App Jobs](https://aspire.dev/integrations/azure-container-app-jobs/) +Aspire 9.5 introduces comprehensive support for Azure Container App Jobs, allowing you to deploy both project and container resources as background job workloads that can run on schedules, in response to events, or be triggered manually. For more information, see [Azure Container App Jobs](https://aspire.dev/integrations/cloud/azure/container-app-jobs/) Container App Jobs complement the existing Container Apps functionality by providing a dedicated way to run finite workloads like data processing, ETL operations, batch jobs, and scheduled maintenance tasks. @@ -906,7 +906,7 @@ builder.Build().Run(); Aspire 9.5 delivers the first iteration of a unified Azure provisioning and deployment pipeline through the `aspire deploy` command. The deployment experience features graph-based dependency planning through `ResourceDeploymentGraph` for correct resource provisioning order and maximum parallelism, support for interactive prompting to gather values required for deployment, and enhanced error reporting for identifying issues during deployment. The AppHost integrates Azure provisioning prompts into the standard interaction system for consistent UX, providing deployment-time flexibility with automatic infrastructure provisioning, container image building and registry pushing, and compute resource deployment to Azure Container Appsβ€”all orchestrated through a single command with real-time progress monitoring and comprehensive error reporting. -For more information on deploying to Azure with the Aspire CLI, read [the official documentation](../deployment/aspire-deploy/aca-deployment-aspire-cli.md). +For more information on deploying to Azure with the Aspire CLI, read [the official documentation](https://aspire.dev/deployment/azure/aca-deployment-aspire-cli/). ### Executable resource configuration APIs diff --git a/docs/whats-new/dotnet-aspire-9.md b/docs/whats-new/dotnet-aspire-9.md index 35abcf6b2e..5c666d1d36 100644 --- a/docs/whats-new/dotnet-aspire-9.md +++ b/docs/whats-new/dotnet-aspire-9.md @@ -100,7 +100,7 @@ For more information on configuring browser telemetry, see [Enable browser telem ## AppHost (Orchestration) -The [Aspire AppHost](../fundamentals/app-host-overview.md) is one of the **most important** features of Aspire. In Aspire 9, several new features were added specific to the AppHost. +The [Aspire AppHost](https://aspire.dev/get-started/app-host/) is one of the **most important** features of Aspire. In Aspire 9, several new features were added specific to the AppHost. ### Waiting for dependencies @@ -223,14 +223,14 @@ The container persistence mechanism attempts to identify when you might wish to ### Resource commands -The AppHost supports adding custom commands to resources. This is useful when you want to add custom functionality that is not natively supported by the AppHost. There's likely many opportunities where exposing custom extension methods on resources will be useful. The [Aspire Community Toolkit](https://aspire.dev/integrations/) might be a good place to share these extensions. +The AppHost supports adding custom commands to resources. This is useful when you want to add custom functionality that is not natively supported by the AppHost. There's likely many opportunities where exposing custom extension methods on resources will be useful. The [Aspire Community Toolkit](https://aspire.dev/integrations/overview/) might be a good place to share these extensions. When you define a custom command, it's available in the dashboard as a user experience feature. > [!IMPORTANT] > These Aspire dashboard commands are only available when running the dashboard locally. They're not available when running the dashboard in Azure Container Apps. -For more information on creating custom resource commands, see [How-to: Create custom resource commands in Aspire](../fundamentals/custom-resource-commands.md). +For more information on creating custom resource commands, see [How-to: Create custom resource commands in Aspire](https://aspire.dev/fundamentals/custom-resource-commands/). ### Container networking @@ -246,7 +246,7 @@ The eventing model allows developers to hook into the lifecycle of the applicati - : An event that is triggered after the resources are created. This runs in Run mode only. - : An event that is triggered after the endpoints are allocated for all resources. This runs in Run mode only. -The global events are analogous to the AppHost life cycle events. For more information, see [AppHost life cycles](../app-host/eventing.md#apphost-life-cycle-events). +The global events are analogous to the AppHost life cycle events. For more information, see [AppHost life cycles](https://aspire.dev/app-host/eventing/#apphost-life-cycle-events). **Per-resource events:** @@ -254,11 +254,11 @@ The global events are analogous to the AppHost life cycle events. For more infor - : An event that is triggered when a connection string is available for a resource. This runs in Run mode only. - : An event that is triggered when a resource is ready to be used. This runs in Run mode only. -For more information, see [Eventing in Aspire](../app-host/eventing.md). +For more information, see [Eventing in Aspire](https://aspire.dev/app-host/eventing/). ## Integrations -Aspire continues to add integrations that make it easy to get started with your favorite services and tools. For more information, see [Aspire integrations overview](../fundamentals/integrations-overview.md). +Aspire continues to add integrations that make it easy to get started with your favorite services and tools. For more information, see [Aspire integrations overview](https://aspire.dev/integrations/overview/). ### Redis Insight @@ -646,7 +646,7 @@ Support for Azure Functions in Aspire is still in preview with support for a lim - [Azure Service Bus triggers](/azure/azure-functions/functions-bindings-service-bus?pivots=programming-language-csharp) - [Azure Event Hubs triggers](/azure/azure-functions/functions-bindings-event-hubs?pivots=programming-language-csharp) -For more information, see the official [Aspire Azure Functions integration (Preview)](https://aspire.dev/integrations/compute/azure-functions/). +For more information, see the official [Aspire Azure Functions integration (Preview)](https://aspire.dev/integrations/cloud/azure/azure-functions/). #### Customization of Azure Container Apps @@ -693,7 +693,7 @@ The preceding code example defers generation of the Azure Container App definiti - [Aspire setup and tooling](../fundamentals/setup-tooling.md) - [Aspire SDK](../fundamentals/dotnet-aspire-sdk.md) - [Aspire templates](../fundamentals/aspire-sdk-templates.md) -- [Aspire orchestration overview](../fundamentals/app-host-overview.md) -- [Eventing in Aspire](../app-host/eventing.md) +- [Aspire orchestration overview](https://aspire.dev/get-started/app-host/) +- [Eventing in Aspire](https://aspire.dev/app-host/eventing/) - [Aspire dashboard overview](https://aspire.dev/dashboard/overview/) - [Explore the Aspire dashboard](https://aspire.dev/dashboard/explore/) diff --git a/docs/whats-new/dotnet-docs-aspire-mod0.md b/docs/whats-new/dotnet-docs-aspire-mod0.md index b87ae5337e..c0064a518b 100644 --- a/docs/whats-new/dotnet-docs-aspire-mod0.md +++ b/docs/whats-new/dotnet-docs-aspire-mod0.md @@ -26,10 +26,10 @@ Welcome to what's new in the Aspire docs for June 2025. This article lists some ### Updated articles - [Aspire MongoDB database integration](https://aspire.dev/integrations/databases/mongodb/) - Documents the issue with deploying data volumes to ACA. -- [Apply Entity Framework Core migrations in Aspire](https://aspire.dev/integrations/databases/ef-core-migrations/) +- [Apply Entity Framework Core migrations in Aspire](https://aspire.dev/integrations/databases/efcore/migrations/) - Altered EF Core Migrations tutorial to ensure that API waits for the migrations to complete - Add Microsoft.EntityFrameworkCore.Tools package guidance to EF Core migrations documentation -- [Seed data in a database using Aspire](https://aspire.dev/integrations/databases/seed-database/) - Update seeding data article to Aspire 9.3 +- [Seed data in a database using Aspire](https://aspire.dev/integrations/databases/efcore/seed-database/) - Update seeding data article to Aspire 9.3 ## Messaging @@ -41,7 +41,7 @@ Welcome to what's new in the Aspire docs for June 2025. This article lists some - [Aspire Azure Service Bus integration](https://aspire.dev/integrations/cloud/azure/azure-service-bus/) - Move the "Infrastructure as code" section of the Azure Overview article into a separate article - Recommend AsExisting() for Azure Integrations -- [Aspire Azure Web PubSub integration](https://aspire.dev/integrations/azure-web-pubsub/) +- [Aspire Azure Web PubSub integration](https://aspire.dev/integrations/cloud/azure/azure-web-pubsub/) - Move the "Infrastructure as code" section of the Azure Overview article into a separate article - Recommend AsExisting() for Azure Integrations @@ -49,7 +49,7 @@ Welcome to what's new in the Aspire docs for June 2025. This article lists some ### Updated articles -- [Aspire Azure Key Vault integration](https://aspire.dev/integrations/azure-key-vault/) +- [Aspire Azure Key Vault integration](https://aspire.dev/integrations/cloud/azure/azure-key-vault/) - Move the "Infrastructure as code" section of the Azure Overview article into a separate article - Recommend AsExisting() for Azure Integrations diff --git a/docs/whats-new/dotnet-docs-aspire-mod1.md b/docs/whats-new/dotnet-docs-aspire-mod1.md index 26197e94df..b9ea5c8420 100644 --- a/docs/whats-new/dotnet-docs-aspire-mod1.md +++ b/docs/whats-new/dotnet-docs-aspire-mod1.md @@ -13,11 +13,11 @@ Welcome to what's new in the Aspire docs for April 2025. This article lists some ### Updated articles -- [Orchestrate Python apps in Aspire](../get-started/build-aspire-apps-with-python.md) +- [Orchestrate Python apps in Aspire](https://aspire.dev/get-started/first-app/?lang=python) - Initial draft of diagnostic redesign - Fix the Python article -- [Quickstart: Build your first Aspire solution](../get-started/build-your-first-aspire-app.md) - Split content -- [Tutorial: Add Aspire to an existing .NET app](../get-started/add-aspire-existing-app.md) - Update the add aspire to existing tutorial +- [Quickstart: Build your first Aspire solution](https://aspire.dev/get-started/first-app/) - Split content +- [Tutorial: Add Aspire to an existing .NET app](https://aspire.dev/get-started/add-aspire-existing-app/) - Update the add aspire to existing tutorial ## Fundamentals @@ -28,19 +28,19 @@ Welcome to what's new in the Aspire docs for April 2025. This article lists some ### Updated articles - [Aspire and launch profiles](https://aspire.dev/fundamentals/launch-profiles/) - Rename configs-replace prefix -- [Aspire orchestration overview](../fundamentals/app-host-overview.md) - Split content +- [Aspire orchestration overview](https://aspire.dev/get-started/app-host/) - Split content - [Aspire service defaults](https://aspire.dev/fundamentals/service-defaults/) - Update service defaults and add filtering details - [Aspire setup and tooling](../fundamentals/setup-tooling.md) - Rename configs-replace prefix - [Aspire templates](../fundamentals/aspire-sdk-templates.md) - Add dev-cert details to templates content -- [Custom HTTP commands in Aspire](../fundamentals/http-commands.md) - Split content +- [Custom HTTP commands in Aspire](https://aspire.dev/fundamentals/http-commands/) - Split content - [Dashboard configuration](https://aspire.dev/dashboard/configuration/) - Rename configs-replace prefix - [Enable browser telemetry](https://aspire.dev/dashboard/enable-browser-telemetry/) - Rename configs-replace prefix - [Explore the Aspire dashboard](https://aspire.dev/dashboard/explore/) - Update the Explore the Aspire Dashboard article for v9.2.0 -- [External parameters](../fundamentals/external-parameters.md) - #3063 - Rename parameter name to not be 'value' +- [External parameters](https://aspire.dev/fundamentals/external-parameters/) - #3063 - Rename parameter name to not be 'value' - [Orchestrate resources in Aspire](../fundamentals/orchestrate-resources.md) - Initial draft of diagnostic redesign - Split content -- [Persist Aspire project data using volumes or bind mounts](../fundamentals/persist-data-volumes.md) - Update the "Persist Aspire project data using volumes" article +- [Persist Aspire project data using volumes or bind mounts](https://aspire.dev/fundamentals/persist-data-volumes/) - Update the "Persist Aspire project data using volumes" article - [Security considerations for running the Aspire dashboard](https://aspire.dev/dashboard/security-considerations/) - Rename configs-replace prefix - [Standalone Aspire dashboard](https://aspire.dev/dashboard/standalone/) - Rename configs-replace prefix @@ -63,7 +63,7 @@ Welcome to what's new in the Aspire docs for April 2025. This article lists some - [Aspire Azure Service Bus integration](https://aspire.dev/integrations/cloud/azure/azure-service-bus/) - Split content - Removes obsolete API: Add breaking changes for `AzureOpenAIDeployment` obsoletion -- [Aspire Azure Web PubSub integration](https://aspire.dev/integrations/azure-web-pubsub/) - Removes obsolete API: Add breaking changes for `AzureOpenAIDeployment` obsoletion +- [Aspire Azure Web PubSub integration](https://aspire.dev/integrations/cloud/azure/azure-web-pubsub/) - Removes obsolete API: Add breaking changes for `AzureOpenAIDeployment` obsoletion - [Aspire NATS integration](https://aspire.dev/integrations/messaging/nats/) - Split content - [Aspire RabbitMQ integration](https://aspire.dev/integrations/messaging/rabbitmq/) - Split content @@ -79,7 +79,7 @@ Welcome to what's new in the Aspire docs for April 2025. This article lists some ### Updated articles -- [Aspire Azure Key Vault integration](https://aspire.dev/integrations/azure-key-vault/) - Removes obsolete API: Add breaking changes for `AzureOpenAIDeployment` obsoletion +- [Aspire Azure Key Vault integration](https://aspire.dev/integrations/cloud/azure/azure-key-vault/) - Removes obsolete API: Add breaking changes for `AzureOpenAIDeployment` obsoletion ## Deployment diff --git a/docs/whats-new/dotnet-docs-aspire-mod2.md b/docs/whats-new/dotnet-docs-aspire-mod2.md index 62c12586bb..894d2164cc 100644 --- a/docs/whats-new/dotnet-docs-aspire-mod2.md +++ b/docs/whats-new/dotnet-docs-aspire-mod2.md @@ -13,17 +13,17 @@ Welcome to what's new in the Aspire docs for May 2025. This article lists some o ### Updated articles -- [Orchestrate Node.js apps in Aspire](../get-started/build-aspire-apps-with-nodejs.md) - Fix errors in seed-database-data.md +- [Orchestrate Node.js apps in Aspire](https://aspire.dev/integrations/frameworks/javascript/) - Fix errors in seed-database-data.md ## Fundamentals ### Updated articles -- [Aspire integrations overview](../fundamentals/integrations-overview.md) - Documentation for Aspire RavenDB Integration +- [Aspire integrations overview](https://aspire.dev/integrations/overview/) - Documentation for Aspire RavenDB Integration - [Aspire setup and tooling](../fundamentals/setup-tooling.md) - Add Rancher Desktop details - Update setup-tooling.md to latest Aspire version -- [External parameters](../fundamentals/external-parameters.md) - Add ReferenceExpression to the External Parameters article +- [External parameters](https://aspire.dev/fundamentals/external-parameters/) - Add ReferenceExpression to the External Parameters article - [Tutorial: Use the Aspire dashboard with Python apps](https://aspire.dev/dashboard/standalone-for-python/) - Update standalone-for-python.md ## Database @@ -31,14 +31,14 @@ Welcome to what's new in the Aspire docs for May 2025. This article lists some o ### New articles - [Aspire Azure SQL Entity Framework Core integration](https://aspire.dev/integrations/cloud/azure/azure-sql-database/) -- [Aspire Azure SQL integration](https://aspire.dev/integrations/azure-sql/) +- [Aspire Azure SQL integration](https://aspire.dev/integrations/cloud/azure/azure-sql-database/) ### Updated articles - [Aspire SQL Server Entity Framework Core integration](https://aspire.dev/integrations/databases/sql-server/) - Add Azure SQL integration articles - [Aspire SQL Server integration](https://aspire.dev/integrations/databases/sql-server/) - Add Azure SQL integration articles -- [Apply Entity Framework Core migrations in Aspire](https://aspire.dev/integrations/databases/ef-core-migrations/) - Add explanatory notes to the EF Core Migrations tutorial. -- [Seed data in a database using Aspire](https://aspire.dev/integrations/databases/seed-database/) +- [Apply Entity Framework Core migrations in Aspire](https://aspire.dev/integrations/databases/efcore/migrations/) - Add explanatory notes to the EF Core Migrations tutorial. +- [Seed data in a database using Aspire](https://aspire.dev/integrations/databases/efcore/seed-database/) - Fix errors in seed-database-data.md - Update Seed data in database article to 9.2