From 21123f7263d965bc9f336adf69dce26ba0a3f3cc Mon Sep 17 00:00:00 2001 From: AJ Matthews Date: Thu, 3 Apr 2025 16:40:43 +0100 Subject: [PATCH 1/9] Initial article split. --- docs/fundamentals/app-host-life-cycles.md | 62 ++++++ docs/fundamentals/app-host-overview.md | 244 +-------------------- docs/fundamentals/orchestrate-resources.md | 212 ++++++++++++++++++ 3 files changed, 279 insertions(+), 239 deletions(-) create mode 100644 docs/fundamentals/app-host-life-cycles.md create mode 100644 docs/fundamentals/orchestrate-resources.md diff --git a/docs/fundamentals/app-host-life-cycles.md b/docs/fundamentals/app-host-life-cycles.md new file mode 100644 index 0000000000..0a0d9668e3 --- /dev/null +++ b/docs/fundamentals/app-host-life-cycles.md @@ -0,0 +1,62 @@ +--- +title: App Host life cycles in .NET Aspire +description: Learn how to create hooks that respond to .NET Aspire life cycles and run custom code. +ms.date: 04/05/2025 +ms.topic: article +uid: dotnet/aspire/app-host-life-cycles +--- + +# App Host life cycles in .NET Aspire + +The .NET Aspire app host exposes several life cycles that you can hook into by implementing the interface. The following lifecycle methods are available: + +| Order | Method | Description | +|--|--|--| +| **1** | | Executes before the distributed application starts. | +| **2** | | Executes after the orchestrator allocates endpoints for resources in the application model. | +| **3** | | Executes after the resource was created by the orchestrator. | + +While the app host provides life cycle hooks, you might want to register custom events. For more information, see [Eventing in .NET Aspire](../app-host/eventing.md). + +## Register a life cycle hook + +To register a life cycle hook, implement the interface and register the hook with the app host using the API: + +:::code source="snippets/lifecycles/AspireApp/AspireApp.AppHost/Program.cs"::: + +The preceding code: + +- Implements the interface as a `LifecycleLogger`. +- Registers the life cycle hook with the app host using the API. +- Logs a message for all the events. + +When this app host is run, the life cycle hook is executed for each event. The following output is generated: + +```Output +info: LifecycleLogger[0] + BeforeStartAsync +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: ..\AspireApp\AspireApp.AppHost +info: LifecycleLogger[0] + AfterEndpointsAllocatedAsync +info: Aspire.Hosting.DistributedApplication[0] + Now listening on: https://localhost:17043 +info: Aspire.Hosting.DistributedApplication[0] + Login to the dashboard at https://localhost:17043/login?t=d80f598bc8a64c7ee97328a1cbd55d72 +info: LifecycleLogger[0] + AfterResourcesCreatedAsync +info: Aspire.Hosting.DistributedApplication[0] + Distributed application started. Press Ctrl+C to shut down. +``` + +The preferred way to hook into the app host life cycle is to use the eventing API. For more information, see [Eventing in .NET Aspire](../app-host/eventing.md). + +## See also + +- [.NET Aspire orchestration overview](app-host-overview.md) +- [Orchestrate resources in .NET Aspire](orchestrate-resources.md) +- [Eventing in .NET Aspire](../app-host/eventing.md) diff --git a/docs/fundamentals/app-host-overview.md b/docs/fundamentals/app-host-overview.md index 59a607cf50..d2923f793a 100644 --- a/docs/fundamentals/app-host-overview.md +++ b/docs/fundamentals/app-host-overview.md @@ -10,7 +10,7 @@ uid: dotnet/aspire/app-host .NET Aspire provides APIs for expressing resources and dependencies within your distributed application. In addition to these APIs, [there's tooling](setup-tooling.md#install-net-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 .NET Aspire: @@ -20,6 +20,8 @@ Before continuing, consider some common terminology used in .NET Aspire: - **Integration**: An integration is a NuGet package for either the _app host_ that models a _resource_ or a package that configures a client for use in a consuming app. For more information, see [.NET 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] > .NET 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. @@ -134,25 +136,6 @@ var apiservice = builder.AddProject("apiservice") The preceding code adds three replicas of the "apiservice" project resource to the app model. For more information, see [.NET Aspire dashboard: Resource replicas](dashboard/explore.md#resource-replicas). -## Configure explicit resource start - -Project, executable and container resources are automatically started with your distributed application by default. A resource can be configured to wait for an explicit startup instruction with the method. A resource configured with is initialized with . - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var postgres = builder.AddPostgres("postgres"); -var postgresdb = postgres.AddDatabase("postgresdb"); - -builder.AddProject("dbmigration") - .WithReference(postgresdb) - .WithExplicitStart(); -``` - -In the preceeding code the "dbmigration" resource is configured to not automatically start with the distributed application. - -Resources with explicit start can be started from the .NET Aspire dashboard by clicking the "Start" command. For more information, see [.NET Aspire dashboard: Stop or Start a resource](dashboard/explore.md#stop-or-start-a-resource). - ## Reference resources A reference represents a dependency between resources. For example, you can probably imagine a scenario where you a web frontend depends on a Redis cache. Consider the following example app host `Program` C# code: @@ -168,145 +151,6 @@ builder.AddProject("webfrontend") The "webfrontend" project resource uses to add a dependency on the "cache" container resource. These dependencies can represent connection strings or [service discovery](../service-discovery/overview.md) 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 [.NET Aspire Redis integration](../caching/stackexchange-redis-caching-overview.md), for example, `ConnectionStrings__cache="localhost:62354"`. -### Waiting for resources - -In some cases, you might want to wait for a resource to be ready before starting another resource. For example, you might want to wait for a database to be ready before starting an API that depends on it. To express this dependency, use the method: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var postgres = builder.AddPostgres("postgres"); -var postgresdb = postgres.AddDatabase("postgresdb"); - -builder.AddProject("apiservice") - .WithReference(postgresdb) - .WaitFor(postgresdb); -``` - -In the preceding code, the "apiservice" project resource waits for the "postgresdb" database resource to enter the . The example code shows the [.NET Aspire PostgreSQL integration](../database/postgresql-integration.md), 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: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var postgres = builder.AddPostgres("postgres"); -var postgresdb = postgres.AddDatabase("postgresdb"); - -var migration = builder.AddProject("migration") - .WithReference(postgresdb) - .WaitFor(postgresdb); - -builder.AddProject("apiservice") - .WithReference(postgresdb) - .WaitForCompletion(migration); -``` - -In the preceding code, the "apiservice" project resource waits for the "migration" project resource to run to completion before starting. The "migration" project resource waits for the "postgresdb" database resource to enter the . This can be useful in scenarios where you want to run a database migration before starting the API service, for example. - -#### Forcing resource start in the dashboard - -Waiting for a resource can be bypassed using the "Start" command in the dashboard. Clicking "Start" on a waiting resource in the dashboard instructs it to start immediately without waiting for the resource to be healthy or completed. This can be useful when you want to test a resource immediately and don't want to wait for the app to be in the right state. - -### APIs for adding and expressing resources - -.NET 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 app host, _hosting integrations_ provide APIs for expressing resources and dependencies within the app host. For more information, see [.NET Aspire integrations overview: Integration responsibilities](integrations-overview.md#integration-responsibilities). - -### Express container resources - -To express a you add it to an instance by calling the method: - -#### [Docker](#tab/docker) - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var ollama = builder.AddContainer("ollama", "ollama/ollama") - .WithBindMount("ollama", "/root/.ollama") - .WithBindMount("./ollamaconfig", "/usr/config") - .WithHttpEndpoint(port: 11434, targetPort: 11434, name: "ollama") - .WithEntrypoint("/usr/config/entrypoint.sh") - .WithContainerRuntimeArgs("--gpus=all"); -``` - -For more information, see [GPU support in Docker Desktop](https://docs.docker.com/desktop/gpu/). - -#### [Podman](#tab/podman) - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var ollama = builder.AddContainer("ollama", "ollama/ollama") - .WithBindMount("ollama", "/root/.ollama") - .WithBindMount("./ollamaconfig", "/usr/config") - .WithHttpEndpoint(port: 11434, targetPort: 11434, name: "ollama") - .WithEntrypoint("/usr/config/entrypoint.sh") - .WithContainerRuntimeArgs("--device", "nvidia.com/gpu=all"); -``` - -For more information, see [GPU support in Podman](https://github.com/containers/podman/issues/19005). - ---- - -The preceding code adds a container resource named "ollama" with the image `ollama/ollama`. The container resource is configured with multiple bind mounts, a named HTTP endpoint, an entrypoint that resolves to Unix shell script, and container run arguments with the method. - -#### 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. .NET 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 [.NET Aspire Redis integration](../caching/stackexchange-redis-integration.md). 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: - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var cache = builder.AddRedis("cache") - .WithImageTag("latest"); - -// Instead of using the "7.4" tag, the "cache" -// container resource now uses the "latest" tag. -``` - -For more information and additional APIs available, see . - -#### Container resource lifecycle - -When the app host is run, the is used to determine what container image to create and start. Under the hood, .NET Aspire runs the container using the defined container image by delegating calls to the appropriate OCI-compliant container runtime, either Docker or Podman. The following commands are used: - -#### [Docker](#tab/docker) - -First, the container is created using the `docker container create` command. Then, the container is started using the `docker container start` command. - -- [docker container create](https://docs.docker.com/reference/cli/docker/container/create/): Creates a new container from the specified image, without starting it. -- [docker container start](https://docs.docker.com/reference/cli/docker/container/start/): Start one or more stopped containers. - -These commands are used instead of `docker run` to manage attached container networks, volumes, and ports. Calling these commands in this order allows any IP (network configuration) to already be present at initial startup. - -#### [Podman](#tab/podman) - -First, the container is created using the `podman container create` command. Then, the container is started using the `podman container start` command. - -- [podman container create](https://docs.podman.io/en/latest/markdown/podman-create.1.html): Creates a writable container layer over the specified image and prepares it for running. -- [podman container start](https://docs.podman.io/en/latest/markdown/podman-start.1.html): Start one or more stopped containers. - -These commands are used instead of `podman run` to manage attached container networks, volumes, and ports. Calling these commands in this order allows any IP (network configuration) to already be present at initial startup. - ---- - -Beyond the base resource types, , , and , .NET Aspire provides extension methods to add common resources to your app model. For more information, see [Hosting integrations](integrations-overview.md#hosting-integrations). - -#### Container resource lifetime - -By default, container resources use the _session_ container lifetime. This means that every time the app host process is started, the container is created and started. When the app host stops, the container is stopped and removed. Container resources can opt-in to a _persistent_ lifetime to avoid unnecessary restarts and use persisted container state. To achieve this, chain a call the API and pass : - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var ollama = builder.AddContainer("ollama", "ollama/ollama") - .WithLifetime(ContainerLifetime.Persistent); -``` - -The preceding code adds a container resource named "ollama" with the image "ollama/ollama" and a persistent lifetime. - ### Connection string and endpoint references It's common to express dependencies between project resources. Consider the following example code: @@ -386,55 +230,6 @@ Some situations warrant that you reference an existing resource, perhaps one tha Likewise, there might be use cases where you want to integrate .NET Aspire into an existing solution. One common approach is to add the .NET Aspire app host project to an existing solution. Within your app host, you express dependencies by adding project references to the app host 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 .NET Aspire to an existing .NET app](../get-started/add-aspire-existing-app.md). -## App host life cycles - -The .NET Aspire app host exposes several life cycles that you can hook into by implementing the interface. The following lifecycle methods are available: - -| Order | Method | Description | -|--|--|--| -| **1** | | Executes before the distributed application starts. | -| **2** | | Executes after the orchestrator allocates endpoints for resources in the application model. | -| **3** | | Executes after the resource was created by the orchestrator. | - -While the app host provides life cycle hooks, you might want to register custom events. For more information, see [Eventing in .NET Aspire](../app-host/eventing.md). - -### Register a life cycle hook - -To register a life cycle hook, implement the interface and register the hook with the app host using the API: - -:::code source="snippets/lifecycles/AspireApp/AspireApp.AppHost/Program.cs"::: - -The preceding code: - -- Implements the interface as a `LifecycleLogger`. -- Registers the life cycle hook with the app host using the API. -- Logs a message for all the events. - -When this app host is run, the life cycle hook is executed for each event. The following output is generated: - -```Output -info: LifecycleLogger[0] - BeforeStartAsync -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: ..\AspireApp\AspireApp.AppHost -info: LifecycleLogger[0] - AfterEndpointsAllocatedAsync -info: Aspire.Hosting.DistributedApplication[0] - Now listening on: https://localhost:17043 -info: Aspire.Hosting.DistributedApplication[0] - Login to the dashboard at https://localhost:17043/login?t=d80f598bc8a64c7ee97328a1cbd55d72 -info: LifecycleLogger[0] - AfterResourcesCreatedAsync -info: Aspire.Hosting.DistributedApplication[0] - Distributed application started. Press Ctrl+C to shut down. -``` - -The preferred way to hook into the app host life cycle is to use the eventing API. For more information, see [Eventing in .NET Aspire](../app-host/eventing.md). - ## Execution context The exposes an execution context (), which provides information about the current execution of the app host. This context can be used to evaluate whether or not the app host is executing as "run" mode, or as part of a publish operation. Consider the following properties: @@ -487,39 +282,10 @@ This logic can easily be inverted to connect to an existing Redis resource when > [!IMPORTANT] > .NET 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](../azure/integrations-overview.md#use-existing-azure-resources). -## Resource relationships - -Resource relationships link resources together. Relationships are informational and don't impact an app's runtime behavior. Instead, they're used when displaying details about resources in the dashboard. For example, relationships are visible in the [dashboard's resource details](./dashboard/explore.md#resource-details), and `Parent` relationships control resource nesting on the resources page. - -Relationships are automatically created by some app model APIs. For example: - -- adds a relationship to the target resource with the type `Reference`. -- adds a relationship to the target resource with the type `WaitFor`. -- Adding a database to a DB container creates a relationship from the database to the container with the type `Parent`. - -Relationships can also be explicitly added to the app model using and . - -```csharp -var builder = DistributedApplication.CreateBuilder(args); - -var catalogDb = builder.AddPostgres("postgres") - .WithDataVolume() - .AddDatabase("catalogdb"); - -builder.AddProject("migration") - .WithReference(catalogDb) - .WithParentRelationship(catalogDb); - -builder.Build().Run(); -``` - -The preceding example uses to configure `catalogdb` database as the `migration` project's parent. The `Parent` relationship is special because it controls resource nesting on the resource page. In this example, `migration` is nested under `catalogdb`. - -> [!NOTE] -> There's validation for parent relationships to prevent a resource from having multiple parents or creating a circular reference. These configurations can't be rendered in the UI, and the app model will throw an error. - ## See also +- [Orchestrate resources in .NET Aspire](orchestrate-resources.md) +- [App Host life cycles in .NET Aspire](app-host-life-cycles.md) - [.NET Aspire integrations overview](integrations-overview.md) - [.NET Aspire SDK](dotnet-aspire-sdk.md) - [Eventing in .NET Aspire](../app-host/eventing.md) diff --git a/docs/fundamentals/orchestrate-resources.md b/docs/fundamentals/orchestrate-resources.md new file mode 100644 index 0000000000..63e4d31fa9 --- /dev/null +++ b/docs/fundamentals/orchestrate-resources.md @@ -0,0 +1,212 @@ +--- +title: Orchestrate resources in .NET Aspire +description: Learn techniques to control the behavior of .NET Aspire resources such as project, containers, and executable resources. +ms.date: 04/05/2025 +ms.topic: article +uid: dotnet/aspire/orchestrate-resources +--- + +# Orchestrate resources in .NET Aspire + +In .NET Aspire a **resource** is a dependant part of a cloud-native application. Resource types include: + +- **.NET Project**: A custom microservice, responsible for specific functionality in your cloud-native application, and often built by a separate team of developers. +- **Executable**: If you need to build microservices with tools like Node.js or Orleans, they run as executable resources. +- **Container**: You can add Docker containers, based on specific images to your .NET Aspire solution. +- **Integration resources**: Integrations often add resources such as databases, caches, and messaging services to your application. + +> [!NOTE] For the fundamentals of .NET Aspire orchestration and how it manages resources, see [.NET Aspire orchestration overview](app-host-overview.md). In this article, you'll learn how to further customize the behavior of resources by writing code in the app host project. + +## Configure explicit resource start + +Project, executable and container resources are automatically started with your distributed application by default. A resource can be configured to wait for an explicit startup instruction with the method. A resource configured with is initialized with . + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var postgres = builder.AddPostgres("postgres"); +var postgresdb = postgres.AddDatabase("postgresdb"); + +builder.AddProject("dbmigration") + .WithReference(postgresdb) + .WithExplicitStart(); +``` + +In the preceeding code the "dbmigration" resource is configured to not automatically start with the distributed application. + +Resources with explicit start can be started from the .NET Aspire dashboard by clicking the "Start" command. For more information, see [.NET Aspire dashboard: Stop or Start a resource](dashboard/explore.md#stop-or-start-a-resource). + +## Waiting for resources + +In some cases, you might want to wait for a resource to be ready before starting another resource. For example, you might want to wait for a database to be ready before starting an API that depends on it. To express this dependency, use the method: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var postgres = builder.AddPostgres("postgres"); +var postgresdb = postgres.AddDatabase("postgresdb"); + +builder.AddProject("apiservice") + .WithReference(postgresdb) + .WaitFor(postgresdb); +``` + +In the preceding code, the "apiservice" project resource waits for the "postgresdb" database resource to enter the . The example code shows the [.NET Aspire PostgreSQL integration](../database/postgresql-integration.md), 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: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var postgres = builder.AddPostgres("postgres"); +var postgresdb = postgres.AddDatabase("postgresdb"); + +var migration = builder.AddProject("migration") + .WithReference(postgresdb) + .WaitFor(postgresdb); + +builder.AddProject("apiservice") + .WithReference(postgresdb) + .WaitForCompletion(migration); +``` + +In the preceding code, the "apiservice" project resource waits for the "migration" project resource to run to completion before starting. The "migration" project resource waits for the "postgresdb" database resource to enter the . This can be useful in scenarios where you want to run a database migration before starting the API service, for example. + +### Forcing resource start in the dashboard + +Waiting for a resource can be bypassed using the "Start" command in the dashboard. Clicking "Start" on a waiting resource in the dashboard instructs it to start immediately without waiting for the resource to be healthy or completed. This can be useful when you want to test a resource immediately and don't want to wait for the app to be in the right state. + +## APIs for adding and expressing resources + +.NET 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 app host, _hosting integrations_ provide APIs for expressing resources and dependencies within the app host. For more information, see [.NET Aspire integrations overview: Integration responsibilities](integrations-overview.md#integration-responsibilities). + +## Express container resources + +To express a you add it to an instance by calling the method: + +### [Docker](#tab/docker) + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var ollama = builder.AddContainer("ollama", "ollama/ollama") + .WithBindMount("ollama", "/root/.ollama") + .WithBindMount("./ollamaconfig", "/usr/config") + .WithHttpEndpoint(port: 11434, targetPort: 11434, name: "ollama") + .WithEntrypoint("/usr/config/entrypoint.sh") + .WithContainerRuntimeArgs("--gpus=all"); +``` + +For more information, see [GPU support in Docker Desktop](https://docs.docker.com/desktop/gpu/). + +### [Podman](#tab/podman) + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var ollama = builder.AddContainer("ollama", "ollama/ollama") + .WithBindMount("ollama", "/root/.ollama") + .WithBindMount("./ollamaconfig", "/usr/config") + .WithHttpEndpoint(port: 11434, targetPort: 11434, name: "ollama") + .WithEntrypoint("/usr/config/entrypoint.sh") + .WithContainerRuntimeArgs("--device", "nvidia.com/gpu=all"); +``` + +For more information, see [GPU support in Podman](https://github.com/containers/podman/issues/19005). + +--- + +The preceding code adds a container resource named "ollama" with the image `ollama/ollama`. The container resource is configured with multiple bind mounts, a named HTTP endpoint, an entrypoint that resolves to Unix shell script, and container run arguments with the method. + +### 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. .NET 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 [.NET Aspire Redis integration](../caching/stackexchange-redis-integration.md). 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: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var cache = builder.AddRedis("cache") + .WithImageTag("latest"); + +// Instead of using the "7.4" tag, the "cache" +// container resource now uses the "latest" tag. +``` + +For more information and additional APIs available, see . + +### Container resource lifecycle + +When the app host is run, the is used to determine what container image to create and start. Under the hood, .NET Aspire runs the container using the defined container image by delegating calls to the appropriate OCI-compliant container runtime, either Docker or Podman. The following commands are used: + +#### [Docker](#tab/docker) + +First, the container is created using the `docker container create` command. Then, the container is started using the `docker container start` command. + +- [docker container create](https://docs.docker.com/reference/cli/docker/container/create/): Creates a new container from the specified image, without starting it. +- [docker container start](https://docs.docker.com/reference/cli/docker/container/start/): Start one or more stopped containers. + +These commands are used instead of `docker run` to manage attached container networks, volumes, and ports. Calling these commands in this order allows any IP (network configuration) to already be present at initial startup. + +#### [Podman](#tab/podman) + +First, the container is created using the `podman container create` command. Then, the container is started using the `podman container start` command. + +- [podman container create](https://docs.podman.io/en/latest/markdown/podman-create.1.html): Creates a writable container layer over the specified image and prepares it for running. +- [podman container start](https://docs.podman.io/en/latest/markdown/podman-start.1.html): Start one or more stopped containers. + +These commands are used instead of `podman run` to manage attached container networks, volumes, and ports. Calling these commands in this order allows any IP (network configuration) to already be present at initial startup. + +--- + +Beyond the base resource types, , , and , .NET Aspire provides extension methods to add common resources to your app model. For more information, see [Hosting integrations](integrations-overview.md#hosting-integrations). + +### Container resource lifetime + +By default, container resources use the _session_ container lifetime. This means that every time the app host process is started, the container is created and started. When the app host stops, the container is stopped and removed. Container resources can opt-in to a _persistent_ lifetime to avoid unnecessary restarts and use persisted container state. To achieve this, chain a call the API and pass : + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var ollama = builder.AddContainer("ollama", "ollama/ollama") + .WithLifetime(ContainerLifetime.Persistent); +``` + +The preceding code adds a container resource named "ollama" with the image "ollama/ollama" and a persistent lifetime. + +## Resource relationships + +Resource relationships link resources together. Relationships are informational and don't impact an app's runtime behavior. Instead, they're used when displaying details about resources in the dashboard. For example, relationships are visible in the [dashboard's resource details](./dashboard/explore.md#resource-details), and `Parent` relationships control resource nesting on the resources page. + +Relationships are automatically created by some app model APIs. For example: + +- adds a relationship to the target resource with the type `Reference`. +- adds a relationship to the target resource with the type `WaitFor`. +- Adding a database to a DB container creates a relationship from the database to the container with the type `Parent`. + +Relationships can also be explicitly added to the app model using and . + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var catalogDb = builder.AddPostgres("postgres") + .WithDataVolume() + .AddDatabase("catalogdb"); + +builder.AddProject("migration") + .WithReference(catalogDb) + .WithParentRelationship(catalogDb); + +builder.Build().Run(); +``` + +The preceding example uses to configure `catalogdb` database as the `migration` project's parent. The `Parent` relationship is special because it controls resource nesting on the resource page. In this example, `migration` is nested under `catalogdb`. + +> [!NOTE] +> There's validation for parent relationships to prevent a resource from having multiple parents or creating a circular reference. These configurations can't be rendered in the UI, and the app model will throw an error. + +## See also + +- [.NET Aspire orchestration overview](app-host-overview.md) +- [App Host life cycles in .NET Aspire](app-host-life-cycles.md) From 366f1efe38a80406ce8e37e4122a6694c22bbad4 Mon Sep 17 00:00:00 2001 From: AJ Matthews Date: Fri, 4 Apr 2025 12:53:24 +0100 Subject: [PATCH 2/9] Completed the restructure and moved life cycle events into the eventing overview. --- docs/app-host/eventing.md | 56 +++++++++++++++++++++- docs/fundamentals/app-host-overview.md | 8 ++-- docs/fundamentals/orchestrate-resources.md | 12 ++--- 3 files changed, 65 insertions(+), 11 deletions(-) diff --git a/docs/app-host/eventing.md b/docs/app-host/eventing.md index 0b079d7389..d1f4c97fa6 100644 --- a/docs/app-host/eventing.md +++ b/docs/app-host/eventing.md @@ -1,7 +1,7 @@ --- title: Eventing in .NET Aspire description: Learn how to use the .NET eventing features with .NET Aspire. -ms.date: 11/13/2024 +ms.date: 04/04/2025 --- # Eventing in .NET Aspire @@ -78,3 +78,57 @@ When events are dispatched, you can control how the events are dispatched to sub - : 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. + +## App Host life cycle events in .NET Aspire + +As you have seen, eventing is the most flexible approach. However, in this section you learn about the alternative: life cycle events. + +The .NET Aspire app host exposes several life cycles that you can hook into by implementing the interface. The following lifecycle methods are available: + +| Order | Method | Description | +|--|--|--| +| **1** | | Executes before the distributed application starts. | +| **2** | | Executes after the orchestrator allocates endpoints for resources in the application model. | +| **3** | | Executes 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 app host using the API: + +:::code source="../fundamentals/snippets/lifecycles/AspireApp/AspireApp.AppHost/Program.cs"::: + +The preceding code: + +- Implements the interface as a `LifecycleLogger`. +- Registers the life cycle hook with the app host using the API. +- Logs a message for all the events. + +When this app host is run, the life cycle hook is executed for each event. The following output is generated: + +```Output +info: LifecycleLogger[0] + BeforeStartAsync +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: ..\AspireApp\AspireApp.AppHost +info: LifecycleLogger[0] + AfterEndpointsAllocatedAsync +info: Aspire.Hosting.DistributedApplication[0] + Now listening on: https://localhost:17043 +info: Aspire.Hosting.DistributedApplication[0] + Login to the dashboard at https://localhost:17043/login?t=d80f598bc8a64c7ee97328a1cbd55d72 +info: LifecycleLogger[0] + AfterResourcesCreatedAsync +info: Aspire.Hosting.DistributedApplication[0] + Distributed application started. Press Ctrl+C to shut down. +``` + +The preferred way to hook into the app host life cycle is to use the eventing API. For more information, see [Eventing in .NET Aspire](#eventing-in-net-aspire). + +## See also + +- [.NET Aspire orchestration overview](app-host-overview.md) +- [Orchestrate resources in .NET Aspire](orchestrate-resources.md) diff --git a/docs/fundamentals/app-host-overview.md b/docs/fundamentals/app-host-overview.md index d2923f793a..02e630b73c 100644 --- a/docs/fundamentals/app-host-overview.md +++ b/docs/fundamentals/app-host-overview.md @@ -1,7 +1,7 @@ --- title: .NET Aspire orchestration overview description: Learn the fundamental concepts of .NET Aspire orchestration and explore the various APIs for adding resources and expressing dependencies. -ms.date: 03/19/2025 +ms.date: 04/15/2025 ms.topic: overview uid: dotnet/aspire/app-host --- @@ -138,7 +138,7 @@ The preceding code adds three replicas of the "apiservice" project resource to t ## Reference resources -A reference represents a dependency between resources. For example, you can probably imagine a scenario where you a web frontend depends on a Redis cache. Consider the following example app host `Program` C# code: +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 app host `Program` C# code: ```csharp var builder = DistributedApplication.CreateBuilder(args); @@ -274,8 +274,8 @@ builder.Build().Run(); In the preceding code: -- If the app host is running in "run" mode, a Redis container resource is added. -- If the app host is running in "publish" mode, a connection string is added. +- If the app host is in "run" mode, a Redis container resource is added. +- If the app host 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. diff --git a/docs/fundamentals/orchestrate-resources.md b/docs/fundamentals/orchestrate-resources.md index 63e4d31fa9..b88b92ec12 100644 --- a/docs/fundamentals/orchestrate-resources.md +++ b/docs/fundamentals/orchestrate-resources.md @@ -1,25 +1,25 @@ --- title: Orchestrate resources in .NET Aspire description: Learn techniques to control the behavior of .NET Aspire resources such as project, containers, and executable resources. -ms.date: 04/05/2025 +ms.date: 04/04/2025 ms.topic: article uid: dotnet/aspire/orchestrate-resources --- # Orchestrate resources in .NET Aspire -In .NET Aspire a **resource** is a dependant part of a cloud-native application. Resource types include: +In .NET Aspire, a **resource** is a dependant part of a cloud-native application. Resource types include: - **.NET Project**: A custom microservice, responsible for specific functionality in your cloud-native application, and often built by a separate team of developers. - **Executable**: If you need to build microservices with tools like Node.js or Orleans, they run as executable resources. - **Container**: You can add Docker containers, based on specific images to your .NET Aspire solution. - **Integration resources**: Integrations often add resources such as databases, caches, and messaging services to your application. -> [!NOTE] For the fundamentals of .NET Aspire orchestration and how it manages resources, see [.NET Aspire orchestration overview](app-host-overview.md). In this article, you'll learn how to further customize the behavior of resources by writing code in the app host project. +> [!NOTE] For the fundamentals of .NET Aspire orchestration and how it manages resources, see [.NET Aspire orchestration overview](app-host-overview.md). In this article, you'll learn how to customize the behavior of resources further by writing code in the app host project. ## Configure explicit resource start -Project, executable and container resources are automatically started with your distributed application by default. A resource can be configured to wait for an explicit startup instruction with the method. A resource configured with is initialized with . +Project, executable, and container resources are automatically started with your distributed application by default. A resource can be configured to wait for an explicit startup instruction with the method. A resource configured with is initialized with . ```csharp var builder = DistributedApplication.CreateBuilder(args); @@ -51,7 +51,7 @@ builder.AddProject("apiservice") .WaitFor(postgresdb); ``` -In the preceding code, the "apiservice" project resource waits for the "postgresdb" database resource to enter the . The example code shows the [.NET Aspire PostgreSQL integration](../database/postgresql-integration.md), 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 [.NET Aspire PostgreSQL integration](../database/postgresql-integration.md), 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: @@ -70,7 +70,7 @@ builder.AddProject("apiservice") .WaitForCompletion(migration); ``` -In the preceding code, the "apiservice" project resource waits for the "migration" project resource to run to completion before starting. The "migration" project resource waits for the "postgresdb" database resource to enter the . This can be useful in scenarios where you want to run a database migration before starting the API service, for example. +In the preceding code, the "apiservice" project resource waits for the "migration" project resource to run to completion before starting. The "migration" project resource waits for the "postgresdb" database resource to enter the state. This can be useful in scenarios where you want to run a database migration before starting the API service, for example. ### Forcing resource start in the dashboard From a9dc8cf8a36b24c931fb739b10d1f7374f320312 Mon Sep 17 00:00:00 2001 From: AJ Matthews Date: Fri, 4 Apr 2025 14:25:34 +0100 Subject: [PATCH 3/9] Updated TOC and removed an unnecessary new file. --- docs/fundamentals/app-host-life-cycles.md | 62 ----------------------- docs/toc.yml | 3 ++ 2 files changed, 3 insertions(+), 62 deletions(-) delete mode 100644 docs/fundamentals/app-host-life-cycles.md diff --git a/docs/fundamentals/app-host-life-cycles.md b/docs/fundamentals/app-host-life-cycles.md deleted file mode 100644 index 0a0d9668e3..0000000000 --- a/docs/fundamentals/app-host-life-cycles.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: App Host life cycles in .NET Aspire -description: Learn how to create hooks that respond to .NET Aspire life cycles and run custom code. -ms.date: 04/05/2025 -ms.topic: article -uid: dotnet/aspire/app-host-life-cycles ---- - -# App Host life cycles in .NET Aspire - -The .NET Aspire app host exposes several life cycles that you can hook into by implementing the interface. The following lifecycle methods are available: - -| Order | Method | Description | -|--|--|--| -| **1** | | Executes before the distributed application starts. | -| **2** | | Executes after the orchestrator allocates endpoints for resources in the application model. | -| **3** | | Executes after the resource was created by the orchestrator. | - -While the app host provides life cycle hooks, you might want to register custom events. For more information, see [Eventing in .NET Aspire](../app-host/eventing.md). - -## Register a life cycle hook - -To register a life cycle hook, implement the interface and register the hook with the app host using the API: - -:::code source="snippets/lifecycles/AspireApp/AspireApp.AppHost/Program.cs"::: - -The preceding code: - -- Implements the interface as a `LifecycleLogger`. -- Registers the life cycle hook with the app host using the API. -- Logs a message for all the events. - -When this app host is run, the life cycle hook is executed for each event. The following output is generated: - -```Output -info: LifecycleLogger[0] - BeforeStartAsync -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: ..\AspireApp\AspireApp.AppHost -info: LifecycleLogger[0] - AfterEndpointsAllocatedAsync -info: Aspire.Hosting.DistributedApplication[0] - Now listening on: https://localhost:17043 -info: Aspire.Hosting.DistributedApplication[0] - Login to the dashboard at https://localhost:17043/login?t=d80f598bc8a64c7ee97328a1cbd55d72 -info: LifecycleLogger[0] - AfterResourcesCreatedAsync -info: Aspire.Hosting.DistributedApplication[0] - Distributed application started. Press Ctrl+C to shut down. -``` - -The preferred way to hook into the app host life cycle is to use the eventing API. For more information, see [Eventing in .NET Aspire](../app-host/eventing.md). - -## See also - -- [.NET Aspire orchestration overview](app-host-overview.md) -- [Orchestrate resources in .NET Aspire](orchestrate-resources.md) -- [Eventing in .NET Aspire](../app-host/eventing.md) diff --git a/docs/toc.yml b/docs/toc.yml index c2f3e66774..6352f2670f 100644 --- a/docs/toc.yml +++ b/docs/toc.yml @@ -36,6 +36,9 @@ items: href: fundamentals/app-host-overview.md - name: Locally orchestrate items: + - name: Orchestrate resources in .NET Aspire + displayName: orchestration,aspire apphost,aspire app + href: fundamentals/orchestrate-resources.md - name: Node.js apps in .NET Aspire href: get-started/build-aspire-apps-with-nodejs.md displayName: node.js,node,express,typescript,javascript,spa,client-side,server-side From 831904f7e79edbd0a9f821e676dc92dafc0b13dd Mon Sep 17 00:00:00 2001 From: AJ Matthews Date: Fri, 4 Apr 2025 15:01:00 +0100 Subject: [PATCH 4/9] Fixed links to moved sections. --- docs/app-host/eventing.md | 6 +- docs/caching/includes/garnet-app-host.md | 2 +- docs/caching/includes/redis-app-host.md | 2 +- docs/caching/includes/valkey-app-host.md | 2 +- docs/community-toolkit/hosting-eventstore.md | 2 +- docs/community-toolkit/hosting-meilisearch.md | 2 +- docs/community-toolkit/ollama.md | 2 +- docs/database/includes/cosmos-app-host.md | 6 +- docs/database/includes/mysql-app-host.md | 2 +- docs/database/includes/postgresql-app-host.md | 2 +- docs/database/includes/sql-app-host.md | 2 +- docs/database/milvus-integration.md | 2 +- docs/database/mongodb-integration.md | 2 +- .../oracle-entity-framework-integration.md | 4 +- docs/database/qdrant-integration.md | 2 +- docs/fundamentals/app-host-overview.md | 1 - docs/fundamentals/orchestrate-resources.md | 5 +- .../build-your-first-aspire-app.md | 2 +- docs/logging/seq-integration.md | 2 +- .../azure-service-bus-integration.md | 2 +- docs/messaging/kafka-integration.md | 2 +- docs/messaging/nats-integration.md | 2 +- docs/messaging/rabbitmq-integration.md | 2 +- docs/search/elasticsearch-integration.md | 2 +- docs/storage/includes/storage-app-host.md | 207 ++++++++++++++++++ docs/whats-new/dotnet-aspire-9.1.md | 2 +- docs/whats-new/dotnet-aspire-9.md | 6 +- 27 files changed, 241 insertions(+), 34 deletions(-) diff --git a/docs/app-host/eventing.md b/docs/app-host/eventing.md index d1f4c97fa6..f2c1502006 100644 --- a/docs/app-host/eventing.md +++ b/docs/app-host/eventing.md @@ -79,7 +79,7 @@ When events are dispatched, you can control how the events are dispatched to sub The default behavior is `EventDispatchBehavior.BlockingSequential`. To override this behavior, when calling a publishing API such as , provide the desired behavior as an argument. -## App Host life cycle events in .NET Aspire +## App Host life cycle events As you have seen, eventing is the most flexible approach. However, in this section you learn about the alternative: life cycle events. @@ -130,5 +130,5 @@ The preferred way to hook into the app host life cycle is to use the eventing AP ## See also -- [.NET Aspire orchestration overview](app-host-overview.md) -- [Orchestrate resources in .NET Aspire](orchestrate-resources.md) +- [.NET Aspire orchestration overview](../fundamentals/app-host-overview.md) +- [Orchestrate resources in .NET Aspire](../fundamentals/orchestrate-resources.md) diff --git a/docs/caching/includes/garnet-app-host.md b/docs/caching/includes/garnet-app-host.md index 8e812517bb..8c4fd6b466 100644 --- a/docs/caching/includes/garnet-app-host.md +++ b/docs/caching/includes/garnet-app-host.md @@ -38,7 +38,7 @@ builder.AddProject() When .NET Aspire adds a container image to the app host, as shown in the preceding example with the `ghcr.io/microsoft/garnet` image, it creates a new Garnet instance on your local machine. A reference to your Garnet resource (the `cache` variable) is added to the `ExampleProject`. -The method configures a connection in the `ExampleProject` named `"cache"`. For more information, see [Container resource lifecycle](../../fundamentals/app-host-overview.md#container-resource-lifecycle). +The method configures a connection in the `ExampleProject` named `"cache"`. For more information, see [Container resource lifecycle](../../fundamentals/orchestrate-resources.md#container-resource-lifecycle). > [!TIP] > If you'd rather connect to an existing Garnet instance, call instead. For more information, see [Reference existing resources](../../fundamentals/app-host-overview.md#reference-existing-resources). diff --git a/docs/caching/includes/redis-app-host.md b/docs/caching/includes/redis-app-host.md index 16c52caac1..2f4961e08c 100644 --- a/docs/caching/includes/redis-app-host.md +++ b/docs/caching/includes/redis-app-host.md @@ -38,7 +38,7 @@ builder.AddProject() When .NET Aspire adds a container image to the app host, as shown in the preceding example with the `docker.io/Redis/Redis` image, it creates a new Redis instance on your local machine. A reference to your Redis resource (the `cache` variable) is added to the `ExampleProject`. -The method configures a connection in the `ExampleProject` named `"cache"`. For more information, see [Container resource lifecycle](../../fundamentals/app-host-overview.md#container-resource-lifecycle). +The method configures a connection in the `ExampleProject` named `"cache"`. For more information, see [Container resource lifecycle](../../fundamentals/orchestrate-resources.md#container-resource-lifecycle). > [!TIP] > If you'd rather connect to an existing Redis instance, call instead. For more information, see [Reference existing resources](../../fundamentals/app-host-overview.md#reference-existing-resources). diff --git a/docs/caching/includes/valkey-app-host.md b/docs/caching/includes/valkey-app-host.md index 61d202a026..d994358faa 100644 --- a/docs/caching/includes/valkey-app-host.md +++ b/docs/caching/includes/valkey-app-host.md @@ -38,7 +38,7 @@ builder.AddProject() When .NET Aspire adds a container image to the app host, as shown in the preceding example with the `docker.io/valkey/valkey` image, it creates a new Valkey instance on your local machine. A reference to your Valkey resource (the `cache` variable) is added to the `ExampleProject`. -The method configures a connection in the `ExampleProject` named `"cache"`. For more information, see [Container resource lifecycle](../../fundamentals/app-host-overview.md#container-resource-lifecycle). +The method configures a connection in the `ExampleProject` named `"cache"`. For more information, see [Container resource lifecycle](../../fundamentals/orchestrate-resources.md#container-resource-lifecycle). > [!TIP] > If you'd rather connect to an existing Valkey instance, call instead. For more information, see [Reference existing resources](../../fundamentals/app-host-overview.md#reference-existing-resources). diff --git a/docs/community-toolkit/hosting-eventstore.md b/docs/community-toolkit/hosting-eventstore.md index afdcb84e24..3c34afde5c 100644 --- a/docs/community-toolkit/hosting-eventstore.md +++ b/docs/community-toolkit/hosting-eventstore.md @@ -50,7 +50,7 @@ builder.AddProject() When .NET Aspire adds a container image to the app host, as shown in the preceding example with the `docker.io/eventstore/eventstore` image, it creates a new EventStore instance on your local machine. A reference to your EventStore resource (the `eventstore` variable) is added to the `ExampleProject`. -For more information, see [Container resource lifecycle](../fundamentals/app-host-overview.md#container-resource-lifecycle). +For more information, see [Container resource lifecycle](../fundamentals/orchestrate-resources.md#container-resource-lifecycle). ### Add EventStore resource with data volume diff --git a/docs/community-toolkit/hosting-meilisearch.md b/docs/community-toolkit/hosting-meilisearch.md index c869aed775..e39b175145 100644 --- a/docs/community-toolkit/hosting-meilisearch.md +++ b/docs/community-toolkit/hosting-meilisearch.md @@ -50,7 +50,7 @@ builder.AddProject() When .NET Aspire adds a container image to the app host, as shown in the preceding example with the `docker.io/getmeili/meilisearch` image, it creates a new Meilisearch instance on your local machine. A reference to your Meilisearch resource (the `meilisearch` variable) is added to the `ExampleProject`. The Meilisearch resource includes a randomly generated `master key` using the method when a master key wasn't provided. -For more information, see [Container resource lifecycle](../fundamentals/app-host-overview.md#container-resource-lifecycle). +For more information, see [Container resource lifecycle](../fundamentals/orchestrate-resources.md#container-resource-lifecycle). ### Add Meilisearch resource with data volume diff --git a/docs/community-toolkit/ollama.md b/docs/community-toolkit/ollama.md index 4bad908487..e232b1a989 100644 --- a/docs/community-toolkit/ollama.md +++ b/docs/community-toolkit/ollama.md @@ -54,7 +54,7 @@ Alternatively, if you want to use a model from the [Hugging Face](https://huggin var llama = ollama.AddHuggingFaceModel("llama", "bartowski/Llama-3.2-1B-Instruct-GGUF:IQ4_XS"); ``` -When .NET Aspire adds a container image to the app host, as shown in the preceding example with the `docker.io/ollama/ollama` image, it creates a new Ollama instance on your local machine. For more information, see [Container resource lifecycle](../fundamentals/app-host-overview.md#container-resource-lifecycle). +When .NET Aspire adds a container image to the app host, as shown in the preceding example with the `docker.io/ollama/ollama` image, it creates a new Ollama instance on your local machine. For more information, see [Container resource lifecycle](../fundamentals/orchestrate-resources.md#container-resource-lifecycle). ### Download the LLM diff --git a/docs/database/includes/cosmos-app-host.md b/docs/database/includes/cosmos-app-host.md index 26f15d2141..73ae9dd568 100644 --- a/docs/database/includes/cosmos-app-host.md +++ b/docs/database/includes/cosmos-app-host.md @@ -181,11 +181,11 @@ var cosmos = builder.AddAzureCosmosDB("cosmos-db") // After adding all resources, run the app... ``` -When you call `RunAsEmulator`, it configures your Cosmos DB resources to run locally using an emulator. The emulator in this case is the [Azure Cosmos DB Emulator](/azure/cosmos-db/local-emulator). The Azure Cosmos DB Emulator provides a free local environment for testing your Azure Cosmos DB apps and it's a perfect companion to the .NET Aspire Azure hosting integration. The emulator isn't installed, instead, it's accessible to .NET Aspire as a container. When you add a container to the app host, as shown in the preceding example with the `mcr.microsoft.com/cosmosdb/emulator` image, it creates and starts the container when the app host starts. For more information, see [Container resource lifecycle](../../fundamentals/app-host-overview.md#container-resource-lifecycle). +When you call `RunAsEmulator`, it configures your Cosmos DB resources to run locally using an emulator. The emulator in this case is the [Azure Cosmos DB Emulator](/azure/cosmos-db/local-emulator). The Azure Cosmos DB Emulator provides a free local environment for testing your Azure Cosmos DB apps and it's a perfect companion to the .NET Aspire Azure hosting integration. The emulator isn't installed, instead, it's accessible to .NET Aspire as a container. When you add a container to the app host, as shown in the preceding example with the `mcr.microsoft.com/cosmosdb/emulator` image, it creates and starts the container when the app host starts. For more information, see [Container resource lifecycle](../../fundamentals/orchestrate-resources.md#container-resource-lifecycle). #### Configure Cosmos DB emulator container -There are various configurations available to container resources, for example, you can configure the container's ports, environment variables, it's [lifetime](../../fundamentals/app-host-overview.md#container-resource-lifetime), and more. +There are various configurations available to container resources, for example, you can configure the container's ports, environment variables, it's [lifetime](../../fundamentals/orchestrate-resources.md#container-resource-lifetime), and more. ##### Configure Cosmos DB emulator container gateway port @@ -231,7 +231,7 @@ var cosmos = builder.AddAzureCosmosDB("cosmos-db").RunAsEmulator( // After adding all resources, run the app... ``` -For more information, see [Container resource lifetime](../../fundamentals/app-host-overview.md#container-resource-lifetime). +For more information, see [Container resource lifetime](../../fundamentals/orchestrate-resources.md#container-resource-lifetime). ##### Configure Cosmos DB emulator container with data volume diff --git a/docs/database/includes/mysql-app-host.md b/docs/database/includes/mysql-app-host.md index e4aac1d64a..89cc6a388b 100644 --- a/docs/database/includes/mysql-app-host.md +++ b/docs/database/includes/mysql-app-host.md @@ -41,7 +41,7 @@ var myService = builder.AddProject() ``` > [!NOTE] -> The SQL Server container is slow to start, so it's best to use a _persistent_ lifetime to avoid unnecessary restarts. For more information, see [Container resource lifetime](../../fundamentals/app-host-overview.md#container-resource-lifetime). +> The SQL Server container is slow to start, so it's best to use a _persistent_ lifetime to avoid unnecessary restarts. For more information, see [Container resource lifetime](../../fundamentals/orchestrate-resources.md#container-resource-lifetime). When .NET Aspire adds a container image to the app host, as shown in the preceding example with the `mysql` image, it creates a new MySQL instance on your local machine. A reference to your MySQL resource builder (the `mysql` variable) is used to add a database. The database is named `mysqldb` and then added to the `ExampleProject`. The MySQL resource includes default credentials with a `username` of `root` and a random `password` generated using the method. diff --git a/docs/database/includes/postgresql-app-host.md b/docs/database/includes/postgresql-app-host.md index d00aceb504..77d827f813 100644 --- a/docs/database/includes/postgresql-app-host.md +++ b/docs/database/includes/postgresql-app-host.md @@ -50,7 +50,7 @@ When adding a database resource to the app model, the database is created if it The PostgreSQL server resource includes default credentials with a `username` of `"postgres"` and randomly generated `password` using the method. -The method configures a connection in the `ExampleProject` named `"messaging"`. For more information, see [Container resource lifecycle](../../fundamentals/app-host-overview.md#container-resource-lifecycle). +The method configures a connection in the `ExampleProject` named `"messaging"`. For more information, see [Container resource lifecycle](../../fundamentals/orchestrate-resources.md#container-resource-lifecycle). > [!TIP] > If you'd rather connect to an existing PostgreSQL server, call instead. For more information, see [Reference existing resources](../../fundamentals/app-host-overview.md#reference-existing-resources). diff --git a/docs/database/includes/sql-app-host.md b/docs/database/includes/sql-app-host.md index 2dbe8dc9dc..1bc3a48d27 100644 --- a/docs/database/includes/sql-app-host.md +++ b/docs/database/includes/sql-app-host.md @@ -41,7 +41,7 @@ builder.AddProject() ``` > [!NOTE] -> The SQL Server container is slow to start, so it's best to use a _persistent_ lifetime to avoid unnecessary restarts. For more information, see [Container resource lifetime](../../fundamentals/app-host-overview.md#container-resource-lifetime). +> The SQL Server container is slow to start, so it's best to use a _persistent_ lifetime to avoid unnecessary restarts. For more information, see [Container resource lifetime](../../fundamentals/orchestrate-resources.md#container-resource-lifetime). When .NET Aspire adds a container image to the app host, as shown in the preceding example with the `mcr.microsoft.com/mssql/server` image, it creates a new SQL Server instance on your local machine. A reference to your SQL Server resource builder (the `sql` variable) is used to add a database. The database is named `database` and then added to the `ExampleProject`. diff --git a/docs/database/milvus-integration.md b/docs/database/milvus-integration.md index 8dc586b79c..e45d169756 100644 --- a/docs/database/milvus-integration.md +++ b/docs/database/milvus-integration.md @@ -56,7 +56,7 @@ builder.AddProject() ``` > [!NOTE] -> The Milvus container can be slow to start, so it's best to use a _persistent_ lifetime to avoid unnecessary restarts. For more information, see [Container resource lifetime](../fundamentals/app-host-overview.md#container-resource-lifetime). +> The Milvus container can be slow to start, so it's best to use a _persistent_ lifetime to avoid unnecessary restarts. For more information, see [Container resource lifetime](../fundamentals/orchestrate-resources.md#container-resource-lifetime). When .NET Aspire adds a container image to the app host, as shown in the preceding example with the `milvusdb/milvus` image, it creates a new Milvus instance on your local machine. A reference to your Milvus resource builder (the `milvus` variable) is used to add a database. The database is named `milvusdb` and then added to the `ExampleProject`. diff --git a/docs/database/mongodb-integration.md b/docs/database/mongodb-integration.md index 4e28bd81e7..2effbcfb29 100644 --- a/docs/database/mongodb-integration.md +++ b/docs/database/mongodb-integration.md @@ -52,7 +52,7 @@ builder.AddProject() ``` > [!NOTE] -> The MongoDB container can be slow to start, so it's best to use a _persistent_ lifetime to avoid unnecessary restarts. For more information, see [Container resource lifetime](../fundamentals/app-host-overview.md#container-resource-lifetime). +> The MongoDB container can be slow to start, so it's best to use a _persistent_ lifetime to avoid unnecessary restarts. For more information, see [Container resource lifetime](../fundamentals/orchestrate-resources.md#container-resource-lifetime). When .NET Aspire adds a container image to the app host, as shown in the preceding example with the `docker.io/library/mongo` image, it creates a new MongoDB instance on your local machine. A reference to your MongoDB server resource builder (the `mongo` variable) is used to add a database. The database is named `mongodb` and then added to the `ExampleProject`. The MongoDB server resource includes default credentials: diff --git a/docs/database/oracle-entity-framework-integration.md b/docs/database/oracle-entity-framework-integration.md index 05ead1e11d..6449e6f56f 100644 --- a/docs/database/oracle-entity-framework-integration.md +++ b/docs/database/oracle-entity-framework-integration.md @@ -52,11 +52,11 @@ builder.AddProject() ``` > [!NOTE] -> The Oracle database container can be slow to start, so it's best to use a _persistent_ lifetime to avoid unnecessary restarts. For more information, see [Container resource lifetime](../fundamentals/app-host-overview.md#container-resource-lifetime). +> The Oracle database container can be slow to start, so it's best to use a _persistent_ lifetime to avoid unnecessary restarts. For more information, see [Container resource lifetime](../fundamentals/orchestrate-resources.md#container-resource-lifetime). When .NET Aspire adds a container image to the app host, as shown in the preceding example with the `container-registry.oracle.com/database/free` image, it creates a new Oracle server on your local machine. A reference to your Oracle resource builder (the `oracle` variable) is used to add a database. The database is named `oracledb` and then added to the `ExampleProject`. The Oracle resource includes a random `password` generated using the method. -The method configures a connection in the `ExampleProject` named `"oracledb"`. For more information, see [Container resource lifecycle](../fundamentals/app-host-overview.md#container-resource-lifecycle). +The method configures a connection in the `ExampleProject` named `"oracledb"`. For more information, see [Container resource lifecycle](../fundamentals/orchestrate-resources.md#container-resource-lifecycle). > [!TIP] > If you'd rather connect to an existing Oracle server, call instead. For more information, see [Reference existing resources](../fundamentals/app-host-overview.md#reference-existing-resources). diff --git a/docs/database/qdrant-integration.md b/docs/database/qdrant-integration.md index 5a7c997f99..6cd94be8b8 100644 --- a/docs/database/qdrant-integration.md +++ b/docs/database/qdrant-integration.md @@ -54,7 +54,7 @@ builder.AddProject() ``` > [!NOTE] -> The Qdrant container can be slow to start, so it's best to use a _persistent_ lifetime to avoid unnecessary restarts. For more information, see [Container resource lifetime](../fundamentals/app-host-overview.md#container-resource-lifetime). +> The Qdrant container can be slow to start, so it's best to use a _persistent_ lifetime to avoid unnecessary restarts. For more information, see [Container resource lifetime](../fundamentals/orchestrate-resources.md#container-resource-lifetime). When .NET Aspire adds a container image to the app host, as shown in the preceding example with the `qdrant/qdrant` image, it creates a new Qdrant instance on your local machine. The resource is named `qdrant` and then added to the `ExampleProject`. diff --git a/docs/fundamentals/app-host-overview.md b/docs/fundamentals/app-host-overview.md index 02e630b73c..f2325bb579 100644 --- a/docs/fundamentals/app-host-overview.md +++ b/docs/fundamentals/app-host-overview.md @@ -285,7 +285,6 @@ This logic can easily be inverted to connect to an existing Redis resource when ## See also - [Orchestrate resources in .NET Aspire](orchestrate-resources.md) -- [App Host life cycles in .NET Aspire](app-host-life-cycles.md) - [.NET Aspire integrations overview](integrations-overview.md) - [.NET Aspire SDK](dotnet-aspire-sdk.md) - [Eventing in .NET Aspire](../app-host/eventing.md) diff --git a/docs/fundamentals/orchestrate-resources.md b/docs/fundamentals/orchestrate-resources.md index b88b92ec12..6486702cec 100644 --- a/docs/fundamentals/orchestrate-resources.md +++ b/docs/fundamentals/orchestrate-resources.md @@ -15,7 +15,8 @@ In .NET Aspire, a **resource** is a dependant part of a cloud-native application - **Container**: You can add Docker containers, based on specific images to your .NET Aspire solution. - **Integration resources**: Integrations often add resources such as databases, caches, and messaging services to your application. -> [!NOTE] For the fundamentals of .NET Aspire orchestration and how it manages resources, see [.NET Aspire orchestration overview](app-host-overview.md). In this article, you'll learn how to customize the behavior of resources further by writing code in the app host project. +> [!NOTE] +> For the fundamentals of .NET Aspire orchestration and how it manages resources, see [.NET Aspire orchestration overview](app-host-overview.md). In this article, you'll learn how to customize the behavior of resources further by writing code in the app host project. ## Configure explicit resource start @@ -209,4 +210,4 @@ The preceding example uses 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 .NET 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 .NET 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 [.NET Aspire orchestration: Waiting for resources](../fundamentals/app-host-overview.md#waiting-for-resources). +- 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 .NET 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 [.NET 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 [.NET Aspire orchestration overview](../fundamentals/app-host-overview.md). diff --git a/docs/logging/seq-integration.md b/docs/logging/seq-integration.md index 9f74ec7cfc..7de9f79ce5 100644 --- a/docs/logging/seq-integration.md +++ b/docs/logging/seq-integration.md @@ -54,7 +54,7 @@ var myService = builder.AddProject() ``` > [!NOTE] -> The Seq container may be slow to start, so it's best to use a _persistent_ lifetime to avoid unnecessary restarts. For more information, see [Container resource lifetime](../fundamentals/app-host-overview.md#container-resource-lifetime). +> The Seq container may be slow to start, so it's best to use a _persistent_ lifetime to avoid unnecessary restarts. For more information, see [Container resource lifetime](../fundamentals/orchestrate-resources.md#container-resource-lifetime). #### Accept the Seq End User License Agreement (EULA) diff --git a/docs/messaging/azure-service-bus-integration.md b/docs/messaging/azure-service-bus-integration.md index ef9175763c..19e5c4ae1e 100644 --- a/docs/messaging/azure-service-bus-integration.md +++ b/docs/messaging/azure-service-bus-integration.md @@ -194,7 +194,7 @@ var serviceBus = builder.AddAzureServiceBus("messaging") // After adding all resources, run the app... ``` -When you call `RunAsEmulator`, it configures your Service Bus resources to run locally using an emulator. The emulator in this case is the [Azure Service Bus Emulator](/azure/service-bus-messaging/overview-emulator). The Azure Service Bus Emulator provides a free local environment for testing your Azure Service Bus apps and it's a perfect companion to the .NET Aspire Azure hosting integration. The emulator isn't installed, instead, it's accessible to .NET Aspire as a container. When you add a container to the app host, as shown in the preceding example with the `mcr.microsoft.com/azure-messaging/servicebus-emulator` image (and the companion `mcr.microsoft.com/azure-sql-edge` image), it creates and starts the container when the app host starts. For more information, see [Container resource lifecycle](../fundamentals/app-host-overview.md#container-resource-lifecycle). +When you call `RunAsEmulator`, it configures your Service Bus resources to run locally using an emulator. The emulator in this case is the [Azure Service Bus Emulator](/azure/service-bus-messaging/overview-emulator). The Azure Service Bus Emulator provides a free local environment for testing your Azure Service Bus apps and it's a perfect companion to the .NET Aspire Azure hosting integration. The emulator isn't installed, instead, it's accessible to .NET Aspire as a container. When you add a container to the app host, as shown in the preceding example with the `mcr.microsoft.com/azure-messaging/servicebus-emulator` image (and the companion `mcr.microsoft.com/azure-sql-edge` image), it creates and starts the container when the app host starts. For more information, see [Container resource lifecycle](../fundamentals/orchestrate-resources.md#container-resource-lifecycle). #### Configure Service Bus emulator container diff --git a/docs/messaging/kafka-integration.md b/docs/messaging/kafka-integration.md index 0109d93d3b..a11d83b1db 100644 --- a/docs/messaging/kafka-integration.md +++ b/docs/messaging/kafka-integration.md @@ -49,7 +49,7 @@ builder.AddProject() When .NET Aspire adds a container image to the app host, as shown in the preceding example with the `docker.io/confluentinc/confluent-local` image, it creates a new Kafka server instance on your local machine. A reference to your Kafka server (the `kafka` variable) is added to the `ExampleProject`. The Kafka server resource includes default ports -The method configures a connection in the `ExampleProject` named `"kafka"`. For more information, see [Container resource lifecycle](../fundamentals/app-host-overview.md#container-resource-lifecycle). +The method configures a connection in the `ExampleProject` named `"kafka"`. For more information, see [Container resource lifecycle](../fundamentals/orchestrate-resources.md#container-resource-lifecycle). > [!TIP] > If you'd rather connect to an existing Kafka server, call instead. For more information, see [Reference existing resources](../fundamentals/app-host-overview.md#reference-existing-resources). diff --git a/docs/messaging/nats-integration.md b/docs/messaging/nats-integration.md index 2f47b46782..b38bb68dcf 100644 --- a/docs/messaging/nats-integration.md +++ b/docs/messaging/nats-integration.md @@ -49,7 +49,7 @@ builder.AddProject() When .NET Aspire adds a container image to the app host, as shown in the preceding example with the `docker.io/library/nats` image, it creates a new NATS server instance on your local machine. A reference to your NATS server (the `nats` variable) is added to the `ExampleProject`. -The method configures a connection in the `ExampleProject` named `"nats"`. For more information, see [Container resource lifecycle](../fundamentals/app-host-overview.md#container-resource-lifecycle). +The method configures a connection in the `ExampleProject` named `"nats"`. For more information, see [Container resource lifecycle](../fundamentals/orchestrate-resources.md#container-resource-lifecycle). > [!TIP] > If you'd rather connect to an existing NATS server, call instead. For more information, see [Reference existing resources](../fundamentals/app-host-overview.md#reference-existing-resources). diff --git a/docs/messaging/rabbitmq-integration.md b/docs/messaging/rabbitmq-integration.md index 15ece97649..6324cdde84 100644 --- a/docs/messaging/rabbitmq-integration.md +++ b/docs/messaging/rabbitmq-integration.md @@ -53,7 +53,7 @@ builder.AddProject() When .NET Aspire adds a container image to the app host, as shown in the preceding example with the `docker.io/library/rabbitmq` image, it creates a new RabbitMQ server instance on your local machine. A reference to your RabbitMQ server (the `rabbitmq` variable) is added to the `ExampleProject`. The RabbitMQ server resource includes default credentials with a `username` of `"guest"` and randomly generated `password` using the method. -The method configures a connection in the `ExampleProject` named `"messaging"`. For more information, see [Container resource lifecycle](../fundamentals/app-host-overview.md#container-resource-lifecycle). +The method configures a connection in the `ExampleProject` named `"messaging"`. For more information, see [Container resource lifecycle](../fundamentals/orchestrate-resources.md#container-resource-lifecycle). > [!TIP] > If you'd rather connect to an existing RabbitMQ server, call instead. For more information, see [Reference existing resources](../fundamentals/app-host-overview.md#reference-existing-resources). diff --git a/docs/search/elasticsearch-integration.md b/docs/search/elasticsearch-integration.md index 2c07cf605c..11b3946a63 100644 --- a/docs/search/elasticsearch-integration.md +++ b/docs/search/elasticsearch-integration.md @@ -49,7 +49,7 @@ builder.AddProject() When .NET Aspire adds a container image to the app host, as shown in the preceding example with the `docker.io/library/elasticsearch` image, it creates a new Elasticsearch instance on your local machine. A reference to your Elasticsearch resource (the `elasticsearch` variable) is added to the `ExampleProject`. The Elasticsearch resource includes default credentials with a `username` of `"elastic"` and randomly generated `password` using the method when a password wasn't provided. -The method configures a connection in the `ExampleProject` named `"elasticsearch"`. For more information, see [Container resource lifecycle](../fundamentals/app-host-overview.md#container-resource-lifecycle). +The method configures a connection in the `ExampleProject` named `"elasticsearch"`. For more information, see [Container resource lifecycle](../fundamentals/orchestrate-resources.md#container-resource-lifecycle). > [!TIP] > If you'd rather connect to an existing Elasticsearch instance, call instead. For more information, see [Reference existing resources](../fundamentals/app-host-overview.md#reference-existing-resources). diff --git a/docs/storage/includes/storage-app-host.md b/docs/storage/includes/storage-app-host.md index 51867f03bc..7477c1676f 100644 --- a/docs/storage/includes/storage-app-host.md +++ b/docs/storage/includes/storage-app-host.md @@ -51,3 +51,210 @@ When you add an `AzureStorageResource` to the app host, it exposes other useful > [!IMPORTANT] > When you call , it implicitly calls —which adds support for generating Azure resources dynamically during app startup. The app must configure the appropriate subscription and location. For more information, see [Local provisioning: Configuration](../../azure/local-provisioning.md#configuration). + +#### Generated provisioning Bicep + +If you're new to [Bicep](/azure/azure-resource-manager/bicep/overview), it's a domain-specific language for defining Azure resources. With .NET Aspire, you don't need to write Bicep by-hand, instead the provisioning APIs generate Bicep for you. When you publish your app, the generated Bicep is output alongside the manifest file. When you add an Azure Storage resource, the following Bicep is generated: + +:::code language="bicep" source="../../snippets/azure/AppHost/storage.module.bicep"::: + +The preceding Bicep is a module that provisions an Azure Storage account with the following defaults: + +- `kind`: The kind of storage account. The default is `StorageV2`. +- `sku`: The SKU of the storage account. The default is `Standard_GRS`. +- `properties`: The properties of the storage account: + - `accessTier`: The access tier of the storage account. The default is `Hot`. + - `allowSharedKeyAccess`: A boolean value that indicates whether the storage account permits requests to be authorized with the account access key. The default is `false`. + - `minimumTlsVersion`: The minimum supported TLS version for the storage account. The default is `TLS1_2`. + - `networkAcls`: The network ACLs for the storage account. The default is `{ defaultAction: 'Allow' }`. + +In addition to the storage account, it also provisions a blob container. + +The following role assignments are added to the storage account to grant your application access. See the [built-in Azure role-based access control (Azure RBAC) roles](/azure/role-based-access-control/built-in-roles#storage) for more information: + +| Role / ID | Description | +|------|-------------| +| Storage Blob Data Contributor
`ba92f5b4-2d11-453d-a403-e96b0029c9fe` | Read, write, and delete Azure Storage containers and blobs. | +| Storage Table Data Contributor
`0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3` | Read, write, and delete Azure Storage tables and entities. | +| Storage Queue Data Contributor
`974c5e8b-45b9-4653-ba55-5f855dd0fb88` | Read, write, and delete Azure Storage queues and queue messages. | + +The generated Bicep is a starting point and is influenced by changes to the provisioning infrastructure in C#. Customizations to the Bicep file directly will be overwritten, so make changes through the C# provisioning APIs to ensure they are reflected in the generated files. + +#### Customize provisioning infrastructure + +All .NET Aspire Azure resources are subclasses of the type. This type enables the customization of the generated Bicep by providing a fluent API to configure the Azure resources—using the API. For example, you can configure the `kind`, `sku`, `properties`, and more. The following example demonstrates how to customize the Azure Storage resource: + +:::code language="csharp" source="../../snippets/azure/AppHost/Program.ConfigureStorageInfra.cs" id="configure"::: + +The preceding code: + +- Chains a call to the API: + - The `infra` parameter is an instance of the type. + - The provisionable resources are retrieved by calling the method. + - The single is retrieved. + - The is assigned to . + - The is assigned to a new with a `Name` of . + - A tag is added to the storage account with a key of `ExampleKey` and a value of `Example value`. + +There are many more configuration options available to customize the Azure Storage resource. For more information, see . + + + +### Connect to an existing Azure Storage account + +You might have an existing Azure Storage account that you want to connect to. Instead of representing a new Azure Storage resource, you can add a connection string to the app host. To add a connection to an existing Azure Storage account, call the method: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var blobs = builder.AddConnectionString("blobs"); + +builder.AddProject("web") + .WithReference(blobs); + +// After adding all resources, run the app... +``` + +[!INCLUDE [connection-strings-alert](../../includes/connection-strings-alert.md)] + +The connection string is configured in the app host's configuration, typically under [User Secrets](/aspnet/core/security/app-secrets), under the `ConnectionStrings` section. The app host injects this connection string as an environment variable into all dependent resources, for example: + +```json +{ + "ConnectionStrings": { + "blobs": "https://{account_name}.blob.core.windows.net/" + } +} +``` + +The dependent resource can access the injected connection string by calling the method, and passing the connection name as the parameter, in this case `"blobs"`. The `GetConnectionString` API is shorthand for `IConfiguration.GetSection("ConnectionStrings")[name]`. + +### Add Azure Storage emulator resource + +To add an Azure Storage emulator resource, chain a call on an `IResourceBuilder` to the API: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var storage = builder.AddAzureStorage("storage") + .RunAsEmulator(); + +// After adding all resources, run the app... +``` + +When you call `RunAsEmulator`, it configures your storage resources to run locally using an emulator. The emulator in this case is [Azurite](/azure/storage/common/storage-use-azurite). The Azurite open-source emulator provides a free local environment for testing your Azure Blob, Queue Storage, and Table Storage apps and it's a perfect companion to the .NET Aspire Azure hosting integration. Azurite isn't installed, instead, it's accessible to .NET Aspire as a container. When you add a container to the app host, as shown in the preceding example with the `mcr.microsoft.com/azure-storage/azurite` image, it creates and starts the container when the app host starts. For more information, see [Container resource lifecycle](../../fundamentals/orchestrate-resources.md#container-resource-lifecycle). + +#### Configure Azurite container + +There are various configurations available to container resources, for example, you can configure the container's ports, environment variables, it's [lifetime](../../fundamentals/orchestrate-resources.md#container-resource-lifetime), and more. + +##### Configure Azurite container ports + +By default, the Azurite container when configured by .NET Aspire, exposes the following endpoints: + +| Endpoint | Container port | Host port | +|----------|----------------|-----------| +| `blob` | 10000 | dynamic | +| `queue` | 10001 | dynamic | +| `table` | 10002 | dynamic | + +The port that they're listening on is dynamic by default. When the container starts, the ports are mapped to a random port on the host machine. To configure the endpoint ports, chain calls on the container resource builder provided by the `RunAsEmulator` method as shown in the following example: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var storage = builder.AddAzureStorage("storage").RunAsEmulator( + azurite => + { + azurite.WithBlobPort(27000) + .WithQueuePort(27001) + .WithTablePort(27002); + }); + +// After adding all resources, run the app... +``` + +The preceding code configures the Azurite container's existing `blob`, `queue`, and `table` endpoints to listen on ports `27000`, `27001`, and `27002`, respectively. The Azurite container's ports are mapped to the host ports as shown in the following table: + +| Endpoint name | Port mapping (`container:host`) | +|--------------:|---------------------------------| +| `blob` | `10000:27000` | +| `queue` | `10001:27001` | +| `table` | `10002:27002` | + +##### Configure Azurite container with persistent lifetime + +To configure the Azurite container with a persistent lifetime, call the method on the Azurite container resource and pass : + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var storage = builder.AddAzureStorage("storage").RunAsEmulator( + azurite => + { + azurite.WithLifetime(ContainerLifetime.Persistent); + }); + +// After adding all resources, run the app... +``` + +For more information, see [Container resource lifetime](../../fundamentals/orchestrate-resources.md#container-resource-lifetime). + +##### Configure Azurite container with data volume + +To add a data volume to the Azure Storage emulator resource, call the method on the Azure Storage emulator resource: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var storage = builder.AddAzureStorage("storage").RunAsEmulator( + azurite => + { + azurite.WithDataVolume(); + }); + +// After adding all resources, run the app... +``` + +The data volume is used to persist the Azurite data outside the lifecycle of its container. The data volume is mounted at the `/data` path in the Azurite container and when a `name` parameter isn't provided, the name is formatted as `.azurite/{resource name}`. For more information on data volumes and details on why they're preferred over [bind mounts](#configure-azurite-container-with-data-bind-mount), see [Docker docs: Volumes](https://docs.docker.com/engine/storage/volumes). + +##### Configure Azurite container with data bind mount + +To add a data bind mount to the Azure Storage emulator resource, call the method: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var storage = builder.AddAzureStorage("storage").RunAsEmulator( + azurite => + { + azurite.WithDataBindMount("../Azurite/Data"); + }); + +// After adding all resources, run the app... +``` + +[!INCLUDE [data-bind-mount-vs-volumes](../../includes/data-bind-mount-vs-volumes.md)] + +Data bind mounts rely on the host machine's filesystem to persist the Azurite data across container restarts. The data bind mount is mounted at the `../Azurite/Data` path on the host machine relative to the app host directory () in the Azurite container. For more information on data bind mounts, see [Docker docs: Bind mounts](https://docs.docker.com/engine/storage/bind-mounts). + +### Connect to storage resources + +When the .NET Aspire app host runs, the storage resources can be accessed by external tools, such as the [Azure Storage Explorer](https://azure.microsoft.com/features/storage-explorer/). If your storage resource is running locally using Azurite, it will automatically be picked up by the Azure Storage Explorer. + +> [!NOTE] +> The Azure Storage Explorer discovers Azurite storage resources assuming the default ports are used. If you've [configured the Azurite container to use different ports](#configure-azurite-container-ports), you'll need to configure the Azure Storage Explorer to connect to the correct ports. + +To connect to the storage resource from Azure Storage Explorer, follow these steps: + +1. Run the .NET Aspire app host. +1. Open the Azure Storage Explorer. +1. View the **Explorer** pane. +1. Select the **Refresh all** link to refresh the list of storage accounts. +1. Expand the **Emulator & Attached** node. +1. Expand the **Storage Accounts** node. +1. You should see a storage account with your resource's name as a prefix: + + :::image type="content" source="../media/azure-storage-explorer.png" lightbox="../media/azure-storage-explorer.png" alt-text="Azure Storage Explorer: Azurite storage resource discovered."::: + +You're free to explore the storage account and its contents using the Azure Storage Explorer. For more information on using the Azure Storage Explorer, see [Get started with Storage Explorer](/azure/storage/storage-explorer/vs-azure-tools-storage-manage-with-storage-explorer). diff --git a/docs/whats-new/dotnet-aspire-9.1.md b/docs/whats-new/dotnet-aspire-9.1.md index 08fec3cf63..e1409537b6 100644 --- a/docs/whats-new/dotnet-aspire-9.1.md +++ b/docs/whats-new/dotnet-aspire-9.1.md @@ -139,7 +139,7 @@ In .NET Aspire 9.1, several improvements to streamline your local development ex You can now tell resources not to start with the rest of your app by using on the resource in your app host. Then, you can start it whenever you're ready from inside the dashboard. -For more information, see [Configure explicit resource start](../fundamentals/app-host-overview.md#configure-explicit-resource-start). +For more information, see [Configure explicit resource start](../fundamentals/orchestrate-resources.md#configure-explicit-resource-start). ### 🐳 Better Docker integration diff --git a/docs/whats-new/dotnet-aspire-9.md b/docs/whats-new/dotnet-aspire-9.md index e4b072f3ec..a02935e025 100644 --- a/docs/whats-new/dotnet-aspire-9.md +++ b/docs/whats-new/dotnet-aspire-9.md @@ -127,7 +127,7 @@ There are two methods exposed to wait for a resource: - : Wait for a resource to be ready before starting another resource. - : Wait for a resource to complete before starting another resource. -For more information, see [.NET Aspire app host: Waiting for resources](../fundamentals/app-host-overview.md#waiting-for-resources). +For more information, see [.NET Aspire app host: Waiting for resources](../fundamentals/orchestrate-resources.md#waiting-for-resources). #### Resource health checks @@ -191,7 +191,7 @@ The : 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 app host life cycle events. For more information, see [App host life cycles](../fundamentals/app-host-overview.md#app-host-life-cycles). +The global events are analogous to the app host life cycle events. For more information, see [App host life cycles](../app-host/eventing.md#app-host-life-cycle-events). **Per-resource events:** From 28c769183c1cee251e1f4353fe4433e58f50efb7 Mon Sep 17 00:00:00 2001 From: AJ Matthews Date: Tue, 15 Apr 2025 17:23:11 +0100 Subject: [PATCH 5/9] Fixed links to moved content. --- docs/fundamentals/http-commands.md | 2 +- docs/storage/includes/storage-emulator.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/fundamentals/http-commands.md b/docs/fundamentals/http-commands.md index 347bd34fea..8bf150a934 100644 --- a/docs/fundamentals/http-commands.md +++ b/docs/fundamentals/http-commands.md @@ -49,7 +49,7 @@ The preceding code: - Adds a [Redis cache](../caching/stackexchange-redis-integration.md) 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](app-host-overview.md#waiting-for-resources). +- 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`). diff --git a/docs/storage/includes/storage-emulator.md b/docs/storage/includes/storage-emulator.md index 3feb0dda0f..52ef95bdbe 100644 --- a/docs/storage/includes/storage-emulator.md +++ b/docs/storage/includes/storage-emulator.md @@ -15,11 +15,11 @@ var storage = builder.AddAzureStorage("storage") // After adding all resources, run the app... ``` -When you call `RunAsEmulator`, it configures your storage resources to run locally using an emulator. The emulator in this case is [Azurite](/azure/storage/common/storage-use-azurite). The Azurite open-source emulator provides a free local environment for testing your Azure Blob, Queue Storage, and Table Storage apps and it's a perfect companion to the .NET Aspire Azure hosting integration. Azurite isn't installed; instead, it's accessible to .NET Aspire as a container. When you add a container to the app host, as shown in the preceding example with the `mcr.microsoft.com/azure-storage/azurite` image, it creates and starts the container when the app host starts. For more information, see [Container resource lifecycle](../../fundamentals/app-host-overview.md#container-resource-lifecycle). +When you call `RunAsEmulator`, it configures your storage resources to run locally using an emulator. The emulator in this case is [Azurite](/azure/storage/common/storage-use-azurite). The Azurite open-source emulator provides a free local environment for testing your Azure Blob, Queue Storage, and Table Storage apps and it's a perfect companion to the .NET Aspire Azure hosting integration. Azurite isn't installed; instead, it's accessible to .NET Aspire as a container. When you add a container to the app host, as shown in the preceding example with the `mcr.microsoft.com/azure-storage/azurite` image, it creates and starts the container when the app host starts. For more information, see [Container resource lifecycle](../../fundamentals/orchestrate-resources.md#container-resource-lifecycle). #### Configure Azurite container -There are various configurations available to container resources, for example, you can configure the container's ports, environment variables, [lifetime](../../fundamentals/app-host-overview.md#container-resource-lifetime), and more. +There are various configurations available to container resources, for example, you can configure the container's ports, environment variables, [lifetime](../../fundamentals/orchestrate-resources.md#container-resource-lifetime), and more. ##### Configure Azurite container ports @@ -71,7 +71,7 @@ var storage = builder.AddAzureStorage("storage").RunAsEmulator( // After adding all resources, run the app... ``` -For more information, see [Container resource lifetime](../../fundamentals/app-host-overview.md#container-resource-lifetime). +For more information, see [Container resource lifetime](../../fundamentals/orchestrate-resources.md#container-resource-lifetime). ##### Configure Azurite container with data volume From 062906b4aca23ede30271b7886e5d5302f2c1b83 Mon Sep 17 00:00:00 2001 From: David Pine Date: Wed, 16 Apr 2025 14:20:32 -0500 Subject: [PATCH 6/9] A few edits --- docs/fundamentals/app-host-overview.md | 4 +--- docs/toc.yml | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/fundamentals/app-host-overview.md b/docs/fundamentals/app-host-overview.md index f2325bb579..fac202f40a 100644 --- a/docs/fundamentals/app-host-overview.md +++ b/docs/fundamentals/app-host-overview.md @@ -10,7 +10,7 @@ uid: dotnet/aspire/app-host .NET Aspire provides APIs for expressing resources and dependencies within your distributed application. In addition to these APIs, [there's tooling](setup-tooling.md#install-net-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 .NET Aspire: @@ -20,8 +20,6 @@ Before continuing, consider some common terminology used in .NET Aspire: - **Integration**: An integration is a NuGet package for either the _app host_ that models a _resource_ or a package that configures a client for use in a consuming app. For more information, see [.NET 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] > .NET 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. diff --git a/docs/toc.yml b/docs/toc.yml index 6352f2670f..4a736a99de 100644 --- a/docs/toc.yml +++ b/docs/toc.yml @@ -36,7 +36,7 @@ items: href: fundamentals/app-host-overview.md - name: Locally orchestrate items: - - name: Orchestrate resources in .NET Aspire + - name: Resources in .NET Aspire displayName: orchestration,aspire apphost,aspire app href: fundamentals/orchestrate-resources.md - name: Node.js apps in .NET Aspire From 12f6dc76035edd07c16493d698dae98b06ca80ac Mon Sep 17 00:00:00 2001 From: David Pine Date: Wed, 16 Apr 2025 14:31:33 -0500 Subject: [PATCH 7/9] Fix MD lint error --- docs/fundamentals/orchestrate-resources.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/fundamentals/orchestrate-resources.md b/docs/fundamentals/orchestrate-resources.md index 6486702cec..3dff6beb3b 100644 --- a/docs/fundamentals/orchestrate-resources.md +++ b/docs/fundamentals/orchestrate-resources.md @@ -1,8 +1,7 @@ --- title: Orchestrate resources in .NET Aspire description: Learn techniques to control the behavior of .NET Aspire resources such as project, containers, and executable resources. -ms.date: 04/04/2025 -ms.topic: article +ms.date: 04/16/2025 uid: dotnet/aspire/orchestrate-resources --- @@ -15,7 +14,7 @@ In .NET Aspire, a **resource** is a dependant part of a cloud-native application - **Container**: You can add Docker containers, based on specific images to your .NET Aspire solution. - **Integration resources**: Integrations often add resources such as databases, caches, and messaging services to your application. -> [!NOTE] +> [!NOTE] > For the fundamentals of .NET Aspire orchestration and how it manages resources, see [.NET Aspire orchestration overview](app-host-overview.md). In this article, you'll learn how to customize the behavior of resources further by writing code in the app host project. ## Configure explicit resource start From a08bf2565f65ced755b5e1120424c34624619c45 Mon Sep 17 00:00:00 2001 From: David Pine Date: Thu, 17 Apr 2025 13:51:22 -0500 Subject: [PATCH 8/9] Apply suggestions from code review Co-authored-by: Andy (Steve) De George <67293991+adegeo@users.noreply.github.com> --- docs/app-host/eventing.md | 6 +++--- docs/fundamentals/orchestrate-resources.md | 7 +++---- docs/storage/includes/storage-app-host.md | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/app-host/eventing.md b/docs/app-host/eventing.md index f2c1502006..9b0f4ed026 100644 --- a/docs/app-host/eventing.md +++ b/docs/app-host/eventing.md @@ -87,9 +87,9 @@ The .NET Aspire app host exposes several life cycles that you can hook into by i | Order | Method | Description | |--|--|--| -| **1** | | Executes before the distributed application starts. | -| **2** | | Executes after the orchestrator allocates endpoints for resources in the application model. | -| **3** | | Executes after the resource was created by the orchestrator. | +| **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 diff --git a/docs/fundamentals/orchestrate-resources.md b/docs/fundamentals/orchestrate-resources.md index 3dff6beb3b..f4d5934b3f 100644 --- a/docs/fundamentals/orchestrate-resources.md +++ b/docs/fundamentals/orchestrate-resources.md @@ -7,15 +7,14 @@ uid: dotnet/aspire/orchestrate-resources # Orchestrate resources in .NET Aspire -In .NET Aspire, a **resource** is a dependant part of a cloud-native application. Resource types include: +In this article, you learn how to customize the behavior of resources further by writing code in the app host project. In .NET Aspire, a **resource** is a dependent part of a cloud-native application. Resource types include: - **.NET Project**: A custom microservice, responsible for specific functionality in your cloud-native application, and often built by a separate team of developers. - **Executable**: If you need to build microservices with tools like Node.js or Orleans, they run as executable resources. - **Container**: You can add Docker containers, based on specific images to your .NET Aspire solution. - **Integration resources**: Integrations often add resources such as databases, caches, and messaging services to your application. -> [!NOTE] -> For the fundamentals of .NET Aspire orchestration and how it manages resources, see [.NET Aspire orchestration overview](app-host-overview.md). In this article, you'll learn how to customize the behavior of resources further by writing code in the app host project. +For the fundamentals of .NET Aspire orchestration and how it manages resources, see [.NET Aspire orchestration overview](app-host-overview.md). ## Configure explicit resource start @@ -32,7 +31,7 @@ builder.AddProject("dbmigration") .WithExplicitStart(); ``` -In the preceeding code the "dbmigration" resource is configured to not automatically start with the distributed application. +In the preceding code the `"dbmigration"` resource is configured to not automatically start with the distributed application. Resources with explicit start can be started from the .NET Aspire dashboard by clicking the "Start" command. For more information, see [.NET Aspire dashboard: Stop or Start a resource](dashboard/explore.md#stop-or-start-a-resource). diff --git a/docs/storage/includes/storage-app-host.md b/docs/storage/includes/storage-app-host.md index 7477c1676f..a66e374331 100644 --- a/docs/storage/includes/storage-app-host.md +++ b/docs/storage/includes/storage-app-host.md @@ -52,7 +52,7 @@ When you add an `AzureStorageResource` to the app host, it exposes other useful > [!IMPORTANT] > When you call , it implicitly calls —which adds support for generating Azure resources dynamically during app startup. The app must configure the appropriate subscription and location. For more information, see [Local provisioning: Configuration](../../azure/local-provisioning.md#configuration). -#### Generated provisioning Bicep +#### Provisioning-generated Bicep If you're new to [Bicep](/azure/azure-resource-manager/bicep/overview), it's a domain-specific language for defining Azure resources. With .NET Aspire, you don't need to write Bicep by-hand, instead the provisioning APIs generate Bicep for you. When you publish your app, the generated Bicep is output alongside the manifest file. When you add an Azure Storage resource, the following Bicep is generated: From 570c5f2502e4ea47834e8def645241336b3fe5c2 Mon Sep 17 00:00:00 2001 From: David Pine Date: Thu, 17 Apr 2025 14:32:00 -0500 Subject: [PATCH 9/9] Update docs/fundamentals/orchestrate-resources.md --- docs/fundamentals/orchestrate-resources.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fundamentals/orchestrate-resources.md b/docs/fundamentals/orchestrate-resources.md index f4d5934b3f..c7c6e2074d 100644 --- a/docs/fundamentals/orchestrate-resources.md +++ b/docs/fundamentals/orchestrate-resources.md @@ -73,7 +73,7 @@ In the preceding code, the "apiservice" project resource waits for the "migratio ### Forcing resource start in the dashboard -Waiting for a resource can be bypassed using the "Start" command in the dashboard. Clicking "Start" on a waiting resource in the dashboard instructs it to start immediately without waiting for the resource to be healthy or completed. This can be useful when you want to test a resource immediately and don't want to wait for the app to be in the right state. +Waiting for a resource can be bypassed using the **Start** command in the dashboard. Selecting **Start** on a waiting resource in the dashboard instructs it to start immediately without waiting for the resource to be healthy or completed. This can be useful when you want to test a resource immediately and don't want to wait for the app to be in the right state. ## APIs for adding and expressing resources