Skip to content
2 changes: 1 addition & 1 deletion docs/ai/evaluation/libraries.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,4 @@ For usage examples, see the following tutorials:

## See also

- [Evaluation of generative AI apps (Foundry)](/azure/ai-studio/concepts/evaluation-approach-gen-ai)
- [Observability in generative AI](/azure/foundry/concepts/observability)
46 changes: 23 additions & 23 deletions docs/azure/includes/dotnet-all.md

Large diffs are not rendered by default.

27 changes: 14 additions & 13 deletions docs/azure/includes/dotnet-new.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/core/compatibility/11.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ See [Breaking changes in EF Core 11](/ef/core/what-is-new/ef-core-11.0/breaking-
| [IHost.RunAsync and IHost.StopAsync throw when a BackgroundService fails](extensions/11/ihost-runasync-stopasync-throw-backgroundservice-failure.md) | Behavioral change |
| [PhysicalFilesWatcher validates root and FileSystemWatcher paths](extensions/11/physicalfileswatcher-validates-root-path.md) | Behavioral change |
| [Some Microsoft.Extensions packages included in shared framework](extensions/11/extensions-in-shared-framework.md) | Behavioral change |
| [Synchronous access to async-validated options throws](extensions/11/async-options-validation-sync-access.md) | Behavioral/source incompatible |

## Globalization

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
title: "Breaking change: Synchronous access to async-validated options throws"
description: "Learn about the breaking change in .NET 11 where synchronous access to options that use async validators throws instead of skipping validation."
ms.date: 09/08/2026
ai-usage: ai-assisted
---

# Synchronous access to async-validated options throws

Starting in .NET 11 RC 1, synchronous access to an options type that uses only asynchronous validators fails fast. Instead of returning an options instance without asynchronous validation, the synchronous creation path throws an <xref:Microsoft.Extensions.Options.OptionsValidationException>.

## Version introduced

.NET 11 RC 1

## Previous behavior

Previously, in .NET 11 Preview 6 and Preview 7, <xref:Microsoft.Extensions.Options.IAsyncValidateOptions`1> was independent from <xref:Microsoft.Extensions.Options.IValidateOptions`1>. Asynchronous validators ran only through the asynchronous startup-validation path.

When you accessed an async-validated options type through a synchronous creation path, such as <xref:Microsoft.Extensions.Options.IOptions`1.Value?displayProperty=nameWithType>, <xref:Microsoft.Extensions.Options.IOptionsMonitor`1.CurrentValue>, <xref:Microsoft.Extensions.Options.IOptionsMonitor`1.Get*>, `IOptionsSnapshot<TOptions>.Value`, <xref:Microsoft.Extensions.Options.IOptionsSnapshot`1.Get*>, or <xref:Microsoft.Extensions.Options.IOptionsFactory`1.Create*>, the asynchronous validator didn't run. The synchronous path returned an unvalidated options instance.

Types that implemented `IAsyncValidateOptions<TOptions>` directly only needed to implement `ValidateAsync`.

## New behavior

Starting in .NET 11 RC 1, `IAsyncValidateOptions<TOptions>` derives from `IValidateOptions<TOptions>`, and the interface is no longer contravariant. Asynchronous validators participate in the same validator collection as synchronous validators.

When you access an options type with only asynchronous validators through a synchronous creation path, the inherited `Validate` method returns a failed <xref:Microsoft.Extensions.Options.ValidateOptionsResult>. <xref:Microsoft.Extensions.Options.OptionsFactory`1.Create*> then throws an `OptionsValidationException`. The exception message directs you to call `ValidateOnStart` and complete startup before you synchronously access the options.

Custom types that implement `IAsyncValidateOptions<TOptions>` directly must now also implement the inherited `Validate` method.

## Type of breaking change

This change is a [behavioral change](../../categories.md#behavioral-change) and can affect [source compatibility](../../categories.md#source-compatibility). In a narrow scenario where a preview binary directly implements `IAsyncValidateOptions<TOptions>` without recompilation, the change can also affect [binary compatibility](../../categories.md#binary-compatibility).

## Reason for change

Asynchronous options validation was introduced in .NET 11 Preview 6 as a startup-only validation path. Later design work for post-startup validation exposed a correctness gap: Options also have synchronous creation and access paths. A validator that implemented only the async interface couldn't run through those synchronous paths, so invalid options could be returned and cached before asynchronous validation ran.

To close that gap before the API reaches a stable release, `IAsyncValidateOptions<TOptions>` now derives from `IValidateOptions<TOptions>`. The unified contract keeps one validator collection, preserves registration order, and makes unsupported synchronous access fail with an actionable exception. For more information, see [dotnet/runtime#131197](https://github.com/dotnet/runtime/pull/131197) and the [approved API proposal](https://github.com/dotnet/runtime/issues/130719).

## Recommended action

For options that use only asynchronous validators, call `ValidateOnStart` and complete host startup before you access the options synchronously:

```csharp
services.AddOptions<MyOptions>()
.Configure(o => o.Value = 42)
.ValidateAsync(o => Task.FromResult(o.Value > 0), "Value must be positive.")
.ValidateOnStart();

await host.StartAsync();
```

Avoid synchronous access to options with only asynchronous validators before startup completes. This guidance applies to `IOptions<TOptions>.Value`, `IOptionsMonitor<TOptions>.CurrentValue`, `IOptionsMonitor<TOptions>.Get`, `IOptionsSnapshot<TOptions>.Value`, `IOptionsSnapshot<TOptions>.Get`, and `IOptionsFactory<TOptions>.Create`.

Some paths remain synchronous even after you use `ValidateOnStart`. Startup validation doesn't seed `IOptionsSnapshot<TOptions>` values for later scopes, and `IOptionsMonitor<TOptions>` recreates options synchronously after a configuration change. If you need those paths to validate successfully, keep at least one synchronous validator.

If you implement `IAsyncValidateOptions<TOptions>` directly, add the inherited `Validate(string? name, TOptions options)` method and recompile against .NET 11. Return <xref:Microsoft.Extensions.Options.ValidateOptionsResult.Skip?displayProperty=nameWithType> when the validator doesn't apply, or return <xref:Microsoft.Extensions.Options.ValidateOptionsResult.Fail*?displayProperty=nameWithType> when synchronous validation isn't supported.

If your code relied on the removed `in TOptions` contravariance, update the affected assignments, casts, or registrations.

You can't control this behavior with an AppContext switch or configuration setting.

## Affected APIs

- <xref:Microsoft.Extensions.Options.IAsyncValidateOptions`1>
- <xref:Microsoft.Extensions.Options.IValidateOptions`1>
- <xref:Microsoft.Extensions.Options.AsyncValidateOptions`1>
- <xref:Microsoft.Extensions.Options.AsyncValidateOptions`2>
- <xref:Microsoft.Extensions.Options.AsyncValidateOptions`3>
- <xref:Microsoft.Extensions.Options.AsyncValidateOptions`4>
- <xref:Microsoft.Extensions.Options.AsyncValidateOptions`5>
- <xref:Microsoft.Extensions.Options.AsyncValidateOptions`6>
- <xref:Microsoft.Extensions.Options.IOptions`1.Value>
- <xref:Microsoft.Extensions.Options.IOptionsMonitor`1.CurrentValue>
- <xref:Microsoft.Extensions.Options.IOptionsMonitor`1.Get*>
- <xref:Microsoft.Extensions.Options.IOptionsSnapshot`1.Get*>
- <xref:Microsoft.Extensions.Options.IOptionsFactory`1.Create*>
- <xref:Microsoft.Extensions.Options.OptionsFactory`1.Create*>
- `ValidateAsync` extension methods on `OptionsBuilder<TOptions>`.
2 changes: 2 additions & 0 deletions docs/core/compatibility/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ items:
href: extensions/11/physicalfileswatcher-validates-root-path.md
- name: Some Microsoft.Extensions packages included in shared framework
href: extensions/11/extensions-in-shared-framework.md
- name: Synchronous access to async-validated options throws
href: extensions/11/async-options-validation-sync-access.md
- name: Globalization
items:
- name: Japanese Calendar minimum supported date corrected
Expand Down
2 changes: 1 addition & 1 deletion docs/core/project-sdk/msbuild-props.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ For more information, see [Target frameworks in SDK-style projects](../../standa
Use the `TargetFrameworks` property when you want your app to target multiple platforms. For a list of valid target framework monikers, see [Target frameworks in SDK-style projects](../../standard/frameworks.md#supported-target-frameworks).

> [!NOTE]
> If `TargetFrameworks` (plural) is specified, `TargetFramework` (singular) is ignored.
> If `TargetFramework` (singular) is specified, `TargetFrameworks` (plural) is ignored, and the project builds as a single-target project.

```xml
<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ MageUI.exe supports the same functionality as the command-line tool Mage.exe, bu

|UI Element|Description|
|----------------|-----------------|
|**This application should check for updates**|Specifies whether ClickOnce should check for application updates. If this check box is not selected, the application will not check for updates unless you update it programmatically by using the APIs in the `System.Deployment.Application` namespace.|
|**This application should check for updates**|Specifies whether ClickOnce should check for application updates. If this check box is not selected, the application will not check for updates unless you update it programmatically by using the APIs in the <xref:System.Deployment.Application> namespace.|
|**Choose when the application should check for updates**|Provides two options for update checks:<br /><br /> - **Before the application starts**. The update check is performed prior to application execution.<br />- **After the application starts**. The update check begins once the main form of the application has initialized, and will run the next time the application starts.|
|**Update check frequency**|Determines how often ClickOnce should check for updates:<br /><br /> - **Check every time the application runs**. ClickOnce will perform an update check every time the user opens the application.<br />- **Check every**: Select a time interval and a unit (hours, days, or weeks) that must elapse before checking for updates.|
|**Specify a minimum required version for this application**|Optional. Specifies that a specific version of your application is a required installation, preventing your users from working with an earlier version.|
Expand Down
Loading