diff --git a/docs/azureai/azureai-openai-component.md b/docs/azureai/azureai-openai-component.md index 1e411aa527..69a0569852 100644 --- a/docs/azureai/azureai-openai-component.md +++ b/docs/azureai/azureai-openai-component.md @@ -2,7 +2,7 @@ title: .NET Aspire Azure AI OpenAI component description: Learn how to use the .NET Aspire Azure AI OpenAI component. ms.topic: how-to -ms.date: 03/13/2024 +ms.date: 04/04/2024 --- # .NET Aspire Azure AI OpenAI component @@ -54,7 +54,22 @@ public class ExampleService(OpenAIClient client) ## App host usage -[!INCLUDE [azure-component-nuget](../includes/azure-component-nuget.md)] +To add Azure AI hosting support to your , install the [Aspire.Hosting.Azure.CognitiveServices](https://www.nuget.org/packages/Aspire.Hosting.Azure.CognitiveServices) NuGet package. + +### [.NET CLI](#tab/dotnet-cli) + +```dotnetcli +dotnet add package Aspire.Hosting.Azure.CognitiveServices --prerelease +``` + +### [PackageReference](#tab/package-reference) + +```xml + +``` + +--- In your app host project, register an Azure AI OpenAI resource using the following methods, such as : diff --git a/docs/azureai/azureai-search-document-component.md b/docs/azureai/azureai-search-document-component.md index 6a90264932..b7de1e56a1 100644 --- a/docs/azureai/azureai-search-document-component.md +++ b/docs/azureai/azureai-search-document-component.md @@ -2,7 +2,7 @@ title: NET Aspire Azure AI Search Documents component description: Learn how to use the NET Aspire Azure AI Search Documents component. ms.topic: how-to -ms.date: 03/11/2024 +ms.date: 04/09/2024 --- # NET Aspire Azure AI Search Documents component @@ -71,11 +71,26 @@ public class ExampleService(SearchIndexClient indexClient) } ``` -For more information, see the [Azure AI Search client library for .NET](https://learn.microsoft.com/dotnet/api/overview/azure/search.documents-readme?view=azure-dotnet&preserve-view=true) for examples on using the `SearchIndexClient`. +For more information, see the [Azure AI Search client library for .NET](/dotnet/api/overview/azure/search.documents-readme?view=azure-dotnet&preserve-view=true) for examples on using the `SearchIndexClient`. ## App host usage -[!INCLUDE [azure-component-nuget](../includes/azure-component-nuget.md)] +To add Azure AI hosting support to your , install the [Aspire.Hosting.Azure.CognitiveServices](https://www.nuget.org/packages/Aspire.Hosting.Azure.CognitiveServices) NuGet package. + +### [.NET CLI](#tab/dotnet-cli) + +```dotnetcli +dotnet add package Aspire.Hosting.Azure.CognitiveServices --prerelease +``` + +### [PackageReference](#tab/package-reference) + +```xml + +``` + +--- In the _Program.cs_ file of `AppHost`, add an Azure Search service and consume the connection using the following methods: @@ -134,7 +149,7 @@ Alternatively, a custom connection string can be used. ### Use configuration providers -The .NET Aspire Azure AI Search library supports [Microsoft.Extensions.Configuration](xref:Microsoft.Extensions.Configuration). It loads the `AzureSearchSettings` and `SearchClientOptions` from configuration by using the `Aspire:Azure:Search:Documents` key. Example `appsettings.json` that configures some of the options: +The .NET Aspire Azure AI Search library supports . It loads the `AzureSearchSettings` and `SearchClientOptions` from configuration by using the `Aspire:Azure:Search:Documents` key. Example `appsettings.json` that configures some of the options: ```json { diff --git a/docs/database/azure-cosmos-db-component.md b/docs/database/azure-cosmos-db-component.md index 4324a8d28f..f1ee084ff3 100644 --- a/docs/database/azure-cosmos-db-component.md +++ b/docs/database/azure-cosmos-db-component.md @@ -2,7 +2,7 @@ title: .NET Aspire Azure Cosmos DB component description: This article describes the .NET Aspire Azure Cosmos DB component features and capabilities. ms.topic: how-to -ms.date: 03/13/2024 +ms.date: 04/09/2024 --- # .NET Aspire Azure Cosmos DB component @@ -51,7 +51,22 @@ For more information on using the , se ## App host usage -[!INCLUDE [azure-component-nuget](../includes/azure-component-nuget.md)] +To add Azure Cosmos DB hosting support to your , install the [Aspire.Hosting.Azure.CosmosDB](https://www.nuget.org/packages/Aspire.Hosting.Azure.CosmosDB) NuGet package. + +### [.NET CLI](#tab/dotnet-cli) + +```dotnetcli +dotnet add package Aspire.Hosting.Azure.CosmosDB --prerelease +``` + +### [PackageReference](#tab/package-reference) + +```xml + +``` + +--- In your app host project, register the .NET Aspire Azure Cosmos DB component and consume the service using the following methods: diff --git a/docs/database/azure-cosmos-db-entity-framework-component.md b/docs/database/azure-cosmos-db-entity-framework-component.md index 04ad4fa126..7803d9dd74 100644 --- a/docs/database/azure-cosmos-db-entity-framework-component.md +++ b/docs/database/azure-cosmos-db-entity-framework-component.md @@ -2,7 +2,7 @@ title: .NET Aspire Microsoft Entity Framework Core Cosmos DB component description: This article describes the .NET Aspire Microsoft Entity Framework Core Cosmos DB component features and capabilities. ms.topic: how-to -ms.date: 01/22/2024 +ms.date: 04/04/2024 --- # .NET Aspire Microsoft Entity Framework Core Cosmos DB component @@ -51,7 +51,22 @@ For more information on using Entity Framework Core with Azure Cosmos DB, see th ## App host usage -[!INCLUDE [azure-component-nuget](../includes/azure-component-nuget.md)] +To add Azure Cosmos DB hosting support to your , install the [Aspire.Hosting.Azure.CosmosDB](https://www.nuget.org/packages/Aspire.Hosting.Azure.CosmosDB) NuGet package. + +### [.NET CLI](#tab/dotnet-cli) + +```dotnetcli +dotnet add package Aspire.Hosting.Azure.CosmosDB --prerelease +``` + +### [PackageReference](#tab/package-reference) + +```xml + +``` + +--- In your app host project, register the .NET Aspire Microsoft Entity Framework Core Cosmos DB component and consume the service using the following methods: diff --git a/docs/database/snippets/tutorial/aspiresqlefcore/AspireSQLEFCore.AppHost/AspireSQLEFCore.AppHost.csproj b/docs/database/snippets/tutorial/aspiresqlefcore/AspireSQLEFCore.AppHost/AspireSQLEFCore.AppHost.csproj index d3e8ae6729..15d411ccca 100644 --- a/docs/database/snippets/tutorial/aspiresqlefcore/AspireSQLEFCore.AppHost/AspireSQLEFCore.AppHost.csproj +++ b/docs/database/snippets/tutorial/aspiresqlefcore/AspireSQLEFCore.AppHost/AspireSQLEFCore.AppHost.csproj @@ -10,11 +10,10 @@ - - - + + + + diff --git a/docs/database/snippets/tutorial/aspiresqlefcore/AspireSQLEFCore.ServiceDefaults/AspireSQLEFCore.ServiceDefaults.csproj b/docs/database/snippets/tutorial/aspiresqlefcore/AspireSQLEFCore.ServiceDefaults/AspireSQLEFCore.ServiceDefaults.csproj index 6eae75c1ac..09e799a0b8 100644 --- a/docs/database/snippets/tutorial/aspiresqlefcore/AspireSQLEFCore.ServiceDefaults/AspireSQLEFCore.ServiceDefaults.csproj +++ b/docs/database/snippets/tutorial/aspiresqlefcore/AspireSQLEFCore.ServiceDefaults/AspireSQLEFCore.ServiceDefaults.csproj @@ -11,13 +11,11 @@ - + - - diff --git a/docs/database/snippets/tutorial/aspiresqlefcore/AspireSQLEFCore.ServiceDefaults/Extensions.cs b/docs/database/snippets/tutorial/aspiresqlefcore/AspireSQLEFCore.ServiceDefaults/Extensions.cs index c6adc5cf68..090aca54f7 100644 --- a/docs/database/snippets/tutorial/aspiresqlefcore/AspireSQLEFCore.ServiceDefaults/Extensions.cs +++ b/docs/database/snippets/tutorial/aspiresqlefcore/AspireSQLEFCore.ServiceDefaults/Extensions.cs @@ -3,11 +3,13 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.ServiceDiscovery; using OpenTelemetry.Logs; using OpenTelemetry.Metrics; using OpenTelemetry.Trace; namespace Microsoft.Extensions.Hosting; + public static class Extensions { public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder) @@ -24,9 +26,15 @@ public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBu http.AddStandardResilienceHandler(); // Turn on service discovery by default - http.UseServiceDiscovery(); + http.AddServiceDiscovery(); }); + // Uncomment the following to restrict the allowed schemes for service discovery. + // builder.Services.Configure(options => + // { + // options.AllowedSchemes = ["https"]; + // }); + return builder; } @@ -42,9 +50,8 @@ public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicati .WithMetrics(metrics => { metrics.AddAspNetCoreInstrumentation() - .AddHttpClientInstrumentation() - .AddProcessInstrumentation() - .AddRuntimeInstrumentation(); + .AddHttpClientInstrumentation() + .AddRuntimeInstrumentation(); }) .WithTracing(tracing => { @@ -55,8 +62,9 @@ public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicati } tracing.AddAspNetCoreInstrumentation() - .AddGrpcClientInstrumentation() - .AddHttpClientInstrumentation(); + // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package) + //.AddGrpcClientInstrumentation() + .AddHttpClientInstrumentation(); }); builder.AddOpenTelemetryExporters(); @@ -103,15 +111,20 @@ public static WebApplication MapDefaultEndpoints(this WebApplication app) // Uncomment the following line to enable the Prometheus endpoint (requires the OpenTelemetry.Exporter.Prometheus.AspNetCore package) // app.MapPrometheusScrapingEndpoint(); - // All health checks must pass for app to be considered ready to accept traffic after starting - app.MapHealthChecks("/health"); - - // Only health checks tagged with the "live" tag must pass for app to be considered alive - app.MapHealthChecks("/alive", new HealthCheckOptions + // Adding health checks endpoints to applications in non-development environments has security implications. + // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments. + if (app.Environment.IsDevelopment()) { - Predicate = r => r.Tags.Contains("live") - }); + // All health checks must pass for app to be considered ready to accept traffic after starting + app.MapHealthChecks("/health"); + + // Only health checks tagged with the "live" tag must pass for app to be considered alive + app.MapHealthChecks("/alive", new HealthCheckOptions + { + Predicate = r => r.Tags.Contains("live") + }); + } return app; } -} +} \ No newline at end of file diff --git a/docs/database/snippets/tutorial/aspiresqlefcore/AspireSQLEFCore/AspireSQLEFCore.csproj b/docs/database/snippets/tutorial/aspiresqlefcore/AspireSQLEFCore/AspireSQLEFCore.csproj index 4aef8cad72..ff40e72b48 100644 --- a/docs/database/snippets/tutorial/aspiresqlefcore/AspireSQLEFCore/AspireSQLEFCore.csproj +++ b/docs/database/snippets/tutorial/aspiresqlefcore/AspireSQLEFCore/AspireSQLEFCore.csproj @@ -7,7 +7,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/docs/deployment/azure/local-provisioning.md b/docs/deployment/azure/local-provisioning.md new file mode 100644 index 0000000000..cf74c5c921 --- /dev/null +++ b/docs/deployment/azure/local-provisioning.md @@ -0,0 +1,140 @@ +--- +title: Local Azure provisioning +description: Learn how to use Azure resources in your local development environment. +ms.date: 04/05/2024 +--- + +# Local Azure provisioning + +.NET Aspire simplifies local cloud-native app development with its compelling app host model. This model allows you to run your app locally with the same configuration and services as in Azure. + +In this article you learn how to provision Azure resources from your local development environment through the [.NET Aspire app host](../../fundamentals/app-host-overview.md). All of this is possible with the help of the [Azure.Provisioning.* libraries](#azure-provisioning-libraries), which provide a set of APIs to provision Azure resources. These packages are transitive dependencies of the .NET Aspire Azure hosting libraries you use in your app host, so you don't need to install them separately. + +## Assumptions + +This article assumes that you have an Azure account and subscription. If you don't have an Azure account, you can create a free one at [Azure Free Account](https://azure.microsoft.com/free/). For provisioning functionality to work correctly, you'll need to be authenticated with Azure. Additionally, you'll need to provide some configuration values so that the provisioning logic can create resources on your behalf. + +## Configuration + +When utilizing Azure resources in your local development environment, you need to provide the necessary configuration values. Configuration values are specified under the `Azure` section: + +- `SubscriptionId`: The Azure subscription ID. +- `AllowResourceGroupCreation`: A boolean value that indicates whether to create a new resource group. +- `ResourceGroup`: The name of the resource group to use. +- `Location`: The Azure region to use. + +Consider the following example _appsettings.json_ configuration: + +```json +{ + "Azure": { + "SubscriptionId": "", + "AllowResourceGroupCreation": true, + "ResourceGroup": "", + "Location": "", + } +} +``` + +> [!IMPORTANT] +> It's recommended to store these values as app secrets. For more information, see [Manage app secrets](/aspnet/core/security/app-secrets). + +After you've configured the necessary values, you can start provisioning Azure resources in your local development environment. + +### Tooling support + +In Visual Studio, you can use Connected Services to configure the default Azure provisioning settings. Select the app host project, right-click on the **Connected Services** node, and select **Azure Resource Provisioning Settings**: + +:::image type="content" source="media/azure-resource-provisioning-settings.png" lightbox="media/azure-resource-provisioning-settings.png" alt-text="Visual Studio 2022: .NET Aspire App Host project, Connected Services context menu."::: + +This will open a dialog where you can configure the Azure provisioning settings, as shown in the following screenshot: + +:::image type="content" source="media/azure-provisioning-settings-dialog.png" lightbox="media/azure-provisioning-settings-dialog.png" alt-text="Visual Studio 2022: Azure Resource Provisioning Settings dialog."::: + +### Missing configuration value hints + +When the `Azure` configuration section is missing, has missing values, or is invalid, the [.NET Aspire dashboard](../../fundamentals/dashboard.md) provides useful hints. For example, consider an app host that's missing the `SubscriptionId` configuration value that's attempting to use an Azure Key Vault resource, the **Resources** page indicates the **State** as **Missing subscription configuration**: + +:::image type="content" source="media/resources-kv-missing-subscription.png" alt-text=".NET Aspire dashboard: Missing subscription configuration."::: + +Additionally, the **Console logs** display this information as well, consider the following screenshot: + +:::image type="content" source="media/console-logs-kv-missing-subscription.png" lightbox="media/console-logs-kv-missing-subscription.png" alt-text=".NET Aspire dashboard: Console logs, missing subscription configuration."::: + +## App host provisioning APIs + +The app host provides a set of APIs to express Azure resources. These APIs are available as extension methods in .NET Aspire Azure hosting libraries, extending the `IDistributedApplicationBuilder` interface. When you add Azure resources to your app host, they'll add the appropriate provisioning functionality implicitly. In other words, you don't need to call any provisioning APIs directly. + +When the app host starts, the following provisioning logic is executed: + +1. The `Azure` configuration section is validated. +1. When invalid the dashboard and app host output provides hints as to what's missing. For more information, see [Missing configuration value hints](#missing-configuration-value-hints). +1. When valid Azure resources are conditionally provisioned: + 1. If an Azure deployment for a given resource doesn't exist, it's created and configured as a deployment. + 1. The configuration of said deployment is stamped with a checksum as a means to support only provisioning resources as necessary. + +### Use existing Azure resources + +The app host automatically manages provisioning of Azure resources. The first time the app host runs, it provisions the resources specified in the app host. Subsequent runs don't provision the resources again unless the app host configuration changes. + +If you've already provisioned Azure resources outside of the app host and want to use them, you can provide the connection string with the `AddConnectionString` API as shown in the following Azure Key Vault example: + +```csharp +// Service registration +var secrets = builder.ExecutionContext.IsPublishMode + ? builder.AddAzureKeyVault("secrets") + : builder.AddConnectionString("secrets"); + +// Service consumption +builder.AddProject() + .WithReference(secrets) +``` + +The preceding code snippet shows how to add an Azure Key Vault to the app host. The `AddAzureKeyVault` API is used to add the Azure Key Vault to the app host. The `AddConnectionString` API is used to provide the connection string to the app host. + +Alternatively, for some Azure resources, you can opt-in to running them as an emulator with the `RunAsEmulator` API. This API is available for Azure Cosmos DB and Azure Storage. For example, to run Azure Cosmos DB as an emulator, you can use the following code snippet: + +```csharp +var cosmos = builder.AddAzureCosmosDB("cosmos") + .RunAsEmulator(); +``` + +The `RunAsEmulator` API configures an Azure Cosmos DB resource to be emulated using the Azure Cosmos DB emulator with the NoSQL API. + +### .NET Aspire Azure hosting libraries + +If you're using Azure resources in your app host, you're using one or more of the [.NET Aspire Azure hosting libraries](../../fundamentals/app-host-overview.md#azure-hosting-libraries). These hosting libraries provide extension methods to the `IDistributedApplicationBuilder` interface to add Azure resources to your app host. + +### Azure provisioning libraries + +The following Azure provisioning libraries are available: + +- [πŸ“¦ Azure.Provisioning.AppConfiguration](https://www.nuget.org/packages/Azure.Provisioning.AppConfiguration) +- [πŸ“¦ Azure.Provisioning.ApplicationInsights](https://www.nuget.org/packages/Azure.Provisioning.ApplicationInsights) +- [πŸ“¦ Azure.Provisioning.CognitiveServices](https://www.nuget.org/packages/Azure.Provisioning.CognitiveServices) +- [πŸ“¦ Azure.Provisioning.CosmosDB](https://www.nuget.org/packages/Azure.Provisioning.CosmosDB) +- [πŸ“¦ Azure.Provisioning.EventHubs](https://www.nuget.org/packages/Azure.Provisioning.EventHubs) +- [πŸ“¦ Azure.Provisioning.KeyVault](https://www.nuget.org/packages/Azure.Provisioning.KeyVault) +- [πŸ“¦ Azure.Provisioning.OperationalInsights](https://www.nuget.org/packages/Azure.Provisioning.OperationalInsights) +- [πŸ“¦ Azure.Provisioning.PostgreSql](https://www.nuget.org/packages/Azure.Provisioning.PostgreSql) +- [πŸ“¦ Azure.Provisioning.Redis](https://www.nuget.org/packages/Azure.Provisioning.Redis) +- [πŸ“¦ Azure.Provisioning.Resources](https://www.nuget.org/packages/Azure.Provisioning.Resources) +- [πŸ“¦ Azure.Provisioning.Search](https://www.nuget.org/packages/Azure.Provisioning.Search) +- [πŸ“¦ Azure.Provisioning.ServiceBus](https://www.nuget.org/packages/Azure.Provisioning.ServiceBus) +- [πŸ“¦ Azure.Provisioning.SignalR](https://www.nuget.org/packages/Azure.Provisioning.SignalR) +- [πŸ“¦ Azure.Provisioning.Sql](https://www.nuget.org/packages/Azure.Provisioning.Sql) +- [πŸ“¦ Azure.Provisioning.Storage](https://www.nuget.org/packages/Azure.Provisioning.Storage) +- [πŸ“¦ Azure.Provisioning](https://www.nuget.org/packages/Azure.Provisioning) + +> [!TIP] +> You shouldn't need to install these packages manually in your projects, as they're transitive dependencies of the corresponding .NET Aspire Azure hosting libraries. + +## Known limitations + +After provisioning Azure resources in this way, you must manually clean up the resources in the Azure portal as .NET Aspire doesn't provide a built-in mechanism to delete Azure resources. The easiest way to achieve this is by deleting the configured resource group. This can be done in the [Azure portal](/azure/azure-resource-manager/management/delete-resource-group?tabs=azure-portal#delete-resource-group) or by using the Azure CLI: + +```azurecli +az group delete --name +``` + +Replace `` with the name of the resource group you want to delete. For more information, see [az group delete](/cli/azure/group#az-group-delete). diff --git a/docs/deployment/azure/media/azure-provisioning-settings-dialog.png b/docs/deployment/azure/media/azure-provisioning-settings-dialog.png new file mode 100644 index 0000000000..379bb79c46 Binary files /dev/null and b/docs/deployment/azure/media/azure-provisioning-settings-dialog.png differ diff --git a/docs/deployment/azure/media/azure-resource-provisioning-settings.png b/docs/deployment/azure/media/azure-resource-provisioning-settings.png new file mode 100644 index 0000000000..5f58caeea7 Binary files /dev/null and b/docs/deployment/azure/media/azure-resource-provisioning-settings.png differ diff --git a/docs/deployment/azure/media/console-logs-kv-missing-subscription.png b/docs/deployment/azure/media/console-logs-kv-missing-subscription.png new file mode 100644 index 0000000000..8129ade611 Binary files /dev/null and b/docs/deployment/azure/media/console-logs-kv-missing-subscription.png differ diff --git a/docs/deployment/azure/media/resources-kv-missing-subscription.png b/docs/deployment/azure/media/resources-kv-missing-subscription.png new file mode 100644 index 0000000000..a493ae2d19 Binary files /dev/null and b/docs/deployment/azure/media/resources-kv-missing-subscription.png differ diff --git a/docs/deployment/manifest-format.md b/docs/deployment/manifest-format.md index 2762222162..e6de37225f 100644 --- a/docs/deployment/manifest-format.md +++ b/docs/deployment/manifest-format.md @@ -1,7 +1,7 @@ --- title: .NET Aspire manifest format for deployment tool builders description: Learn about the .NET Aspire manifest format in this comprehensive deployment tool builder guide. -ms.date: 03/13/2024 +ms.date: 03/29/2024 ms.topic: reference --- @@ -44,6 +44,23 @@ info: Aspire.Hosting.Publishing.ManifestPublisher[0] The file generated is the .NET Aspire manifest and is used by tools to support deploying into target cloud environments. +> [!NOTE] +> You can also generate a manifest as part of the launch profile. Consider the following _launchSettings.json_: +> +> ```json +> { +> "$schema": "http://json.schemastore.org/launchsettings.json", +> "profiles": { +> "generate-manifest": { +> "commandName": "Project", +> "launchBrowser": false, +> "dotnetRunMessages": true, +> "commandLineArgs": "--publisher manifest --output-path aspire-manifest.json" +> } +> } +> } +> ``` + ## Basic manifest format Publishing the manifest from the default starter template for .NET Aspire produces the following JSON output: diff --git a/docs/deployment/overview.md b/docs/deployment/overview.md index 6ed36503ee..2c0a93d59a 100644 --- a/docs/deployment/overview.md +++ b/docs/deployment/overview.md @@ -2,22 +2,22 @@ title: .NET Aspire deployments description: Learn about essential deployment concepts for .NET Aspire. ms.topic: overview -ms.date: 02/26/2024 +ms.date: 04/03/2024 --- # .NET Aspire deployments -.NET Aspire applications are built with cloud-agnostic principles, allowing deployment flexibility across various platforms supporting .NET and containers. Users can adapt the provided guidelines for deployment on other cloud environments or local hosting. The manual deployment process, while feasible, involves exhaustive steps prone to errors. We anticipate users will prefer leveraging CI/CD pipelines and cloud-specific tooling for a more streamlined deployment experience tailored to their chosen infrastructure. +.NET Aspire applications are built with cloud-agnostic principles, allowing deployment flexibility across various platforms supporting .NET and containers. Users can adapt the provided guidelines for deployment on other cloud environments or local hosting. The manual deployment process, while feasible, involves exhaustive steps prone to errors. Users prefer leveraging CI/CD pipelines and cloud-specific tooling for a more streamlined deployment experience tailored to their chosen infrastructure. ## Deployment manifest -To enable deployment tools from Microsoft and other cloud providers to understand the structure of .NET Aspire applications, specialized targets of the AppHost project can be executed to generate a manifest file describing the projects/services used by the app and the properties necessary for deployment, such as environment variables. +To enable deployment tools from Microsoft and other cloud providers to understand the structure of .NET Aspire applications, specialized targets of the [AppHost project](../fundamentals/app-host-overview.md) can be executed to generate a manifest file describing the projects/services used by the app and the properties necessary for deployment, such as environment variables. -For more information on the schema of the manifest and how to run AppHost project targets, see [.NET Aspire manifest format for deployment tool builders](manifest-format.md). +For more information on the schema of the manifest and how to run app host project targets, see [.NET Aspire manifest format for deployment tool builders](manifest-format.md). ## Deploy to Azure -.NET Aspire enables deployment to Azure Container Apps. We expect the number of environments Aspire can deploy to to grow over time. +.NET Aspire enables deployment to Azure Container Apps. The number of environments .NET Aspire can deploy to will grow over time. ### Azure Container Apps @@ -25,4 +25,23 @@ For more information on the schema of the manifest and how to run AppHost projec ### Use Application Insights for .NET Aspire telemetry -.NET Aspire apps are designed to emit Telemetry using OpenTelemetry which uses a provider model. .NET Aspire Apps can direct their telemetry to Azure Monitor / Application Insights using the Azure Monitor telemetry distro. For more information, see [Application Insights](/azure/azure-monitor/app/app-insights-overview) for step-by-step instructions. +.NET Aspire apps are designed to emit Telemetry using OpenTelemetry which uses a provider model. .NET Aspire Apps can direct their telemetry to Azure Monitor / Application Insights using the Azure Monitor telemetry distro. For more information, see [Use Application Insights for .NET Aspire telemetry](azure/application-insights.md) for step-by-step instructions. + +## Deploy to Kubernetes + +Kubernetes is a popular container orchestration platform that can run .NET Aspire applications. To deploy .NET Aspire apps to Kubernetes clusters, you need to map the .NET Aspire JSON manifest to a Kubernetes YAML manifest file. There are two ways to do this: by using the Aspir8 project and by manually creating Kubernetes manifests. + +### The Aspir8 project + +**Aspir8**, an open-source project, handles the generation of deployment YAML based on the .NET Aspire app host manifest. The project outputs a .NET global tool that can be used to perform a series of tasks, resulting in the generation of Kubernetes manifests: + +- `aspirate init`: Initializes the **Aspir8** project in the current directory. +- `aspirate generate`: Generates Kubernetes manifests based on the .NET Aspire app host manifest. +- `aspirate apply`: Applies the generated Kubernetes manifests to the Kubernetes cluster. +- `aspirate destroy`: Deletes the resources created by the `apply` command. + +With these commands, you can build your apps, containerize them, and deploy them to Kubernetes clusters. For more information, see [Aspir8](https://prom3theu5.github.io/aspirational-manifests/getting-started.html). + +### Manually create Kubernetes manifests + +Alternatively, the Kubernetes manifests can be created manually. This involves more effort and is more time consuming. For more information, see [Deploy a .NET microservice to Kubernetes](/training/modules/dotnet-deploy-microservices-kubernetes/). diff --git a/docs/diagnostics/overview.md b/docs/diagnostics/overview.md new file mode 100644 index 0000000000..ae46068ec5 --- /dev/null +++ b/docs/diagnostics/overview.md @@ -0,0 +1,30 @@ +--- +title: .NET Aspire diagnostics overview +description: Learn about the diagnostics tools and features available in .NET Aspire. +ms.topic: overview +ms.date: 03/25/2024 +--- + +# .NET Aspire diagnostics overview + +Several APIs of .NET Aspire are decorated with the . This attribute indicates that the API is experimental and may be removed or changed in future versions of .NET Aspire. The attribute is used to identify APIs that aren't yet stable and may not be suitable for production use. + +## ASPIRE0001 + +.NET Aspire provides various overloads for Cloud Development Kit (CDK) resource types. The overloads are used to create resources with different configurations. The overloads are experimental and may be removed or changed in future versions of .NET Aspire. + +To suppress this diagnostic with the `SuppressMessageAttribute`, add the following code to your project: + +```csharp +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("ASPIRE0001", "Justification")] +``` + +Alternatively, you can suppress this diagnostic with preprocessor directive by adding the following code to your project: + +```csharp +#pragma warning disable ASPIRE0001 + // API that is causing the warning. +#pragma warning restore ASPIRE0001 +``` diff --git a/docs/fundamentals/app-host-overview.md b/docs/fundamentals/app-host-overview.md index 37ef17a7b9..81e5e86ee4 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 to express resource references. -ms.date: 03/13/2024 +ms.date: 04/09/2024 ms.topic: overview --- @@ -114,8 +114,8 @@ var apiservice = builder.AddProject("apiservice") .WithReference(endpoint); ``` -| Method | Environment variable | -|---------------------------|--------------------------------------------------| +| Method | Environment variable | +|---------------------------|-------------------------------------------------| | `WithReference(endpoint)` | `services__myapp__0=endpoint://localhost:65256` | The `containerPort` parameter is the port that the container is listening on. For more information on container ports, see [Container ports](networking-overview.md#container-ports). For more information on service discovery, see [.NET Aspire service discovery](../service-discovery/overview.md). @@ -124,7 +124,20 @@ The `containerPort` parameter is the port that the container is listening on. Fo Beyond the base resource types, , , and , .NET Aspire provides extension methods to add common resources to your app model. The following table lists the methods and their corresponding resource types: -**Cloud-agnostic resources available in the [πŸ“¦ Aspire.Hosting](https://www.nuget.org/packages/Aspire.Hosting) NuGet package (available by default in .NET Aspire templates with the AppHost project):** +**Cloud-agnostic resources are available in the following NuGet packages:** + +- [πŸ“¦ Aspire.Hosting.Kafka](https://www.nuget.org/packages/Aspire.Hosting.Kafka) +- [πŸ“¦ Aspire.Hosting.MongoDB](https://www.nuget.org/packages/Aspire.Hosting.MongoDB) +- [πŸ“¦ Aspire.Hosting.MySql](https://www.nuget.org/packages/Aspire.Hosting.MySql) +- [πŸ“¦ Aspire.Hosting.Nats](https://www.nuget.org/packages/Aspire.Hosting.Nats) +- [πŸ“¦ Aspire.Hosting.NodeJs](https://www.nuget.org/packages/Aspire.Hosting.NodeJs) +- [πŸ“¦ Aspire.Hosting.Oracle](https://www.nuget.org/packages/Aspire.Hosting.Oracle) +- [πŸ“¦ Aspire.Hosting.Orleans](https://www.nuget.org/packages/Aspire.Hosting.Orleans) +- [πŸ“¦ Aspire.Hosting.PostgreSQL](https://www.nuget.org/packages/Aspire.Hosting.PostgreSQL) +- [πŸ“¦ Aspire.Hosting.RabbitMQ](https://www.nuget.org/packages/Aspire.Hosting.RabbitMQ) +- [πŸ“¦ Aspire.Hosting.Redis](https://www.nuget.org/packages/Aspire.Hosting.Redis) +- [πŸ“¦ Aspire.Hosting.Seq](https://www.nuget.org/packages/Aspire.Hosting.Seq) +- [πŸ“¦ Aspire.Hosting.SqlServer](https://www.nuget.org/packages/Aspire.Hosting.SqlServer) | Method | Resource type | Description | |--|--|--| @@ -139,7 +152,24 @@ Beyond the base resource types, | | Adds a Redis container resource. | | | | Adds a SQL Server server resource. | -**Azure specific resources available in the [πŸ“¦ Aspire.Hosting.Azure](https://www.nuget.org/packages/Aspire.Hosting.Azure) NuGet package:** +**Azure specific resources are available in the following NuGet packages:** + + + +- [πŸ“¦ Aspire.Hosting.Azure.AppConfiguration](https://www.nuget.org/packages/Aspire.Hosting.Azure.AppConfiguration) +- [πŸ“¦ Aspire.Hosting.Azure.ApplicationInsights](https://www.nuget.org/packages/Aspire.Hosting.Azure.ApplicationInsights) +- [πŸ“¦ Aspire.Hosting.Azure.CognitiveServices](https://www.nuget.org/packages/Aspire.Hosting.Azure.CognitiveServices) +- [πŸ“¦ Aspire.Hosting.Azure.CosmosDB](https://www.nuget.org/packages/Aspire.Hosting.Azure.CosmosDB) +- [πŸ“¦ Aspire.Hosting.Azure.EventHubs](https://www.nuget.org/packages/Aspire.Hosting.Azure.EventHubs) +- [πŸ“¦ Aspire.Hosting.Azure.KeyVault](https://www.nuget.org/packages/Aspire.Hosting.Azure.KeyVault) +- [πŸ“¦ Aspire.Hosting.Azure.OperationalInsights](https://www.nuget.org/packages/Aspire.Hosting.Azure.OperationalInsights) +- [πŸ“¦ Aspire.Hosting.Azure.PostgreSQL](https://www.nuget.org/packages/Aspire.Hosting.Azure.PostgreSQL) +- [πŸ“¦ Aspire.Hosting.Azure.Redis](https://www.nuget.org/packages/Aspire.Hosting.Azure.Redis) +- [πŸ“¦ Aspire.Hosting.Azure.Search](https://www.nuget.org/packages/Aspire.Hosting.Azure.Search) +- [πŸ“¦ Aspire.Hosting.Azure.ServiceBus](https://www.nuget.org/packages/Aspire.Hosting.Azure.ServiceBus) +- [πŸ“¦ Aspire.Hosting.Azure.SignalR](https://www.nuget.org/packages/Aspire.Hosting.Azure.SignalR) +- [πŸ“¦ Aspire.Hosting.Azure.Sql](https://www.nuget.org/packages/Aspire.Hosting.Azure.Sql) +- [πŸ“¦ Aspire.Hosting.Azure.Storage](https://www.nuget.org/packages/Aspire.Hosting.Azure.Storage) | Method | Resource type | Description | |--|--|--| @@ -153,6 +183,17 @@ Beyond the base resource types, | | Configures SQL Server resource to be deployed as Azure SQL Database (server). | | | | Adds an Azure Service Bus resource. | +> [!IMPORTANT] +> The .NET Aspire Azure hosting libraries rely on `Azure.Provisioning.*` libraries to provision Azure resources. For more information, [Azure provisioning libraries](../deployment/azure/local-provisioning.md#azure-provisioning-libraries). + +**AWS specific resources are available in the following NuGet package:** + + + +- [πŸ“¦ Aspire.Hosting.AWS](https://www.nuget.org/packages/Aspire.Hosting.AWS) + +For more information, see [GitHub: Aspire.Hosting.AWS library](https://github.com/dotnet/aspire/tree/release/8.0-preview5/src/Aspire.Hosting.AWS). + ## See also - [.NET Aspire components overview](components-overview.md) diff --git a/docs/fundamentals/health-checks.md b/docs/fundamentals/health-checks.md index 4aae5c36aa..0913c496b0 100644 --- a/docs/fundamentals/health-checks.md +++ b/docs/fundamentals/health-checks.md @@ -1,7 +1,7 @@ --- title: .NET Aspire health checks description: Explore .NET Aspire health checks -ms.date: 12/08/2023 +ms.date: 04/02/2024 ms.topic: quickstart --- @@ -15,7 +15,7 @@ Health checks provide availability and state information about an app. Health ch ## .NET Aspire health check endpoints -.NET Aspire exposes two default health check HTTP endpoints when the `AddServiceDefaults` and `MapDefaultEndpoints` methods are called from the _Program.cs_ file: +.NET Aspire exposes two default health check HTTP endpoints in **Development** environments when the `AddServiceDefaults` and `MapDefaultEndpoints` methods are called from the _Program.cs_ file: - The `/health` endpoint indicates if the app is running normally where it's ready to receive requests. All health checks must pass for app to be considered ready to accept traffic after starting. @@ -35,6 +35,28 @@ Health checks provide availability and state information about an app. Health ch The `AddServiceDefaults` and `MapDefaultEndpoints` methods also apply various configurations to your app beyond just health checks, such as OpenTelemetry and service discovery configurations. +### Non-development environments + +In non-development environments, the `/health` and `/alive` endpoints are disabled by default. If you need to enable them, its recommended to protect these endpoints with various routing features, such as host filtering and/or authorization. For more information, see [Health checks in ASP.NET Core](/aspnet/core/host-and-deploy/health-checks#use-health-checks-routing). + +Additionally, it may advantageous to configure request timeouts and output caching for these endpoints to prevent abuse or denial-of-service attacks. To do so, consider the following modified `AddDefaultHealthChecks` method: + +:::code language="csharp" source="snippets/healthz/Healthz.ServiceDefaults/Extensions.cs" id="healthchecks"::: + +The preceding code: + +- Adds a timeout of 5 seconds to the health check requests with a policy named `HealthChecks`. +- Adds a 10-second cache to the health check responses with a policy named `HealthChecks`. + +Now consider the updated `MapDefaultEndpoints` method: + +:::code language="csharp" source="snippets/healthz/Healthz.ServiceDefaults/Extensions.cs" id="mapendpoints"::: + +The preceding code: + +- Groups the health check endpoints under the `/` path. +- Caches the output and specifies a request time with the corresponding `HealthChecks` policy. + ## Component health checks .NET Aspire components can also register additional health checks for your app. These health checks contribute to the returned status of the `/health` and `/alive` endpoints. For example, the .NET Aspire PostgreSQL component automatically adds a health check to verify the following conditions: diff --git a/docs/fundamentals/networking-overview.md b/docs/fundamentals/networking-overview.md index 838d8db98a..1d8aaac02b 100644 --- a/docs/fundamentals/networking-overview.md +++ b/docs/fundamentals/networking-overview.md @@ -47,11 +47,7 @@ For the remainder of this article, imagine that you've created an : - -:::code source="snippets/networking/Networking.AppHost/Program.WithLaunchProfile.cs" id="withlaunchprofile"::: - -This will select the **https** launch profile from _launchSettings.json_. The `applicationUrl` of that launch profile is used to create a service binding for this project. This is the equivalent of: +To specify that the **https** launch profile should be used, select the **https** launch profile from _launchSettings.json_. The `applicationUrl` of that launch profile is used to create a service binding for this project. This is the equivalent of: :::code source="snippets/networking/Networking.AppHost/Program.WithLaunchProfile.cs" id="verbose"::: diff --git a/docs/fundamentals/service-defaults.md b/docs/fundamentals/service-defaults.md index e25ed159a2..9899ab1e70 100644 --- a/docs/fundamentals/service-defaults.md +++ b/docs/fundamentals/service-defaults.md @@ -1,7 +1,7 @@ --- title: .NET Aspire service defaults description: Learn about the .NET Aspire service defaults project. -ms.date: 12/08/2023 +ms.date: 04/05/2024 ms.topic: reference --- @@ -33,7 +33,12 @@ For more information, see [Provided extension methods](#provided-extension-metho The _YourAppName.ServiceDefaults_ project is a .NET 8.0 library that contains the following XML: -:::code language="xml" source="snippets/template/YourAppName/YourAppName.ServiceDefaults.csproj"::: +:::code language="xml" source="snippets/template/YourAppName/YourAppName.ServiceDefaults.csproj" highlight="11"::: + +The service defaults project template imposes a `FrameworkReference` dependency on `Microsoft.AspNetCore.App`. + +> [!TIP] +> If you don't want to take a dependency on `Microsoft.AspNetCore.App`, you can create a custom service defaults project. For more information, see [Custom service defaults](#custom-service-defaults). The `IsAspireSharedProject` property is set to `true`, which indicates that this project is a shared project. The .NET Aspire tooling uses this project as a reference for other projects added to a .NET Aspire solution. When you enlist the new project for orchestration, it automatically references the _YourAppName.ServiceDefaults_ project and updates the _Program.cs_ file to call the `AddServiceDefaults` method. @@ -73,7 +78,8 @@ The `ConfigureOpenTelemetry` method: - Adds [.NET Aspire telemetry](telemetry.md) logging to include formatted messages and scopes. - Adds OpenTelemetry metrics and tracing that include: - Runtime instrumentation metrics. - - Builtin meters. + - ASP.NET Core instrumentation metrics. + - HttpClient instrumentation metrics. - In a development environment, the `AlwaysOnSampler` is used to view all traces. - Tracing details for ASP.NET Core, gRPC and HTTP instrumentation. - Adds OpenTelemetry exporters, by calling `AddOpenTelemetryExporters`. @@ -111,6 +117,119 @@ The `MapDefaultEndpoints` method: For more information, see [.NET Aspire health checks](health-checks.md). +## Custom service defaults + +If the default service configuration provided by the project template is not sufficient for your needs, you have the option to create your own service defaults project. This is especially useful when your consuming project, such as a Worker project or WinForms project, cannot or does not want to have a `FrameworkReference` dependency on `Microsoft.AspNetCore.App`. + +To do this, create a new .NET 8.0 class library project and add the necessary dependencies to the project file, consider the following example: + +```xml + + + + Library + net8.0 + + + + + + + + + + + + +``` + +Then create an extensions class that contains the necessary methods to configure the app defaults: + +```csharp +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using OpenTelemetry.Logs; +using OpenTelemetry.Metrics; +using OpenTelemetry.Trace; + +namespace Microsoft.Extensions.Hosting; + +public static class AppDefaultsExtensions +{ + public static IHostApplicationBuilder AddAppDefaults( + this IHostApplicationBuilder builder) + { + builder.ConfigureAppOpenTelemetry(); + + builder.Services.AddServiceDiscovery(); + + builder.Services.ConfigureHttpClientDefaults(http => + { + // Turn on resilience by default + http.AddStandardResilienceHandler(); + + // Turn on service discovery by default + http.AddServiceDiscovery(); + }); + + return builder; + } + + public static IHostApplicationBuilder ConfigureAppOpenTelemetry( + this IHostApplicationBuilder builder) + { + builder.Logging.AddOpenTelemetry(logging => + { + logging.IncludeFormattedMessage = true; + logging.IncludeScopes = true; + }); + + builder.Services.AddOpenTelemetry() + .WithMetrics(static metrics => + { + metrics.AddRuntimeInstrumentation(); + }) + .WithTracing(tracing => + { + if (builder.Environment.IsDevelopment()) + { + // We want to view all traces in development + tracing.SetSampler(new AlwaysOnSampler()); + } + + tracing.AddGrpcClientInstrumentation() + .AddHttpClientInstrumentation(); + }); + + builder.AddOpenTelemetryExporters(); + + return builder; + } + + private static IHostApplicationBuilder AddOpenTelemetryExporters( + this IHostApplicationBuilder builder) + { + var useOtlpExporter = + !string.IsNullOrWhiteSpace( + builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]); + + if (useOtlpExporter) + { + builder.Services.Configure( + logging => logging.AddOtlpExporter()); + builder.Services.ConfigureOpenTelemetryMeterProvider( + metrics => metrics.AddOtlpExporter()); + builder.Services.ConfigureOpenTelemetryTracerProvider( + tracing => tracing.AddOtlpExporter()); + } + + return builder; + } +} +``` + +This is only an example, and you can customize the `AppDefaultsExtensions` class to meet your specific needs. + ## Next steps This code is derived from the .NET Aspire Starter Application template and is intended as a starting point. You're free to modify this code however you deem necessary to meet your needs. It's important to know that service defaults project and its functionality are automatically applied to all project resources in a .NET Aspire solution. diff --git a/docs/fundamentals/setup-tooling.md b/docs/fundamentals/setup-tooling.md index 8f916b10c9..ecaed0f95b 100644 --- a/docs/fundamentals/setup-tooling.md +++ b/docs/fundamentals/setup-tooling.md @@ -1,7 +1,7 @@ --- title: .NET Aspire tooling description: Learn about essential tooling concepts for .NET Aspire. -ms.date: 03/25/2024 +ms.date: 04/02/2024 --- # .NET Aspire setup and tooling @@ -134,8 +134,13 @@ There are currently four project templates available: - **.NET Aspire App Host**: A standalone **.AppHost** project that can be used to orchestrate and manage the different projects and services of your app. +- **.NET Aspire Test Project (xUnit)**: A project that contains xUnit.net integration of a .NET Aspire AppHost project. + - **.NET Aspire Service Defaults**: A standalone **.ServiceDefaults** project that can be used to manage configurations that are reused across the projects in your solution related to [resilience](/dotnet/core/resilience/http-resilience), [service discovery](../service-discovery/overview.md), and [telemetry](./telemetry.md). + > [!IMPORTANT] + > The service defaults project template takes a `FrameworkReference` dependency on `Microsoft.AspNetCore.App`. This may not be ideal for some project types. For more information, see [.NET Aspire service defaults](service-defaults.md). + Use Visual Studio or the .NET CLI to create new apps using these project templates. Explore additional .NET Aspire project templates in the [.NET Aspire samples](https://github.com/dotnet/aspire-samples) repository. # [Visual Studio](#tab/visual-studio) @@ -157,12 +162,13 @@ When the .NET Aspire workload is installed, you'll see the following .NET Aspire ```Output These templates matched your input: 'aspire' -Template Name Short Name Language Tags -------------------------------- ---------------------- -------- ------------------------------------------------------- -.NET Aspire App Host aspire-apphost [C#] Common/.NET Aspire/Cloud -.NET Aspire Application aspire [C#] Common/.NET Aspire/Cloud/Web/Web API/API/Service -.NET Aspire Service Defaults aspire-servicedefaults [C#] Common/.NET Aspire/Cloud/Web/Web API/API/Service -.NET Aspire Starter Application aspire-starter [C#] Common/.NET Aspire/Blazor/Web/Web API/API/Service/Cloud +Template Name Short Name Language Tags +-------------------------------- ---------------------- -------- ------------------------------------------------------- +.NET Aspire App Host aspire-apphost [C#] Common/.NET Aspire/Cloud +.NET Aspire Application aspire [C#] Common/.NET Aspire/Cloud/Web/Web API/API/Service +.NET Aspire Service Defaults aspire-servicedefaults [C#] Common/.NET Aspire/Cloud/Web/Web API/API/Service +.NET Aspire Starter Application aspire-starter [C#] Common/.NET Aspire/Blazor/Web/Web API/API/Service/Cloud +.NET Aspire Test Project (xUnit) aspire-xunit [C#] Common/.NET Aspire/Cloud/Web/Web API/API/Service/Test ``` To create a .NET Aspire project using the .NET CLI, use the `dotnet new` command and specify which template you would like to create. @@ -207,10 +213,22 @@ You add .NET Aspire components to your app like any other NuGet package using Vi 1. The package manager will open with search results pre-configured (populating filter criteria) for .NET Aspire components, allowing you to easily browse and select the desired component. The **Include prerelease** checkbox needs to be checked to see preview components. - :::image type="content" source="../media/visual-studio-add-aspire-comp-nuget.png" lightbox="../media/visual-studio-add-aspire-comp-nuget.png" alt-text="The Visual Studio context menu displaying the Add .NET Aspire options."::: + :::image type="content" source="../media/visual-studio-add-aspire-comp-nuget.png" lightbox="../media/visual-studio-add-aspire-comp-nuget.png" alt-text="The Visual Studio context menu displaying the Add .NET Aspire component options."::: For more information on .NET Aspire components, see [.NET Aspire components overview](components-overview.md). +### Add hosting packages + +.NET Aspire hosting packages are used to configure various resources and dependencies an app may depend on or consume. Hosting packages are differentiated from other component packages in that they are added to the **.AppHost** project. To add a hosting package to your app, follow these steps: + +1. In Visual Studio, right click on the **.AppHost** project and select **Add** > **.NET Aspire package...**. + + :::image type="content" source="../media/visual-studio-add-aspire-hosting-package.png" lightbox="../media/visual-studio-add-aspire-hosting-package.png" alt-text="The Visual Studio context menu displaying the Add .NET Aspire Hosting Resource option."::: + +1. The package manager will open with search results pre-configured (populating filter criteria) for .NET Aspire hosting packages, allowing you to easily browse and select the desired package. The **Include prerelease** checkbox needs to be checked to see preview packages. + + :::image type="content" source="../media/visual-studio-add-aspire-hosting-nuget.png" lightbox="../media/visual-studio-add-aspire-hosting-nuget.png" alt-text="The Visual Studio context menu displaying the Add .NET Aspire resource options."::: + ### Add orchestration projects You can add .NET Aspire orchestration projects to an existing app using the following steps: diff --git a/docs/fundamentals/snippets/components/AspireApp/AspireApp.AppHost/AspireApp.AppHost.csproj b/docs/fundamentals/snippets/components/AspireApp/AspireApp.AppHost/AspireApp.AppHost.csproj index c439f9d88f..1bd6a22ffe 100644 --- a/docs/fundamentals/snippets/components/AspireApp/AspireApp.AppHost/AspireApp.AppHost.csproj +++ b/docs/fundamentals/snippets/components/AspireApp/AspireApp.AppHost/AspireApp.AppHost.csproj @@ -1,4 +1,4 @@ - +ο»Ώ Exe @@ -9,7 +9,8 @@ - + + diff --git a/docs/fundamentals/snippets/components/AspireApp/AspireApp.ServiceDefaults/AspireApp.ServiceDefaults.csproj b/docs/fundamentals/snippets/components/AspireApp/AspireApp.ServiceDefaults/AspireApp.ServiceDefaults.csproj index 6eae75c1ac..09e799a0b8 100644 --- a/docs/fundamentals/snippets/components/AspireApp/AspireApp.ServiceDefaults/AspireApp.ServiceDefaults.csproj +++ b/docs/fundamentals/snippets/components/AspireApp/AspireApp.ServiceDefaults/AspireApp.ServiceDefaults.csproj @@ -11,13 +11,11 @@ - + - - diff --git a/docs/fundamentals/snippets/components/AspireApp/AspireApp.ServiceDefaults/Extensions.cs b/docs/fundamentals/snippets/components/AspireApp/AspireApp.ServiceDefaults/Extensions.cs index c6adc5cf68..090aca54f7 100644 --- a/docs/fundamentals/snippets/components/AspireApp/AspireApp.ServiceDefaults/Extensions.cs +++ b/docs/fundamentals/snippets/components/AspireApp/AspireApp.ServiceDefaults/Extensions.cs @@ -3,11 +3,13 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.ServiceDiscovery; using OpenTelemetry.Logs; using OpenTelemetry.Metrics; using OpenTelemetry.Trace; namespace Microsoft.Extensions.Hosting; + public static class Extensions { public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder) @@ -24,9 +26,15 @@ public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBu http.AddStandardResilienceHandler(); // Turn on service discovery by default - http.UseServiceDiscovery(); + http.AddServiceDiscovery(); }); + // Uncomment the following to restrict the allowed schemes for service discovery. + // builder.Services.Configure(options => + // { + // options.AllowedSchemes = ["https"]; + // }); + return builder; } @@ -42,9 +50,8 @@ public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicati .WithMetrics(metrics => { metrics.AddAspNetCoreInstrumentation() - .AddHttpClientInstrumentation() - .AddProcessInstrumentation() - .AddRuntimeInstrumentation(); + .AddHttpClientInstrumentation() + .AddRuntimeInstrumentation(); }) .WithTracing(tracing => { @@ -55,8 +62,9 @@ public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicati } tracing.AddAspNetCoreInstrumentation() - .AddGrpcClientInstrumentation() - .AddHttpClientInstrumentation(); + // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package) + //.AddGrpcClientInstrumentation() + .AddHttpClientInstrumentation(); }); builder.AddOpenTelemetryExporters(); @@ -103,15 +111,20 @@ public static WebApplication MapDefaultEndpoints(this WebApplication app) // Uncomment the following line to enable the Prometheus endpoint (requires the OpenTelemetry.Exporter.Prometheus.AspNetCore package) // app.MapPrometheusScrapingEndpoint(); - // All health checks must pass for app to be considered ready to accept traffic after starting - app.MapHealthChecks("/health"); - - // Only health checks tagged with the "live" tag must pass for app to be considered alive - app.MapHealthChecks("/alive", new HealthCheckOptions + // Adding health checks endpoints to applications in non-development environments has security implications. + // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments. + if (app.Environment.IsDevelopment()) { - Predicate = r => r.Tags.Contains("live") - }); + // All health checks must pass for app to be considered ready to accept traffic after starting + app.MapHealthChecks("/health"); + + // Only health checks tagged with the "live" tag must pass for app to be considered alive + app.MapHealthChecks("/alive", new HealthCheckOptions + { + Predicate = r => r.Tags.Contains("live") + }); + } return app; } -} +} \ No newline at end of file diff --git a/docs/fundamentals/snippets/components/AspireApp/WorkerService/WorkerService.csproj b/docs/fundamentals/snippets/components/AspireApp/WorkerService/WorkerService.csproj index 32624a41dc..1e579df9c1 100644 --- a/docs/fundamentals/snippets/components/AspireApp/WorkerService/WorkerService.csproj +++ b/docs/fundamentals/snippets/components/AspireApp/WorkerService/WorkerService.csproj @@ -8,7 +8,7 @@ - + diff --git a/docs/fundamentals/snippets/healthz/Healthz.ServiceDefaults/Extensions.cs b/docs/fundamentals/snippets/healthz/Healthz.ServiceDefaults/Extensions.cs new file mode 100644 index 0000000000..e79e751e95 --- /dev/null +++ b/docs/fundamentals/snippets/healthz/Healthz.ServiceDefaults/Extensions.cs @@ -0,0 +1,59 @@ +ο»Ώusing Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; + +namespace Microsoft.Extensions.Hosting; + +public static class Extensions +{ + public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder) + { + builder.AddDefaultHealthChecks(); + + return builder; + } + + // + public static IHostApplicationBuilder AddDefaultHealthChecks(this IHostApplicationBuilder builder) + { + builder.Services.AddRequestTimeouts( + configure: static timeouts => + timeouts.AddPolicy("HealthChecks", TimeSpan.FromSeconds(5))); + + builder.Services.AddOutputCache( + configureOptions: static caching => + caching.AddPolicy("HealthChecks", + build: static policy => policy.Expire(TimeSpan.FromSeconds(10)))); + + builder.Services.AddHealthChecks() + // Add a default liveness check to ensure app is responsive + .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]); + + return builder; + } + // + + // + public static WebApplication MapDefaultEndpoints(this WebApplication app) + { + var healthChecks = app.MapGroup(""); + + healthChecks + .CacheOutput("HealthChecks") + .WithRequestTimeout("HealthChecks"); + + // All health checks must pass for app to be + // considered ready to accept traffic after starting + healthChecks.MapHealthChecks("/health"); + + // Only health checks tagged with the "live" tag + // must pass for app to be considered alive + healthChecks.MapHealthChecks("/alive", new() + { + Predicate = static r => r.Tags.Contains("live") + }); + + return app; + } + // +} diff --git a/docs/fundamentals/snippets/healthz/Healthz.ServiceDefaults/Healthz.ServiceDefaults.csproj b/docs/fundamentals/snippets/healthz/Healthz.ServiceDefaults/Healthz.ServiceDefaults.csproj new file mode 100644 index 0000000000..055f91eff0 --- /dev/null +++ b/docs/fundamentals/snippets/healthz/Healthz.ServiceDefaults/Healthz.ServiceDefaults.csproj @@ -0,0 +1,22 @@ + + + + net8.0 + enable + enable + true + + + + + + + + + + + + + + + diff --git a/docs/fundamentals/snippets/healthz/Healthz.ServiceDefaults/healthz.sln b/docs/fundamentals/snippets/healthz/Healthz.ServiceDefaults/healthz.sln new file mode 100644 index 0000000000..118f200ed9 --- /dev/null +++ b/docs/fundamentals/snippets/healthz/Healthz.ServiceDefaults/healthz.sln @@ -0,0 +1,25 @@ +ο»Ώ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.10.34727.303 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Healthz.ServiceDefaults", "Healthz.ServiceDefaults.csproj", "{489CF15E-6758-4CD5-80B7-DD698ED2D964}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {489CF15E-6758-4CD5-80B7-DD698ED2D964}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {489CF15E-6758-4CD5-80B7-DD698ED2D964}.Debug|Any CPU.Build.0 = Debug|Any CPU + {489CF15E-6758-4CD5-80B7-DD698ED2D964}.Release|Any CPU.ActiveCfg = Release|Any CPU + {489CF15E-6758-4CD5-80B7-DD698ED2D964}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B445EE8B-3BD1-4F13-A5BB-DE20505966D9} + EndGlobalSection +EndGlobal diff --git a/docs/fundamentals/snippets/networking/Networking.AppHost/Networking.AppHost.csproj b/docs/fundamentals/snippets/networking/Networking.AppHost/Networking.AppHost.csproj index 8aace9bed4..5b58b68cd2 100644 --- a/docs/fundamentals/snippets/networking/Networking.AppHost/Networking.AppHost.csproj +++ b/docs/fundamentals/snippets/networking/Networking.AppHost/Networking.AppHost.csproj @@ -9,7 +9,8 @@ - + + diff --git a/docs/fundamentals/snippets/networking/Networking.AppHost/Program.ContainerPort.cs b/docs/fundamentals/snippets/networking/Networking.AppHost/Program.ContainerPort.cs index 73446395df..b5958eb719 100644 --- a/docs/fundamentals/snippets/networking/Networking.AppHost/Program.ContainerPort.cs +++ b/docs/fundamentals/snippets/networking/Networking.AppHost/Program.ContainerPort.cs @@ -4,7 +4,7 @@ public static void ContainerPort(IDistributedApplicationBuilder builder) { // builder.AddContainer("frontend", "mcr.microsoft.com/dotnet/samples", "aspnetapp") - .WithHttpEndpoint(hostPort: 8000, containerPort: 8080); + .WithHttpEndpoint(port: 8000, targetPort: 8080); // } } diff --git a/docs/fundamentals/snippets/networking/Networking.AppHost/Program.EnvVarPort.cs b/docs/fundamentals/snippets/networking/Networking.AppHost/Program.EnvVarPort.cs index fdb49061b9..677a2887b1 100644 --- a/docs/fundamentals/snippets/networking/Networking.AppHost/Program.EnvVarPort.cs +++ b/docs/fundamentals/snippets/networking/Networking.AppHost/Program.EnvVarPort.cs @@ -4,7 +4,7 @@ public static void EnvVarPort(IDistributedApplicationBuilder builder) { // builder.AddNpmApp("frontend", "../NodeFrontend", "watch") - .WithHttpEndpoint(hostPort: 5067, env: "PORT"); + .WithHttpEndpoint(port: 5067, env: "PORT"); // } } diff --git a/docs/fundamentals/snippets/networking/Networking.AppHost/Program.HostPortAndRandomPort.cs b/docs/fundamentals/snippets/networking/Networking.AppHost/Program.HostPortAndRandomPort.cs index d6b17a1ab2..247ff49b9f 100644 --- a/docs/fundamentals/snippets/networking/Networking.AppHost/Program.HostPortAndRandomPort.cs +++ b/docs/fundamentals/snippets/networking/Networking.AppHost/Program.HostPortAndRandomPort.cs @@ -4,7 +4,7 @@ public static void HostPortWithRandomServicePort(IDistributedApplicationBuilder { // builder.AddProject("frontend") - .WithHttpEndpoint(hostPort: 5066); + .WithHttpEndpoint(port: 5066); // } } diff --git a/docs/fundamentals/snippets/networking/Networking.AppHost/Program.WithLaunchProfile.cs b/docs/fundamentals/snippets/networking/Networking.AppHost/Program.WithLaunchProfile.cs index e80447a704..108cee9906 100644 --- a/docs/fundamentals/snippets/networking/Networking.AppHost/Program.WithLaunchProfile.cs +++ b/docs/fundamentals/snippets/networking/Networking.AppHost/Program.WithLaunchProfile.cs @@ -2,15 +2,10 @@ { public static void WithLaunchProfile(IDistributedApplicationBuilder builder) { - // - builder.AddProject("frontend") - .WithLaunchProfile("https"); - // - // builder.AddProject("frontend") - .WithHttpEndpoint(hostPort: 5066) - .WithHttpsEndpoint(hostPort: 7239); + .WithHttpEndpoint(port: 5066) + .WithHttpsEndpoint(port: 7239); // } } diff --git a/docs/fundamentals/snippets/networking/Networking.AppHost/Program.WithReplicas.cs b/docs/fundamentals/snippets/networking/Networking.AppHost/Program.WithReplicas.cs index 9acbcc169b..a47f3eacbf 100644 --- a/docs/fundamentals/snippets/networking/Networking.AppHost/Program.WithReplicas.cs +++ b/docs/fundamentals/snippets/networking/Networking.AppHost/Program.WithReplicas.cs @@ -4,7 +4,7 @@ public static void WithReplicas(IDistributedApplicationBuilder builder) { // builder.AddProject("frontend") - .WithHttpEndpoint(hostPort: 5066) + .WithHttpEndpoint(port: 5066) .WithReplicas(2); // } diff --git a/docs/fundamentals/snippets/networking/Networking.ServiceDefaults/Extensions.cs b/docs/fundamentals/snippets/networking/Networking.ServiceDefaults/Extensions.cs index c6adc5cf68..090aca54f7 100644 --- a/docs/fundamentals/snippets/networking/Networking.ServiceDefaults/Extensions.cs +++ b/docs/fundamentals/snippets/networking/Networking.ServiceDefaults/Extensions.cs @@ -3,11 +3,13 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.ServiceDiscovery; using OpenTelemetry.Logs; using OpenTelemetry.Metrics; using OpenTelemetry.Trace; namespace Microsoft.Extensions.Hosting; + public static class Extensions { public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder) @@ -24,9 +26,15 @@ public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBu http.AddStandardResilienceHandler(); // Turn on service discovery by default - http.UseServiceDiscovery(); + http.AddServiceDiscovery(); }); + // Uncomment the following to restrict the allowed schemes for service discovery. + // builder.Services.Configure(options => + // { + // options.AllowedSchemes = ["https"]; + // }); + return builder; } @@ -42,9 +50,8 @@ public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicati .WithMetrics(metrics => { metrics.AddAspNetCoreInstrumentation() - .AddHttpClientInstrumentation() - .AddProcessInstrumentation() - .AddRuntimeInstrumentation(); + .AddHttpClientInstrumentation() + .AddRuntimeInstrumentation(); }) .WithTracing(tracing => { @@ -55,8 +62,9 @@ public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicati } tracing.AddAspNetCoreInstrumentation() - .AddGrpcClientInstrumentation() - .AddHttpClientInstrumentation(); + // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package) + //.AddGrpcClientInstrumentation() + .AddHttpClientInstrumentation(); }); builder.AddOpenTelemetryExporters(); @@ -103,15 +111,20 @@ public static WebApplication MapDefaultEndpoints(this WebApplication app) // Uncomment the following line to enable the Prometheus endpoint (requires the OpenTelemetry.Exporter.Prometheus.AspNetCore package) // app.MapPrometheusScrapingEndpoint(); - // All health checks must pass for app to be considered ready to accept traffic after starting - app.MapHealthChecks("/health"); - - // Only health checks tagged with the "live" tag must pass for app to be considered alive - app.MapHealthChecks("/alive", new HealthCheckOptions + // Adding health checks endpoints to applications in non-development environments has security implications. + // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments. + if (app.Environment.IsDevelopment()) { - Predicate = r => r.Tags.Contains("live") - }); + // All health checks must pass for app to be considered ready to accept traffic after starting + app.MapHealthChecks("/health"); + + // Only health checks tagged with the "live" tag must pass for app to be considered alive + app.MapHealthChecks("/alive", new HealthCheckOptions + { + Predicate = r => r.Tags.Contains("live") + }); + } return app; } -} +} \ No newline at end of file diff --git a/docs/fundamentals/snippets/networking/Networking.ServiceDefaults/Networking.ServiceDefaults.csproj b/docs/fundamentals/snippets/networking/Networking.ServiceDefaults/Networking.ServiceDefaults.csproj index 6eae75c1ac..09e799a0b8 100644 --- a/docs/fundamentals/snippets/networking/Networking.ServiceDefaults/Networking.ServiceDefaults.csproj +++ b/docs/fundamentals/snippets/networking/Networking.ServiceDefaults/Networking.ServiceDefaults.csproj @@ -11,13 +11,11 @@ - + - - diff --git a/docs/fundamentals/snippets/params/Parameters.ApiService/Parameters.ApiService.csproj b/docs/fundamentals/snippets/params/Parameters.ApiService/Parameters.ApiService.csproj index 9a553e93b0..39837a4ff9 100644 --- a/docs/fundamentals/snippets/params/Parameters.ApiService/Parameters.ApiService.csproj +++ b/docs/fundamentals/snippets/params/Parameters.ApiService/Parameters.ApiService.csproj @@ -7,7 +7,7 @@ - + diff --git a/docs/fundamentals/snippets/params/Parameters.AppHost/Parameters.AppHost.csproj b/docs/fundamentals/snippets/params/Parameters.AppHost/Parameters.AppHost.csproj index 87aa8ba5bc..5cc9d85b6f 100644 --- a/docs/fundamentals/snippets/params/Parameters.AppHost/Parameters.AppHost.csproj +++ b/docs/fundamentals/snippets/params/Parameters.AppHost/Parameters.AppHost.csproj @@ -9,7 +9,8 @@ - + + diff --git a/docs/fundamentals/snippets/params/Parameters.ServiceDefaults/Extensions.cs b/docs/fundamentals/snippets/params/Parameters.ServiceDefaults/Extensions.cs index 01ffab806b..090aca54f7 100644 --- a/docs/fundamentals/snippets/params/Parameters.ServiceDefaults/Extensions.cs +++ b/docs/fundamentals/snippets/params/Parameters.ServiceDefaults/Extensions.cs @@ -3,11 +3,13 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.ServiceDiscovery; using OpenTelemetry.Logs; using OpenTelemetry.Metrics; using OpenTelemetry.Trace; namespace Microsoft.Extensions.Hosting; + public static class Extensions { public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder) @@ -24,9 +26,15 @@ public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBu http.AddStandardResilienceHandler(); // Turn on service discovery by default - http.UseServiceDiscovery(); + http.AddServiceDiscovery(); }); + // Uncomment the following to restrict the allowed schemes for service discovery. + // builder.Services.Configure(options => + // { + // options.AllowedSchemes = ["https"]; + // }); + return builder; } @@ -41,8 +49,9 @@ public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicati builder.Services.AddOpenTelemetry() .WithMetrics(metrics => { - metrics.AddRuntimeInstrumentation() - .AddBuiltInMeters(); + metrics.AddAspNetCoreInstrumentation() + .AddHttpClientInstrumentation() + .AddRuntimeInstrumentation(); }) .WithTracing(tracing => { @@ -53,8 +62,9 @@ public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicati } tracing.AddAspNetCoreInstrumentation() - .AddGrpcClientInstrumentation() - .AddHttpClientInstrumentation(); + // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package) + //.AddGrpcClientInstrumentation() + .AddHttpClientInstrumentation(); }); builder.AddOpenTelemetryExporters(); @@ -78,8 +88,11 @@ private static IHostApplicationBuilder AddOpenTelemetryExporters(this IHostAppli // .WithMetrics(metrics => metrics.AddPrometheusExporter()); // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package) - // builder.Services.AddOpenTelemetry() - // .UseAzureMonitor(); + //if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"])) + //{ + // builder.Services.AddOpenTelemetry() + // .UseAzureMonitor(); + //} return builder; } @@ -98,21 +111,20 @@ public static WebApplication MapDefaultEndpoints(this WebApplication app) // Uncomment the following line to enable the Prometheus endpoint (requires the OpenTelemetry.Exporter.Prometheus.AspNetCore package) // app.MapPrometheusScrapingEndpoint(); - // All health checks must pass for app to be considered ready to accept traffic after starting - app.MapHealthChecks("/health"); - - // Only health checks tagged with the "live" tag must pass for app to be considered alive - app.MapHealthChecks("/alive", new HealthCheckOptions + // Adding health checks endpoints to applications in non-development environments has security implications. + // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments. + if (app.Environment.IsDevelopment()) { - Predicate = r => r.Tags.Contains("live") - }); + // All health checks must pass for app to be considered ready to accept traffic after starting + app.MapHealthChecks("/health"); + + // Only health checks tagged with the "live" tag must pass for app to be considered alive + app.MapHealthChecks("/alive", new HealthCheckOptions + { + Predicate = r => r.Tags.Contains("live") + }); + } return app; } - - private static MeterProviderBuilder AddBuiltInMeters(this MeterProviderBuilder meterProviderBuilder) => - meterProviderBuilder.AddMeter( - "Microsoft.AspNetCore.Hosting", - "Microsoft.AspNetCore.Server.Kestrel", - "System.Net.Http"); -} +} \ No newline at end of file diff --git a/docs/fundamentals/snippets/params/Parameters.ServiceDefaults/Parameters.ServiceDefaults.csproj b/docs/fundamentals/snippets/params/Parameters.ServiceDefaults/Parameters.ServiceDefaults.csproj index 0a3d399462..84a4cf6467 100644 --- a/docs/fundamentals/snippets/params/Parameters.ServiceDefaults/Parameters.ServiceDefaults.csproj +++ b/docs/fundamentals/snippets/params/Parameters.ServiceDefaults/Parameters.ServiceDefaults.csproj @@ -12,11 +12,10 @@ - + - diff --git a/docs/fundamentals/snippets/template/YourAppName/Extensions.cs b/docs/fundamentals/snippets/template/YourAppName/Extensions.cs index 3aa622ec29..97e3cc6b28 100644 --- a/docs/fundamentals/snippets/template/YourAppName/Extensions.cs +++ b/docs/fundamentals/snippets/template/YourAppName/Extensions.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.ServiceDiscovery; using OpenTelemetry.Logs; using OpenTelemetry.Metrics; using OpenTelemetry.Trace; @@ -27,9 +28,15 @@ public static IHostApplicationBuilder AddServiceDefaults( http.AddStandardResilienceHandler(); // Turn on service discovery by default - http.UseServiceDiscovery(); + http.AddServiceDiscovery(); }); + // Uncomment the following to restrict the allowed schemes for service discovery. + // builder.Services.Configure(options => + // { + // options.AllowedSchemes = ["https"]; + // }); + return builder; } // @@ -47,8 +54,9 @@ public static IHostApplicationBuilder ConfigureOpenTelemetry( builder.Services.AddOpenTelemetry() .WithMetrics(metrics => { - metrics.AddRuntimeInstrumentation() - .AddBuiltInMeters(); + metrics.AddAspNetCoreInstrumentation() + .AddHttpClientInstrumentation() + .AddRuntimeInstrumentation(); }) .WithTracing(tracing => { @@ -59,8 +67,10 @@ public static IHostApplicationBuilder ConfigureOpenTelemetry( } tracing.AddAspNetCoreInstrumentation() - .AddGrpcClientInstrumentation() - .AddHttpClientInstrumentation(); + // Uncomment the following line to enable gRPC instrumentation + // (requires the OpenTelemetry.Instrumentation.GrpcNetClient package) + //.AddGrpcClientInstrumentation() + .AddHttpClientInstrumentation(); }); builder.AddOpenTelemetryExporters(); @@ -86,15 +96,19 @@ private static IHostApplicationBuilder AddOpenTelemetryExporters( tracing => tracing.AddOtlpExporter()); } - // Uncomment the following lines to enable the Prometheus exporter + // Uncomment the following lines to enable the Prometheus exporter // (requires the OpenTelemetry.Exporter.Prometheus.AspNetCore package) // builder.Services.AddOpenTelemetry() // .WithMetrics(metrics => metrics.AddPrometheusExporter()); // Uncomment the following lines to enable the Azure Monitor exporter - // (requires the Azure.Monitor.OpenTelemetry.Exporter package) - // builder.Services.AddOpenTelemetry() - // .UseAzureMonitor(); + // (requires the Azure.Monitor.OpenTelemetry.AspNetCore package) + //if (!string.IsNullOrEmpty( + // builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"])) + //{ + // builder.Services.AddOpenTelemetry() + // .UseAzureMonitor(); + //} return builder; } @@ -119,27 +133,25 @@ public static WebApplication MapDefaultEndpoints(this WebApplication app) // (requires the OpenTelemetry.Exporter.Prometheus.AspNetCore package) // app.MapPrometheusScrapingEndpoint(); - // All health checks must pass for app to be considered ready to - // accept traffic after starting - app.MapHealthChecks("/health"); - - // Only health checks tagged with the "live" tag must pass for app - // to be considered alive - app.MapHealthChecks("/alive", new HealthCheckOptions + // Adding health checks endpoints to applications in non-development + // environments has security implications. + // See https://aka.ms/dotnet/aspire/healthchecks for details before + // enabling these endpoints in non-development environments. + if (app.Environment.IsDevelopment()) { - Predicate = r => r.Tags.Contains("live") - }); + // All health checks must pass for app to be considered ready to + // accept traffic after starting + app.MapHealthChecks("/health"); + + // Only health checks tagged with the "live" tag must pass for + // app to be considered alive + app.MapHealthChecks("/alive", new HealthCheckOptions + { + Predicate = r => r.Tags.Contains("live") + }); + } return app; } // - - // - private static MeterProviderBuilder AddBuiltInMeters( - this MeterProviderBuilder meterProviderBuilder) => - meterProviderBuilder.AddMeter( - "Microsoft.AspNetCore.Hosting", - "Microsoft.AspNetCore.Server.Kestrel", - "System.Net.Http"); - // } \ No newline at end of file diff --git a/docs/fundamentals/snippets/template/YourAppName/YourAppName.ServiceDefaults.csproj b/docs/fundamentals/snippets/template/YourAppName/YourAppName.ServiceDefaults.csproj index 6eae75c1ac..09e799a0b8 100644 --- a/docs/fundamentals/snippets/template/YourAppName/YourAppName.ServiceDefaults.csproj +++ b/docs/fundamentals/snippets/template/YourAppName/YourAppName.ServiceDefaults.csproj @@ -11,13 +11,11 @@ - + - - diff --git a/docs/get-started/snippets/quickstart/AspireSample/AspireSample.AppHost/AspireSample.AppHost.csproj b/docs/get-started/snippets/quickstart/AspireSample/AspireSample.AppHost/AspireSample.AppHost.csproj index 6328979883..c303472666 100644 --- a/docs/get-started/snippets/quickstart/AspireSample/AspireSample.AppHost/AspireSample.AppHost.csproj +++ b/docs/get-started/snippets/quickstart/AspireSample/AspireSample.AppHost/AspireSample.AppHost.csproj @@ -1,4 +1,4 @@ - +ο»Ώ Exe @@ -14,7 +14,8 @@ - + + diff --git a/docs/get-started/snippets/quickstart/AspireSample/AspireSample.ServiceDefaults/AspireSample.ServiceDefaults.csproj b/docs/get-started/snippets/quickstart/AspireSample/AspireSample.ServiceDefaults/AspireSample.ServiceDefaults.csproj index 6006dee048..548cb661df 100644 --- a/docs/get-started/snippets/quickstart/AspireSample/AspireSample.ServiceDefaults/AspireSample.ServiceDefaults.csproj +++ b/docs/get-started/snippets/quickstart/AspireSample/AspireSample.ServiceDefaults/AspireSample.ServiceDefaults.csproj @@ -11,13 +11,11 @@ - + - - diff --git a/docs/get-started/snippets/quickstart/AspireSample/AspireSample.ServiceDefaults/Extensions.cs b/docs/get-started/snippets/quickstart/AspireSample/AspireSample.ServiceDefaults/Extensions.cs index c6adc5cf68..f00dc4ecea 100644 --- a/docs/get-started/snippets/quickstart/AspireSample/AspireSample.ServiceDefaults/Extensions.cs +++ b/docs/get-started/snippets/quickstart/AspireSample/AspireSample.ServiceDefaults/Extensions.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Builder; +ο»Ώusing Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; @@ -8,6 +8,7 @@ using OpenTelemetry.Trace; namespace Microsoft.Extensions.Hosting; + public static class Extensions { public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder) @@ -24,9 +25,15 @@ public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBu http.AddStandardResilienceHandler(); // Turn on service discovery by default - http.UseServiceDiscovery(); + http.AddServiceDiscovery(); }); + // Uncomment the following to restrict the allowed schemes for service discovery. + // builder.Services.Configure(options => + // { + // options.AllowedSchemes = ["https"]; + // }); + return builder; } @@ -42,9 +49,8 @@ public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicati .WithMetrics(metrics => { metrics.AddAspNetCoreInstrumentation() - .AddHttpClientInstrumentation() - .AddProcessInstrumentation() - .AddRuntimeInstrumentation(); + .AddHttpClientInstrumentation() + .AddRuntimeInstrumentation(); }) .WithTracing(tracing => { @@ -55,8 +61,9 @@ public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicati } tracing.AddAspNetCoreInstrumentation() - .AddGrpcClientInstrumentation() - .AddHttpClientInstrumentation(); + // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package) + //.AddGrpcClientInstrumentation() + .AddHttpClientInstrumentation(); }); builder.AddOpenTelemetryExporters(); @@ -103,14 +110,19 @@ public static WebApplication MapDefaultEndpoints(this WebApplication app) // Uncomment the following line to enable the Prometheus endpoint (requires the OpenTelemetry.Exporter.Prometheus.AspNetCore package) // app.MapPrometheusScrapingEndpoint(); - // All health checks must pass for app to be considered ready to accept traffic after starting - app.MapHealthChecks("/health"); - - // Only health checks tagged with the "live" tag must pass for app to be considered alive - app.MapHealthChecks("/alive", new HealthCheckOptions + // Adding health checks endpoints to applications in non-development environments has security implications. + // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments. + if (app.Environment.IsDevelopment()) { - Predicate = r => r.Tags.Contains("live") - }); + // All health checks must pass for app to be considered ready to accept traffic after starting + app.MapHealthChecks("/health"); + + // Only health checks tagged with the "live" tag must pass for app to be considered alive + app.MapHealthChecks("/alive", new HealthCheckOptions + { + Predicate = r => r.Tags.Contains("live") + }); + } return app; } diff --git a/docs/get-started/snippets/quickstart/AspireSample/AspireSample.Web/AspireSample.Web.csproj b/docs/get-started/snippets/quickstart/AspireSample/AspireSample.Web/AspireSample.Web.csproj index 4cb3d34164..1509de9746 100644 --- a/docs/get-started/snippets/quickstart/AspireSample/AspireSample.Web/AspireSample.Web.csproj +++ b/docs/get-started/snippets/quickstart/AspireSample/AspireSample.Web/AspireSample.Web.csproj @@ -12,7 +12,7 @@ - + diff --git a/docs/includes/azure-component-nuget.md b/docs/includes/azure-component-nuget.md deleted file mode 100644 index 389725cffc..0000000000 --- a/docs/includes/azure-component-nuget.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -ms.date: 01/22/2024 -ms.topic: include ---- - -The .NET Aspire Azure hosting APIs are available in the `Aspire.Hosting.Azure` NuGet package. These APIs provide Azure-specific resources used within the App Host. To add Azure resources to your , install the [Aspire.Hosting.Azure](https://www.nuget.org/packages/Aspire.Hosting.Azure) NuGet package. - -### [.NET CLI](#tab/dotnet-cli) - -```dotnetcli -dotnet add package Aspire.Hosting.Azure --prerelease -``` - -### [PackageReference](#tab/package-reference) - -```xml - -``` - ---- diff --git a/docs/index.yml b/docs/index.yml index 728cae4f42..5994810e09 100644 --- a/docs/index.yml +++ b/docs/index.yml @@ -9,7 +9,7 @@ metadata: description: Samples, tutorials, and education for .NET Aspire, your cloud-native app stack build around components that provide production-ready telemetry, health checks, configurability, and testability. ms.topic: hub-page ms.service: dotnet-aspire - ms.date: 02/13/2024 + ms.date: 03/28/2024 highlightedContent: items: @@ -118,12 +118,21 @@ conceptualContent: - itemType: tutorial text: Implement Messaging with .NET Aspire url: messaging/messaging-components.md + - itemType: overview + text: Azure Event Hubs + url: messaging/azure-event-hubs-component.md - itemType: overview text: Azure Service Bus url: messaging/azure-service-bus-component.md - itemType: how-to-guide text: RabbitMQ client .NET Aspire component url: messaging/rabbitmq-client-component.md + - itemType: how-to-guide + text: Apache Kafka + url: messaging/kafka-component.md + - itemType: how-to-guide + text: NATs + url: messaging/nats-component.md - title: Caching links: diff --git a/docs/logging/seq-component.md b/docs/logging/seq-component.md new file mode 100644 index 0000000000..4a8c716062 --- /dev/null +++ b/docs/logging/seq-component.md @@ -0,0 +1,128 @@ +--- +title: .NET Aspire Seq component +description: Learn how to use the .NET Aspire Seq component to add OpenTelemetry Protocol (OTLP) exporters that send logs and traces to a Seq Server. +ms.topic: how-to +ms.date: 04/09/2024 +--- + +# .NET Aspire Seq component + +In this article, you learn how to use the .NET Aspire Seq component to add OpenTelemetry Protocol (OTLP) exporters that send logs and traces to a Seq Server. The component supports persistent logs and traces across application restarts via configuration. + +## Get started + +To get started with the .NET Aspire Seq component, install the [Aspire.Seq](https://www.nuget.org/packages/Aspire.Seq) NuGet package. + +### [.NET CLI](#tab/dotnet-cli) + +```dotnetcli +dotnet add package Aspire.Seq --prerelease +``` + +### [PackageReference](#tab/package-reference) + +```xml + +``` + +--- + +For more information, see [dotnet add package](/dotnet/core/tools/dotnet-add-package) or [Manage package dependencies in .NET applications](/dotnet/core/tools/dependencies). + +## Example usage + + + +In the _Program.cs_ file of your projects, call the `AddSeqEndpoint` extension method to register OpenTelemetry Protocol exporters to send logs and traces to Seq and the .NET Aspire Dashboard. The method takes a connection name parameter. + +```csharp +builder.AddSeqEndpoint("seq"); +``` + +## Configuration + +The .NET Aspire Seq component provides options to configure the connection to Seq. + +### Use configuration providers + +The .NET Aspire Seq component supports . It loads the `SeqSettings` from configuration by using the `Aspire:Seq` key. Example `appsettings.json` that configures some of the options: + +```json +{ + "Aspire": { + "Seq": { + "HealthChecks": false, + "ServerUrl": "http://localhost:5341" + } + } +} +``` + +### Use inline delegates + +You can pass the `Action configureSettings` delegate to set up some or all the options inline, for example to disable health checks from code: + +```csharp +builder.AddSeqEndpoint("seq", static settings => +{ + settings.HealthChecks = false; + settings.ServerUrl = "http://localhost:5341" +}); +``` + +## AppHost extensions + +In your AppHost project, install the `Aspire.Hosting.Seq` library with [NuGet](https://www.nuget.org): + +```dotnetcli +dotnet add package Aspire.Hosting.Seq +``` + +Then, in the _Program.cs_ file of the **.AppHost** project, register a Seq server and propagate its configuration using the following methods (note that you must accept the [Seq End User Licence Agreement](https://datalust.co/doc/eula-current.pdf) for Seq to start): + +```csharp +var seq = builder.AddSeq("seq"); + +var myService = builder.AddProject() + .WithReference(seq); +``` + +In the _Program.cs_ file of the **MyService** project, configure logging and tracing to Seq using the following code: + +```csharp +builder.AddSeqEndpoint("seq"); +``` + +### Persistent logs and traces + +Register Seq with a data directory in your AppHost project to retain Seq's data and configuration across application restarts. + +```csharp +var seq = builder.AddSeq("seq", seqDataDirectory: "./seqdata"); +``` + +The directory specified must already exist. + +### Seq in the .NET Aspire manifest + +Seq isn't part of the .NET Aspire deployment manifest. It's recommended you set up a secure production Seq server outside of .NET Aspire. + +[!INCLUDE [component-health-checks](../includes/component-health-checks.md)] + +The .NET Aspire Seq component handles the following: + +- Integrates with the `/health` HTTP endpoint, which specifies all registered health checks must pass for app to be considered ready to accept traffic. + +[!INCLUDE [component-observability-and-telemetry](../includes/component-observability-and-telemetry.md)] + +### Logging + +The .NET Aspire Seq component uses the following log categories: + +- `Seq` + +## See also + +- [.NET Aspire Seq README](https://github.com/dotnet/aspire/tree/main/src/Components/README.md) +- [SEQ Query Language](https://docs.datalust.co/docs/the-seq-query-language) diff --git a/docs/media/aspire-templates.png b/docs/media/aspire-templates.png index 8ef9f79464..5c6eebbf78 100644 Binary files a/docs/media/aspire-templates.png and b/docs/media/aspire-templates.png differ diff --git a/docs/media/visual-studio-add-aspire-comp-nuget.png b/docs/media/visual-studio-add-aspire-comp-nuget.png index 6b3d65405f..0972f4a9b3 100644 Binary files a/docs/media/visual-studio-add-aspire-comp-nuget.png and b/docs/media/visual-studio-add-aspire-comp-nuget.png differ diff --git a/docs/media/visual-studio-add-aspire-component.png b/docs/media/visual-studio-add-aspire-component.png index 89dbab7c88..bc183bfd98 100644 Binary files a/docs/media/visual-studio-add-aspire-component.png and b/docs/media/visual-studio-add-aspire-component.png differ diff --git a/docs/media/visual-studio-add-aspire-hosting-nuget.png b/docs/media/visual-studio-add-aspire-hosting-nuget.png new file mode 100644 index 0000000000..c41fb56f73 Binary files /dev/null and b/docs/media/visual-studio-add-aspire-hosting-nuget.png differ diff --git a/docs/media/visual-studio-add-aspire-hosting-package.png b/docs/media/visual-studio-add-aspire-hosting-package.png new file mode 100644 index 0000000000..e342a90943 Binary files /dev/null and b/docs/media/visual-studio-add-aspire-hosting-package.png differ diff --git a/docs/media/visual-studio-add-aspire-orchestrator.png b/docs/media/visual-studio-add-aspire-orchestrator.png index 2c907cb828..64d67a5044 100644 Binary files a/docs/media/visual-studio-add-aspire-orchestrator.png and b/docs/media/visual-studio-add-aspire-orchestrator.png differ diff --git a/docs/messaging/azure-event-hubs-component.md b/docs/messaging/azure-event-hubs-component.md new file mode 100644 index 0000000000..47f34bccfe --- /dev/null +++ b/docs/messaging/azure-event-hubs-component.md @@ -0,0 +1,213 @@ +--- +title: .NET Aspire Azure Event Hubs component +description: This article describes the .NET Aspire Azure Event Hubs component features and capabilities. +ms.topic: how-to +ms.date: 04/09/2024 +--- + +# .NET Aspire Azure Event Hubs component + +In this article, you learn how to use the .NET Aspire Azure Event Hubs component. The `Aspire.Azure.Messaging.EventHubs` library offers options for registering an , an , an or a in the DI container for connecting to [Azure Event Hubs](/azure/event-hubs). + +## Prerequisites + +- Azure subscription: [create one for free](https://azure.microsoft.com/free/). +- Azure Event Hubs namespace: for more information, see [add an Event Hubs namespace](/azure/event-hubs/event-hubs-create). Alternatively, you can use a connection string, which isn't recommended in production environments. + +## Get started + +To get started with the .NET Aspire Azure Event Hubs component, install the [Aspire.Azure.Messaging.EventHubs](https://www.nuget.org/packages/Aspire.Azure.Messaging.EventHubs) NuGet package. + +### [.NET CLI](#tab/dotnet-cli) + +```dotnetcli +dotnet add package Aspire.Azure.Messaging.EventHubs --prerelease +``` + +### [PackageReference](#tab/package-reference) + +```xml + +``` + +--- + +For more information, see [dotnet add package](/dotnet/core/tools/dotnet-add-package) or [Manage package dependencies in .NET applications](/dotnet/core/tools/dependencies). + +## Supported clients with options classes + +The following clients are supported by the library, along with their corresponding options and settings classes: + +| Client type | Options class | Settings class | +|--------------------------|---------------------------------|----------------------------------------------------| +| `EventHubProducerClient` | `EventHubProducerClientOptions` | `AzureMessagingEventHubsProducerSettings` | +| `EventHubConsumerClient` | `EventHubConsumerClientOptions` | `AzureMessagingEventHubsConsumerSettings` | +| `EventProcessorClient` | `EventProcessorClientOptions` | `AzureMessagingEventHubsProcessorSettings` | +| `PartitionReceiver` | `PartitionReceiverOptions` | `AzureMessagingEventHubsPartitionReceiverSettings` | + +## Example usage + +The following example assumes that you have an Azure Event Hubs namespace and an Event Hub created and wish to configure an `EventHubProducerClient` to send events to the Event Hub. The `EventHubConsumerClient`, `EventProcessorClient`, and `PartitionReceiver`are configured in a similar manner. + +In the _Program.cs_ file of your component-consuming project, call the `AddAzureEventHubProducerClient` extension to register a `EventHubProducerClient` for use via the dependency injection container. + +```csharp +builder.AddAzureEventHubProducerClient("eventHubsConnectionName"); +``` + +You can then retrieve the `EventHubProducerClient` instance using dependency injection. For example, to retrieve the client from a service: + +```csharp +public class ExampleService(EventHubProducerClient client) +{ + // Use client... +} +``` + +For more information, see the [Azure.Messaging.EventHubs documentation](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/eventhub/Azure.Messaging.EventHubs/README.md) for examples on using the `EventHubProducerClient`. + +## App host usage + +To add Azure Event Hub hosting support to your , install the [Aspire.Hosting.Azure.EventHubs](https://www.nuget.org/packages/Aspire.Hosting.Azure.EventHubs) NuGet package. + +### [.NET CLI](#tab/dotnet-cli) + +```dotnetcli +dotnet add package Aspire.Hosting.Azure.EventHubs --prerelease +``` + +### [PackageReference](#tab/package-reference) + +```xml + +``` + +--- + +In your app host project, add an Event Hubs connection and an Event Hub resource and consume the connection using the following methods: + +```csharp +var eventHubs = builder.AddAzureEventHubs("eventHubsConnectionName") + .AddEventHub("MyHub");; + +var ExampleService = builder.AddProject() + .WithReference(eventHubs); +``` + +The `AddAzureEventHubs` method will read connection information from the AppHost's configuration (for example, from "user secrets") under the `ConnectionStrings:eventHubsConnectionName` config key. The `WithReference` method passes that connection information into a connection string named `eventHubsConnectionName` in the `ExampleService` project. + +> [!IMPORTANT] +> Even though we are creating an Event Hub using the `AddEventHub` at the same time as the namespace, as of .NET Aspire version `preview-5`, the connection string will not include the `EntityPath` property, so the `EventHubName` property must be set in the settings callback for the preferred client. Future versions of Aspire will include the `EntityPath` property in the connection string and will not require the `EventHubName` property to be set in this scenario. + +In the _Program.cs_ file of `ExampleService`, the connection can be consumed using by calling of the supported Event Hubs client extension methods: + +```csharp +builder.AddAzureEventProcessorClient( + "eventHubsConnectionName", + static settings => + { + settings.EventHubName = "MyHub"; + }); +``` + +## Configuration + +The .NET Aspire Azure Event Hubs library provides multiple options to configure the Azure Event Hubs connection based on the requirements and conventions of your project. Either a `Namespace` or a `ConnectionString` is a required to be supplied. + +### Use a connection string + +When using a connection string from the `ConnectionStrings` configuration section, provide the name of the connection string when calling `builder.AddAzureEventHubProducerClient()` and other supported Event Hubs clients. In this example, the connection string does not include the `EntityPath` property, so the `EventHubName` property must be set in the settings callback: + +```csharp +builder.AddAzureEventHubProducerClient( + "eventHubsConnectionName", + static settings => + { + settings.EventHubName = "MyHub"; + }); +``` + +And then the connection information will be retrieved from the `ConnectionStrings` configuration section. Two connection formats are supported: + +#### Fully Qualified Namespace (FQN) + +The recommended approach is to use a fully qualified namespace, which works with the `AzureMessagingEventHubsSettings.Credential` property to establish a connection. If no credential is configured, the is used. + +```json +{ + "ConnectionStrings": { + "eventHubsConnectionName": "{your_namespace}.servicebus.windows.net" + } +} +``` + +#### Connection string + +Alternatively, use a connection string: + +```json +{ + "ConnectionStrings": { + "eventHubsConnectionName": "Endpoint=sb://mynamespace.servicebus.windows.net/;SharedAccessKeyName=accesskeyname;SharedAccessKey=accesskey;EntityPath=MyHub" + } +} +``` + +### Use configuration providers + +The .NET Aspire Azure Event Hubs library supports . It loads the `AzureMessagingEventHubsSettings` and the associated Options, e.g. `EventProcessorClientOptions`, from configuration by using the `Aspire:Azure:Messaging:EventHubs:` key prefix, followed by the name of the specific client in use. For example, consider the `appsettings.json` that configures some of the options for an `EventProcessorClient`: + +```json +{ + "Aspire": { + "Azure": { + "Messaging": { + "EventHubs": { + "EventProcessorClient": { + "EventHubName": "MyHub", + "ClientOptions": { + "Identifier": "PROCESSOR_ID" + } + } + } + } + } + } +} +``` + +You can also setup the Options type using the optional `Action> configureClientBuilder` parameter of the `AddAzureEventProcessorClient` method. For example, to set the processor's client ID for this client: + +```csharp +builder.AddAzureEventProcessorClient( + "eventHubsConnectionName", + configureClientBuilder: clientBuilder => clientBuilder.ConfigureOptions( + options => options.Identifier = "PROCESSOR_ID")); +``` + +[!INCLUDE [component-observability-and-telemetry](../includes/component-observability-and-telemetry.md)] + +### Logging + +The .NET Aspire Azure Event Hubs component uses the following log categories: + +- `Azure.Core` +- `Azure.Identity` + +### Tracing + +The .NET Aspire Azure Event Hubs component will emit the following tracing activities using OpenTelemetry: + +- "Azure.Messaging.EventHubs.*" + +### Metrics + +The .NET Aspire Azure Event Hubs component currently doesn't support metrics by default due to limitations with the Azure SDK for .NET. If that changes in the future, this section will be updated to reflect those changes. + +## See also + +- [Azure Event Hubs](/azure/event-hubs/) +- [.NET Aspire components](../fundamentals/components-overview.md) +- [.NET Aspire GitHub repo](https://github.com/dotnet/aspire) diff --git a/docs/messaging/azure-service-bus-component.md b/docs/messaging/azure-service-bus-component.md index 7f1e99ae43..9650da5ba7 100644 --- a/docs/messaging/azure-service-bus-component.md +++ b/docs/messaging/azure-service-bus-component.md @@ -2,7 +2,7 @@ title: .NET Aspire Azure Service Bus component description: This article describes the .NET Aspire Azure Service Bus component features and capabilities ms.topic: how-to -ms.date: 01/22/2024 +ms.date: 04/04/2024 --- # .NET Aspire Azure Service Bus component @@ -57,7 +57,22 @@ public class ExampleService(ServiceBusClient client) ## App host usage -[!INCLUDE [azure-component-nuget](../includes/azure-component-nuget.md)] +To add Azure Service Bus hosting support to your , install the [Aspire.Hosting.Azure.ServiceBus](https://www.nuget.org/packages/Aspire.Hosting.Azure.ServiceBus) NuGet package. + +### [.NET CLI](#tab/dotnet-cli) + +```dotnetcli +dotnet add package Aspire.Hosting.Azure.ServiceBus --prerelease +``` + +### [PackageReference](#tab/package-reference) + +```xml + +``` + +--- In your app host project, register the Service Bus component and consume the service using the following methods: @@ -157,13 +172,6 @@ The following configurable options are exposed through the +``` + +--- + +For more information, see [dotnet add package](/dotnet/core/tools/dotnet-add-package) or [Manage package dependencies in .NET applications](/dotnet/core/tools/dependencies). + +## Example usage + + + +In the _Program.cs_ file of your projects, call the `AddNatsClient` extension method to register an `INatsConnection` to send logs and traces to NATS and the .NET Aspire Dashboard. The method takes a connection name parameter. + +```csharp +builder.AddNatsClient("nats"); +``` + +You can then retrieve the `INatsConnection` instance using dependency injection. For example, to retrieve the client from a service: + +```csharp +public class ExampleService(INatsConnection client) +{ + // Use client... +} +``` + +## Configuration + +The .NET Aspire NATS component provides multiple options to configure the NATS connection based on the requirements and conventions of your project. + +### Use a connection string + +Provide the name of the connection string when you call `builder.AddNatsClient()`: + +```csharp +builder.AddNatsClient("myConnection"); +``` + +The connection string is retrieved from the `ConnectionStrings` configuration section: + +```json +{ + "ConnectionStrings": { + "myConnection": "nats://nats:4222" + } +} +``` + +See the [ConnectionString documentation](https://docs.nats.io/using-nats/developer/connecting#nats-url) for more information on how to format this connection string. + +### Use configuration providers + +The .NET Aspire NATS component supports [Microsoft.Extensions.Configuration](/dotnet/api/microsoft.extensions.configuration). It loads the `NatsClientSettings` from configuration using the `Aspire:Nats:Client` key. Example `appsettings.json` that configures some of the options: + +```json +{ + "Aspire": { + "Nats": { + "Client": { + "HealthChecks": false + } + } + } +} +``` + +### Use inline delegates + +Pass the `Action configureSettings` delegate to set up some or all the options inline, for example to disable health checks from code: + +```csharp +builder.AddNatsClient("nats", settings => settings.HealthChecks = false); +``` + +## AppHost extensions + +In your AppHost project, install the `Aspire.Hosting.Nats` library with [NuGet](https://www.nuget.org): + +```dotnetcli +dotnet add package Aspire.Hosting.Nats +``` + +Then, in the _Program.cs_ file of `AppHost`, register a NATS server and consume the connection using the following methods: + +```csharp +var nats = builder.AddNats("nats"); + +var myService = builder.AddProject() + .WithReference(nats); +``` + +The `WithReference` method configures a connection in the `MyService` project named `nats`. In the _Program.cs_ file of `MyService`, the NATS connection can be consumed using: + +```csharp +builder.AddNatsClient("nats"); +``` + +### Persistent logs and traces + +Register NATS with a data directory in your **.AppHost** project to retain NATS's data and configuration across application restarts. + +```csharp +var NATS = builder.AddNATS("NATS", NATSDataDirectory: "./NATSdata"); +``` + +The directory specified must already exist. + +### NATS in the .NET Aspire manifest + +NATS isn't part of the .NET Aspire deployment manifest. It's recommended you set up a secure production NATS server outside of .NET Aspire. + +[!INCLUDE [component-health-checks](../includes/component-health-checks.md)] + +The .NET Aspire NATS component handles the following: + +- Integrates with the `/health` HTTP endpoint, which specifies all registered health checks must pass for app to be considered ready to accept traffic. + +[!INCLUDE [component-observability-and-telemetry](../includes/component-observability-and-telemetry.md)] + +### Logging + +The .NET Aspire NATS component uses the following log categories: + +- `NATS` + +### Tracing + +The .NET Aspire NATS component emits the following tracing activities: + +- `NATS.Net` + +## See also + +- [NATS.Net quickstart](https://nats-io.github.io/nats.net.v2/documentation/intro.html?tabs=core-nats) +- [NATS component README](https://github.com/dotnet/aspire/tree/main/src/Components/README.md) diff --git a/docs/real-time/azure-signalr-scenario.md b/docs/real-time/azure-signalr-scenario.md index d39e1cc789..ced800c154 100644 --- a/docs/real-time/azure-signalr-scenario.md +++ b/docs/real-time/azure-signalr-scenario.md @@ -2,7 +2,7 @@ title: .NET Aspire support for Azure SignalR Service description: Learn how to use the Azure SignalR Service with .NET Aspire. ms.topic: how-to -ms.date: 03/01/2024 +ms.date: 04/04/2024 --- # .NET Aspire support for Azure SignalR Service diff --git a/docs/real-time/snippets/signalr/SignalR.AppHost/SignalR.AppHost.csproj b/docs/real-time/snippets/signalr/SignalR.AppHost/SignalR.AppHost.csproj index 1a1f307751..a4aea4add3 100644 --- a/docs/real-time/snippets/signalr/SignalR.AppHost/SignalR.AppHost.csproj +++ b/docs/real-time/snippets/signalr/SignalR.AppHost/SignalR.AppHost.csproj @@ -15,8 +15,8 @@ - - + + diff --git a/docs/real-time/snippets/signalr/SignalR.ServiceDefaults/Extensions.cs b/docs/real-time/snippets/signalr/SignalR.ServiceDefaults/Extensions.cs index c6adc5cf68..090aca54f7 100644 --- a/docs/real-time/snippets/signalr/SignalR.ServiceDefaults/Extensions.cs +++ b/docs/real-time/snippets/signalr/SignalR.ServiceDefaults/Extensions.cs @@ -3,11 +3,13 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.ServiceDiscovery; using OpenTelemetry.Logs; using OpenTelemetry.Metrics; using OpenTelemetry.Trace; namespace Microsoft.Extensions.Hosting; + public static class Extensions { public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder) @@ -24,9 +26,15 @@ public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBu http.AddStandardResilienceHandler(); // Turn on service discovery by default - http.UseServiceDiscovery(); + http.AddServiceDiscovery(); }); + // Uncomment the following to restrict the allowed schemes for service discovery. + // builder.Services.Configure(options => + // { + // options.AllowedSchemes = ["https"]; + // }); + return builder; } @@ -42,9 +50,8 @@ public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicati .WithMetrics(metrics => { metrics.AddAspNetCoreInstrumentation() - .AddHttpClientInstrumentation() - .AddProcessInstrumentation() - .AddRuntimeInstrumentation(); + .AddHttpClientInstrumentation() + .AddRuntimeInstrumentation(); }) .WithTracing(tracing => { @@ -55,8 +62,9 @@ public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicati } tracing.AddAspNetCoreInstrumentation() - .AddGrpcClientInstrumentation() - .AddHttpClientInstrumentation(); + // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package) + //.AddGrpcClientInstrumentation() + .AddHttpClientInstrumentation(); }); builder.AddOpenTelemetryExporters(); @@ -103,15 +111,20 @@ public static WebApplication MapDefaultEndpoints(this WebApplication app) // Uncomment the following line to enable the Prometheus endpoint (requires the OpenTelemetry.Exporter.Prometheus.AspNetCore package) // app.MapPrometheusScrapingEndpoint(); - // All health checks must pass for app to be considered ready to accept traffic after starting - app.MapHealthChecks("/health"); - - // Only health checks tagged with the "live" tag must pass for app to be considered alive - app.MapHealthChecks("/alive", new HealthCheckOptions + // Adding health checks endpoints to applications in non-development environments has security implications. + // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments. + if (app.Environment.IsDevelopment()) { - Predicate = r => r.Tags.Contains("live") - }); + // All health checks must pass for app to be considered ready to accept traffic after starting + app.MapHealthChecks("/health"); + + // Only health checks tagged with the "live" tag must pass for app to be considered alive + app.MapHealthChecks("/alive", new HealthCheckOptions + { + Predicate = r => r.Tags.Contains("live") + }); + } return app; } -} +} \ No newline at end of file diff --git a/docs/real-time/snippets/signalr/SignalR.ServiceDefaults/SignalR.ServiceDefaults.csproj b/docs/real-time/snippets/signalr/SignalR.ServiceDefaults/SignalR.ServiceDefaults.csproj index 6eae75c1ac..09e799a0b8 100644 --- a/docs/real-time/snippets/signalr/SignalR.ServiceDefaults/SignalR.ServiceDefaults.csproj +++ b/docs/real-time/snippets/signalr/SignalR.ServiceDefaults/SignalR.ServiceDefaults.csproj @@ -11,13 +11,11 @@ - + - - diff --git a/docs/security/azure-security-key-vault-component.md b/docs/security/azure-security-key-vault-component.md index 7c7fcfed8a..2c405ecd1a 100644 --- a/docs/security/azure-security-key-vault-component.md +++ b/docs/security/azure-security-key-vault-component.md @@ -49,7 +49,22 @@ public class ExampleService(SecretClient client) ## App host usage -[!INCLUDE [azure-component-nuget](../includes/azure-component-nuget.md)] +To add Azure Key Vault hosting support to your , install the [Aspire.Hosting.Azure.KeyVault](https://www.nuget.org/packages/Aspire.Hosting.Azure.KeyVault) NuGet package. + +### [.NET CLI](#tab/dotnet-cli) + +```dotnetcli +dotnet add package Aspire.Hosting.Azure.KeyVault --prerelease +``` + +### [PackageReference](#tab/package-reference) + +```xml + +``` + +--- In your app host project, register the Azure Key Vault component and consume the service using the following methods: diff --git a/docs/storage/azure-storage-blobs-component.md b/docs/storage/azure-storage-blobs-component.md index e162f829f7..8a24744fb6 100644 --- a/docs/storage/azure-storage-blobs-component.md +++ b/docs/storage/azure-storage-blobs-component.md @@ -2,7 +2,7 @@ title: .NET Aspire Azure Blob Storage component description: This article describes the .NET Aspire Azure Blob Storage component features and capabilities. ms.topic: how-to -ms.date: 03/13/2024 +ms.date: 04/04/2024 --- # .NET Aspire Azure Blob Storage component @@ -49,7 +49,22 @@ public class ExampleService(BlobServiceClient client) ## App host usage -[!INCLUDE [azure-component-nuget](../includes/azure-component-nuget.md)] +To add Azure Storage hosting support to your , install the [Aspire.Hosting.Azure.Storage](https://www.nuget.org/packages/Aspire.Hosting.Azure.Storage) NuGet package. + +### [.NET CLI](#tab/dotnet-cli) + +```dotnetcli +dotnet add package Aspire.Hosting.Azure.Storage --prerelease +``` + +### [PackageReference](#tab/package-reference) + +```xml + +``` + +--- In your app host project, register the Azure Blob Storage component and consume the service using the following methods, such as : diff --git a/docs/storage/azure-storage-components.md b/docs/storage/azure-storage-components.md index 08b0d000f8..8aed44212d 100644 --- a/docs/storage/azure-storage-components.md +++ b/docs/storage/azure-storage-components.md @@ -1,7 +1,7 @@ --- title: Connect an ASP.NET Core app to .NET Aspire storage components description: Learn how to connect an ASP.NET Core app to .NET Aspire storage components. -ms.date: 01/22/2024 +ms.date: 04/09/2024 ms.topic: tutorial zone_pivot_groups: azure-storage-mechanism ms.custom: devx-track-extended-azdevcli @@ -170,19 +170,19 @@ Visual Studio tooling added this line of code to register your new project with ## [.NET CLI](#tab/net-cli) -1. In the root directory of the app, use the [`dotnet new`](/dotnet/core/tools/dotnet-new) command to create a new Worker Service app: +1. In the root directory of the app, use the [dotnet new](/dotnet/core/tools/dotnet-new) command to create a new Worker Service app: ```dotnetcli dotnet new worker --name AspireStorage.WorkerService ``` -1. Use the [`dotnet sln`](/dotnet/core/tools/dotnet-sln) command to add the project to the solution: +1. Use the [dotnet sln](/dotnet/core/tools/dotnet-sln) command to add the project to the solution: ``` dotnet sln AspireStorage.sln add AspireStorage.WorkerService/AspireStorage.WorkerService.csproj ``` -1. Use the [`dotnet add`](/dotnet/core/tools/dotnet-add) command to add project reference between the **.AppHost** and **.WorkerService** project: +1. Use the [dotnet add package](/dotnet/core/tools/dotnet-add-package)command to add project reference between the **.AppHost** and **.WorkerService** project: ```dotnetcli dotnet add AspireStorage.AppHost/AspireStorage.AppHost.csproj reference AspireStorage.WorkerService/AspireStorage.WorkerService.csproj @@ -270,7 +270,22 @@ For more information about creating forms in Blazor, see [ASP.NET Core Blazor fo The _AspireStorage.AppHost_ project is the orchestrator for your app. It's responsible for connecting and configuring the different projects and services of your app. The orchestrator should be set as the startup project. -[!INCLUDE [azure-component-nuget](../includes/azure-component-nuget.md)] +To add Azure Storage hosting support to your , install the [Aspire.Hosting.Azure.Storage](https://www.nuget.org/packages/Aspire.Hosting.Azure.Storage) NuGet package. + +### [.NET CLI](#tab/dotnet-cli) + +```dotnetcli +dotnet add package Aspire.Hosting.Azure.Storage --prerelease +``` + +### [PackageReference](#tab/package-reference) + +```xml + +``` + +--- Replace the contents of the _Program.cs_ file in the _AspireStorage.AppHost_ project with the following code: diff --git a/docs/storage/azure-storage-queues-component.md b/docs/storage/azure-storage-queues-component.md index 22bf3a3878..a54d42ace8 100644 --- a/docs/storage/azure-storage-queues-component.md +++ b/docs/storage/azure-storage-queues-component.md @@ -2,7 +2,7 @@ title: .NET Aspire Azure Queue Storage component description: This article describes the .NET Aspire Azure Queue Storage component features and capabilities ms.topic: how-to -ms.date: 03/13/2024 +ms.date: 04/04/2024 --- # .NET Aspire Azure Queue Storage component @@ -49,7 +49,22 @@ public class ExampleService(QueueServiceClient client) ## App host usage -[!INCLUDE [azure-component-nuget](../includes/azure-component-nuget.md)] +To add Azure Storage hosting support to your , install the [Aspire.Hosting.Azure.Storage](https://www.nuget.org/packages/Aspire.Hosting.Azure.Storage) NuGet package. + +### [.NET CLI](#tab/dotnet-cli) + +```dotnetcli +dotnet add package Aspire.Hosting.Azure.Storage --prerelease +``` + +### [PackageReference](#tab/package-reference) + +```xml + +``` + +--- In your app host project, add a Storage Queue connection and consume the connection using the following methods, such as : diff --git a/docs/storage/azure-storage-tables-component.md b/docs/storage/azure-storage-tables-component.md index cf4f529f1b..a99bbf4c60 100644 --- a/docs/storage/azure-storage-tables-component.md +++ b/docs/storage/azure-storage-tables-component.md @@ -1,7 +1,7 @@ --- title: .NET Aspire Azure Data Tables component description: This article describes the .NET Aspire Azure Data Tables component features and capabilities. -ms.date: 01/22/2024 +ms.date: 04/04/2024 ms.topic: how-to --- @@ -57,7 +57,22 @@ public class ExampleService(TableServiceClient client) ## App host usage -[!INCLUDE [azure-component-nuget](../includes/azure-component-nuget.md)] +To add Azure Storage hosting support to your , install the [Aspire.Hosting.Azure.Storage](https://www.nuget.org/packages/Aspire.Hosting.Azure.Storage) NuGet package. + +### [.NET CLI](#tab/dotnet-cli) + +```dotnetcli +dotnet add package Aspire.Hosting.Azure.Storage --prerelease +``` + +### [PackageReference](#tab/package-reference) + +```xml + +``` + +--- In your app host project, register the Azure Table Storage component and consume the service using the following methods: diff --git a/docs/storage/snippets/tutorial/AspireStorage/AspireStorage.AppHost/AspireStorage.AppHost.csproj b/docs/storage/snippets/tutorial/AspireStorage/AspireStorage.AppHost/AspireStorage.AppHost.csproj index 4c6311bd2f..5b39b4589a 100644 --- a/docs/storage/snippets/tutorial/AspireStorage/AspireStorage.AppHost/AspireStorage.AppHost.csproj +++ b/docs/storage/snippets/tutorial/AspireStorage/AspireStorage.AppHost/AspireStorage.AppHost.csproj @@ -1,4 +1,4 @@ - +ο»Ώ Exe @@ -9,8 +9,9 @@ - - + + + diff --git a/docs/storage/snippets/tutorial/AspireStorage/AspireStorage.ServiceDefaults/AspireStorage.ServiceDefaults.csproj b/docs/storage/snippets/tutorial/AspireStorage/AspireStorage.ServiceDefaults/AspireStorage.ServiceDefaults.csproj index 6eae75c1ac..09e799a0b8 100644 --- a/docs/storage/snippets/tutorial/AspireStorage/AspireStorage.ServiceDefaults/AspireStorage.ServiceDefaults.csproj +++ b/docs/storage/snippets/tutorial/AspireStorage/AspireStorage.ServiceDefaults/AspireStorage.ServiceDefaults.csproj @@ -11,13 +11,11 @@ - + - - diff --git a/docs/storage/snippets/tutorial/AspireStorage/AspireStorage.ServiceDefaults/Extensions.cs b/docs/storage/snippets/tutorial/AspireStorage/AspireStorage.ServiceDefaults/Extensions.cs index c6adc5cf68..090aca54f7 100644 --- a/docs/storage/snippets/tutorial/AspireStorage/AspireStorage.ServiceDefaults/Extensions.cs +++ b/docs/storage/snippets/tutorial/AspireStorage/AspireStorage.ServiceDefaults/Extensions.cs @@ -3,11 +3,13 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.ServiceDiscovery; using OpenTelemetry.Logs; using OpenTelemetry.Metrics; using OpenTelemetry.Trace; namespace Microsoft.Extensions.Hosting; + public static class Extensions { public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder) @@ -24,9 +26,15 @@ public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBu http.AddStandardResilienceHandler(); // Turn on service discovery by default - http.UseServiceDiscovery(); + http.AddServiceDiscovery(); }); + // Uncomment the following to restrict the allowed schemes for service discovery. + // builder.Services.Configure(options => + // { + // options.AllowedSchemes = ["https"]; + // }); + return builder; } @@ -42,9 +50,8 @@ public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicati .WithMetrics(metrics => { metrics.AddAspNetCoreInstrumentation() - .AddHttpClientInstrumentation() - .AddProcessInstrumentation() - .AddRuntimeInstrumentation(); + .AddHttpClientInstrumentation() + .AddRuntimeInstrumentation(); }) .WithTracing(tracing => { @@ -55,8 +62,9 @@ public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicati } tracing.AddAspNetCoreInstrumentation() - .AddGrpcClientInstrumentation() - .AddHttpClientInstrumentation(); + // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package) + //.AddGrpcClientInstrumentation() + .AddHttpClientInstrumentation(); }); builder.AddOpenTelemetryExporters(); @@ -103,15 +111,20 @@ public static WebApplication MapDefaultEndpoints(this WebApplication app) // Uncomment the following line to enable the Prometheus endpoint (requires the OpenTelemetry.Exporter.Prometheus.AspNetCore package) // app.MapPrometheusScrapingEndpoint(); - // All health checks must pass for app to be considered ready to accept traffic after starting - app.MapHealthChecks("/health"); - - // Only health checks tagged with the "live" tag must pass for app to be considered alive - app.MapHealthChecks("/alive", new HealthCheckOptions + // Adding health checks endpoints to applications in non-development environments has security implications. + // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments. + if (app.Environment.IsDevelopment()) { - Predicate = r => r.Tags.Contains("live") - }); + // All health checks must pass for app to be considered ready to accept traffic after starting + app.MapHealthChecks("/health"); + + // Only health checks tagged with the "live" tag must pass for app to be considered alive + app.MapHealthChecks("/alive", new HealthCheckOptions + { + Predicate = r => r.Tags.Contains("live") + }); + } return app; } -} +} \ No newline at end of file diff --git a/docs/storage/snippets/tutorial/AspireStorage/AspireStorage.Worker/AspireStorage.Worker.csproj b/docs/storage/snippets/tutorial/AspireStorage/AspireStorage.Worker/AspireStorage.Worker.csproj index b35998409a..bb6b7dc4b6 100644 --- a/docs/storage/snippets/tutorial/AspireStorage/AspireStorage.Worker/AspireStorage.Worker.csproj +++ b/docs/storage/snippets/tutorial/AspireStorage/AspireStorage.Worker/AspireStorage.Worker.csproj @@ -7,7 +7,7 @@ - + diff --git a/docs/storage/snippets/tutorial/AspireStorage/AspireStorage/AspireStorage.csproj b/docs/storage/snippets/tutorial/AspireStorage/AspireStorage/AspireStorage.csproj index fd4ef59dde..919d35ef15 100644 --- a/docs/storage/snippets/tutorial/AspireStorage/AspireStorage/AspireStorage.csproj +++ b/docs/storage/snippets/tutorial/AspireStorage/AspireStorage/AspireStorage.csproj @@ -8,9 +8,9 @@ + Version="8.0.0-preview.5.24201.12" /> + Version="8.0.0-preview.5.24201.12" /> diff --git a/docs/toc.yml b/docs/toc.yml index fc4486f9aa..f32568ffee 100644 --- a/docs/toc.yml +++ b/docs/toc.yml @@ -20,8 +20,8 @@ items: - name: What's new in .NET Aspire items: - - name: .NET Aspire preview 4 - href: whats-new/preview-4.md + - name: .NET Aspire preview 5 + href: whats-new/preview-5.md - name: Fundamentals items: @@ -68,6 +68,11 @@ items: href: storage/azure-storage-queues-component.md - name: Azure Table Storage component href: storage/azure-storage-tables-component.md + + - name: Logging + items: + - name: SEQ component + href: logging/seq-component.md - name: Database items: @@ -109,12 +114,16 @@ items: items: - name: Tutorial - Messaging using .NET Aspire components href: messaging/messaging-components.md + - name: Azure Event Hubs component + href: messaging/azure-event-hubs-component.md - name: Azure Service Bus component href: messaging/azure-service-bus-component.md - name: RabbitMQ service broker component href: messaging/rabbitmq-client-component.md - name: Apache Kafka component href: messaging/kafka-component.md + - name: NATS component + href: messaging/nats-component.md - name: Caching items: @@ -138,6 +147,8 @@ items: href: deployment/overview.md - name: Azure items: + - name: Local Azure provisioning + href: deployment/azure/local-provisioning.md - name: Tutorial - Azure Container Apps href: deployment/azure/aca-deployment.md displayName: azure container apps,aca @@ -154,6 +165,12 @@ items: - name: Reference - Tool-builder manifest schemas href: deployment/manifest-format.md + - name: Troubleshooting + items: + - name: Allow unsecure transport + displayName: unsecure transport,http,non-tls + href: troubleshooting/allow-unsecure-transport.md + - name: Resources items: - name: .NET Aspire @@ -171,5 +188,7 @@ items: - name: Reference items: + - name: Diagnostics overview + href: diagnostics/overview.md - name: .NET Aspire FAQ href: reference/aspire-faq.yml diff --git a/docs/troubleshooting/allow-unsecure-transport.md b/docs/troubleshooting/allow-unsecure-transport.md new file mode 100644 index 0000000000..2144a07197 --- /dev/null +++ b/docs/troubleshooting/allow-unsecure-transport.md @@ -0,0 +1,75 @@ +--- +title: Allow unsecure transport in .NET Aspire +description: Learn how to allow unsecure transport in .NET Aspire applications. +ms.date: 04/09/2024 +--- + +# Allow unsecure transport in .NET Aspire + +Starting with .NET Aspire preview 5, the app host will crash if an `applicationUrl` is configured with an unsecure transport (non-TLS `http`) protocol. This is a security feature to prevent accidental exposure of sensitive data. However, there are scenarios where you might need to allow unsecure transport. This article explains how to allow unsecure transport in .NET Aspire applications. + +## Symptoms + +When you run a .NET Aspire application with an `applicationUrl` configured with an unsecure transport protocol, you might see the following error message: + +```Output +The 'applicationUrl' setting must be an https address unless the +'ASPIRE_ALLOW_UNSECURED_TRANSPORT' environment variable is set to true. + +This configuration is commonly set in the launch profile. +``` + +## How to allow unsecure transport + +To allow an unsecure transport in .NET Aspire, set the `ASPIRE_ALLOW_UNSECURED_TRANSPORT` environment variable to `true`. This environment variable is used to control the behavior of the app host when an `applicationUrl` is configured with an insecure transport protocol: + +## [Unix](#tab/unix) + +```bash +export ASPIRE_ALLOW_UNSECURED_TRANSPORT=true +``` + +## [Windows](#tab/windows) + +```powershell +$env:ASPIRE_ALLOW_UNSECURED_TRANSPORT = "true" +``` + +--- + +Alternatively, you can control this via the launch profile as it exposes the ability to configure environment variables per profile. To do this, consider the following example settings in the `launchSettings.json` file: + +```json +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:15015;http://localhost:15016", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:16099", + "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:17037" + } + }, + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:15016", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:16099", + "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:17038", + "ASPIRE_ALLOW_UNSECURED_TRANSPORT": "true" + } + } + } +} +``` + +The preceding example shows two profiles, `https` and `http`. The `https` profile is configured with a secure transport protocol, while the `http` profile is configured with an insecure transport protocol. The `ASPIRE_ALLOW_UNSECURED_TRANSPORT` environment variable is set to `true` in the `http` profile to allow unsecure transport. diff --git a/docs/whats-new/index.yml b/docs/whats-new/index.yml index 94411c87a3..6c24f46c42 100644 --- a/docs/whats-new/index.yml +++ b/docs/whats-new/index.yml @@ -12,6 +12,8 @@ landingContent: linkLists: - linkListType: whats-new links: + - text: .NET Aspire preview 5 + url: preview-5.md - text: .NET Aspire preview 4 url: preview-4.md - text: .NET Aspire preview 3 diff --git a/docs/whats-new/media/preview-5/aspire-preview-5-relnotes.gif b/docs/whats-new/media/preview-5/aspire-preview-5-relnotes.gif new file mode 100644 index 0000000000..7942898543 Binary files /dev/null and b/docs/whats-new/media/preview-5/aspire-preview-5-relnotes.gif differ diff --git a/docs/whats-new/media/preview-5/azure-resource-provisioning-on-dashboard.png b/docs/whats-new/media/preview-5/azure-resource-provisioning-on-dashboard.png new file mode 100644 index 0000000000..68ab643ec5 Binary files /dev/null and b/docs/whats-new/media/preview-5/azure-resource-provisioning-on-dashboard.png differ diff --git a/docs/whats-new/media/preview-5/console-logs-performance.gif b/docs/whats-new/media/preview-5/console-logs-performance.gif new file mode 100644 index 0000000000..09435aae22 Binary files /dev/null and b/docs/whats-new/media/preview-5/console-logs-performance.gif differ diff --git a/docs/whats-new/media/preview-5/dashboard-structure-logs-detail.png b/docs/whats-new/media/preview-5/dashboard-structure-logs-detail.png new file mode 100644 index 0000000000..c251298d6f Binary files /dev/null and b/docs/whats-new/media/preview-5/dashboard-structure-logs-detail.png differ diff --git a/docs/whats-new/media/preview-5/receive-message.png b/docs/whats-new/media/preview-5/receive-message.png new file mode 100644 index 0000000000..a70e33636c Binary files /dev/null and b/docs/whats-new/media/preview-5/receive-message.png differ diff --git a/docs/whats-new/media/preview-5/remove-environment.gif b/docs/whats-new/media/preview-5/remove-environment.gif new file mode 100644 index 0000000000..665dac991b Binary files /dev/null and b/docs/whats-new/media/preview-5/remove-environment.gif differ diff --git a/docs/whats-new/media/preview-5/send-message.png b/docs/whats-new/media/preview-5/send-message.png new file mode 100644 index 0000000000..c17224aaae Binary files /dev/null and b/docs/whats-new/media/preview-5/send-message.png differ diff --git a/docs/whats-new/media/preview-5/vs-upgrade-assistant.png b/docs/whats-new/media/preview-5/vs-upgrade-assistant.png new file mode 100644 index 0000000000..4e0125c09e Binary files /dev/null and b/docs/whats-new/media/preview-5/vs-upgrade-assistant.png differ diff --git a/docs/whats-new/preview-5.md b/docs/whats-new/preview-5.md new file mode 100644 index 0000000000..9c5b166a88 --- /dev/null +++ b/docs/whats-new/preview-5.md @@ -0,0 +1,773 @@ +--- +title: .NET Aspire preview 5 +description: .NET Aspire preview 5 is now available and includes many improvements and new capabilities. +ms.date: 04/09/2024 +--- + +# .NET Aspire preview 5 + +.NET Aspire preview 5 introduces breaking changes to hosting NuGet packages. In addition to these breaking changes, there are several sweeping improvements and additions to be aware of, including support for AWS and improvements for Azure. The following article provides an overview of the major changes in .NET Aspire preview 5: `8.0.0-preview.5.24201.12`. + +If you're using Visual Studio, see the [Use Upgrade Assistant to update to preview 5](#use-upgrade-assistant-to-update-to-preview-5). + +## Packaging changes + +As part of our journey to GA we have split up the `Aspire.Hosting` and `Aspire.Hosting.Azure` packages. These changes will allow us greater flexibility for servicing and ensure that appropriate boundaries are maintained between our core abstractions for .NET Aspire and various cloud-native dependencies that an application may require. + +The following table maps between Aspire extension methods you might be using today in your AppHost and the package +in which they are now contained: + +| Extension method | Package | +|----------------------|------------------------------| +| `AddProject(...)` | `Aspire.Hosting` (unchanged) | +| `AddContainer(...)` | `Aspire.Hosting` (unchanged) | +| `AddExecutable(...)` | `Aspire.Hosting` (unchanged) | +| `AddKafka(...)` | `Aspire.Hosting.Kakfa` | +| `AddMongoDB(...)` | `Aspire.Hosting.MongoDB` | +| `AddMySql(...)` | `Aspire.Hosting.MySql` | +| `AddNpmApp(...)` | `Aspire.Hosting.NodeJs` | +| `AddNodeApp(...)` | `Aspire.Hosting.NodeJs` | +| `AddOracle(...)` | `Aspire.Hosting.Oracle` | +| `AddPostgres(...)` | `Aspire.Hosting.PostgreSQL` | +| `AddRabbitMQ(...)` | `Aspire.Hosting.RabbitMQ` | +| `AddRedis(...)` | `Aspire.Hosting.Redis` | +| `AddSeq(...)` | `Aspire.Hosting.Seq` | +| `AddSqlServer(...)` | `Aspire.Hosting.SqlServer` | + +For more information, see [.NET Aspire orchestration overview](../fundamentals/app-host-overview.md). + +The `Aspire.Hosting.Azure` APIs have been broken up in to the following packages: + +| Extension method | Package | +|--------------------------------------|--------------------------------------------| +| `AddBicepTemplate(...)` | `Aspire.Hosting.Azure` (unchanged) | +| `AddBicepTemplateString(...)` | `Aspire.Hosting.Azure` (unchanged) | +| `AddAzureConstruct(...)` | `Aspire.Hosting.Azure` (unchanged) | +| `AddAzureAppConfiguration(...)` | `Aspire.Hosting.Azure.AppConfiguration` | +| `AddAzureApplicationInsights(...)` | `Aspire.Hosting.Azure.ApplicationInsights` | +| `AddAzureOpenAI(...)` | `Aspire.Hosting.Azure.CognitiveServices` | +| `AddAzureCosmosDB(...)` | `Aspire.Hosting.Azure.CosmosDB` | +| `AddAzureEventHubs(...)` | `Aspire.Hosting.Azure.EventHubs` | +| `AddAzureKeyVault(...)` | `Aspire.Hosting.Azure.KeyVault` | +| `AddAzureLogAnalyticsWorkspace(...)` | `Aspire.Hosting.Azure.OperationalInsights` | +| `AsAzurePostgresFlexibleServer(...)` | `Aspire.Hosting.Azure.PostgreSQL` | +| `AsAzureRedis(...)` | `Aspire.Hosting.Azure.Redis` | +| `AddAzureSearch(...)` | `Aspire.Hosting.Azure.Search` | +| `AddAzureServiceBus(...)` | `Aspire.Hosting.Azure.ServiceBus` | +| `AddAzureSignalR(...)` | `Aspire.Hosting.Azure.SignalR` | +| `AsAzureSqlDatabase(...)` | `Aspire.Hosting.Azure.Sql` | +| `AddAzureStorage(...)` | `Aspire.Hosting.Azure.Storage` | + +For more information, see [Azure-specific resource types](../deployment/manifest-format.md#azure-specific-resource-types). + +## Application model changes + +At the core of .NET Aspire's capabilities is the application model. The application model is a set of abstractions that allow you to define the components of your application and how they interact with each other. There were several changes to the application model in preview 5. + +### Allow unsecure transport for HTTP endpoints + +In preview 5, the **app host will crash** if an `applicationUrl` is configured with an unsecure transport. This can be avoided by setting the `ASPIRE_ALLOW_UNSECURED_TRANSPORT` environment variable. For more information, see [Allow unsecure transport in .NET Aspire](../troubleshooting/allow-unsecure-transport.md). + +### Enable forwarded headers by default for .NET projects + +If a .NET project is added to your distributed application model, and that project has endpoints defined the `ASPNETCORE_FORWARDEDHEADERS_ENABLED` environment variable is automatically set, which has the effect of enabling handling for forwarded headers. This is because the primary deployment target for Aspire applications is containerized environments where a reverse proxy is deployed in front of the workload. + +This can be disabled using the `DisableForwardedHeaders()` extension method. + +### Custom resources support in the dashboard + +We have made improvements to the application model to allow custom resources to update their status in the dashboard and log console output. This is extremely useful for cloud hosted resources that need to be deployed when an application starts. + +Two new services exist within the DI container which can be injected into lifecycle hooks called `ResourceNotificationService` and `ResourceLoggerService`. For more information, see the [CustomResources "playground" sample](https://github.com/dotnet/aspire/blob/1b627b7d5d399d4f9118366e7611e11e56de4554/playground/CustomResources/CustomResources.AppHost/TestResource.cs#L30) in the repo for how to use these APIs. + +### Improved volume mount APIs + +We have improved the ease of configuring persistence between container restarts for many of the container-based .NET Aspire resources. It's now possible to enable persistence on many containers through the use of an extension method. For example, consider volume mounts: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +// Uses a volume mount to store data between restarts. +var pg1 = builder.AddPostgres("pgsql1") + .WithDataVolume(); +``` + +Likewise, it's possible to use a bind mount to store data between restarts. This is useful when you want to store data on the host machine rather than in the container: + +```csharp +var builder = DistributedApplication.CreateBuilder(args) + +// Uses a bind mount to store data. +var pg1 = builder.AddPostgres("pgsql1") + .WithDataBindVolume(path); +``` + +We've also worked with the Azure Developer CLI team to add support for creating volume mounts in Azure Storage for container apps when Aspire apps are deployed to Azure. + +### RabbitMQ management UI + +We've added the ability to enable the RabbitMQ management UI: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var messaging = builder.AddRabbitMQ("messaging") + .WithManagementPlugin(); +``` + +When the app host starts up the dashboard will show a HTTP endpoint. If you click on the endpoint you will be prompted for a username and password. The username and password is visible in the environment variables assigned to the container. + +### Automatic password generation + +In previous previews of Aspire, each resource created a random password when the resource was added to the app model, taking an optional password argument if required. In preview 5 we have modified the API to take a `IResourceBuilder` argument for usernames and passwords. If these parameters are omitted a parameter will be automatically injected into the application model with a default random value. + +During deployment with tools such as the Azure Developer CLI (`azd`) the password will be generated automatically and stored in a KeyVault for later use by container workloads. + +### API for expressing Docker build args + +Before preview 5, it wasn't possible to express [Docker build args](https://docs.docker.com/reference/cli/docker/image/build/#build-arg) when an executable resource was published as a `dockerfile.v0`. The app model updated the `PublishAsDockerfile` extension method to accept an `IEnumerable` parameter. This allows you to pass in build arguments to the Docker build process. This is useful when you want to pass in secrets or other configuration values at build time. + +```csharp +var builder = DistributedApplication.CreateBuilder(); + +var frontend = builder + .AddNpmApp("frontend", "NodeFrontend", "watch") + .PublishAsDockerFile( + buildArgs: + [ + new DockerBuildArg("NODE_ENV", "staging"), + new DockerBuildArg("WEATHER_API") // Null means docker pulls the env var value + ] + ); +``` + +For more information on the output in the manifest, see [Docker build arguments](#docker-build-arguments). + +### Deferred string interpolation for WithEnvironment(...) and reference expressions + +We have added a new overload to the `WithEnvironment(...)` extension method which supports interpolated strings: + +```csharp +public static IResourceBuilder WithEnvironment( + this IResourceBuilder builder, + string name, + in ReferenceExpression.ExpressionInterpolatedStringHandler value) +``` + +This allows you to write code like this: + +```csharp +var containerA = builder.AddContainer("container1", "image") + .WithHttpEndpoint(name: "primary", targetPort: 10005); + +var endpoint = containerA.GetEndpoint("primary"); + +// The {endpoint} placeholder is evaluated AFTER containerA has started +// and the dynamically allocated port can be determined. +var containerB = + builder.AddContainer("container2", "imageB") + .WithEnvironment("URL", $"{endpoint}/foo") + .WithEnvironment("PORT", $"{endpoint.Property(EndpointProperty.Port)}") + .WithEnvironment("TARGET_PORT", $"{endpoint.Property(EndpointProperty.TargetPort)}") + .WithEnvironment("HOST", $"{test.Resource};name=1"); +``` + +Underlying this improvement is a series of changes to the way that references between resources are handled. For example resources that expose connection strings now have async methods instead of synchronous methods which allow the start-up of a micro-service to block whilst a cloud resource is being initialized. + +A good illustration of the changes here can be seen on the `IResourceWithConnectionString` interface. The code below shows the preview 4 and preview 5 versions one after another. + +```csharp +// Preview 4 +public interface IResourceWithConnectionString : IResource +{ + string? GetConnectionString(); + + string? ConnectionStringExpression => { get; } + + string ConnectionStringReferenceExpression { get; } + + string? ConnectionStringEnvironmentVariable { get; } +} + +// Preview 5 +public interface IResourceWithConnectionString : + IResource, + IManifestExpressionProvider, + IValueProvider, + IValueWithReferences +{ + ValueTask GetConnectionStringAsync( + CancellationToken cancellationToken = default); + + string IManifestExpressionProvider.ValueExpression { get; } + + ValueTask IValueProvider.GetValueAsync( + CancellationToken cancellationToken); + + ReferenceExpression ConnectionStringExpression { get; } + + string? ConnectionStringEnvironmentVariable { get; } + + IEnumerable IValueWithReferences.References { get; } +} +``` + +The `GetConnectionString` method has been made asynchronous. But there are many other properties that have been added. This allows for better tracking of dependencies within the application model. These are defined by interfaces like `IValueProvider` and `IManifestExpressionProvider`. + +The basic usage pattern for adding a reference from one resource to another hasn't changed. The changes above primarily impact the internal implementation details and only impact you if you are building custom resource types or if you are using the string interpolation features mentioned above. + +## Dashboard + +In preview 5, our primary focus has been on non-functional requirements, particularly around security and performance improvements. + +### Structured logs details + +Structured logs provide structured, contextual data along with the log message. Previously, the dashboard UI displayed all information related to a structured log entry in a single list. + +In preview 5, the dashboard UI has been updated to group structured logs information into sections: + +- **Log Entry** - The log level, message, and structured data. This is the most frequently used information. +- **Context** - The context in which the log entry was created. For example, the category and trace IDs. +- **Resource** - The app that sent the log entry to the dashboard. + +:::image type="content" source="media/preview-5/dashboard-structure-logs-detail.png" lightbox="media/preview-5/dashboard-structure-logs-detail.png" alt-text="Structure logs page with details open"::: + +### Trace messaging icon + +Spans are created by sending and receiving messages using libraries such as Azure Service Bus or RabbitMQ. In preview 5, messaging spans have custom icons. + +Sending a message displays an envelope: + +:::image type="content" source="media/preview-5/send-message.png" lightbox="media/preview-5/send-message.png" alt-text="Span with send message icon"::: + +So of course receiving a message is a mailbox: + +:::image type="content" source="media/preview-5/receive-message.png" lightbox="media/preview-5/receive-message.png" alt-text="Span with receive message icon"::: + +### Display times using browser local timezone + +The dashboard now uses the local browser's timezone to display times in the UI. Most users will not notice a change, as the dashboard app typically runs on their local machine. However, if the dashboard is hosted on an external server, times will now be displayed in your local timezone. + +### Security updates + +Communication across the following endpoints has been secured: + +- Dashboard frontend +- OTLP endpoint +- Resource service + +There is no change in the user experience when the dashboard automatically launches with your Aspire app; it is configured to be secure by default. For instance, telemetry received by the dashboard is now protected by an API key that is automatically configured by the Aspire app host. + +However, if you're launching the dashboard in standalone mode, it will now throw an error. Authentication must either be configured or opted out using the `DOTNET_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS` setting. + +```bash +docker run --rm -it -p 18888:18888 -p 4317:18889 -d --name aspire-dashboard \ + -e DOTNET_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS='true' \ + mcr.microsoft.com/dotnet/nightly/aspire-dashboard:8.0.0-preview.5 +``` + +This is temporary situation for preview 5. We're working on providing an easy-to-use authentication mechanism for the dashboard frontend. The standalone dashboard will default to it in the future. + +#### OTLP endpoint security + +The OTLP endpoint can be secured with [client certificate](/aspnet/core/security/authentication/certauth) or API key authentication. + +- `Dashboard:Otlp:AuthMode` specifies the authentication mode on the OTLP endpoint. Possible values are `Certificate`, `ApiKey`, `Unsecured`. This configuration is required. +- `Dashboard:Otlp:ApiKey` specifies the API key for the OTLP endpoint when API key authentication is enabled. This configuration is required for API key authentication. + +#### Dashboard authentication + +The dashboard's web application frontend supports OpenID Connect (OIDC) for authentication. These can be applied via configurable settings, once `Dashboard:Frontend:AuthMode` is set to `OpenIdConnect`: + +- `Authentication:Schemes:OpenIdConnect:Authority` — URL to the identity provider (IdP) +- `Authentication:Schemes:OpenIdConnect:ClientId` — Identity of the relying party (RP) +- `Authentication:Schemes:OpenIdConnect:ClientSecret`— A secret that only the real RP would know +- Other properties of [`OpenIdConnectOptions`](/dotnet/api/microsoft.aspnetcore.builder.openidconnectoptions) specified in configuration container `Authentication:Schemes:OpenIdConnect:*` + +#### Resource server endpoint security + +The resource server client supports client certificates. This can be applied via configurable settings, once ResourceServiceClient:AuthMode to Certificate + +- `ResourceServiceClient:ClientCertificate:Source` (required) one of: + - `File` to load the cert from a file path, configured with: + - `ResourceServiceClient:ClientCertificate:FilePath` (required, string) + - `ResourceServiceClient:ClientCertificate:Password` (optional, string) + - `KeyStore` to load the cert from a key store, configured with: + - `ResourceServiceClient:ClientCertificate:Subject` (required, string) + - `ResourceServiceClient:ClientCertificate:KeyStore:Name` (optional, [`StoreName`](/dotnet/api/system.security.cryptography.x509certificates.storename), defaults to `My`) + - `ResourceServiceClient:ClientCertificate:KeyStore:Location` (optional, [`StoreLocation`](/dotnet/api/system.security.cryptography.x509certificates.storelocation), defaults to `CurrentUser`) +- `ResourceServiceClient:Ssl` (optional, [`SslClientAuthenticationOptions`](/dotnet/api/system.net.security.sslclientauthenticationoptions)) + +#### Cross-site scripting (XSS) fixes + +We've reviewed and hardened the dashboard against XSS attacks by carefully managing how external data from the resource service and telemetry is presented. + +For more information, see [Prevent Cross-Site Scripting (XSS) in ASP.NET Core](/aspnet/core/security/cross-site-scripting). + +### Performance improvements + +Preview 5 includes numerous performance enhancements. We've leveraged virtualization for UI components displaying large amounts of data, allowing for more efficient rendering. Notable improvements include: + +- **Resources page** - Optimized resource loading with enabled virtualization for smoother experiences with numerous resources. +- **Console log page** - Previously, loading extensive console logs could impact performance. Virtualization now allows for smooth handling of tens of thousands of console logs. +- **Trace detail virtualization** - The trace detail page shows a timeline of spans inside a trace. There is no limit to the number of spans a trace can have. Enabling virtualization again allows the UI to scale up to thousands of items without a problem. +- **Rate limit UI updates** - The dashboard automatically updates as it receives new data, such as resource state changes or new telemetry. The UI now limits to a maximum of 10 UI updates per-second. This change keeps the dashboard responsive while at the same time not overwhelming your local machine with unnecessarily frequent updates. + +Console logs page with tens of thousands of console lines: + +:::image type="content" source="media/preview-5/console-logs-performance.gif" lightbox="media/preview-5/console-logs-performance.gif" alt-text="Using console logs page with a lot of data"::: + +## Templates + +- HTTPs by default. +- Test project support. For more information, see [.NET Aspire project templates](../fundamentals/setup-tooling.md#net-aspire-project-templates). + +## Service Discovery + +- Service discovery API changes. +- Service discovery auto scheme detection. + +## Developer Tools + +For Preview 5 we've improved support with our Visual Studio family of products focusing on supporting new capabilities and improving deployment workflows. + +### Visual Studio Code C# DevKit tooling + +With the April release of C# Dev Kit, you can now launch all projects in a .NET Aspire from Visual Studio Code. To launch your .NET Aspire application, simply Ctrl-F5 (Run without debugging). This will launch the app host project and all the associated projects in your .NET Aspire application (front-end and APIs). Similarly, you can debug your .NET Aspire application, simply F5 (Start debugging) and all the projects will attach to the debugger, allowing you to have breakpoints set across projects and each one will be hit when appropriate. + +### Visual Studio tooling updates + +In Visual Studio 17.10 we've continued to improve the end-to-end experience for developers using right-click publish to Azure Container Apps. You no longer need to login separately to `azd`, Visual Studio will log you in seamlessly. Now, when you use the "Remove Environment" feature in the Visual Studio publishing dialog, you can opt for deleting the Azure Developer CLI (azd) environment from your live Azure subscription. This makes it easies for you to iterate, creating and deleting environments with simplicity. + +:::image type="content" source="media/preview-5/remove-environment.gif" lightbox="media/preview-5/remove-environment.gif" alt-text="Removing a local and live Azure environment"::: + +This release of Visual Studio also adds support for the Azure Provisioning features in the release. When you're using Azure resources in a .NET Aspire app, like OpenAI, and need to have use the remote resources during your local development, Visual Studio gives you a way of creating or selecting an existing resource group in which those resources can be provisioned. This animation shows the process of adding OpenAI support to an Aspire app, then running the app only to learn the resources need to be created with the warnings in the Aspire dashboard. At this point, you can flip back into Visual Studio and use Connected Services to set up Azure provisioning so your dev-time resources can be created on the fly. + +:::image type="content" source="media/preview-5/aspire-preview-5-relnotes.gif" lightbox="media/preview-5/aspire-preview-5-relnotes.gif" alt-text="Using Connected Services to configure Azure provisioning"::: + +#### Use Upgrade Assistant to update to preview 5 + +We've also released a new version of the [Upgrade Assistant](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.upgradeassistant), a Visual Studio extension that helps you upgrade projects in various scenarios. We've added support for upgrading .NET Aspire Preview 4 projects to Preview 5. Install the extension and run 'Upgrade' from the context menu of an Aspire-related project like the `AppHost` or client projects to update packages and API changes. + +:::image type="content" source="media/preview-5/vs-upgrade-assistant.png" lightbox="media/preview-5/vs-upgrade-assistant.png" alt-text="Visual Studio Upgrade Assistant with .NET Aspire option"::: + +You will need to run this on each project in your solution. + +## Resources and components + +Each release brings new resources and components thanks to community feedback and contributions. + +### New resources and components + +The following list outlines new components and their corresponding component articles: + +- [Azure Event Hubs](https://azure.microsoft.com/products/event-hubs): [.NET Aspire Azure Event Hubs component](../messaging/azure-event-hubs-component.md). +- [NATS](https://nats.io/): [.NET Aspire support for NATS](../messaging/nats-component.md). +- [Seq](https://datalust.co/seq): [.NET Aspire support for Seq](../logging/seq-component.md). + +### Component breaking changes + +In previous versions, it was confusing what project the following code snippet is from: + +```csharp +builder.AddRedis("redis"); +``` + +because both the `AppHost` and application projects have extension methods named `builder.AddRedis(string)`. To help reduce this confusion, the runtime component libraries renamed their extension methods to append the word `Client` on the extension methods. + +```csharp +builder.AddRedisClient("redis"); +``` + +This makes it clear that we are adding a "client" object to the `WebApplicationBuilder` or `HostApplicationBuilder`. + +## Azure improvements + +The primary focus of the Azure improvements in preview 5 is to make it easier to use Azure resources in your .NET Aspire application. This includes improvements to the Azure provisioning libraries, support for local development with Azure resources, and other Azure-related improvements. + +### Azure provisioning libraries + +In preview 5 the Azure-specific extensions for .NET Aspire have adopted the Azure Provisioning libraries being developed by the Azure SDK team. The Azure Provisioning libraries allow as to use a C# object model to declare Azure resources and at deployment time translate that object model into Bicep which is then used to automate deployment. + +If you are already using Azure-based resources with your .NET Aspire application the APIs you use today continue to work. For example the following code creates an Azure Cosmos database and wires up the connection string to your application. + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var cosmos = builder.AddAzureCosmosDB("mycosmos") + .AddDatabase("inventory"); + +builder.AddProject("inventoryapi") + .WithReference(cosmos); +``` + +In preview 4, if you didn't like the defaults that we specified for Azure Cosmos you would need to provide your own Bicep and use the `AddBicepTemplate` extension. In preview 5 we provide a callback mechanism which allows you to tweak properties. + +For example, if you wanted to modify the consistency level of your Cosmos DB account you could do the following: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var cosmos = builder + .AddAzureCosmosDB( + "mycosmos", + (resource, construct, account, databases) => + { + account.AssignProperty( + p => p.ConsistencyPolicy.DefaultConsistencyLevel, + "`Session`"); + } + ) + .AddDatabase("inventory"); + +builder.AddProject("inventoryapi") + .WithReference(cosmos); +``` + +Azure Provisioning libraries are still experimental and evolving rapidly. Developers are free to use them in their applications but expect the API surface to evolve before reaching stability. To remind developers of this, using the overloads that expose Azure Provisioning types will require the use of a code analysis suppression: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +#pragma warning disable ASPIRE001 +var cosmos = builder + .AddAzureCosmosDB( + "mycosmos", + (resource, construct, account, databases) => + { + account.AssignProperty( + p => p.ConsistencyPolicy.DefaultConsistencyLevel, + "`Session`" + ); + } + ) + .AddDatabase("inventory"); +#pragma warning restore ASPIRE001 + +builder.AddProject("inventoryapi") + .WithReference(cosmos); +``` + +This can be applied globally in your project or in a more localized way as shown above. For more information, see [.NET Aspire diagnostics overview](../diagnostics/overview.md). + +### Azure provisioning for local development + +Previous .NET Aspire previews have had limited support for using cloud based resources for local development. You could use an emulator (such as Azurite for Azure Storage) or you could provision a real resource in the cloud and place a connection string in your AppHost's user secrets. + +In preview 5 if you want to use an Azure resource where an emulator does not exist you can add +the following settings to user `secrets.json` file: + +```json +{ + "Azure": { + "SubscriptionId": "", + "Location": "", + "ResourceGroup": "" + } +} +``` + +When you launch the AppHost the dashboard will show that it is create the Azure resources for you and provide helpful links to the deployment into the Azure portal, or in the case of failure logs that provide hints as to what might be causing the deployment issue. + +:::image type="content" source="media/preview-5/azure-resource-provisioning-on-dashboard.png" lightbox="media/preview-5/azure-resource-provisioning-on-dashboard.png" alt-text=".NET Aspire dashboard: Azure provisioning."::: + +To use Azure provisioning you only need to make use of one of an Azure resource. For example: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var blobs = builder.AzureStorage("storage") + .AddBlobs("blobs"); + +builder.AddProject("galleryapp") + .WithReference(blobs); +``` + +Some resources in .NET Aspire such as Postgres are not cloud specific and can run locally in a container but when deployed use a managed service (such as Azure Postgres Flexible Server). + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var db = builder.AddPostgres("pgsql") + .PublishAsAzurePostgresFlexibleServer() + .AddDatabase("inventorydb"); + +builder.AddProject("inventoryapi") + .WithReference(db); +``` + +It is also possible to use an Azure hosted resource for local development by using the `AsAzurePostgresFlexibleServer()` extension method instead. When this method is used the container will not be started locally and cloud-based instance will be created just like the Azure only resource types. The `PublishAsX` and `AsX` methods also support callbacks to customize the underlying Azure resources as shown above in the Cosmos DB example. + +For more information, see [Local Azure provisioning](../deployment/azure/local-provisioning.md). + +### No more exposed endpoint selection in AZD + +In previous previews, when an Aspire application was deployed to Azure, part of the initialization +process for Azure Developer CLI (`azd`) was to select the services that would be exposed externally +to the Internet. This included container-based resources that may or may not be hardened for Internet +access. + +In preview 5 we have worked with the Azure Developer CLI team to not display this prompt. Now, by default +endpoints on all resources only accessible only within the Azure Container Apps environment. To make http endpoints externally accessible on a resource you need to use the `WithExternalHttpEndpoints(...)` extension +to enable this explicitly in the application model. + +```csharp +builder.AddContainer("grafana", "grafana/grafana") + .WithHttpEndpoint(name: "http", targetPort: 3000) + .WithExternalHttpEndpoints(); +``` + +This will expose all endpoints defined on the resource. Alternatively it is possible to modify a single +endpoint when defining it: + +```csharp +var catalogDb = builder.AddPostgres("postgres") + .WithPgAdmin() + .WithEndpoint("tcp", endpoint => + { + // This callback can be used for mutating other + // values on existing endpoints as well. + endpoint.IsExternal = true; + }) + .AddDatabase("catalogdb"); +``` + +### Azure OpenAI + +The `AddAzureOpenAI(...)` extension method will now result in an Azure Open AI resource being provisioned in Azure. This support was missing from preview 4 but was added in preview 5 as part of the overall improvements to Azure resource usage for local development mentioned above. + +```csharp +var openai = builder + .AddAzureOpenAI("openai") + .AddDeployment(new("mydeployment", "gpt-35-turbo", "0613")); +``` + +> [!NOTE] +> Currently the Azure Open AI resource provider in Azure does not allow two model deployments at the same time. If you want to deploy multiple models within your application you will need to use separate Azure Open AI resources. + +### Azure Event Hubs + +Also in preview 5 we added support for Azure Event Hubs. You can add Azure Event Hubs to your application model using the `AddAzureEventHubs(...)` extension method. This will result in the creation of an Event Hubs namespace. Use the `AddHub(...)` method. + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +// required for the event processor client which will use the connectionName to get the connectionString. +var blob = builder.AddAzureStorage("ehstorage") + .AddBlobs("checkpoints"); + +var eventHub = builder.AddAzureEventHubs("eventhubns") + .AddEventHub("hub"); + +builder.AddProject("consumer") + .WithReference(eventHub) + .WithReference(blob); + +builder.AddProject("api") + .WithExternalHttpEndpoints() + .WithReference(eventHub); + +builder.Build().Run(); +``` + +As can be seen above the Event Hubs integration includes support for the Event Hubs processor architecture not just the consumer model (although either can be used). Refer to the README for the `Aspire.Azure.Messaging.EventHubs` package for examples of how to wire-up to the provisioned Event Hubs resource in your service projects. + +For more information, see [.NET Aspire Azure Event Hubs component](../messaging/azure-event-hubs-component.md). + +## AWS support + +Starting with .NET Aspire preview 5, you can use the [Aspire.Hosting.AWS](https://www.nuget.org/packages/Aspire.Hosting.AWS) NuGet package to express AWS resources in your application model. This package provides a set of extension methods that allow you to add AWS resources to your application model. + +### Configuring the AWS SDK for .NET + +The AWS profile and region the SDK should use can be configured using the `AddAWSSDKConfig` method. The following example creates a config using the dev profile from the `~/.aws/credentials` file and points the SDK to the +`us-west-2` region. + +```csharp +var awsConfig = builder.AddAWSSDKConfig() + .WithProfile("dev") + .WithRegion(RegionEndpoint.USWest2); +``` + +The configuration can be attached to projects using the `WithReference` method. This will set the `AWS_PROFILE` and `AWS_REGION` environment variables on the project to the profile and region configured by the `AddAWSSDKConfig` method. SDK service clients created in the project without explicitly setting the credentials and region will pick up these environment variables and use them to configure the service client. + +```csharp +builder.AddProject("Frontend") + .WithReference(awsConfig) +``` + +### Provision app resources with AWS CloudFormation + +AWS application resources like Amazon DynamoDB tables or Amazon Simple Queue Service (SQS) queues can be provisioning during AppHost startup using a CloudFormation template. + +In the AppHost project create either a JSON or YAML CloudFormation template. Here is an example template called `app-resources.template` that creates a queue and topic. + +```json +{ + "AWSTemplateFormatVersion" : "2010-09-09", + "Parameters" : { + "DefaultVisibilityTimeout" : { + "Type" : "Number", + "Description" : "The default visiblity timeout for messages in SQS queue." + } + }, + "Resources" : { + "ChatMessagesQueue" : { + "Type" : "AWS::SQS::Queue", + "Properties" : { + "VisibilityTimeout" : { "Ref" : "DefaultVisibilityTimeout" } + } + }, + "ChatTopic" : { + "Type" : "AWS::SNS::Topic", + "Properties" : { + "Subscription" : [ + {"Protocol" : "sqs", "Endpoint" : {"Fn::GetAtt" : [ "ChatMessagesQueue", "Arn"]}} + ] + } + } + }, + "Outputs" : { + "ChatMessagesQueueUrl" : { + "Value" : { "Ref" : "ChatMessagesQueue" } + }, + "ChatTopicArn" : { + "Value" : { "Ref" : "ChatTopic" } + } + } +} +``` + +In the AppHost the `AddAWSCloudFormationTemplate` method is used to register the CloudFormation resource. The first parameter, which is the Aspire resource name, is used as the CloudFormation stack name. If the template defines parameters the value can be provided using the `WithParameter` method. To configure what AWS account and region to deploy the CloudFormation stack, the `WithReference` method is used to associate a SDK configuration. + +```csharp +var awsResources = builder.AddAWSCloudFormationTemplate("AspireSampleDevResources", "app-resources.template") + .WithParameter("DefaultVisibilityTimeout", "30") + .WithReference(awsConfig); +``` + +The outputs of a CloudFormation stack can be associated to a project using the `WithReference` method. + +```csharp +builder.AddProject("Frontend") + .WithReference(awsResources); +``` + +The output parameters from the CloudFormation stack can be found in the `IConfiguration` under the `AWS:Resources` config section. The config section can be changed by setting the `configSection` parameter of the `WithReference` method associating the CloudFormation stack to the project. + +```csharp +var chatTopicArn = builder.Configuration["AWS:Resources:ChatTopicArn"]; +``` + +Alternatively a single CloudFormation stack output parameter can be assigned to an environment variable using the `GetOutput` method. + +```csharp +builder.AddProject("Frontend") + .WithEnvironment("ChatTopicArnEnv", awsResources.GetOutput("ChatTopicArn")) +``` + +### Import existing AWS resources + +To import AWS resources that were created by a CloudFormation stack outside of the AppHost the `AddAWSCloudFormationStack` method can be used. It will associated the outputs of the CloudFormation stack the same as the provisioning method `AddAWSCloudFormationTemplate`. + +```csharp +var awsResources = builder.AddAWSCloudFormationStack("ExistingStackName") + .WithReference(awsConfig); + +builder.AddProject("Frontend") + .WithReference(awsResources); +``` + +## Manifest changes + +The manifest format has been updated to support the new features in preview 5. The following sections outline the changes to the manifest format. + +### Volume in the manifest + +One of the features we have been wanted to add for some time is support +for volumes in the manifest. Volumes are essential for some scale out scenarios +around containers and for resiliency. + +Here is an example of a container in the manifest which defines multiple volumes: + +```json +{ + "type": "container.v0", + "image": "image/name:latest", + "volumes": + [ + { + "name": "myvolume", + "target": "/mount/here", + "readOnly": false + }, + { + "name": "myreadonlyvolume", + "target": "/mount/there", + "readOnly": true + }, + { + "target": "/mount/everywhere", + "readOnly": false + } + ] +} +``` + +> [!NOTE] +> The manifest can express both volumes and bind mounts. Bind mounts require a physical mapping from the host machine and may not work in all deployment scenarios. + +It's up to the deployment tool that you are using to deploy the Aspire application to interpret these volume mounts and the technology that supports them. For example when using the Azure Developer CLI (`azd`) an Azure Storage account is created which exposes an Azure Files endpointβ€”and this is bound to the Azure Container App. + +A tool that targets Kubernetes might use Kubernetes' own concept of volumes, or one of the many storage providers that Kubernetes supports. + +### Endpoints + +We have expended the level of support for defining multiple endpoints in the manifest. To support this we added the `"port":` field to items in the `"bindings":` property on `container.v0` and `project.v0` resources. This port defines the exposed port that the target deployment environment will use when exposing the service. If not explicitly provided this port is assigned (in sequence) at manifest generation time. + +> [!IMPORTANT] +> The `containerPort` property has been renamed to `targetPort` to make it a little bit more compute agnostic. + +We've added a new API to express endpoints as external endpoints in the manifest, with the `WithExternalHttpEndpoints` extension method. This is useful when you want to expose a service to the Internet. Consider the following JSON snippet before calling this API and then after as an example: + +**Before:** + +```json +"https": { + "scheme": "https", + "protocol": "tcp", + "transport": "http" +}, +``` + +**After:** + +```json +"https": { + "scheme": "https", + "protocol": "tcp", + "transport": "http", + "external": true +}, +``` + +We've worked with the Azure Developer CLI team to make sure `azd` supports these new endpoint features when deploying workloads to Azure Container Apps. + +### Docker build arguments + +We have added support for Docker build arguments in the manifest. This is useful when you want to pass in secrets or other configuration values at build time. Here is an example of Docker build arguments are represented in the manifest: + +```json +{ + "type": "dockerfile.v0", + "path": "NodeFrontend/Dockerfile", + "context": "NodeFrontend", + "buildArgs": { + "NODE_ENV": "production", + "WEATHER_API": null + }, + "env": { + "NODE_ENV": "production" + } +} +``` diff --git a/docs/whats-new/toc.yml b/docs/whats-new/toc.yml index be6cb1f92b..77c9446640 100644 --- a/docs/whats-new/toc.yml +++ b/docs/whats-new/toc.yml @@ -6,6 +6,8 @@ items: - name: Latest product updates expanded: true items: + - name: .NET Aspire preview 5 + href: preview-5.md - name: .NET Aspire preview 4 href: preview-4.md - name: .NET Aspire preview 3