AOT-safe auth provider with feature switch and trimmer support#4348
AOT-safe auth provider with feature switch and trimmer support#4348paulmedynski wants to merge 7 commits into
Conversation
- 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
There was a problem hiding this comment.
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
SqlAuthenticationProviderManagerpublic withGetProvider/SetProviderAPIs and addedApplicationClientIdas part of the public surface. - Added
Microsoft.Data.SqlClient.EnableReflectionBasedAuthenticationProviderDiscoveryfeature switch with trimmer support ([FeatureSwitchDefinition]on .NET 9+ andILLink.Substitutions.xmlfor .NET 8). - Added an
tools/AotCompatibilitytest 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);
- 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
left a comment
There was a problem hiding this comment.
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.
… 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
|
Addressed all actionable review feedback in 11d75ab:
|
Codecov Report❌ Patch coverage is
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
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
- 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; } } |
There was a problem hiding this comment.
This shouldn't be public, it's an optional and in absence driver's own will be picked automatically.
There was a problem hiding this comment.
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.
|
@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 |
Summary
Make
SqlAuthenticationProviderManagerpublic with a staticGetProvider/SetProviderAPI and add trimmer/AOT support via a feature switch.Changes
SqlAuthenticationProviderManager.GetProvider(),SetProvider(), andApplicationClientIdas the public surface for authentication provider registrationMicrosoft.Data.SqlClient.EnableReflectionBasedAuthenticationProviderDiscovery[FeatureSwitchDefinition]on .NET 9+ for linker-integrated trimmingILLink.Substitutions.xmlfor .NET 8 trimmer supportfalse, the reflection-basedLoadAzureExtensionProvider()is trimmed awayILLink.Substitutions.xml— cross-platform (all non-net462 TFMs), contains only the auth provider feature switchILLink.Substitutions.Windows.xml— Windows-only, containsUseManagedNetworkingOnWindowsentries. Prevents a breaking change where Unix consumers setting the switch tofalsewould haveUseManagedNetworkingincorrectly stubbedtools/AotCompatibility/): Validates Native AOT publish succeeds and verifies trimmer removes reflection code when feature switch is disabledILLinkSubstitutionsTestsverifying correct embedded resources per platformVerification
dotnet build -t:Buildsucceeds (0 warnings, 0 errors)dotnet publishwith Native AOT succeeds for net9.0/net10.0LoadAzureExtensionProvideris trimmed when feature switch isfalseILLink.Substitutions.xmlILLink.Substitutions.xmlandILLink.Substitutions.Windows.xmlNotes
SspiAuthenticationParameters, column encryption providers)