From da8dc81fb0182332dc71200b46c6707456541593 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 20 Oct 2025 15:27:03 +0000
Subject: [PATCH 1/3] Initial plan
From 210bc8aeb733d4fe7b4a481e3c7032e327801b49 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 20 Oct 2025 15:38:39 +0000
Subject: [PATCH 2/3] Add conceptual articles for new .NET Extensions packages
Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com>
---
.../ambient-metadata-application.md | 340 +++++++++++++++
docs/core/extensions/async-state.md | 290 +++++++++++++
docs/core/extensions/audit-reports.md | 327 ++++++++++++++
.../dependency-injection-auto-activation.md | 188 +++++++++
docs/core/extensions/timeprovider-testing.md | 399 ++++++++++++++++++
docs/fundamentals/toc.yml | 15 +
6 files changed, 1559 insertions(+)
create mode 100644 docs/core/extensions/ambient-metadata-application.md
create mode 100644 docs/core/extensions/async-state.md
create mode 100644 docs/core/extensions/audit-reports.md
create mode 100644 docs/core/extensions/dependency-injection-auto-activation.md
create mode 100644 docs/core/extensions/timeprovider-testing.md
diff --git a/docs/core/extensions/ambient-metadata-application.md b/docs/core/extensions/ambient-metadata-application.md
new file mode 100644
index 0000000000000..5108dfe1aafae
--- /dev/null
+++ b/docs/core/extensions/ambient-metadata-application.md
@@ -0,0 +1,340 @@
+---
+title: Application ambient metadata
+description: Learn how to capture and flow application metadata for telemetry enrichment using Microsoft.Extensions.AmbientMetadata.Application in .NET.
+author: IEvangelist
+ms.author: dapine
+ms.date: 10/20/2025
+ms.topic: concept-article
+ai-usage: ai-assisted
+---
+
+# Application ambient metadata
+
+The [`Microsoft.Extensions.AmbientMetadata.Application`](https://www.nuget.org/packages/Microsoft.Extensions.AmbientMetadata.Application) NuGet package provides functionality to capture and flow application-level ambient metadata throughout your application. This metadata includes information such as the application name, version, deployment environment, and deployment ring, which is valuable for enriching telemetry, troubleshooting, and analysis.
+
+## Why use application metadata
+
+Application metadata provides essential context about your running application that can enhance observability:
+
+- **Telemetry enrichment**: Automatically add application details to logs, metrics, and traces.
+- **Troubleshooting**: Quickly identify which version of your application is experiencing issues.
+- **Environment identification**: Distinguish between Development, Staging, and Production environments in your telemetry.
+- **Deployment tracking**: Track issues across different deployment rings or regions.
+- **Consistent metadata**: Ensure all components in your application use the same metadata values.
+
+## Get started
+
+To get started with application metadata, install the [`Microsoft.Extensions.AmbientMetadata.Application`](https://www.nuget.org/packages/Microsoft.Extensions.AmbientMetadata.Application) NuGet package.
+
+### [.NET CLI](#tab/dotnet-cli)
+
+```dotnetcli
+dotnet add package Microsoft.Extensions.AmbientMetadata.Application
+```
+
+### [PackageReference](#tab/package-reference)
+
+```xml
+
+```
+
+---
+
+For more information, see [dotnet add package](../tools/dotnet-add-package.md) or [Manage package dependencies in .NET applications](../tools/dependencies.md).
+
+## Configure application metadata
+
+Application metadata can be configured through your application's configuration system. The package looks for metadata under the `ambientmetadata:application` configuration section by default.
+
+### Configure with appsettings.json
+
+Add the application metadata to your `appsettings.json` file:
+
+```json
+{
+ "ambientmetadata": {
+ "application": {
+ "ApplicationName": "MyWebApi",
+ "BuildVersion": "1.0.0",
+ "DeploymentRing": "Production",
+ "EnvironmentName": "Production"
+ }
+ }
+}
+```
+
+### Configure with IHostBuilder
+
+Use the extension method to register application metadata:
+
+```csharp
+using Microsoft.Extensions.Hosting;
+
+var builder = Host.CreateApplicationBuilder(args);
+
+builder.UseApplicationMetadata();
+
+var host = builder.Build();
+
+await host.RunAsync();
+```
+
+### Configure with IHostApplicationBuilder
+
+For applications using , such as ASP.NET Core applications:
+
+```csharp
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.Hosting;
+
+var builder = WebApplication.CreateBuilder(args);
+
+builder.UseApplicationMetadata();
+
+var app = builder.Build();
+
+app.MapGet("/", () => "Hello World!");
+
+app.Run();
+```
+
+## Access application metadata
+
+Once configured, you can inject and use the type:
+
+```csharp
+using Microsoft.Extensions.AmbientMetadata;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+var builder = Host.CreateApplicationBuilder(args);
+
+builder.UseApplicationMetadata();
+builder.Services.AddSingleton();
+
+var host = builder.Build();
+
+var metadataService = host.Services.GetRequiredService();
+metadataService.DisplayMetadata();
+
+public class MetadataService
+{
+ private readonly ApplicationMetadata _metadata;
+
+ public MetadataService(ApplicationMetadata metadata)
+ {
+ _metadata = metadata;
+ }
+
+ public void DisplayMetadata()
+ {
+ Console.WriteLine($"Application: {_metadata.ApplicationName}");
+ Console.WriteLine($"Version: {_metadata.BuildVersion}");
+ Console.WriteLine($"Environment: {_metadata.EnvironmentName}");
+ Console.WriteLine($"Deployment Ring: {_metadata.DeploymentRing}");
+ }
+}
+```
+
+## ApplicationMetadata properties
+
+The class includes the following properties:
+
+| Property | Description |
+|----------|-------------|
+| `ApplicationName` | The name of the application. |
+| `BuildVersion` | The version of the application build. |
+| `DeploymentRing` | The deployment ring or stage (for example, Canary, Production). |
+| `EnvironmentName` | The environment where the application is running (for example, Development, Staging, Production). |
+
+## Use with logging
+
+Application metadata is particularly useful for enriching log messages:
+
+```csharp
+using Microsoft.Extensions.AmbientMetadata;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+var builder = Host.CreateApplicationBuilder(args);
+
+builder.UseApplicationMetadata();
+builder.Services.AddSingleton();
+
+var host = builder.Build();
+
+var loggingService = host.Services.GetRequiredService();
+loggingService.LogWithMetadata();
+
+public class LoggingService
+{
+ private readonly ILogger _logger;
+ private readonly ApplicationMetadata _metadata;
+
+ public LoggingService(ILogger logger, ApplicationMetadata metadata)
+ {
+ _logger = logger;
+ _metadata = metadata;
+ }
+
+ public void LogWithMetadata()
+ {
+ _logger.LogInformation(
+ "Processing request in {ApplicationName} v{Version} ({Environment})",
+ _metadata.ApplicationName,
+ _metadata.BuildVersion,
+ _metadata.EnvironmentName);
+ }
+}
+```
+
+## Custom configuration section
+
+If you prefer to use a different configuration section name, specify it when calling `UseApplicationMetadata`:
+
+```csharp
+using Microsoft.Extensions.Hosting;
+
+var builder = Host.CreateApplicationBuilder(args);
+
+// Use custom configuration section
+builder.UseApplicationMetadata("myapp:metadata");
+
+var host = builder.Build();
+
+await host.RunAsync();
+```
+
+With this configuration, your settings would look like:
+
+```json
+{
+ "myapp": {
+ "metadata": {
+ "ApplicationName": "MyWebApi",
+ "BuildVersion": "1.0.0",
+ "DeploymentRing": "Production",
+ "EnvironmentName": "Production"
+ }
+ }
+}
+```
+
+## Environment-specific configuration
+
+You can provide different metadata for different environments using environment-specific configuration files:
+
+**appsettings.Development.json**:
+
+```json
+{
+ "ambientmetadata": {
+ "application": {
+ "ApplicationName": "MyWebApi",
+ "BuildVersion": "1.0.0-dev",
+ "DeploymentRing": "Development",
+ "EnvironmentName": "Development"
+ }
+ }
+}
+```
+
+**appsettings.Production.json**:
+
+```json
+{
+ "ambientmetadata": {
+ "application": {
+ "ApplicationName": "MyWebApi",
+ "BuildVersion": "1.0.0",
+ "DeploymentRing": "Production",
+ "EnvironmentName": "Production"
+ }
+ }
+}
+```
+
+## Practical example: Telemetry enrichment
+
+Here's a complete example showing how to use application metadata to enrich telemetry in an ASP.NET Core application:
+
+```csharp
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.AmbientMetadata;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+var builder = WebApplication.CreateBuilder(args);
+
+builder.UseApplicationMetadata();
+builder.Services.AddSingleton();
+
+var app = builder.Build();
+
+app.Use(async (context, next) =>
+{
+ var enricher = context.RequestServices.GetRequiredService();
+ enricher.EnrichRequest(context);
+ await next();
+});
+
+app.MapGet("/api/health", (ApplicationMetadata metadata) =>
+{
+ return Results.Ok(new
+ {
+ Status = "Healthy",
+ Application = metadata.ApplicationName,
+ Version = metadata.BuildVersion,
+ Environment = metadata.EnvironmentName
+ });
+});
+
+app.Run();
+
+public class TelemetryEnricher
+{
+ private readonly ILogger _logger;
+ private readonly ApplicationMetadata _metadata;
+
+ public TelemetryEnricher(
+ ILogger logger,
+ ApplicationMetadata metadata)
+ {
+ _logger = logger;
+ _metadata = metadata;
+ }
+
+ public void EnrichRequest(HttpContext context)
+ {
+ using var scope = _logger.BeginScope(new Dictionary
+ {
+ ["ApplicationName"] = _metadata.ApplicationName ?? "Unknown",
+ ["BuildVersion"] = _metadata.BuildVersion ?? "Unknown",
+ ["Environment"] = _metadata.EnvironmentName ?? "Unknown",
+ ["DeploymentRing"] = _metadata.DeploymentRing ?? "Unknown",
+ ["RequestPath"] = context.Request.Path.Value ?? "Unknown"
+ });
+
+ _logger.LogInformation("Request received");
+ }
+}
+```
+
+## Best practices
+
+When using application metadata, consider the following best practices:
+
+- **Automate version setting**: Use your CI/CD pipeline to automatically set the `BuildVersion` from your version control system or build number.
+- **Environment consistency**: Ensure environment names are consistent across all your applications for easier querying and filtering in telemetry systems.
+- **Configuration management**: Use environment-specific configuration files or environment variables to manage different metadata values across environments.
+- **Validate metadata**: Ensure required metadata fields are present during application startup to catch configuration issues early.
+- **Telemetry integration**: Integrate application metadata with your telemetry system (such as Application Insights or OpenTelemetry) for comprehensive observability.
+
+## See also
+
+- [Configuration in .NET](configuration.md)
+- [Configuration providers in .NET](configuration-providers.md)
+- [Logging in .NET](logging.md)
+- [Options pattern in .NET](options.md)
diff --git a/docs/core/extensions/async-state.md b/docs/core/extensions/async-state.md
new file mode 100644
index 0000000000000..b494844225673
--- /dev/null
+++ b/docs/core/extensions/async-state.md
@@ -0,0 +1,290 @@
+---
+title: Asynchronous state management
+description: Learn how to efficiently manage ambient state in asynchronous contexts using Microsoft.Extensions.AsyncState in .NET.
+author: IEvangelist
+ms.author: dapine
+ms.date: 10/20/2025
+ms.topic: concept-article
+ai-usage: ai-assisted
+---
+
+# Asynchronous state management
+
+The [`Microsoft.Extensions.AsyncState`](https://www.nuget.org/packages/Microsoft.Extensions.AsyncState) NuGet package provides functionality to store and retrieve objects within the current asynchronous context. This package offers performance and usability improvements over using directly, particularly when multiple objects need to be shared across asynchronous operations.
+
+## Why use AsyncState
+
+While .NET provides `AsyncLocal` for managing ambient data in asynchronous contexts, using it directly can have drawbacks:
+
+- **Performance**: Each `AsyncLocal` instance adds overhead. When multiple objects need to flow through async contexts, managing many `AsyncLocal` instances can impact performance.
+- **Abstraction**: Direct use of `AsyncLocal` couples your code to a specific implementation, making it harder to optimize or change in the future.
+- **Lifetime management**: The AsyncState package provides better control over the lifetime of ambient data through explicit APIs.
+
+The `Microsoft.Extensions.AsyncState` package addresses these concerns by providing:
+
+- An optimized implementation that reduces the number of `AsyncLocal` instances needed.
+- A clean abstraction for storing and retrieving ambient data.
+- Integration with dependency injection for easier testing and configuration.
+
+## Get started
+
+To get started with asynchronous state management, install the [`Microsoft.Extensions.AsyncState`](https://www.nuget.org/packages/Microsoft.Extensions.AsyncState) NuGet package.
+
+### [.NET CLI](#tab/dotnet-cli)
+
+```dotnetcli
+dotnet add package Microsoft.Extensions.AsyncState
+```
+
+### [PackageReference](#tab/package-reference)
+
+```xml
+
+```
+
+---
+
+For more information, see [dotnet add package](../tools/dotnet-add-package.md) or [Manage package dependencies in .NET applications](../tools/dependencies.md).
+
+## Register async state services
+
+Register the async state services with your dependency injection container using the extension method:
+
+```csharp
+using Microsoft.Extensions.DependencyInjection;
+
+var services = new ServiceCollection();
+
+services.AddAsyncState();
+
+var provider = services.BuildServiceProvider();
+```
+
+This registration makes the and interfaces available for dependency injection.
+
+## Use IAsyncContext
+
+The interface provides methods to get and set values in the current asynchronous context:
+
+```csharp
+using Microsoft.Extensions.AsyncState;
+using Microsoft.Extensions.DependencyInjection;
+
+var services = new ServiceCollection();
+services.AddAsyncState();
+
+var provider = services.BuildServiceProvider();
+var context = provider.GetRequiredService>();
+
+// Set a value in the async context
+var userContext = new UserContext { UserId = "12345", UserName = "Alice" };
+context.Set(userContext);
+
+// Retrieve the value
+if (context.TryGet(out var retrievedContext))
+{
+ Console.WriteLine($"User: {retrievedContext.UserName}");
+}
+
+public class UserContext
+{
+ public string UserId { get; set; } = string.Empty;
+ public string UserName { get; set; } = string.Empty;
+}
+```
+
+The value set in the context flows through asynchronous operations, making it available to all code executing within the same async context.
+
+## Use IAsyncState
+
+The interface provides a simpler property-based API for accessing async state:
+
+```csharp
+using Microsoft.Extensions.AsyncState;
+using Microsoft.Extensions.DependencyInjection;
+
+var services = new ServiceCollection();
+services.AddAsyncState();
+
+var provider = services.BuildServiceProvider();
+var asyncState = provider.GetRequiredService>();
+
+// Initialize the state
+asyncState.Initialize();
+
+// Set a value
+asyncState.Value = new RequestInfo
+{
+ RequestId = Guid.NewGuid().ToString(),
+ Timestamp = DateTimeOffset.UtcNow
+};
+
+// Access the value
+Console.WriteLine($"Request ID: {asyncState.Value.RequestId}");
+
+// Reset the state
+asyncState.Reset();
+
+public class RequestInfo
+{
+ public string RequestId { get; set; } = string.Empty;
+ public DateTimeOffset Timestamp { get; set; }
+}
+```
+
+## Practical example: Request correlation
+
+A common use case for async state is maintaining correlation information across an HTTP request:
+
+```csharp
+using Microsoft.Extensions.AsyncState;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+var builder = Host.CreateApplicationBuilder(args);
+
+builder.Services.AddAsyncState();
+builder.Services.AddSingleton();
+
+var host = builder.Build();
+
+var processor = host.Services.GetRequiredService();
+await processor.ProcessRequestAsync("ABC-123");
+
+public class RequestProcessor
+{
+ private readonly IAsyncContext _asyncContext;
+
+ public RequestProcessor(IAsyncContext asyncContext)
+ {
+ _asyncContext = asyncContext;
+ }
+
+ public async Task ProcessRequestAsync(string correlationId)
+ {
+ // Set correlation context at the beginning of request processing
+ _asyncContext.Set(new CorrelationContext { CorrelationId = correlationId });
+
+ // The correlation ID flows through all async operations
+ await Step1Async();
+ await Step2Async();
+ }
+
+ private async Task Step1Async()
+ {
+ await Task.Delay(100);
+
+ if (_asyncContext.TryGet(out var context))
+ {
+ Console.WriteLine($"Step 1 - Correlation ID: {context.CorrelationId}");
+ }
+ }
+
+ private async Task Step2Async()
+ {
+ await Task.Delay(100);
+
+ if (_asyncContext.TryGet(out var context))
+ {
+ Console.WriteLine($"Step 2 - Correlation ID: {context.CorrelationId}");
+ }
+ }
+}
+
+public class CorrelationContext
+{
+ public string CorrelationId { get; set; } = string.Empty;
+}
+```
+
+In this example, the correlation ID is set once at the beginning of request processing and is automatically available in all subsequent async operations without needing to pass it as a parameter.
+
+## ASP.NET Core integration
+
+In ASP.NET Core applications, you can use async state to flow request-specific information through your application:
+
+```csharp
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.AsyncState;
+using Microsoft.Extensions.DependencyInjection;
+
+var builder = WebApplication.CreateBuilder(args);
+
+builder.Services.AddAsyncState();
+builder.Services.AddScoped();
+
+var app = builder.Build();
+
+app.Use(async (context, next) =>
+{
+ var asyncContext = context.RequestServices.GetRequiredService>();
+
+ // Set request metadata at the beginning of the pipeline
+ asyncContext.Set(new RequestMetadata
+ {
+ RequestId = context.TraceIdentifier,
+ RequestPath = context.Request.Path,
+ StartTime = DateTimeOffset.UtcNow
+ });
+
+ await next();
+});
+
+app.MapGet("/api/data", async (RequestHandler handler) =>
+{
+ return await handler.GetDataAsync();
+});
+
+app.Run();
+
+public class RequestHandler
+{
+ private readonly IAsyncContext _asyncContext;
+
+ public RequestHandler(IAsyncContext asyncContext)
+ {
+ _asyncContext = asyncContext;
+ }
+
+ public async Task