Skip to content

AOT-safe auth provider with feature switch and trimmer support#4348

Open
paulmedynski wants to merge 7 commits into
mainfrom
dev/paul/aot
Open

AOT-safe auth provider with feature switch and trimmer support#4348
paulmedynski wants to merge 7 commits into
mainfrom
dev/paul/aot

Conversation

@paulmedynski

@paulmedynski paulmedynski commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Make SqlAuthenticationProviderManager public with a static GetProvider/SetProvider API and add trimmer/AOT support via a feature switch.

Changes

  • Public API: Expose SqlAuthenticationProviderManager.GetProvider(), SetProvider(), and ApplicationClientId as the public surface for authentication provider registration
  • Feature switch: Microsoft.Data.SqlClient.EnableReflectionBasedAuthenticationProviderDiscovery
    • Uses [FeatureSwitchDefinition] on .NET 9+ for linker-integrated trimming
    • Uses ILLink.Substitutions.xml for .NET 8 trimmer support
    • When set to false, the reflection-based LoadAzureExtensionProvider() is trimmed away
  • ILLink substitutions split into platform-specific files:
    • ILLink.Substitutions.xml — cross-platform (all non-net462 TFMs), contains only the auth provider feature switch
    • ILLink.Substitutions.Windows.xml — Windows-only, contains UseManagedNetworkingOnWindows entries. Prevents a breaking change where Unix consumers setting the switch to false would have UseManagedNetworking incorrectly stubbed
  • Ref assembly: Updated without nullable annotations (per existing codebase convention)
  • AotCompatibility test app (tools/AotCompatibility/): Validates Native AOT publish succeeds and verifies trimmer removes reflection code when feature switch is disabled
  • Unit tests:
    • New tests for the public provider manager API
    • New ILLinkSubstitutionsTests verifying correct embedded resources per platform

Verification

  • dotnet build -t:Build succeeds (0 warnings, 0 errors)
  • Unit tests pass (782/783 — 1 pre-existing failure unrelated to this PR)
  • dotnet publish with Native AOT succeeds for net9.0/net10.0
  • ILC map file confirms LoadAzureExtensionProvider is trimmed when feature switch is false
  • Unix assembly contains only ILLink.Substitutions.xml
  • Windows assembly contains both ILLink.Substitutions.xml and ILLink.Substitutions.Windows.xml

Notes

  • The notsupported files need regeneration via GenAPI to pick up the ref assembly changes (not included in this PR to avoid noise)
  • Nullable annotations are intentionally omitted from the ref assembly, consistent with existing patterns (e.g., SspiAuthenticationParameters, column encryption providers)

- Make SqlAuthenticationProviderManager public with static GetProvider/SetProvider API
- Add FeatureSwitchDefinition for reflection-based provider discovery
  (Microsoft.Data.SqlClient.EnableReflectionBasedAuthenticationProviderDiscovery)
- Add ILLink.Substitutions.xml for net8.0 trimmer support
- Add AotCompatibility test app (tools/AotCompatibility) validating
  Native AOT publish and trimmer behavior
- Update ref assembly (no nullable annotations, per codebase convention)
- Add unit tests for provider manager public API
Copilot AI review requested due to automatic review settings June 9, 2026 13:56
@github-project-automation github-project-automation Bot moved this to To triage in SqlClient Board Jun 9, 2026
@paulmedynski paulmedynski moved this from To triage to In progress in SqlClient Board Jun 9, 2026
@paulmedynski paulmedynski added Public API 🆕 Issues/PRs that introduce new APIs to the driver. Area\Azure Connectivity Use this to tag issues that are related to Azure connectivity. Hotfix 7.0.2 PRs targeting main that should be backported to release/7.0 for the 7.0.2 release. labels Jun 9, 2026
@paulmedynski paulmedynski added this to the 7.1.0-preview2 milestone Jun 9, 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 exposes an AOT-friendly public authentication provider registration surface (SqlAuthenticationProviderManager) and introduces a feature switch to enable trimming away reflection-based Azure extension provider discovery for NativeAOT/trimming scenarios.

Changes:

  • Made SqlAuthenticationProviderManager public with GetProvider/SetProvider APIs and added ApplicationClientId as part of the public surface.
  • Added Microsoft.Data.SqlClient.EnableReflectionBasedAuthenticationProviderDiscovery feature switch with trimmer support ([FeatureSwitchDefinition] on .NET 9+ and ILLink.Substitutions.xml for .NET 8).
  • Added an tools/AotCompatibility test app plus new/updated unit & functional tests covering the new public API and config behavior.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
tools/AotCompatibility/README.md Documents the AOT compatibility test app and feature switch usage.
tools/AotCompatibility/Program.cs Implements runtime checks and trimming verification via the ILC map file.
tools/AotCompatibility/Directory.Packages.props Enables CPM for the tool (project-mode, no package versions).
tools/AotCompatibility/Directory.Build.props Prevents inheriting repo-wide build props for the tool.
tools/AotCompatibility/AotCompatibility.csproj Adds the NativeAOT/trimming test app and propagates the feature switch via RuntimeHostConfigurationOption.
src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/SqlAuthenticationProviderManagerTests.cs Adds unit tests for the new public manager API and interop with Abstractions.
src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/LocalAppContextSwitchesTest.cs Extends default-switch tests to cover the new auth discovery switch.
src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlAuthenticationProviderManagerTests.cs Adjusts tests (pragma) and adds validation for reading ApplicationClientId from config.
src/Microsoft.Data.SqlClient/tests/FunctionalTests/app.config Adds applicationClientId attribute to the auth provider config section.
src/Microsoft.Data.SqlClient/tests/FunctionalTests/AADAuthenticationTests.cs Adds pragma suppression around newly-obsoleted Abstractions API usage.
src/Microsoft.Data.SqlClient/tests/Common/LocalAppContextSwitchesHelper.cs Adds helper plumbing to reset the new switch in tests.
src/Microsoft.Data.SqlClient/src/Resources/ILLink.Substitutions.xml Adds substitutions for the new feature switch (and retains UseManagedNetworking stubs).
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.cs Makes the type public and guards reflection-based discovery behind the new switch; adds AOT/trimming annotations.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalAppContextSwitches.cs Introduces the new switch property and [FeatureSwitchDefinition] for .NET 9+.
src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj Embeds ILLink.Substitutions.xml for all non-net462 TFMs.
src/Microsoft.Data.SqlClient/ref/Microsoft.Data.SqlClient.cs Adds the new public API to the reference assembly (without nullable annotations).
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProvider.Internal.cs Updates reflection binding flags to target public manager methods.
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProvider.cs Marks legacy Abstractions APIs obsolete in favor of the new manager APIs.
doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationProviderManager.xml Adds public XML doc content for the new manager API.
Comments suppressed due to low confidence (1)

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.cs:346

  • SetProvider is now a public API but does not validate the provider argument; passing null currently results in a NullReferenceException. Public APIs should throw ArgumentNullException for null arguments.
        /// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationProviderManager.xml' path='docs/members[@name="SqlAuthenticationProviderManager"]/SetProvider/*'/>
        public static bool SetProvider(SqlAuthenticationMethod authenticationMethod, SqlAuthenticationProvider provider)
        {
            if (!provider.IsSupported(authenticationMethod))
            {
                throw SQL.UnsupportedAuthenticationByProvider(authenticationMethod.ToString(), provider.GetType().Name);

Comment thread doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationProviderManager.xml Outdated
Comment thread doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationProviderManager.xml Outdated
Comment thread tools/AotCompatibility/Program.cs
Comment thread tools/AotCompatibility/Program.cs Outdated
Comment thread tools/AotCompatibility/README.md Outdated
Comment thread src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj Outdated
@paulmedynski paulmedynski changed the title feat: AOT-safe auth provider with feature switch and trimmer support AOT-safe auth provider with feature switch and trimmer support Jun 9, 2026
- Fix SetProvider exception docs: SqlException → NotSupportedException
- Clarify AOT remarks: static ctor uses reflection by default; describe
  how to disable it for full AOT compatibility
- Return non-zero exit code on SqlConnection construction failure
- Replace Directory.GetFiles with EnumerateFiles(IgnoreInaccessible)
- Clarify README: 'the test app default' vs library default
- Add XML summary docs to all new unit test methods
- Remove [Obsolete] from SqlAuthenticationProvider.GetProvider/SetProvider;
  add remarks pointing to SqlAuthenticationProviderManager equivalents
  noting future deprecation and removal
- Remove corresponding #pragma CS0618 suppressions from tests
- Document applicationClientId in test app.config

@paulmedynski paulmedynski left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I decided against the obsoletion.

Separate UseManagedNetworkingOnWindows entries into a Windows-only
ILLink.Substitutions.Windows.xml file to prevent a breaking change for
cross-platform consumers who set the switch to false expecting it to be
a no-op on Unix.

Add unit tests verifying the correct substitution files are embedded
per platform.
Copilot AI review requested due to automatic review settings June 9, 2026 17:05

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

Copilot reviewed 22 out of 22 changed files in this pull request and generated 6 comments.

Comment thread tools/AotCompatibility/README.md
… doc fixes

- Wrap `using System.Diagnostics.CodeAnalysis` in #if NET (unused on net462)
- Gate ILLink substitution tests by TFM; add NETFRAMEWORK negative assertions
- Fix remarks: "on all TFMs" -> "on .NET 8+" (net462 has no trimmer)
- Add -f/-r flags to AotCompatibility README publish examples
@paulmedynski

Copy link
Copy Markdown
Contributor Author

Addressed all actionable review feedback in 11d75ab:

  1. Unused using on net462 (comment): Wrapped using System.Diagnostics.CodeAnalysis; in #if NET since the attributes are only referenced inside that conditional.

  2. Missing using for SqlConnection (comment): No change needed — SqlConnection resolves via parent namespace (Microsoft.Data.SqlClient.UnitTestsMicrosoft.Data.SqlClient). Build confirms clean with no CS0246.

  3. Cross-platform substitution assertion on net462 (comment): Added #if NETFRAMEWORK branch with negative assertion (DoesNotContain) confirming the resource is correctly excluded, matching the csproj condition.

  4. Windows substitution assertion on net462 (comment): Same approach — net462 now asserts DoesNotContain("ILLink.Substitutions.Windows.xml").

  5. "on all TFMs" wording (comment): Reworded to "on .NET 8+" to accurately reflect that net462 has no trimmer support.

  6. Publish commands missing -f/-r (comment): Added explicit -f net9.0 -r linux-x64 (and -r win-x64 for Windows) so the commands match the documented output paths.

@codecov

codecov Bot commented Jun 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 77.77778% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.19%. Comparing base (5ac26c9) to head (6038cb0).
⚠️ Report is 12 commits behind head on main.

Files with missing lines Patch % Lines
...icrosoft/Data/SqlClient/LocalAppContextSwitches.cs 63.63% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4348      +/-   ##
==========================================
- Coverage   66.50%   64.19%   -2.32%     
==========================================
  Files         285      280       -5     
  Lines       43311    66184   +22873     
==========================================
+ Hits        28806    42485   +13679     
- Misses      14505    23699    +9194     
Flag Coverage Δ
CI-SqlClient ?
PR-SqlClient-Project 64.19% <77.77%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj
@paulmedynski paulmedynski marked this pull request as ready for review June 10, 2026 11:34
@paulmedynski paulmedynski requested a review from a team as a code owner June 10, 2026 11:34
Copilot AI review requested due to automatic review settings June 10, 2026 11:34
@paulmedynski paulmedynski enabled auto-merge (squash) June 10, 2026 11:34

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

Copilot reviewed 22 out of 22 changed files in this pull request and generated 2 comments.

- Remove 'using Microsoft.Data.SqlClient.Tests.Common;' from SqlAuthenticationProviderManagerTests.cs
- Remove 'using System.Reflection;' from ILLinkSubstitutionsTests.cs

Both would cause CS8019 with warnings-as-errors.
Restructure UseManagedNetworking so it no longer needs a per-OS
ILLink substitution file:

  public static bool UseManagedNetworking =>

The platform guard guarantees managed SNI on non-Windows regardless of
the trimmer-substituted value of UseManagedNetworkingOnWindows, making
it safe to embed the substitution entries in the cross-platform
ILLink.Substitutions.xml on all platforms.

Changes:
- LocalAppContextSwitches: split UseManagedNetworking into a public
  expression-bodied property with platform guard + private
  UseManagedNetworkingOnWindows property (trimmer target)
- Widen UseManagedNetworkingOnWindowsString and cache field from
  '#if NET && _WINDOWS' to '#if NET'
- Merge ILLink.Substitutions.Windows.xml entries into the
  cross-platform ILLink.Substitutions.xml (targeting
  get_UseManagedNetworkingOnWindows instead of get_UseManagedNetworking)
- Delete ILLink.Substitutions.Windows.xml
- Remove conditional Windows-only embedding from csproj
- Update ILLinkSubstitutionsTests to match: single cross-platform
  resource on all .NET TFMs, no Windows-specific resource
public sealed class SqlAuthenticationProviderManager
{
/// <include file='../../../doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationProviderManager.xml' path='docs/members[@name="SqlAuthenticationProviderManager"]/ApplicationClientId/*'/>
public static string ApplicationClientId { get { throw null; } }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This shouldn't be public, it's an optional and in absence driver's own will be picked automatically.

@paulmedynski paulmedynski Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The docs explain why it is public - for AOT apps that want to continue using our Provider, but need a custom app ID that only the Manager knows (i.e. read from config). In the automatic-registration-reflection flow, the Manager supplies it to the Provider's constructor. In the (new) manual-registration flow, the app would have to read it from the same config if this wasn't public. That's an additional burden that we didn't want to impose.

@github-project-automation github-project-automation Bot moved this from In progress to Waiting for customer in SqlClient Board Jun 12, 2026
@cheenamalhotra cheenamalhotra added the Author attention needed PRs that require author to respond or make updates to PR. label Jun 12, 2026
@github-actions

Copy link
Copy Markdown

@paulmedynski This pull request has been marked as Author attention needed.

When you have addressed the reviewer feedback and are ready for another review, please post a comment with /ready to remove the label and re-engage reviewers.

@paulmedynski paulmedynski removed the Author attention needed PRs that require author to respond or make updates to PR. label Jun 15, 2026
@paulmedynski paulmedynski moved this from Waiting for customer to In review in SqlClient Board Jun 15, 2026
Copilot AI review requested due to automatic review settings June 16, 2026 10:41
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. Hotfix 7.0.2 PRs targeting main that should be backported to release/7.0 for the 7.0.2 release. Public API 🆕 Issues/PRs that introduce new APIs to the driver.

Projects

Status: In review

Development

Successfully merging this pull request may close these issues.

Entra ID authentication broken under NativeAOT in v7.0 — Extensions.Azure reflection-based discovery is AOT-incompatible

5 participants