diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index e3a5e7f6ad9cf..7c3fa1b632662 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -44,6 +44,7 @@ For snippets >6 lines: 1. All code should use the latest stable versions/features. 1. Create examples in both C# and Visual Basic unless the article referencing the snippet resides in the in the `csharp`, `fsharp`, and `visual-basic` language folders. 1. When you add code, use code comments sparingly because they don't get localized. You can use them to briefly clarify code-specific details (such as logic, parameters, or edge cases). Put any critical information and context in the markdown text of the referencing article. +1. IMPORTANT: For created code, always try to encapsulate it in an standalone executable (e.g. `dotnet fsi myFile.fsx` or `dotnet run myFile.cs`, add the necessary boilerplate/imports/usings where needed, and execute it.). Run it, and for every code snippet, include a PR commentary checking each code sample and proving what it has produced - this can be diagnostics, standard output, or a result value. That standalone file is just for the purpose of verification within copilot's execution environment, the published docs snippet should remain a subset as you would normally write to maximize clarity. ## File Naming @@ -69,4 +70,4 @@ When assigned an issue or directly given a task in GitHub: 3. Check for build warnings in the OpenPublishing.Build status check 4. If warnings exist: - Click "View Details" to open the build report - - Resolve any build warnings you introduced \ No newline at end of file + - Resolve any build warnings you introduced diff --git a/.github/workflows/dependabot-bot.yml b/.github/workflows/dependabot-bot.yml index 4037629d8e59f..2a68abe8e9bea 100644 --- a/.github/workflows/dependabot-bot.yml +++ b/.github/workflows/dependabot-bot.yml @@ -40,7 +40,9 @@ jobs: - name: "Print manual run reason" if: ${{ github.event_name == 'workflow_dispatch' }} run: | - echo "Reason: ${{ github.event.inputs.reason }}" + echo "Reason: $REASON" + env: + REASON: ${{ github.event.inputs.reason }} # Run the .NET dependabot-bot tool - name: dependabot-bot id: dependabot-bot diff --git a/.github/workflows/quest-bulk.yml b/.github/workflows/quest-bulk.yml index b8900f7c9c3b7..6fd60faafb767 100644 --- a/.github/workflows/quest-bulk.yml +++ b/.github/workflows/quest-bulk.yml @@ -35,7 +35,9 @@ jobs: - name: "Print manual bulk import run reason" if: ${{ github.event_name == 'workflow_dispatch' }} run: | - echo "Reason: ${{ github.event.inputs.reason }}" + echo "Reason: $REASON" + env: + REASON: ${{ github.event.inputs.reason }} - name: Azure OpenID Connect id: azure-oidc-auth diff --git a/.github/workflows/quest.yml b/.github/workflows/quest.yml index 4fbcd659d63f5..e30dbc5b9390a 100644 --- a/.github/workflows/quest.yml +++ b/.github/workflows/quest.yml @@ -36,8 +36,11 @@ jobs: - name: "Print manual run reason" if: ${{ github.event_name == 'workflow_dispatch' }} run: | - echo "Reason: ${{ github.event.inputs.reason }}" - echo "Issue number: ${{ github.event.inputs.issue }}" + echo "Reason: $REASON" + echo "Issue number: $ISSUENUMBER" + env: + REASON: ${{ github.event.inputs.reason }} + ISSUENUMBER: ${{ github.event.inputs.issue }} - name: Azure OpenID Connect id: azure-oidc-auth diff --git a/docs/ai/quickstarts/snippets/text-to-image/hosting/Program.cs b/docs/ai/quickstarts/snippets/text-to-image/hosting/Program.cs new file mode 100644 index 0000000000000..3f23739b7127e --- /dev/null +++ b/docs/ai/quickstarts/snippets/text-to-image/hosting/Program.cs @@ -0,0 +1,44 @@ +// +using Aspire.Azure.AI.OpenAI; +using Microsoft.Extensions.AI; +using OpenAI; + +WebApplicationBuilder builder = WebApplication.CreateBuilder(args); + +// Add the Azure OpenAI client using hosting integration. +AspireAzureOpenAIClientBuilder openai = builder.AddAzureOpenAIClient("openai"); +// + +// +// Register the image generator with dependency injection. +ImageGeneratorBuilder imageBuilder = builder.Services.AddImageGenerator(services => +{ + OpenAIClient openAiClient = services.GetRequiredService(); + OpenAI.Images.ImageClient imageClient = openAiClient.GetImageClient("gpt-image-1"); + #pragma warning disable MEAI001 // Type is for evaluation purposes only. + return imageClient.AsIImageGenerator(); + #pragma warning restore MEAI001 +}); +// + +// +imageBuilder.ConfigureOptions(options => +{ + options.MediaType = "image/png"; +}).UseLogging(); +// + +WebApplication app = builder.Build(); + +// +// Use the image generator in an endpoint. +app.MapPost("/generate-image", async (IImageGenerator generator, string prompt) => +{ + ImageGenerationResponse response = await generator.GenerateImagesAsync(prompt); + DataContent dataContent = response.Contents.OfType().First(); + + return Results.File(dataContent.Data.ToArray(), "image/png"); +}); +// + +app.Run(); diff --git a/docs/ai/quickstarts/snippets/text-to-image/hosting/Properties/launchSettings.json b/docs/ai/quickstarts/snippets/text-to-image/hosting/Properties/launchSettings.json new file mode 100644 index 0000000000000..a320d48079109 --- /dev/null +++ b/docs/ai/quickstarts/snippets/text-to-image/hosting/Properties/launchSettings.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:5219", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:7210;http://localhost:5219", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/docs/ai/quickstarts/snippets/text-to-image/hosting/TextToImageHosting.csproj b/docs/ai/quickstarts/snippets/text-to-image/hosting/TextToImageHosting.csproj new file mode 100644 index 0000000000000..63a42a18ed6ad --- /dev/null +++ b/docs/ai/quickstarts/snippets/text-to-image/hosting/TextToImageHosting.csproj @@ -0,0 +1,17 @@ + + + + net10.0 + enable + enable + $(NoWarn);MEAI001 + a9e545e9-e2b5-4e1b-81ce-217ca2d281c6 + + + + + + + + + diff --git a/docs/ai/quickstarts/snippets/text-to-image/hosting/appsettings.Development.json b/docs/ai/quickstarts/snippets/text-to-image/hosting/appsettings.Development.json new file mode 100644 index 0000000000000..0c208ae9181e5 --- /dev/null +++ b/docs/ai/quickstarts/snippets/text-to-image/hosting/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/docs/ai/quickstarts/snippets/text-to-image/hosting/appsettings.json b/docs/ai/quickstarts/snippets/text-to-image/hosting/appsettings.json new file mode 100644 index 0000000000000..2a36d2d501808 --- /dev/null +++ b/docs/ai/quickstarts/snippets/text-to-image/hosting/appsettings.json @@ -0,0 +1,12 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "ConnectionStrings": { + "openai": "Endpoint=https://your-endpoint.com/;Key=your-api-key" + } +} diff --git a/docs/ai/quickstarts/text-to-image.md b/docs/ai/quickstarts/text-to-image.md index 326891d94041e..89acb7f041ae7 100644 --- a/docs/ai/quickstarts/text-to-image.md +++ b/docs/ai/quickstarts/text-to-image.md @@ -100,6 +100,65 @@ You can customize image generation by providing other options such as size, resp - : The callback that creates the raw representation of the image generation options from an underlying implementation. - : Options are , , and . +## Use hosting integration + +When you build web apps or hosted services, you can integrate image generation using dependency injection and hosting patterns. This approach provides better lifecycle management, configuration integration, and testability. + +### Configure hosting services + +The `Aspire.Azure.AI.OpenAI` package provides extension methods to register Azure OpenAI services with your application's dependency injection container: + +1. Add the necessary packages to your web application: + + ```dotnetcli + dotnet add package Aspire.Azure.AI.OpenAI --prerelease + dotnet add package Azure.AI.OpenAI + dotnet add package Microsoft.Extensions.AI.OpenAI --prerelease + ``` + +1. Configure the Azure OpenAI client and image generator in your `Program.cs` file: + + :::code language="csharp" source="snippets/text-to-image/hosting/Program.cs" id="SnippetSetup"::: + + The method registers the Azure OpenAI client with dependency injection. The connection string (named `"openai"`) is retrieved from configuration, typically from `appsettings.json` or environment variables: + + ```json + { + "ConnectionStrings": { + "openai": "Endpoint=https://your-resource-name.openai.azure.com/;Key=your-api-key" + } + } + ``` + +1. Register the service with dependency injection: + + :::code language="csharp" source="snippets/text-to-image/hosting/Program.cs" id="SnippetAddImageGenerator"::: + + The method registers the image generator as a singleton service that can be injected into controllers, services, or minimal API endpoints. + +1. Add options and logging:: + + :::code language="csharp" source="snippets/text-to-image/hosting/Program.cs" id="SnippetConfigureOptions"::: + + The preceding code: + + - Configures options by calling the extension method on the . This method configures the to be passed to the next generator in the pipeline. + - Adds logging to the image generator pipeline by calling the extension method. + +### Use the image generator in endpoints + +Once registered, you can inject `IImageGenerator` into your endpoints or services: + +:::code language="csharp" source="snippets/text-to-image/hosting/Program.cs" id="SnippetUseImageGenerator"::: + +This hosting approach provides several benefits: + +- **Configuration management**: Connection strings and settings are managed through the .NET configuration system. +- **Dependency injection**: The image generator is available throughout your application via DI. +- **Lifecycle management**: Services are properly initialized and disposed of by the hosting infrastructure. +- **Testability**: Mock implementations can be easily substituted for testing. +- **Integration with .NET Aspire**: When using .NET Aspire, the `AddAzureOpenAIClient` method integrates with service discovery and telemetry. + ## Best practices When implementing text-to-image generation in your applications, consider these best practices: diff --git a/docs/azure/includes/dotnet-all.md b/docs/azure/includes/dotnet-all.md index ecb9ed9db6468..49169ff2093c2 100644 --- a/docs/azure/includes/dotnet-all.md +++ b/docs/azure/includes/dotnet-all.md @@ -124,7 +124,7 @@ | WCF Storage Queues | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/Microsoft.WCF.Azure.StorageQueues/1.0.0-beta.1) | [docs](/dotnet/api/overview/azure/Microsoft.WCF.Azure.StorageQueues-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Microsoft.WCF.Azure.StorageQueues_1.0.0-beta.1/sdk/extension-wcf/Microsoft.WCF.Azure.StorageQueues/) | | Web PubSub | NuGet [1.6.0](https://www.nuget.org/packages/Azure.Messaging.WebPubSub/1.6.0) | [docs](/dotnet/api/overview/azure/Messaging.WebPubSub-readme) | GitHub [1.6.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Messaging.WebPubSub_1.6.0/sdk/webpubsub/Azure.Messaging.WebPubSub/) | | Web PubSub Client | NuGet [1.0.0](https://www.nuget.org/packages/Azure.Messaging.WebPubSub.Client/1.0.0) | [docs](/dotnet/api/overview/azure/Messaging.WebPubSub.Client-readme) | GitHub [1.0.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Messaging.WebPubSub.Client_1.0.0/sdk/webpubsub/Azure.Messaging.WebPubSub.Client/) | -| Azure client library integration for ASP.NET Core | NuGet [1.13.0](https://www.nuget.org/packages/Microsoft.Extensions.Azure/1.13.0) | [docs](/dotnet/api/overview/azure/Microsoft.Extensions.Azure-readme) | GitHub [1.13.0](https://github.com/Azure/azure-sdk-for-net/tree/Microsoft.Extensions.Azure_1.13.0/sdk/extensions/Microsoft.Extensions.Azure/) | +| Azure client library integration for ASP.NET Core | NuGet [1.13.1](https://www.nuget.org/packages/Microsoft.Extensions.Azure/1.13.1) | [docs](/dotnet/api/overview/azure/Microsoft.Extensions.Azure-readme) | GitHub [1.13.1](https://github.com/Azure/azure-sdk-for-net/tree/Microsoft.Extensions.Azure_1.13.1/sdk/extensions/Microsoft.Extensions.Azure/) | | Blob Storage Key Store for .NET Data Protection | NuGet [1.5.1](https://www.nuget.org/packages/Azure.Extensions.AspNetCore.DataProtection.Blobs/1.5.1) | [docs](/dotnet/api/overview/azure/Extensions.AspNetCore.DataProtection.Blobs-readme) | GitHub [1.5.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Extensions.AspNetCore.DataProtection.Blobs_1.5.1/sdk/extensions/Azure.Extensions.AspNetCore.DataProtection.Blobs/) | | CloudNative CloudEvents with Event Grid | NuGet [1.0.0](https://www.nuget.org/packages/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/1.0.0) | [docs](/dotnet/api/overview/azure/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents-readme) | GitHub [1.0.0](https://github.com/Azure/azure-sdk-for-net/tree/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents_1.0.0/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/) | | Core - Client - Spatial | NuGet [1.1.0](https://www.nuget.org/packages/Microsoft.Azure.Core.Spatial/1.1.0)
NuGet [1.2.0-beta.1](https://www.nuget.org/packages/Microsoft.Azure.Core.Spatial/1.2.0-beta.1) | [docs](/dotnet/api/overview/azure/Microsoft.Azure.Core.Spatial-readme) | GitHub [1.1.0](https://github.com/Azure/azure-sdk-for-net/tree/Microsoft.Azure.Core.Spatial_1.1.0/sdk/core/Microsoft.Azure.Core.Spatial/)
GitHub [1.2.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Microsoft.Azure.Core.Spatial_1.2.0-beta.1/sdk/core/Microsoft.Azure.Core.Spatial/) | diff --git a/docs/azure/includes/dotnet-new.md b/docs/azure/includes/dotnet-new.md index 4327af08ac7b5..1f3be21bfd64b 100644 --- a/docs/azure/includes/dotnet-new.md +++ b/docs/azure/includes/dotnet-new.md @@ -134,7 +134,7 @@ | WCF Storage Queues | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/Microsoft.WCF.Azure.StorageQueues/1.0.0-beta.1) | [docs](/dotnet/api/overview/azure/Microsoft.WCF.Azure.StorageQueues-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Microsoft.WCF.Azure.StorageQueues_1.0.0-beta.1/sdk/extension-wcf/Microsoft.WCF.Azure.StorageQueues/) | | Web PubSub | NuGet [1.6.0](https://www.nuget.org/packages/Azure.Messaging.WebPubSub/1.6.0) | [docs](/dotnet/api/overview/azure/Messaging.WebPubSub-readme) | GitHub [1.6.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Messaging.WebPubSub_1.6.0/sdk/webpubsub/Azure.Messaging.WebPubSub/) | | Web PubSub Client | NuGet [1.0.0](https://www.nuget.org/packages/Azure.Messaging.WebPubSub.Client/1.0.0) | [docs](/dotnet/api/overview/azure/Messaging.WebPubSub.Client-readme) | GitHub [1.0.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Messaging.WebPubSub.Client_1.0.0/sdk/webpubsub/Azure.Messaging.WebPubSub.Client/) | -| Azure client library integration for ASP.NET Core | NuGet [1.13.0](https://www.nuget.org/packages/Microsoft.Extensions.Azure/1.13.0) | [docs](/dotnet/api/overview/azure/Microsoft.Extensions.Azure-readme) | GitHub [1.13.0](https://github.com/Azure/azure-sdk-for-net/tree/Microsoft.Extensions.Azure_1.13.0/sdk/extensions/Microsoft.Extensions.Azure/) | +| Azure client library integration for ASP.NET Core | NuGet [1.13.1](https://www.nuget.org/packages/Microsoft.Extensions.Azure/1.13.1) | [docs](/dotnet/api/overview/azure/Microsoft.Extensions.Azure-readme) | GitHub [1.13.1](https://github.com/Azure/azure-sdk-for-net/tree/Microsoft.Extensions.Azure_1.13.1/sdk/extensions/Microsoft.Extensions.Azure/) | | Blob Storage Key Store for .NET Data Protection | NuGet [1.5.1](https://www.nuget.org/packages/Azure.Extensions.AspNetCore.DataProtection.Blobs/1.5.1) | [docs](/dotnet/api/overview/azure/Extensions.AspNetCore.DataProtection.Blobs-readme) | GitHub [1.5.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Extensions.AspNetCore.DataProtection.Blobs_1.5.1/sdk/extensions/Azure.Extensions.AspNetCore.DataProtection.Blobs/) | | CloudNative CloudEvents with Event Grid | NuGet [1.0.0](https://www.nuget.org/packages/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/1.0.0) | [docs](/dotnet/api/overview/azure/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents-readme) | GitHub [1.0.0](https://github.com/Azure/azure-sdk-for-net/tree/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents_1.0.0/sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/) | | Core - Client - Spatial | NuGet [1.1.0](https://www.nuget.org/packages/Microsoft.Azure.Core.Spatial/1.1.0)
NuGet [1.2.0-beta.1](https://www.nuget.org/packages/Microsoft.Azure.Core.Spatial/1.2.0-beta.1) | [docs](/dotnet/api/overview/azure/Microsoft.Azure.Core.Spatial-readme) | GitHub [1.1.0](https://github.com/Azure/azure-sdk-for-net/tree/Microsoft.Azure.Core.Spatial_1.1.0/sdk/core/Microsoft.Azure.Core.Spatial/)
GitHub [1.2.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Microsoft.Azure.Core.Spatial_1.2.0-beta.1/sdk/core/Microsoft.Azure.Core.Spatial/) | diff --git a/docs/core/compatibility/10.0.md b/docs/core/compatibility/10.0.md index 385de81807dd7..994060f75659e 100644 --- a/docs/core/compatibility/10.0.md +++ b/docs/core/compatibility/10.0.md @@ -78,6 +78,7 @@ If you're migrating an app to .NET 10, the breaking changes listed here might af | Title | Type of change | |-------|---------------------| | [BackgroundService runs all of ExecuteAsync as a Task](extensions/10.0/backgroundservice-executeasync-task.md) | Behavioral change | +| [Fix issues in GetKeyedService() and GetKeyedServices() with AnyKey](extensions/10.0/getkeyedservice-anykey.md) | Behavioral change | | [Null values preserved in configuration](extensions/10.0/configuration-null-values-preserved.md) | Behavioral change | | [Message no longer duplicated in Console log output](extensions/10.0/console-json-logging-duplicate-messages.md) | Behavioral change | | [ProviderAliasAttribute moved to Microsoft.Extensions.Logging.Abstractions assembly](extensions/10.0/provideraliasattribute-moved-assembly.md) | Source incompatible | diff --git a/docs/core/compatibility/extensions/10.0/getkeyedservice-anykey.md b/docs/core/compatibility/extensions/10.0/getkeyedservice-anykey.md new file mode 100644 index 0000000000000..835a5fcb1ba81 --- /dev/null +++ b/docs/core/compatibility/extensions/10.0/getkeyedservice-anykey.md @@ -0,0 +1,57 @@ +--- +title: "Breaking change: Fix issues in GetKeyedService() and GetKeyedServices() with AnyKey" +description: "Learn about the breaking change in .NET 10 where GetKeyedService() and GetKeyedServices() behavior changed when using KeyedService.AnyKey as the lookup key." +ms.date: 11/19/2025 +ai-usage: ai-assisted +--- + +# Fix issues in GetKeyedService() and GetKeyedServices() with AnyKey + +The behavior of the and methods in the `Microsoft.Extensions.DependencyInjection` library was updated to address inconsistencies in handling the registration. Specifically, `GetKeyedService()` now throws an exception when you attempt to resolve a single service using `KeyedService.AnyKey` as the lookup key, and `GetKeyedServices()` (plural) no longer returns `AnyKey` registrations when queried with `KeyedService.AnyKey`. + +## Version introduced + +.NET 10 + +## Previous behavior + +Previously, calling `GetKeyedService()` with `KeyedService.AnyKey` returned a service registration associated with `AnyKey`. This behavior was inconsistent with the intended semantics, as `AnyKey` is meant to represent a special case of keyed services rather than a specific registration. + +Calling `GetKeyedServices()` with `KeyedService.AnyKey` returned all registrations for `AnyKey`. This behavior was also inconsistent with the intended semantics, as `AnyKey` is not meant to enumerate all keyed services. + +## New behavior + +Starting in .NET 10, calling `GetKeyedService()` with `KeyedService.AnyKey` throws an . This ensures that `AnyKey` can't be used to resolve a single service, as it's intended to represent a special case rather than a specific key. + +```csharp +var service = serviceProvider.GetKeyedService(typeof(IMyService), KeyedService.AnyKey); +// Throws InvalidOperationException: "Cannot resolve a single service using AnyKey." +``` + +Additionally, calling `GetKeyedServices()` with `KeyedService.AnyKey` no longer returns registrations for `AnyKey`. Instead, it adheres to the updated semantics where `AnyKey` is treated as a special case and doesn't enumerate services. + +```csharp +var services = serviceProvider.GetKeyedServices(typeof(IMyService), KeyedService.AnyKey); +// Returns an empty collection. +``` + +## Type of breaking change + +This change is a [behavioral change](../../categories.md#behavioral-change). + +## Reason for change + +The previous behavior of `GetKeyedService()` and `GetKeyedServices()` with `KeyedService.AnyKey` was inconsistent with the intended semantics of `AnyKey`. The changes were introduced to ensure that `AnyKey` is treated as a special case and can't be used to resolve a single service, and to prevent `GetKeyedServices()` from returning `AnyKey` registrations when queried with `AnyKey`. These updates improve the predictability and correctness of the `Microsoft.Extensions.DependencyInjection` library's behavior when working with keyed services. For more details, see the [pull request](https://github.com/dotnet/runtime/pull/113137) and the associated [merge commit](https://github.com/dotnet/runtime/commit/deee462fc8421a7e18b8916eb5a5eacb9d09169d). + +## Recommended action + +If you use `GetKeyedService()` or `GetKeyedServices()` with `KeyedService.AnyKey`, review your code and update it to use specific keys instead of `AnyKey`. + +For `GetKeyedService(KeyedService.AnyKey)`, replace calls to `GetKeyedService()` with `KeyedService.AnyKey` with specific keys or alternative logic to handle service resolution. + +For `GetKeyedServices(KeyedService.AnyKey)`, replace calls to `GetKeyedServices()` with `KeyedService.AnyKey` with calls that use specific keys, or update your logic to enumerate only the services you intend to retrieve. + +## Affected APIs + +- +- diff --git a/docs/core/compatibility/toc.yml b/docs/core/compatibility/toc.yml index c06b689bde9a1..98e7aa1f57fe9 100644 --- a/docs/core/compatibility/toc.yml +++ b/docs/core/compatibility/toc.yml @@ -90,6 +90,8 @@ items: items: - name: BackgroundService runs all of ExecuteAsync as a Task href: extensions/10.0/backgroundservice-executeasync-task.md + - name: Fix issues in GetKeyedService() and GetKeyedServices() with AnyKey + href: extensions/10.0/getkeyedservice-anykey.md - name: Message no longer duplicated in Console log output href: extensions/10.0/console-json-logging-duplicate-messages.md - name: Null values preserved in configuration diff --git a/docs/core/diagnostics/observability-prgrja-example.md b/docs/core/diagnostics/observability-prgrja-example.md index d3506bb961a08..263d5e0a8f143 100644 --- a/docs/core/diagnostics/observability-prgrja-example.md +++ b/docs/core/diagnostics/observability-prgrja-example.md @@ -36,21 +36,16 @@ The following code defines a new metric (`greetings.count`) for the number of ti Use the NuGet Package Manager or command line to add the following NuGet packages: -```xml - - - - - - - - - +```dotnetcli +dotnet add package OpenTelemetry.Exporter.Console +dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol +dotnet add package OpenTelemetry.Exporter.Prometheus.AspNetCore +dotnet add package OpenTelemetry.Exporter.Zipkin +dotnet add package OpenTelemetry.Extensions.Hosting +dotnet add package OpenTelemetry.Instrumentation.AspNetCore +dotnet add package OpenTelemetry.Instrumentation.Http ``` -> [!NOTE] -> Use the latest versions, as the OTel APIs are constantly evolving. - ## 5. Configure OpenTelemetry with the correct providers :::code language="csharp" source="snippets/OTel-Prometheus-Grafana-Jaeger/csharp/Program.cs" id="Snippet_OTEL"::: diff --git a/docs/core/runtime-config/debugging-profiling.md b/docs/core/runtime-config/debugging-profiling.md index 13cdea3ccba28..60f9de723910f 100644 --- a/docs/core/runtime-config/debugging-profiling.md +++ b/docs/core/runtime-config/debugging-profiling.md @@ -9,6 +9,9 @@ This article details the settings you can use to configure .NET debugging and pr [!INCLUDE [complus-prefix](../../../includes/complus-prefix.md)] +> [!NOTE] +> Starting in .NET 11, profiler environment variables now support both `DOTNET` and `CORECLR` prefixes. The `DOTNET` prefix is the new standard, while `CORECLR` is maintained for backwards compatibility and might be removed in the future. + ## Enable diagnostics - Configures whether the debugger, the profiler, and EventPipe diagnostics are enabled or disabled. @@ -23,11 +26,12 @@ This article details the settings you can use to configure .NET debugging and pr - Configures whether profiling is enabled for the currently running process. - If you omit this setting, profiling is disabled. This is equivalent to setting the value to `0`. +- To load a profiler, in addition to enabling profiling, the profiler GUID and profiler location also need to be configured using these settings. | | Setting name | Values | | - | - | - | | **runtimeconfig.json** | N/A | N/A | -| **Environment variable** | `CORECLR_ENABLE_PROFILING` | `0` - disabled
`1` - enabled | +| **Environment variable** | `CORECLR_ENABLE_PROFILING` or `DOTNET_ENABLE_PROFILING` | `0` - disabled
`1` - enabled | ## Profiler GUID @@ -36,19 +40,28 @@ This article details the settings you can use to configure .NET debugging and pr | | Setting name | Values | | - | - | - | | **runtimeconfig.json** | N/A | N/A | -| **Environment variable** | `CORECLR_PROFILER` | *string-guid* | +| **Environment variable** | `CORECLR_PROFILER` or `DOTNET_PROFILER` | *string-guid* | ## Profiler location +Once profiling is enabled, the profiler can be loaded in two ways: with environment variables (cross-plat) or through the registry (Windows only). The profiler path environment variables take precedence over any COM library path in the registry if both are specified. + +### Environment variable (cross-plat) + - Specifies the path to the profiler DLL to load into the currently running process (or 32-bit or 64-bit process). - If more than one variable is set, the bitness-specific variables take precedence. They specify which bitness of profiler to load. -- For more information, see [Finding the profiler library](https://github.com/dotnet/runtime/blob/main/docs/design/coreclr/profiling/Profiler%20Loading.md). | | Setting name | Values | | - | - | - | -| **Environment variable** | `CORECLR_PROFILER_PATH` | *string-path* | -| **Environment variable** | `CORECLR_PROFILER_PATH_32` | *string-path* | -| **Environment variable** | `CORECLR_PROFILER_PATH_64` | *string-path* | +| **Environment variable** | `CORECLR_PROFILER_PATH` or `DOTNET_PROFILER_PATH` | *string-path* | +| **Environment variable** | `CORECLR_PROFILER_PATH_32` or `DOTNET_PROFILER_PATH_32` | *string-path* | +| **Environment variable** | `CORECLR_PROFILER_PATH_64` or `DOTNET_PROFILER_PATH_64` | *string-path* | +| **Environment variable** | `CORECLR_PROFILER_PATH_ARM32` or `DOTNET_PROFILER_PATH_ARM32` | *string-path* | +| **Environment variable** | `CORECLR_PROFILER_PATH_ARM64` or `DOTNET_PROFILER_PATH_ARM64` | *string-path* | + +### Through the registry (Windows only) + +When the `DOTNET_PROFILER_PATH*` [environment variables](#environment-variable-cross-plat) aren't set while running on Windows, coreclr looks up the CLSID from `DOTNET_PROFILER` in the registry to find the full path to the profiler's DLL. Just like with any COM server DLL, the profiler's CLSID is looked up under HKEY_CLASSES_ROOT, which merges the classes from HKLM and HKCU. ## Export perf maps and jit dumps diff --git a/docs/core/testing/media/test-azdoreport-failure.png b/docs/core/testing/media/test-azdoreport-failure.png new file mode 100644 index 0000000000000..bc31b5c5a6d20 Binary files /dev/null and b/docs/core/testing/media/test-azdoreport-failure.png differ diff --git a/docs/core/testing/microsoft-testing-platform-extensions-test-reports.md b/docs/core/testing/microsoft-testing-platform-extensions-test-reports.md index d4c5fe6392844..c3de71910cd24 100644 --- a/docs/core/testing/microsoft-testing-platform-extensions-test-reports.md +++ b/docs/core/testing/microsoft-testing-platform-extensions-test-reports.md @@ -16,9 +16,6 @@ A test report is a file that contains information about the execution and outcom The Visual Studio test result file (or TRX) is the default format for publishing test results. This extension is shipped as part of [Microsoft.Testing.Extensions.TrxReport](https://nuget.org/packages/Microsoft.Testing.Extensions.TrxReport) package. -> [!IMPORTANT] -> The package is shipped with Microsoft .NET library closed-source free to use licensing model. - The available options as follows: | Option | Description | @@ -27,3 +24,33 @@ The available options as follows: | `--report-trx-filename` | The name of the generated TRX report. The default name matches the following format `__.trx`. | The report is saved inside the default _TestResults_ folder that can be specified through the `--results-directory` command line argument. + +## Azure DevOps reports + +Azure DevOps report plugin enhances test running for developers that host their code on GitHub, but build on Azure DevOps build agents. It adds additional information to failures to show failure directly in GitHub PR. + +![Error annotation in GitHub PR files view](./media/test-azdoreport-failure.png) + +The extension is shipped in [Microsoft.Testing.Extensions.AzureDevOpsReport](https://nuget.org/packages/Microsoft.Testing.Extensions.AzureDevOpsReport) package. + +The available options as follows: + +| Option | Description | +|--|--| +| `--report-azdo` | Enable outputting errors / warnings in CI builds. | +| `--report-azdo-severity` | Severity to use for the reported event. Options are: `error` (default) and `warning`. | + +The extension automatically detects that it is running in continuous integration (CI) environment by checking the `TF_BUILD` environment variable. + +### Determining the line to report + +To highlight the correct line in code where failure occurred, AzureDevOps report plugin searches the error stacktrace for a file that exists in the current repository. + +To determine this it: + +- finds the repository root, this is done by searching the `.git` directory closest to the location from where the test application is started (as determined by `AppContext.BaseDirectory`). +- finds the first line in stack trace that has file location and line (the library needs to have debug symbols). +- excludes all files that end with `Assert.cs` to avoid showing details of your assertion implementations or wrappers. +- excludes all files that don't exist on disk (typically those are lines from external libraries that ship debug symbols e.g. MSTest). + +(These are internal details that serve to aid debugging the behavior and might change in the future.) diff --git a/docs/core/testing/unit-testing-fsharp-with-xunit.md b/docs/core/testing/unit-testing-fsharp-with-xunit.md index 064366680b4e4..b1b5c8a8e5261 100644 --- a/docs/core/testing/unit-testing-fsharp-with-xunit.md +++ b/docs/core/testing/unit-testing-fsharp-with-xunit.md @@ -62,6 +62,9 @@ The test project requires other packages to create and run unit tests. `dotnet n dotnet reference add ../MathService/MathService.fsproj ``` +> [!TIP] +> If you're using .NET 9 SDK or earlier, use the "verb first" form (`dotnet add reference`) instead. The "noun first" form was introduced in .NET 10. + You can see the entire file in the [samples repository](https://github.com/dotnet/samples/blob/main/core/getting-started/unit-testing-with-fsharp/MathService.Tests/MathService.Tests.fsproj) on GitHub. You have the following final solution layout: diff --git a/docs/core/testing/unit-testing-mstest-sdk.md b/docs/core/testing/unit-testing-mstest-sdk.md index df8566a175799..df51a1d4f10a1 100644 --- a/docs/core/testing/unit-testing-mstest-sdk.md +++ b/docs/core/testing/unit-testing-mstest-sdk.md @@ -104,6 +104,7 @@ You can set the profile using the property `TestingExtensionsProfile` with one o * [Hot Reload](./microsoft-testing-platform-extensions-hosting.md#hot-reload) * [Retry](./microsoft-testing-platform-extensions-policy.md#retry) * [Trx Report](./microsoft-testing-platform-extensions-test-reports.md#visual-studio-test-reports) + * [AzureDevOpsReport](./microsoft-testing-platform-extensions-test-reports.md#azure-devops-reports) Here's a full example, using the `None` profile: @@ -118,17 +119,19 @@ Here's a full example, using the `None` profile: ``` -| Extension/Profile | None | Default | AllMicrosoft | -|-------------------------------------------------------------------------------------------|:----:|:------------------:|:--------------------------------------:| -| [Code Coverage](https://www.nuget.org/packages/Microsoft.Testing.Extensions.CodeCoverage) | | :heavy_check_mark: | :heavy_check_mark: | -| [Crash Dump](https://www.nuget.org/packages/Microsoft.Testing.Extensions.CrashDump) | | | :heavy_check_mark: | -| [Fakes](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Fakes) | | | :heavy_check_mark:† | -| [Hang Dump](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HangDump) | | | :heavy_check_mark: | -| [Hot Reload](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HotReload) | | | :heavy_check_mark: | -| [Retry](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry) | | | :heavy_check_mark: | -| [Trx](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport) | | :heavy_check_mark: | :heavy_check_mark: | - -† MSTest.Sdk 3.7.0+ +| Extension/Profile | None | Default | AllMicrosoft | +| ------------------------------------------------------------------------------------------------- | :---: | :----------------: | :-----------------: | +| [Code Coverage](https://www.nuget.org/packages/Microsoft.Testing.Extensions.CodeCoverage) | | :heavy_check_mark: | :heavy_check_mark: | +| [Crash Dump](https://www.nuget.org/packages/Microsoft.Testing.Extensions.CrashDump) | | | :heavy_check_mark: | +| [Fakes](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Fakes) | | | :heavy_check_mark:¹ | +| [Hang Dump](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HangDump) | | | :heavy_check_mark: | +| [Hot Reload](https://www.nuget.org/packages/Microsoft.Testing.Extensions.HotReload) | | | :heavy_check_mark: | +| [Retry](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Retry) | | | :heavy_check_mark: | +| [Trx](https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport) | | :heavy_check_mark: | :heavy_check_mark: | +| [AzureDevOpsReport](./microsoft-testing-platform-extensions-test-reports.md#azure-devops-reports) | | | :heavy_check_mark:² | + +¹ MSTest.Sdk 3.7.0+ +² MSTest.Sdk 3.11.0+ ### Enable or disable extensions diff --git a/docs/core/tools/enable-tab-autocomplete.md b/docs/core/tools/enable-tab-autocomplete.md index 5ea6ce26c1f26..5ae6e350908a9 100644 --- a/docs/core/tools/enable-tab-autocomplete.md +++ b/docs/core/tools/enable-tab-autocomplete.md @@ -20,10 +20,10 @@ Starting with .NET 10, the .NET CLI includes native shell completion scripts tha ### Generate completion scripts -Use the `dotnet completions generate` command to generate a completion script for your shell: +Use the `dotnet completions script` command to generate a completion script for your shell: ```console -dotnet completions generate [SHELL] +dotnet completions script [SHELL] ``` The `[SHELL]` parameter accepts one of the following values: @@ -62,7 +62,7 @@ Add the appropriate command to your shell's profile to enable native completions Add the following line to your PowerShell profile (`$PROFILE`): ```powershell -dotnet completions generate pwsh | Out-String | Invoke-Expression +dotnet completions script pwsh | Out-String | Invoke-Expression ``` #### Bash @@ -70,7 +70,7 @@ dotnet completions generate pwsh | Out-String | Invoke-Expression Add the following line to your `.bashrc` file: ```bash -eval "$(dotnet completions generate bash)" +eval "$(dotnet completions script bash)" ``` #### Zsh @@ -78,7 +78,7 @@ eval "$(dotnet completions generate bash)" Add the following line to your `.zshrc` file: ```zsh -eval "$(dotnet completions generate zsh)" +eval "$(dotnet completions script zsh)" ``` #### Fish @@ -86,7 +86,7 @@ eval "$(dotnet completions generate zsh)" Add the following line to your `config.fish` file: ```fish -dotnet completions generate fish | source +dotnet completions script fish | source ``` #### Nushell @@ -94,7 +94,7 @@ dotnet completions generate fish | source Add the following to the beginning of your `config.nu` file: ```nu -dotnet completions generate nushell | save -f ~/.local/share/nushell/completions/dotnet.nu +dotnet completions script nushell | save -f ~/.local/share/nushell/completions/dotnet.nu use ~/.local/share/nushell/completions/dotnet.nu * ``` diff --git a/docs/core/tools/global-json.md b/docs/core/tools/global-json.md index cf343c3851629..52d89063aa5c1 100644 --- a/docs/core/tools/global-json.md +++ b/docs/core/tools/global-json.md @@ -12,18 +12,18 @@ ai-usage: ai-assisted The *global.json* file allows you to define which .NET SDK version is used when you run .NET CLI commands. Selecting the .NET SDK version is independent from specifying the runtime version a project targets. The .NET SDK version indicates which version of the .NET CLI is used. This article explains how to select the SDK version by using *global.json*. -If you always want to use the latest SDK version that is installed on your machine, no *global.json* file is needed. In CI (continuous integration) scenarios, however, you typically want to specify an acceptable range for the SDK version that is used. The *global.json* file has a `rollForward` feature that provides flexible ways to specify an acceptable range of versions. For example, the following *global.json* file selects 8.0.300 or any later [feature band or patch](../releases-and-support.md) for 8.0 that is installed on the machine: +If you always want to use the latest SDK version that is installed on your machine, no *global.json* file is needed. In CI (continuous integration) scenarios, however, you typically want to specify an acceptable range for the SDK version that is used. The *global.json* file has a `rollForward` feature that provides flexible ways to specify an acceptable range of versions. For example, the following *global.json* file selects 10.0.100 or any later [feature band or patch](../releases-and-support.md) for 10.0 that is installed on the machine: ```json { "sdk": { - "version": "8.0.300", + "version": "10.0.100", "rollForward": "latestFeature" } } ``` -The .NET SDK looks for a *global.json* file in the current working directory (which isn't necessarily the same as the project directory) or one of its parent directories. +The .NET SDK looks for a *global.json* file in the current working directory (which isn't necessarily the same as the project directory) or one of its ancestor directories. For information about specifying the runtime version instead of the SDK version, see [Target frameworks](../../standard/frameworks.md). @@ -43,8 +43,8 @@ The version of the .NET SDK to use. This field: -- Requires the full version number, such as 9.0.100. -- Doesn't support version numbers like 9, 9.0, or 9.0.x. +- Requires the full version number, such as 10.0.100. +- Doesn't support version numbers like 10, 10.0, or 10.0.x. - Doesn't have wildcard support. - Doesn't support version ranges. diff --git a/docs/core/whats-new/dotnet-10/sdk.md b/docs/core/whats-new/dotnet-10/sdk.md index 4c7acfff1c9da..4dab76b974366 100644 --- a/docs/core/whats-new/dotnet-10/sdk.md +++ b/docs/core/whats-new/dotnet-10/sdk.md @@ -251,10 +251,10 @@ The `--interactive` flag is now enabled by default for CLI commands in interacti ## Native shell tab-completion scripts -The `dotnet` CLI now supports generating native tab-completion scripts for popular shells using the `dotnet completions generate [SHELL]` command. Supported shells include `bash`, `fish`, `nushell`, `powershell`, and `zsh`. These scripts improve usability by providing faster and more integrated tab-completion features. For example, in PowerShell, you can enable completions by adding the following to your `$PROFILE`: +The `dotnet` CLI now supports generating native tab-completion scripts for popular shells using the `dotnet completions script [SHELL]` command. Supported shells include `bash`, `fish`, `nushell`, `powershell`, and `zsh`. These scripts improve usability by providing faster and more integrated tab-completion features. For example, in PowerShell, you can enable completions by adding the following to your `$PROFILE`: ```powershell -dotnet completions script pwsh | out-String | Invoke-Expression -ErrorAction SilentlyContinue +dotnet completions script pwsh | Out-String | Invoke-Expression ``` ## Console apps can natively create container images diff --git a/docs/csharp/fundamentals/types/index.md b/docs/csharp/fundamentals/types/index.md index 209be162b385e..7bd6f7b6b1d93 100644 --- a/docs/csharp/fundamentals/types/index.md +++ b/docs/csharp/fundamentals/types/index.md @@ -71,7 +71,7 @@ One of the first decisions you make when defining a type is deciding which const It's important to understand two fundamental points about the type system in .NET: - It supports the principle of inheritance. Types can derive from other types, called *base types*. The derived type inherits (with some restrictions) the methods, properties, and other members of the base type. The base type can in turn derive from some other type, in which case the derived type inherits the members of both base types in its inheritance hierarchy. All types, including built-in numeric types such as (C# keyword: `int`), derive ultimately from a single base type, which is (C# keyword: [`object`](../../language-reference/builtin-types/reference-types.md)). This unified type hierarchy is called the [Common Type System](../../../standard/base-types/common-type-system.md) (CTS). For more information about inheritance in C#, see [Inheritance](../object-oriented/inheritance.md). -- Each type in the CTS is defined as either a *value type* or a *reference type*. These types include all custom types in the .NET class library and also your own user-defined types. Types that you define by using the `struct` keyword are value types; all the built-in numeric types are `structs`. Types that you define by using the `class` or `record` keyword are reference types. Reference types and value types have different compile-time rules, and different run-time behavior. +- Each type in the CTS is defined as either a *value type* or a *reference type*. These types include all custom types in the .NET class library and also your own user-defined types. Types that you define by using the `struct` or `record struct` keywords are value types; all the built-in numeric types are `structs`. Types that you define by using the `class`, `record class`, or `record` keywords are reference types. Reference types and value types have different compile-time rules, and different run-time behavior. The following illustration shows the relationship between value types and reference types in the CTS. @@ -124,7 +124,7 @@ All enums inherit from , which in ### Reference types -A type that is defined as a `class`, `record`, [`delegate`](../../language-reference/builtin-types/reference-types.md), array, or [`interface`](../../language-reference/keywords/interface.md) is a [`reference type`](../../language-reference/keywords/reference-types.md). +A type that is defined as a `class`, `record class`, `record`, [`delegate`](../../language-reference/builtin-types/reference-types.md), array, or [`interface`](../../language-reference/keywords/interface.md) is a [`reference type`](../../language-reference/keywords/reference-types.md). When you declare a variable of a [`reference type`](../../language-reference/keywords/reference-types.md), it contains the value [`null`](../../language-reference/keywords/null.md) until you assign it with an instance of that type or create one using the [`new`](../../language-reference/operators/new-operator.md) operator. Creation and assignment of a class are demonstrated in the following example: diff --git a/docs/csharp/whats-new/tutorials/compound-assignment-operators.md b/docs/csharp/whats-new/tutorials/compound-assignment-operators.md index b0ec9ec4faa36..db0c96febd3ca 100644 --- a/docs/csharp/whats-new/tutorials/compound-assignment-operators.md +++ b/docs/csharp/whats-new/tutorials/compound-assignment-operators.md @@ -7,6 +7,7 @@ ms.service: dotnet-csharp ms.topic: tutorial ms.date: 11/14/2025 ai-usage: ai-assisted +ms.custom: peer-review-program #customer intent: As a C# developer, I want to implement user-defined instance compound assignment operators so that my algorithms are more efficient. --- # Tutorial: Create compound assignment operators