diff --git a/docs/core/extensions/options.md b/docs/core/extensions/options.md index bdcc512d97bb9..cca813322fa82 100644 --- a/docs/core/extensions/options.md +++ b/docs/core/extensions/options.md @@ -141,6 +141,46 @@ builder.Services In the preceding code, the `Configure` method is used to register a configuration instance that `TOptions` will bind against, and updates the options when the configuration changes. +### Performance considerations + +`IOptionsSnapshot` recomputes the options instance on every new scope by +re-running the full configuration pipeline (`IConfigureOptions`, +`IConfigureNamedOptions`, `IPostConfigureOptions`, `IValidateOptions`, +and any `IConfiguration` binding registered via `Configure(section)`). It +does this whether or not the underlying configuration has actually changed, and +once per named instance resolved in that scope. + +In ASP.NET Core, a scope corresponds to a single HTTP request, so this cost is +paid on the request hot path. For options whose binding or post-configuration is +non-trivial (large or deeply nested configuration sections, expensive +`PostConfigure`, validation, and so on), this can add measurable per-request +overhead. + +Consider the following alternatives: + +- If you don't need the value to change after the app starts, prefer + `IOptions`. It's a singleton and the value is computed once for the + lifetime of the app. +- If you need to observe configuration changes but want to avoid rebuilding + options on every scope, prefer `IOptionsMonitor`. It's a singleton that + caches the options instance and only rebuilds when the underlying configuration + emits a change notification. Steady-state reads of `CurrentValue` or + `Get(name)` are cache hits. + +If you still need snapshot semantics (a value guaranteed not to change within a +scope) but want to avoid the per-scope rebuild cost, you can layer on top of +`IOptionsMonitor` in one of two ways: + +- Capture `monitor.CurrentValue` once at the start of the scope and read it + from there for the rest of the scope. +- Register the options type as scoped with a factory: + + ```csharp + services.AddScoped(sp => + sp.GetRequiredService>().CurrentValue); + ``` + + ## IOptionsMonitor The `IOptionsMonitor` type supports change notifications and enables scenarios where your app may need to respond to configuration source changes dynamically. This is useful when you need to react to changes in configuration data after the app has started. Change notifications are only supported for file-system based configuration providers, such as the following: diff --git a/docs/framework/migration-guide/retargeting/4.5.x.md b/docs/framework/migration-guide/retargeting/4.5.x.md index 67c82db66ddcc..4cafd2410466a 100644 --- a/docs/framework/migration-guide/retargeting/4.5.x.md +++ b/docs/framework/migration-guide/retargeting/4.5.x.md @@ -43,6 +43,42 @@ This article lists the app compatibility issues that were introduced in .NET Fra [!INCLUDE[EncoderParameter ctor is obsolete](~/includes/migration-guide/retargeting/winforms/encoderparameter-ctor-obsolete.md)] +#### Default SubsystemVersion changed from 4.00 to 6.00 + +| | Value | +|---|---| +| **Scope** | Minor | +| **Version introduced** | 4.5 | +| **Type of change** | Retargeting | + +##### Details + +Starting with .NET Framework 4.5, the C# and Visual Basic compilers set the default `SubsystemVersion` of compiled executables to `6.00`, up from the previous default of `4.00`. This change enables Windows features introduced in Windows Vista, such as improved virtual memory handling and DPI awareness per monitor. + +A `SubsystemVersion` of `6.00` signals to Windows that the application supports higher-resolution DPI modes, which causes the operating system to return different values from several Windows API calls (including `GetSystemMetrics`). As a result, properties of the class that are backed by `GetSystemMetrics`—such as , , and related metrics—may return values that differ from those returned under .NET Framework 4.0. This can cause layout issues in applications that manually calculate or set form sizes using these properties. + +This change only affects applications that target .NET Framework 4.5 or later. Applications that target .NET Framework 4.0 are not affected. + +##### Suggestion + +If your application experiences unexpected WinForms window sizing or layout issues after migrating to .NET Framework 4.5 or later, you can restore the previous behavior by explicitly setting `SubsystemVersion` to `4.00` in your project file: + +```xml + + 4.00 + +``` + +> [!NOTE] +> Setting `SubsystemVersion` to `4.00` opts out of certain Windows Vista and later features. Evaluate the trade-offs for your application before applying this workaround. + +##### References + +- [Form height and width changes with Visual Studio 2012](https://learn.microsoft.com/previous-versions/troubleshoot/dotnet/framework/wrong-winform-height-width) +- [Advanced C# compiler options - SubsystemVersion](https://learn.microsoft.com/dotnet/csharp/language-reference/compiler-options/advanced#subsystemversion) +- + + ### Windows Communication Foundation (WCF) [!INCLUDE [onwritebodycontents-change](~/includes/migration-guide/retargeting/wcf/onwritebodycontents-change.md)]