Skip to content

AOT-safe authentication provider discovery with feature switch and trimmer support - #4573

Draft
paulmedynski wants to merge 4 commits into
dev/paul/assembly-signing-azurefrom
dev/paul/aot-azure-fix
Draft

AOT-safe authentication provider discovery with feature switch and trimmer support#4573
paulmedynski wants to merge 4 commits into
dev/paul/assembly-signing-azurefrom
dev/paul/aot-azure-fix

Conversation

@paulmedynski

Copy link
Copy Markdown
Contributor

Summary

Replays the AOT work from #4348 on top of the new assembly-signing stack (#4566#4570), so it no longer carries a stale copy of the signing changes.

dev/paul/aot was based on a pre-rebase copy of dev/paul/assembly-signing-core and therefore included an old duplicate of the signing commit. This branch drops that commit and keeps only the AOT work, rebased onto current main via the stack.

Commits

  • AOT-safe authentication provider discovery
  • Refactor auth bootstrapper to auto-properties; simplify registry; add tests
  • Tidying up the AotCompatibility tool
  • Assert the reflection-discovery switch directly in the defaults test (integration fix)

Conflict resolutions worth reviewing

Replaying onto current main required resolving conflicts introduced by work that landed after the AOT branch point:

  • LocalAppContextSwitches.cs — kept the AOT two-property design (UseManagedNetworking platform guard + UseManagedNetworkingOnWindows as the trimmer substitution target) and the s_useManagedNetworkingOnWindows field. Retained main's default-value documentation.
  • AuthenticationBootstrapper.cs — main's SqlAuthenticationProviderManager.cs is renamed here. Took the AOT version; the strong-name–verified Azure extension loading is preserved, relocated into a [RequiresUnreferencedCode]/[RequiresDynamicCode]-annotated method.
  • LocalAppContextSwitchesHelper.cs — kept main's GetLocalAppContextSwitchesType() refactor and runtime OS check, adopting the AOT field rename.
  • LocalAppContextSwitchesTest.cs — kept main's switchesHelper assertions (including UseLegacyIdleTimeoutBehavior) and added the new switch assertion.

Known follow-up

The relocated Azure-loading trace calls use interpolated strings, so this branch does not carry #4528's parameterized trace-call conversion for that code. That conversion applied only to the block the AOT commit rewrites. Worth re-applying before this leaves draft.

Validation

  • Microsoft.Data.SqlClient builds clean for net8.0
  • Unit tests: 1085 passed, 0 failed, 14 skipped (net8.0)

Supersedes the AOT content of #4348.

Gate the reflection-based config/Azure-extension provider discovery behind a
feature switch so the trimmer can remove it, and relocate the provider registry
into the shared Abstractions assembly. The public surface stays
SqlAuthenticationProvider.GetProvider/SetProvider (no new public type).

- Registry: move into Abstractions as internal AuthenticationProviderRegistry
  (one ConcurrentDictionary of a ProviderEntry record struct; IsExternalInit
  polyfill for netstandard2.0); delete the Abstractions->core reflection bridge.
- Bootstrapper: replace SqlAuthenticationProviderManager with an internal,
  core-side AuthenticationBootstrapper that lazily (Lazy<T>) discovers
  config-driven and Azure-extension providers and seeds the registry, triggered
  once from SqlConnectionInternal.GetFedAuthToken.
- AOT: feature switch
  Microsoft.Data.SqlClient.EnableReflectionBasedAuthenticationProviderDiscovery
  ([FeatureSwitchDefinition] on .NET 9+, ILLink.Substitutions.xml on .NET 8)
  trims LoadAzureExtensionProvider when disabled; AotCompatibility tool
  validates Native AOT publish and trimming.
- Behavior: app-config ("permanent") providers take precedence and are
  last-in-wins; BeforeLoad fires on first registration; lifecycle callbacks are
  isolated from exceptions and documented as idempotent.
- Tests: registry and bootstrapper tests reorganized -- UnitTests covers the
  Azure-absent and stub paths, Azure.Test covers the real provider (global vs
  non-global split); serialized collection renamed to SqlAuthenticationProviderGlobal.
… tests

- AuthenticationBootstrapper: replace backing fields with internal
  auto-properties (Registry, ApplicationClientId, UseWamBroker).
- AuthenticationProviderRegistry: remove PermanentProviderException
  sentinel; document SetProvider null behavior.
- UnitTests: assert Registry/ApplicationClientId/UseWamBroker; add
  UseWamBroker config tests (app.config sets useWamBroker=true).
Integration fix for replaying the AOT commits onto current main.  Main's
LocalAppContextSwitchesHelper resolves switch defaults by reflecting over public
static properties, but EnableReflectionBasedAuthenticationProviderDiscovery is
internal, so the helper cannot see it.  Assert it directly on
LocalAppContextSwitches, as the original AOT test did, and keep the helper's
field-based accessor unchanged.
Copilot AI lite review requested due to automatic review settings August 21, 2026 16:00
@github-project-automation github-project-automation Bot moved this to To triage in SqlClient Board Aug 21, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR replays and updates the AOT-/trimmer-safe authentication provider discovery work on top of the newer assembly-signing stack by (1) moving the auth-provider registry into the Abstractions assembly, (2) isolating reflection-based discovery behind a feature switch + trimmer substitutions, and (3) adding/reshaping tests and an AOT compatibility tool to validate trimming behavior.

Changes:

  • Introduces AuthenticationBootstrapper to lazily seed providers from app.config and the optional Azure extension, gated by Microsoft.Data.SqlClient.EnableReflectionBasedAuthenticationProviderDiscovery for AOT/trimming.
  • Moves the provider registry into Microsoft.Data.SqlClient.Extensions.Abstractions and rewires SqlAuthenticationProvider.GetProvider/SetProvider to use it directly (removing the Abstractions→SqlClient reflection bridge).
  • Adds/updates unit tests and a tools/AotCompatibility app to validate NativeAOT publish and trimming of the reflection-based discovery path.

Reviewed changes

Copilot reviewed 53 out of 54 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tools/AotCompatibility/README.md Documents what the AOT compatibility tool validates and how to run/publish it.
tools/AotCompatibility/Program.cs Implements runtime checks and ILC map-file verification for trimming behavior.
tools/AotCompatibility/Directory.Packages.props Enables central package management for the tool without specifying versions (project-mode).
tools/AotCompatibility/Directory.Build.props Prevents inheriting repo-wide Directory.Build.props settings for the tool.
tools/AotCompatibility/AotCompatibility.csproj Defines the AOT/trimming validation app and sets the runtime host configuration option for the feature switch.
src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/SqlAuthenticationProviderManagerTests.cs Removes legacy manager-based tests replaced by bootstrapper/registry coverage.
src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/LocalAppContextSwitchesTest.cs Asserts the new internal reflection-discovery switch default directly.
src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/ILLinkSubstitutionsTests.cs Adds tests ensuring the unified ILLink substitution resource is embedded on non-net462 TFMs.
src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/DummySqlAuthenticationProvider.cs Adds a dummy provider used by net462 UnitTests app.config-based registration tests.
src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/AuthenticationBootstrapperTests.cs Adds core bootstrapper tests (Azure extension absent) covering config and constructor-selection logic via stubs.
src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft.Data.SqlClient.UnitTests.csproj Ensures net462 app.config is copied to output for config-driven provider tests.
src/Microsoft.Data.SqlClient/tests/UnitTests/app.config Adds UnitTests app.config configuring a dummy provider and bootstrapper settings for net462 tests.
src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlAuthenticationProviderManagerTests.cs Removes legacy functional tests tied to the old manager/app.config flow.
src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.FunctionalTests.csproj Removes copying FunctionalTests app.config for net462 (tests moved/restructured).
src/Microsoft.Data.SqlClient/tests/FunctionalTests/DataCommon/DummySqlAuthenticationProvider.cs Removes functional-tests dummy provider implementation (test moved/rewired).
src/Microsoft.Data.SqlClient/tests/FunctionalTests/app.config Removes functional-tests app.config for dummy provider registration.
src/Microsoft.Data.SqlClient/tests/FunctionalTests/AADAuthenticationTests.cs Removes dummy-provider registration test from FunctionalTests (moved to Azure.Test/global bootstrap tests).
src/Microsoft.Data.SqlClient/tests/Common/LocalAppContextSwitchesHelper.cs Updates helper to reflect new cached-field naming and adds helper for the new internal switch.
src/Microsoft.Data.SqlClient/src/Resources/ILLink.Substitutions.xml Unifies trimmer substitutions for auth-provider discovery and managed-networking switch in one cross-platform file.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalAppContextSwitches.cs Adds the new reflection-discovery switch and refactors managed-networking switch into a trimmer substitution target property.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Connection/SqlConnectionInternal.cs Ensures authentication bootstrap runs before resolving a provider on the fed-auth path.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/AuthenticationBootstrapper.cs Replaces legacy manager with a lazy bootstrapper that loads config + Azure extension behind a feature switch and AOT annotations.
src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj Embeds the unified ILLink substitution resource for all non-net462 TFMs.
src/Microsoft.Data.SqlClient/ref/Microsoft.Data.SqlClient.cs Adds a note clarifying ref assemblies intentionally omit nullable annotations.
src/Microsoft.Data.SqlClient.Extensions/Azure/test/WamBrokerTests.cs Updates comments/collection usage and removes a global-state mutation test that’s no longer needed in this form.
src/Microsoft.Data.SqlClient.Extensions/Azure/test/SqlAuthenticationProviderGlobalCollection.cs Renames the serialized collection definition used for tests mutating the global registry.
src/Microsoft.Data.SqlClient.Extensions/Azure/test/DefaultAuthProviderTests.cs Removes legacy “default provider installed” test tied to old manager static-init behavior.
src/Microsoft.Data.SqlClient.Extensions/Azure/test/AuthenticationBootstrapperTests.cs Adds Azure-present, non-global bootstrapper tests (constructor selection via reflection access).
src/Microsoft.Data.SqlClient.Extensions/Azure/test/AuthenticationBootstrapperGlobalTests.cs Adds Azure-present tests that force the full bootstrap and verify global provider registration.
src/Microsoft.Data.SqlClient.Extensions/Azure/test/AADAuthenticationTests.cs Moves these tests into the global serialized collection to account for shared registry mutations.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationProviderTest.cs Updates tests to validate the public API delegates to the shared registry instance (no SqlClient assembly required).
src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/AuthenticationProviderRegistryTest.cs Adds comprehensive isolated tests for registry behavior (overrides, permanence, lifecycle callbacks).
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Strings.zh-Hant.resx Adds localized string resources used by Abstractions exception messages.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Strings.zh-Hans.resx Adds localized string resources used by Abstractions exception messages.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Strings.tr.resx Adds localized string resources used by Abstractions exception messages.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Strings.ru.resx Adds localized string resources used by Abstractions exception messages.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Strings.resx Adds the invariant resource string(s) used by Abstractions exception messages.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Strings.pt-BR.resx Adds localized string resources used by Abstractions exception messages.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Strings.pl.resx Adds localized string resources used by Abstractions exception messages.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Strings.ko.resx Adds localized string resources used by Abstractions exception messages.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Strings.ja.resx Adds localized string resources used by Abstractions exception messages.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Strings.it.resx Adds localized string resources used by Abstractions exception messages.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Strings.fr.resx Adds localized string resources used by Abstractions exception messages.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Strings.es.resx Adds localized string resources used by Abstractions exception messages.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Strings.Designer.cs Adds the strongly-typed resource accessor for Abstractions strings.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Strings.de.resx Adds localized string resources used by Abstractions exception messages.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Strings.cs.resx Adds localized string resources used by Abstractions exception messages.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProvider.Internal.cs Removes the Abstractions→SqlClient reflection bridge for provider get/set.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProvider.cs Rewires GetProvider/SetProvider to call the shared registry directly.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/IsExternalInit.cs Adds an IsExternalInit polyfill for record/init support on non-NET TFMs.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/AuthenticationProviderRegistry.cs Introduces the shared concurrent provider registry with permanence semantics and lifecycle callback handling.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj Updates InternalsVisibleTo to include SqlClient and UnitTests under signing conditions.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationProvider.xml Updates docs to reflect concurrency/idempotency expectations and clarifies canonical Get/Set usage.
aot-auth-provider-proposal.md Adds/updates design proposal documentation for the AOT-safe registration approach.
Files not reviewed (1)
  • src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Strings.Designer.cs: Generated file
Suppressed comments (2)

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/AuthenticationBootstrapper.cs:280

  • These trace calls build interpolated/concatenated strings at the call site, which allocates even when tracing is disabled. Since SqlClientEventSource.TryTraceEvent only formats when enabled, switch to a parameterized call and compute expensive arguments (like the token string) only inside an IsTraceEnabled() guard.
    src/Microsoft.Data.SqlClient/tests/Common/LocalAppContextSwitchesHelper.cs:388
  • The remarks still refer to the old cached-field name (s_useManagedNetworking). After the rename to s_useManagedNetworkingOnWindows, this comment is now inaccurate and could mislead future edits to this reflection-based helper.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +102 to +108
/// <exception cref="NullReferenceException">
/// <paramref name="provider"/> is <see langword="null"/>.
/// </exception>
internal bool SetProvider(SqlAuthenticationMethod authenticationMethod, SqlAuthenticationProvider provider)
{
if (!provider.IsSupported(authenticationMethod))
{
@paulmedynski paulmedynski added Area\Engineering Use this for issues that are targeted for changes in the 'eng' folder or build systems. Area\Azure Connectivity Use this to tag issues that are related to Azure connectivity. labels Aug 21, 2026
@paulmedynski paulmedynski moved this from To triage to In progress in SqlClient Board Aug 21, 2026
@paulmedynski paulmedynski added this to the 8.0.0-preview1 milestone Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area\Azure Connectivity Use this to tag issues that are related to Azure connectivity. Area\Engineering Use this for issues that are targeted for changes in the 'eng' folder or build systems.

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

2 participants