From f6a74cc8c27571550788e52d04bb977d369f2344 Mon Sep 17 00:00:00 2001
From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com>
Date: Tue, 30 Sep 2025 15:11:04 -0300
Subject: [PATCH 01/16] Abstractions Package - C# project changes (#3626)
---
.editorconfig | 2 +-
BUILDGUIDE.md | 81 +++--
NuGet.config | 21 +-
build.proj | 162 ++++++++--
.../jobs/build-signed-package-job.yml | 1 +
.../templates/jobs/ci-build-nugets-job.yml | 2 +
.../steps/generate-nuget-package-step.yml | 14 +-
.../libraries/ci-build-variables.yml | 10 +
eng/pipelines/libraries/common-variables.yml | 12 +-
src/Directory.Build.props | 1 -
src/Directory.Packages.props | 7 +
.../Abstractions/README.md | 285 ++++++++++++++++++
.../Abstractions/doc/Sample.xml | 18 ++
.../Abstractions/src/Abstractions.csproj | 71 +++++
.../src/AbstractionsVersions.props | 70 +++++
.../Abstractions/src/Sample.cs | 20 ++
.../test/Abstractions.Test.csproj | 26 ++
.../Abstractions/test/SampleTest.cs | 19 ++
src/Microsoft.Data.SqlClient.sln | 43 ++-
.../add-ons/Directory.Build.props | 1 -
.../ref/Microsoft.Data.SqlClient.csproj | 18 +-
.../src/Microsoft.Data.SqlClient.csproj | 16 +
.../netfx/ref/Microsoft.Data.SqlClient.csproj | 17 ++
.../netfx/src/Microsoft.Data.SqlClient.csproj | 17 ++
tools/props/Versions.props | 70 +++--
tools/specs/Microsoft.Data.SqlClient.nuspec | 4 +
...waysEncrypted.AzureKeyVaultProvider.nuspec | 34 ++-
tools/targets/GenerateMdsPackage.targets | 13 +
tools/targets/GenerateNugetPackage.targets | 31 --
.../targets/GenerateSqlServerPackage.targets | 13 +
.../GenerateAKVProviderNugetPackage.targets | 12 -
.../add-ons/GenerateAkvPackage.targets | 13 +
32 files changed, 951 insertions(+), 173 deletions(-)
create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/README.md
create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/Sample.xml
create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj
create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/AbstractionsVersions.props
create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Sample.cs
create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj
create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SampleTest.cs
create mode 100644 tools/targets/GenerateMdsPackage.targets
delete mode 100644 tools/targets/GenerateNugetPackage.targets
create mode 100644 tools/targets/GenerateSqlServerPackage.targets
delete mode 100644 tools/targets/add-ons/GenerateAKVProviderNugetPackage.targets
create mode 100644 tools/targets/add-ons/GenerateAkvPackage.targets
diff --git a/.editorconfig b/.editorconfig
index cbc3fa7858..1b76fecaaa 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -162,7 +162,7 @@ dotnet_diagnostic.xUnit1031.severity=none
dotnet_diagnostic.xUnit1030.severity=none
# Xml files
-[*.{xml,csproj,stylecop,resx,ruleset,props,targets,config,nuspec}]
+[*.{xml,slnx,proj,csproj,stylecop,resx,ruleset,props,targets,config,nuspec}]
indent_size = 2
# Shell scripts
diff --git a/BUILDGUIDE.md b/BUILDGUIDE.md
index efeb747cad..7984813fb1 100644
--- a/BUILDGUIDE.md
+++ b/BUILDGUIDE.md
@@ -16,28 +16,33 @@ Once the environment is setup properly, execute the desired set of commands belo
### Targets
+The following build targets are defined in `build.proj`:
+
|Target|Description|
|-|-|
|`BuildAllConfigurations`|Default target. Builds the .NET Framework and .NET drivers for all target frameworks and operating systems.|
+|`BuildAbstractions`|Restore, build, and pack the Abstractions package, publishing the resulting NuGet into `packages/`.|
|`BuildNetCore`|Builds the .NET driver for all target frameworks.|
|`BuildNetCoreAllOS`|Builds the .NET driver for all target frameworks and operating systems.|
|`BuildNetFx`|Builds the .NET Framework driver for all target frameworks.|
|`BuildTestsNetCore`|Builds tests for the .NET driver.|
|`BuildTestsNetFx`|Builds tests for the .NET Framework driver.|
-|`Clean`|Cleans generated files.|
-|`Restore`|Restores Nuget packages.|
+|`Clean`|Cleans all generated files.|
+|`Restore`|Restores NuGet packages.|
|`RunTests`|Runs the unit, functional, and manual tests for the .NET Framework and .NET drivers|
|`RunUnitTests`|Runs just the unit tests for the .NET Framework and .NET drivers|
|`RunFunctionalTests`|Runs just the functional tests for the .NET Framework and .NET drivers|
|`RunManualTests`|Runs just the manual tests for the .NET Framework and .NET drivers|
|`BuildAkv`|Builds the Azure Key Vault Provider package for all supported platforms.|
-
### Parameters
+
+The following parameters may be defined as MSBuild properties to configure the
+build:
+
|Name|Supported Values|Default|Description|
|-|-|-|-|
|`Configuration`|`Debug`, `Release`|`Debug`|Sets the release configuration.|
-|`BuildNetFx`|`true`, `false`|`true` (Windows), `false` (other)|If false, skips building the .NET Framework driver on Windows.|
|`OSGroup`|`Unix`, `Windows_NT`, `AnyOS`|typically defaults to the client system's OS, unless using `BuildAllConfigurations` or an `AnyOS` specific target|The operating system to target.|
|`Platform`|`AnyCPU`, `x86`, `x64`, `ARM`, `ARM64`|`AnyCPU`|May only be set when using package reference type or running tests.|
|`TestSet`|`1`, `2`, `3`, `AE`|all|Build or run a subset of the manual tests. Omit (default) to target all tests.|
@@ -45,12 +50,11 @@ Once the environment is setup properly, execute the desired set of commands belo
|`TF`|`net8.0`, `net462`, `net47`, `net471`, `net472`, `net48`, `net481`|`net8.0` in netcore, `net462` in netfx|Sets the target framework when building or running tests. Not applicable when building the drivers.|
|`ResultsDirectory`|An absolute file path|./TestResults relative to current directory|Specifies where to write test results.|
-
## Example Workflows using MSBuild (Recommended)
+
Using the default configuration and running all tests:
```bash
-msbuild
msbuild -t:BuildTestsNetFx -p:TF=net462
msbuild -t:BuildTestsNetCore
msbuild -t:RunTests
@@ -59,28 +63,25 @@ msbuild -t:RunTests
Using the Release configuration:
```bash
-msbuild -p:configuration=Release
-msbuild -t:BuildTestsNetFx -p:TF=net462 -p:configuration=Release
-msbuild -t:BuildTestsNetCore -p:configuration=Release
-msbuild -t:RunTests -p:configuration=Release
+msbuild -t:BuildTestsNetFx -p:TF=net462 -p:Configuration=Release
+msbuild -t:BuildTestsNetCore -p:Configuration=Release
+msbuild -t:RunTests -p:Configuration=Release
```
Running only the unit tests:
```bash
-msbuild
msbuild -t:BuildTestsNetFx -p:TF=net462
msbuild -t:BuildTestsNetCore
msbuild -t:RunUnitTests
```
-Using a specific dotnet version/architecture:
+Using a specific .NET runtime to run tests:
```bash
-msbuild -p:configuration=Release
-msbuild -t:BuildTestsNetFx -p:TF=net462 -p:configuration=Release
-msbuild -t:BuildTestsNetCore -p:configuration=Release
-msbuild -t:RunTests -p:configuration=Release -p:DotnetPath=C:\net8-win-x86\
+msbuild -t:BuildTestsNetFx -p:TF=net462
+msbuild -t:BuildTestsNetCore
+msbuild -t:RunTests -p:DotnetPath=C:\net8-win-x86\
```
### Running Manual Tests
@@ -119,15 +120,13 @@ Manual Tests require the below setup to run:
|IsManagedInstance | (Optional) When set to `true` **TVP** related tests will use on non-Azure bs files to compare test results. this is needed when testing against Managed Instances or TVP Tests will fail on Test set 3. The default value is `false`. |
|PowerShellPath | The full path to PowerShell.exe. This is not required if the path is present in the PATH environment variable. | `D:\\escaped\\absolute\\path\\to\\PowerShell.exe` |
-
## Example workflows using the Dotnet SDK
-#### Run Functional Tests
+### Run Functional Tests
- Windows (`netfx x86`):
```bash
-msbuild
dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Platform="x86" -p:Configuration="Release" -p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests"
```
@@ -152,7 +151,8 @@ dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.S
```bash
dotnet test "src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj" -p:Platform="AnyCPU" -p:Configuration="Release" -p:TestTargetOS="Unixnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonlinuxtests&category!=nonuaptests"
```
-#### Run Manual Tests
+
+### Run Manual Tests
- Windows (`netfx x86`):
@@ -194,35 +194,39 @@ dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlCl
Tests can be built and run with custom "Reference Type" property that enables different styles of testing:
-- "Project" => Build and run tests with Microsoft.Data.SqlClient as Project Reference
-- "Package" => Build and run tests with Microsoft.Data.SqlClient as Package Reference with configured "TestMicrosoftDataSqlClientVersion" in "Versions.props" file.
+- "Project" => Build and run tests with Microsoft.Data.SqlClient as a Project Reference
+- "Package" => Build and run tests with Microsoft.Data.SqlClient as a Package Reference with configured "TestMicrosoftDataSqlClientVersion" in "Versions.props" file.
> ************** IMPORTANT NOTE BEFORE PROCEEDING WITH "PACKAGE" REFERENCE TYPE ***************
> CREATE A NUGET PACKAGE WITH BELOW COMMAND AND ADD TO LOCAL FOLDER + UPDATE NUGET CONFIG FILE TO READ FROM THAT LOCATION
>
> ```bash
-> msbuild -p:configuration=Release
+> msbuild -p:Configuration=Release
> ```
A non-AnyCPU platform reference can only be used with package reference type. Otherwise, the specified platform will be replaced with AnyCPU in the build process.
### Building Tests with Reference Type
-For .NET, all 4 reference types are supported:
+For .NET:
```bash
+# Project is the default reference type. The below commands are equivalent:
+msbuild -t:BuildTestsNetCore
msbuild -t:BuildTestsNetCore -p:ReferenceType=Project
-# Default setting uses Project Reference.
+# Package reference type:
msbuild -t:BuildTestsNetCore -p:ReferenceType=Package
```
-For .NET Framework, below reference types are supported:
+For .NET Framework:
```bash
+# Project is the default reference type. The below commands are equivalent:
+msbuild -t:BuildTestsNetFx -p:TF=net462
msbuild -t:BuildTestsNetFx -p:TF=net462 -p:ReferenceType=Project
-# Default setting uses Project Reference.
+# Package reference type:
msbuild -t:BuildTestsNetFx -p:TF=net462 -p:ReferenceType=Package
```
@@ -241,26 +245,25 @@ Tests can be built and run with custom Target Frameworks. See the below examples
### Building Tests with custom target framework
```bash
-msbuild -t:BuildTestsNetFx -p:TF=net462
# Build the tests for custom .NET Framework target
+msbuild -t:BuildTestsNetFx -p:TF=net462
```
```bash
-msbuild -t:BuildTestsNetCore -p:TF=net8.0
# Build the tests for custom .NET target
+msbuild -t:BuildTestsNetCore -p:TF=net8.0
```
### Running Tests with custom target framework (traditional)
```bash
+# Run tests with custom .NET Framework target
dotnet test -p:TargetNetFxVersion=net462 ...
-# Use above property to run Functional Tests with custom .NET Framework target
+# Run tests with custom .NET target
dotnet test -p:TargetNetCoreVersion=net8.0 ...
-# Use above property to run Functional Tests with custom .NET target
```
-
## Using Managed SNI on Windows
Managed SNI can be enabled on Windows by enabling the below AppContext switch:
@@ -285,20 +288,6 @@ When connecting to a server, if a protocol lower than TLS 1.2 is negotiated, a s
`Switch.Microsoft.Data.SqlClient.SuppressInsecureTLSWarning`
-### Troubleshooting Docker issues
-
-There may be times where connection cannot be made to SQL Server, we found below ideas helpful:
-
-- Clear Docker images to create clean image from time-to-time, and clear docker cache if needed by running `docker system prune` in Command Prompt.
-
-- If you face `Microsoft.Data.SqlClient.SNI.dll not found` errors when debugging, try updating the below properties in the netcore\Microsoft.Data.SqlClient.csproj file and try again:
-
- ```xml
- Unix
- false
- true
- ```
-
## Collecting Code Coverage
### Using VSTest
diff --git a/NuGet.config b/NuGet.config
index d93875f3fb..3e762e7fe9 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -1,11 +1,30 @@
+
+
-
+
+
+
+
+
+
+
+
diff --git a/build.proj b/build.proj
index 79635218ff..af26f1dbfc 100644
--- a/build.proj
+++ b/build.proj
@@ -2,8 +2,9 @@
-
-
+
+
+
@@ -29,7 +30,7 @@
true
Configuration=$(Configuration);AssemblyVersion=$(SqlServerAssemblyVersion);AssemblyFileVersion=$(SqlServerAssemblyFileVersion);Version=$(SqlServerPackageVersion);
Configuration=$(Configuration);AssemblyFileVersion=$(AssemblyFileVersion);TargetsWindows=$(TargetsWindows);TargetsUnix=$(TargetsUnix);
- BuildProjectReferences=false;$(ProjectProperties);BuildForRelease=false;TargetNetCoreVersion=$(TargetNetCoreVersion);TargetNetFxVersion=$(TargetNetFxVersion)
+ $(ProjectProperties);BuildForRelease=false;TargetNetCoreVersion=$(TargetNetCoreVersion);TargetNetFxVersion=$(TargetNetFxVersion)
TestResults
+
+
@@ -89,32 +92,96 @@
-
-
-
+
+
+
-
-
+
+
+
+
+
+
+ AbstractionsPackageVersion=$(AbstractionsPackageVersion)
+
+
+
+
+ $(AbstractionsProperties);AbstractionsAssemblyFileVersion=$(AbstractionsAssemblyFileVersion)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
@@ -127,7 +194,10 @@
-
+
@@ -144,27 +214,37 @@
-
+
-
+
+
-
+
-
-
+
+
@@ -173,7 +253,9 @@
-
+
@@ -182,12 +264,18 @@
-
+
-
+
@@ -196,7 +284,10 @@
-
+
@@ -353,14 +444,14 @@
-
+
-
-
-
-
-
-
+
+
+
+
+
+
@@ -395,7 +486,10 @@
-
+
@@ -405,7 +499,9 @@
-
+
@@ -415,7 +511,9 @@
-
+
diff --git a/eng/pipelines/common/templates/jobs/build-signed-package-job.yml b/eng/pipelines/common/templates/jobs/build-signed-package-job.yml
index 91eb864337..21539540df 100644
--- a/eng/pipelines/common/templates/jobs/build-signed-package-job.yml
+++ b/eng/pipelines/common/templates/jobs/build-signed-package-job.yml
@@ -51,6 +51,7 @@ jobs:
- template: ../steps/generate-nuget-package-step.yml@self
parameters:
OutputDirectory: $(artifactDirectory)
+ properties: 'AbstractionsPackageVersion=$(abstractionsPackageVersion)'
- template: ../steps/esrp-code-signing-step.yml@self
parameters:
diff --git a/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml b/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml
index cb3790262c..5642d5be47 100644
--- a/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml
+++ b/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml
@@ -58,6 +58,7 @@ jobs:
nuspecPath: 'tools/specs/Microsoft.Data.SqlClient.nuspec'
OutputDirectory: $(packagePath)
generateSymbolsPackage: false
+ properties: 'AbstractionsPackageVersion=$(abstractionsPackageVersion)'
displayName: 'Generate NuGet package M.D.SqlClient'
- template: ../steps/generate-nuget-package-step.yml@self
@@ -67,6 +68,7 @@ jobs:
nuspecPath: 'tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec'
OutputDirectory: $(packagePath)
generateSymbolsPackage: false
+ properties: 'MdsPackageVersion=$(mdsPackageVersion)'
installNuget: false
displayName: 'Generate NuGet package AKV Provider'
diff --git a/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml b/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml
index 4e32f989c3..8a8fd00f6f 100644
--- a/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml
+++ b/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml
@@ -32,11 +32,11 @@ parameters:
type: boolean
default: true
- - name: referenceType
- default: project
- values:
- - project
- - package
+ # Semi-colon separated properties to pass to nuget via the -properties
+ # argument.
+ - name: properties
+ type: string
+ default: ''
steps:
- ${{ if parameters.installNuget }}:
@@ -55,6 +55,6 @@ steps:
inputs:
command: custom
${{ if parameters.generateSymbolsPackage }}:
- arguments: 'pack -Symbols -SymbolPackageFormat snupkg ${{parameters.nuspecPath}} -Version ${{parameters.NugetPackageVersion}} -OutputDirectory ${{parameters.OutputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};ReferenceType=${{parameters.referenceType}}"'
+ arguments: 'pack -Symbols -SymbolPackageFormat snupkg ${{parameters.nuspecPath}} -Version ${{parameters.NugetPackageVersion}} -OutputDirectory ${{parameters.OutputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};${{parameters.properties}}"'
${{else }}:
- arguments: 'pack ${{parameters.nuspecPath}} -Version ${{parameters.NugetPackageVersion}} -OutputDirectory ${{parameters.OutputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};ReferenceType=${{parameters.referenceType}}"'
+ arguments: 'pack ${{parameters.nuspecPath}} -Version ${{parameters.NugetPackageVersion}} -OutputDirectory ${{parameters.OutputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};${{parameters.properties}}"'
diff --git a/eng/pipelines/libraries/ci-build-variables.yml b/eng/pipelines/libraries/ci-build-variables.yml
index 122281e083..d3ae6fcbc3 100644
--- a/eng/pipelines/libraries/ci-build-variables.yml
+++ b/eng/pipelines/libraries/ci-build-variables.yml
@@ -23,3 +23,13 @@ variables:
value: false
- name: packagePath
value: '$(Build.SourcesDirectory)/packages'
+
+ # TODO(ADO-38703): Remove these when the other pipeline changes arrive.
+ - name: baseBuildNumber
+ value: $[ split(variables['Build.BuildNumber'], '.')[0] ]
+ - name: abstractionsPackageVersion
+ value: 1.0.0.$(baseBuildNumber)
+ - name: mdsPackageVersion
+ value: $(NugetPackageVersion)
+ - name: akvPackageVersion
+ value: $(NugetPackageVersion)
diff --git a/eng/pipelines/libraries/common-variables.yml b/eng/pipelines/libraries/common-variables.yml
index 20753536b8..a986c714af 100644
--- a/eng/pipelines/libraries/common-variables.yml
+++ b/eng/pipelines/libraries/common-variables.yml
@@ -34,7 +34,7 @@ variables:
- name: Patch
value: '0'
- # Update this for preview releases.
+ # Update this for preview releases.
- name: Preview
value: '-preview'
- name: Revision
@@ -48,3 +48,13 @@ variables:
value: '$(Major).$(Minor)$(Patch).$(Build.BuildNumber)'
- name: nuspecPath
value: '$(REPOROOT)/tools/specs/Microsoft.Data.SqlClient.nuspec'
+
+ # TODO(ADO-38703): Remove these when the other pipeline changes arrive.
+ - name: baseBuildNumber
+ value: $[ split(variables['Build.BuildNumber'], '.')[0] ]
+ - name: abstractionsPackageVersion
+ value: 1.0.0.$(baseBuildNumber)
+ - name: mdsPackageVersion
+ value: $(NugetPackageVersion)
+ - name: akvPackageVersion
+ value: $(NugetPackageVersion)
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 4c210df737..86f3529cbb 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -20,7 +20,6 @@
> msbuild -p:configuration=Release
-->
Project
- $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
$([System.IO.Path]::Combine('$(IntermediateOutputPath)','$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension)'))
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index db7bf67c00..c01b28e57e 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -7,6 +7,13 @@
+
+
+
+
+
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/README.md b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/README.md
new file mode 100644
index 0000000000..fbb8bfb738
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/README.md
@@ -0,0 +1,285 @@
+# MDS Azure Extension Design
+
+## Overview
+
+For the MDS 7.0.0 release, we are proposing the following package architecture
+changes that will decouple several large dependencies from MDS and move them
+into a new `Azure` extension package:
+
+- Create a new `Abstractions` package that all other MDS packages depend on.
+ - This will contain types and definitions common to the other MDS packages,
+ such as base classes, enums, delegates, etc.
+- Create a new `Azure` package that will own the following implementations:
+ - Azure Authentication
+ - Azure Attestation
+ - Azure Key Vault interactions
+- Move the above implementations out of MDS and into the new `Azure` package.
+- Move the existing `AzureKeyVaultProvider` (AKV) implementation into the new
+ `Azure` extension package.
+
+This will reduce the main MDS package dependency tree along with a moderate
+package size reduction.
+
+## Motivation
+
+Issue: [#1108](https://github.com/dotnet/SqlClient/issues/1108)
+
+Customers and the developer community have voiced concerns with MDS being
+tightly coupled to Azure dependencies. Many customers do not use Azure and do
+not want to deploy unnecessary DLLs with their applications.
+
+Moving the Azure dependent implementations into a separate `Azure` extension
+package achieves two goals:
+
+- Remove Azure packages as direct dependencies of MDS and reduce the MDS
+ dependency tree.
+- Clearly expose existing MDS extension points, prove their functionality, and
+ demonstrate how to use them.
+
+The following dependencies will be removed from the main MDS package:
+
+- `Azure.Identity`
+ - `Azure.Core` (transitive)
+ - `Microsoft.Identity.Client` (transitive)
+- `Microsoft.IdentityModel.JsonWebTokens`
+ - `Microsoft.IdentityModel.Tokens` (transitive)
+ - `Microsoft.IdentityModel.Logging` (transitive)
+- `Microsoft.IdentityModel.Protocols.OpenIdConnect`
+ - `Microsoft.IdentityModel.Protocols` (transitive)
+
+The following dependencies will be removed from the AKV Provider package:
+
+- `Azure.Core`
+- `Azure.Security.KeyVault.Keys`
+
+## Package Architecture
+
+```mermaid
+classDiagram
+class MDS
+class MDS.Extensions.Abstractions
+class MDS.Extensions.Azure
+class AKV Provider
+
+MDS --> MDS.Extensions.Abstractions
+MDS ..> MDS.Extensions.Azure
+MDS ..> AKV Provider
+MDS.Extensions.Azure --> MDS.Extensions.Abstractions
+AKV Provider --> MDS.Extensions.Azure
+
+MDS: Depend on MDS.Extensions.Abstractions
+MDS: Load Azure or AKV assembly
+MDS.Extensions.Abstractions: Azure Authentication Types
+MDS.Extensions.Abstractions: Azure Attestation Types
+MDS.Extensions.Abstractions: Azure Key Vault Types
+MDS.Extensions.Azure: Depend on MDS.Extensions.Abstractions
+MDS.Extensions.Azure: Authentication Implementation
+MDS.Extensions.Azure: Attestation Implementation
+MDS.Extensions.Azure: Key Vault Implementation
+AKV Provider: Depend on MDS.Extensions.Azure
+```
+
+In previous MDS versions, the AKV package depended directly on the main MDS
+package through a ranged version (for example [6.0.0, 7.0.0) - all 6.x
+versions). With the new package architecture this is no longer the case.
+Extension packages will not depend on the main MDS package, nor will the main
+MDS package depend on any extension packages. All dependencies between MDS and
+its extensions will occur through the `Abstractions` package.
+
+This new looser coupling gives applications the flexibility to depend on only
+the main MDS package, or on MDS and a subset of it extension packages if
+desired.
+
+## Consuming
+
+There are several ways that applications may consume MDS and its extensions:
+
+- MDS without Azure features
+- MDS with MDS-supplied Azure features
+- MDS with externally supplied Azure features
+
+Applications never need to directly depend on the `Abstractions` base package.
+This will be transitively depended on by other MDS packages.
+
+### Without Azure Features
+
+Applications that do not use any Azure features will no longer bring in those
+unwanted dependencies transitively. Simply include the main MDS package by
+itself:
+
+```xml
+
+
+
+```
+
+Calls to MDS APIs that require Azure features will throw an exception, since
+no Azure feature implementation is present.
+
+### With MDS Azure Features
+
+Applications that wish to use MDS-supplied Azure features will need to include
+the new `Azure` extension package as a direct dependency alongside the main MDS
+package:
+
+```xml
+
+
+
+
+```
+
+MDS will automatically detect the `Azure` extension assemblies and load them.
+
+### With External Azure Features
+
+Applications that wish to use Azure features supplied by another (non-MDS)
+package will need to include that package as a direct dependency alongside the
+main MDS package:
+
+```xml
+
+
+
+
+```
+
+Additionally, applications will need to instruct MDS to use the external Azure
+feature implementations via the appropriate APIs at runtime:
+
+- Authentication: [SqlAuthenticationProvider](https://learn.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient.sqlauthenticationprovider?view=sqlclient-dotnet-core-6.0)
+- Attestation: _**New API will be exposed.**_
+- Key Valut: [SqlColumnEncryptionKeyStoreProvider](https://learn.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient.sqlcolumnencryptionkeystoreprovider?view=sqlclient-dotnet-core-6.0)
+
+## Versioning Strategy
+
+The MDS suite of packages will be versioned independently. This provides
+flexibility to update APIs and implementations for packages as needed, avoiding
+unnecessary version bumps and releases. The initial release of these packages
+will have the following versions:
+
+|Package|Version|Comment|
+|-|-|-|
+|`Microsoft.Data.SqlClient.Extensions.Abstractions`|1.0.0|First version of this package.|
+|`Microsoft.Data.SqlClient`|7.0.0|Major version bump due to breaking changes described in this document.|
+|`Microsoft.Data.SqlClient.Extensions.Azure`|1.0.0|First version of this package.|
+|`Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider`|7.0.0|_**Deprecated.**_|
+
+Going forward, each package will be versioned appropriately based on the nature
+of the changes included with subsequent releases.
+
+**Note**: The `AzureKeyVaultProvider` package will remain at 7.0.0. It will be
+deprecated and eventually removed, as it has been replaced by the `Azure`
+extension package.
+
+## Intradependence
+
+The main MDS package and the new `Azure` package will depend on the
+`Abstractions` package. When APIs are added, modified, or removed from the
+`Abstractions` package, corresponding changes will be made to the dependent
+packages as well. Those dependent packages will then take a strict dependency
+on the appropriate `Abstractions` package version. This ensures that only
+compatible extensions package versions can co-exist with the main MDS package.
+
+For example, imagine that a new extensible conenction pooling feature is added
+to MDS. The `Abstractions` package would be updated to include any new pooling
+APIs, the main MDS package would be updated to accept extensible pooling, and
+the new pooling implementation would be included in a new `ConnectionPooling`
+extension package. The versions of these packages would look something like
+this:
+
+|Package|Version|
+|-|-|
+|`Microsoft.Data.SqlClient.Extensions.Abstractions`|1.1.0|
+|`Microsoft.Data.SqlClient`|7.1.0|
+|`Microsoft.Data.SqlClient.Extensions.ConnectionPooling`|1.0.0|
+
+Both the main MDS package and the new `ConnectionPooling` package would depend
+on `Abstractions` v1.1.0.
+
+An application wishing to use the new `ConnectionPooling` v1.0.0 package must
+also update the main MDS package to v7.1.0. The application would not be able
+to use `ConnectionPooling` v1.0.0 and MDS v7.0.0.
+
+## Backwards Compatibility
+
+There are several backwards compatibility scenarios to consider for applications
+that rely on MDS Azure features currently implemented in the main MDS package
+and the AKV package. The new extensions package architecture aims to reduce the
+friction for these apps, but not all scenarios will be seamless.
+
+All of the scenarios below assume that the application is upgrading to the
+latest versions of MDS packages.
+
+### Apps using MDS Azure Authentication
+
+Applications currently using the MDS-supplied Azure Authentication features will
+need to add a dependency on the `Azure` extension package to their project
+alongside the main MDS package:
+
+```xml
+
+
+
+
+```
+
+All Azure Authentication namespaces and types will remain the same, so this
+should be the only change necessary for applications.
+
+### Apps using MDS Azure Attestation
+
+Applications currently using the MDS-supplied Azure Attestation features will
+need to add a dependency on the `Azure` extension package to their project
+alongside the main MDS package:
+
+```xml
+
+
+
+
+```
+
+All Azure Attestation namespaces and types will remain the same, so this should
+be the only change necessary for applications.
+
+### Apps using AKV Provider
+
+Applications currently using the MDS-supplied AKV provider will have two options
+when upgrading to MDS v7.0.0. Both options rely on the main MDS package finding
+and loading an appropriate DLL (assembly) at runtime. The absence of an
+appropriate DLL will cause Azure Key Vault operations to throw an exception.
+
+#### Use Azure Extension
+
+This is the preferred approach. The application would be updated to depend
+on the main MDS package and the `Azure` extension package:
+
+```xml
+
+
+
+
+```
+
+The `Azure` extension package will contain the same namespaces and types as the
+current AKV provider and will be a drop-in replacement. The main MDS v7.0.0
+package will look for the `Azure` extension assembly and automatically load it.
+
+#### Use AKV Provider v7.0.0
+
+This is a temporary solution. The AKV provider v7.0.0 will be marked as
+deprecated and removed entirely at some point in the future. The applictaion
+would remain dependent on the AKV provider, but must update to the v7.0.0
+package. Previous AKV package versions do not support main MDS package versions
+beyond the v6.x range.
+
+```xml
+
+
+
+
+```
+
+This AKV Provider v7.0.0 package will be empty and simply depend on the `Azure`
+extension package to transitively provide the Azure Key Vault features.
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/Sample.xml b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/Sample.xml
new file mode 100644
index 0000000000..8d5f5c44d5
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/Sample.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+ Sample class to demonstrate packaging and pipelines.
+
+
+
+ Construct with a name.
+ The name.
+
+
+ Gets the name.
+ The name.
+
+
+
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj
new file mode 100644
index 0000000000..485a3de83a
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+ netstandard2.0
+
+
+
+
+ enable
+ enable
+
+
+
+
+ Microsoft.Data.SqlClient.Extensions.Abstractions
+ Microsoft.Data.SqlClient.Extensions.Abstractions
+
+
+ $(_DefaultMajorVersion).0.0.0
+
+ $(AbstractionsAssemblyFileVersion)
+ $(AbstractionsAssemblyFileVersion)
+ $(AbstractionsPackageVersion)
+
+
+
+
+ <_Parameter1>true
+
+
+
+
+
+
+
+
+ $(AssemblyName)
+ $(AbstractionsPackageVersion)
+ $(PackagesDir)
+ true
+ snupkg
+
+ Microsoft Corporation
+ Microsoft Corporation
+ Microsoft.Data.SqlClient Extensions Abstractions
+ https://github.com/dotnet/SqlClient
+ MIT
+ dotnet.png
+
+
+
+
+
+
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/AbstractionsVersions.props b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/AbstractionsVersions.props
new file mode 100644
index 0000000000..29ff5899af
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/AbstractionsVersions.props
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ <_DefaultMajorVersion>1
+
+
+ <_OurPackageVersion Condition="'$(AbstractionsPackageVersion)' != ''">$(AbstractionsPackageVersion)
+ <_OurPackageVersion Condition="'$(AbstractionsPackageVersion)' == ''">$(_DefaultMajorVersion).0.0.$(BuildNumber)-dev
+
+
+
+ <_OurAssemblyFileVersion Condition="'$(AbstractionsAssemblyFileVersion)' != ''">$(AbstractionsAssemblyFileVersion)
+
+ <_OurAssemblyFileVersion Condition="'$(AbstractionsAssemblyFileVersion)' == '' and '$(AbstractionsPackageVersion)' != ''">$(AbstractionsPackageVersion.Split('-')[0])
+
+ <_OurAssemblyFileVersion Condition="'$(AbstractionsAssemblyFileVersion)' == '' and '$(AbstractionsPackageVersion)' == ''">$(_DefaultMajorVersion).0.0.$(BuildNumber)
+
+
+ $(_OurPackageVersion)
+ $(_OurAssemblyFileVersion)
+
+
+
+
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Sample.cs b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Sample.cs
new file mode 100644
index 0000000000..bf22119436
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Sample.cs
@@ -0,0 +1,20 @@
+namespace Microsoft.Data.SqlClient.Extensions.Abstractions;
+
+///
+public class Sample
+{
+ ///
+ public Sample(string name)
+ {
+ Name = name;
+ }
+
+ ///
+ public string Name { get; private set; }
+
+ // Update the name.
+ internal void SetName(string name)
+ {
+ Name = name;
+ }
+}
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj
new file mode 100644
index 0000000000..118b215737
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj
@@ -0,0 +1,26 @@
+
+
+
+ net462;net47;net471;net472;net48;net481;net8.0;net9.0
+ enable
+ enable
+ false
+ true
+ Microsoft.Data.SqlClient.Extensions.Abstractions.Test
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SampleTest.cs b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SampleTest.cs
new file mode 100644
index 0000000000..ab8e9da052
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SampleTest.cs
@@ -0,0 +1,19 @@
+namespace Microsoft.Data.SqlClient.Extensions.Abstractions.Test;
+
+public class SampleTest
+{
+ [Fact]
+ public void Construction()
+ {
+ Assert.Equal("test", new Sample("test").Name);
+ }
+
+ [Fact]
+ public void SetName()
+ {
+ var sample = new Sample("test");
+ Assert.Equal("test", sample.Name);
+ sample.SetName("new name");
+ Assert.Equal("new name", sample.Name);
+ }
+}
diff --git a/src/Microsoft.Data.SqlClient.sln b/src/Microsoft.Data.SqlClient.sln
index 94900021ac..d7a2f70689 100644
--- a/src/Microsoft.Data.SqlClient.sln
+++ b/src/Microsoft.Data.SqlClient.sln
@@ -1,6 +1,7 @@
+
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
-VisualStudioVersion = 17.0.31912.275
+VisualStudioVersion = 17.14.36203.30
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Data.SqlClient", "Microsoft.Data.SqlClient\netfx\src\Microsoft.Data.SqlClient.csproj", "{407890AC-9876-4FEF-A6F1-F36A876BAADE}"
EndProject
@@ -314,6 +315,17 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SqlClient.Stress.Runner", "Microsoft.Data.SqlClient\tests\StressTests\SqlClient.Stress.Runner\SqlClient.Stress.Runner.csproj", "{4A9C11F4-9577-ABEC-C070-83A194746D9B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SqlClient.Stress.Tests", "Microsoft.Data.SqlClient\tests\StressTests\SqlClient.Stress.Tests\SqlClient.Stress.Tests.csproj", "{FAA1E517-581A-D3DC-BAC9-FAD1D5A5142C}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.Data.SqlClient.Extensions", "Microsoft.Data.SqlClient.Extensions", "{19F1F1E5-3013-7660-661A-2A15F7D606C1}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Abstractions", "Abstractions", "{556B486E-F9B0-7EA9-6A25-DA560C312761}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{210228A5-979A-DE06-EE1F-B35C65E1583C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Abstractions", "Microsoft.Data.SqlClient.Extensions\Abstractions\src\Abstractions.csproj", "{B21E7C94-D805-427E-928A-8DE8EA2F08CC}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{59667E4C-0BD2-9F48-FB50-9E55DD8B1011}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Abstractions.Test", "Microsoft.Data.SqlClient.Extensions\Abstractions\test\Abstractions.Test.csproj", "{04ACBF75-CFF2-41AB-B652-776BC0533490}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -643,6 +655,30 @@ Global
{FAA1E517-581A-D3DC-BAC9-FAD1D5A5142C}.Release|x64.Build.0 = Release|Any CPU
{FAA1E517-581A-D3DC-BAC9-FAD1D5A5142C}.Release|x86.ActiveCfg = Release|Any CPU
{FAA1E517-581A-D3DC-BAC9-FAD1D5A5142C}.Release|x86.Build.0 = Release|Any CPU
+ {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Debug|x64.Build.0 = Debug|Any CPU
+ {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Debug|x86.Build.0 = Debug|Any CPU
+ {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Release|x64.ActiveCfg = Release|Any CPU
+ {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Release|x64.Build.0 = Release|Any CPU
+ {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Release|x86.ActiveCfg = Release|Any CPU
+ {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Release|x86.Build.0 = Release|Any CPU
+ {04ACBF75-CFF2-41AB-B652-776BC0533490}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {04ACBF75-CFF2-41AB-B652-776BC0533490}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {04ACBF75-CFF2-41AB-B652-776BC0533490}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {04ACBF75-CFF2-41AB-B652-776BC0533490}.Debug|x64.Build.0 = Debug|Any CPU
+ {04ACBF75-CFF2-41AB-B652-776BC0533490}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {04ACBF75-CFF2-41AB-B652-776BC0533490}.Debug|x86.Build.0 = Debug|Any CPU
+ {04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|Any CPU.Build.0 = Release|Any CPU
+ {04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|x64.ActiveCfg = Release|Any CPU
+ {04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|x64.Build.0 = Release|Any CPU
+ {04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|x86.ActiveCfg = Release|Any CPU
+ {04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -699,6 +735,11 @@ Global
{92D9C6D6-6925-1AD1-69FA-485F83943BD2} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{4A9C11F4-9577-ABEC-C070-83A194746D9B} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{FAA1E517-581A-D3DC-BAC9-FAD1D5A5142C} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
+ {556B486E-F9B0-7EA9-6A25-DA560C312761} = {19F1F1E5-3013-7660-661A-2A15F7D606C1}
+ {210228A5-979A-DE06-EE1F-B35C65E1583C} = {556B486E-F9B0-7EA9-6A25-DA560C312761}
+ {B21E7C94-D805-427E-928A-8DE8EA2F08CC} = {210228A5-979A-DE06-EE1F-B35C65E1583C}
+ {59667E4C-0BD2-9F48-FB50-9E55DD8B1011} = {556B486E-F9B0-7EA9-6A25-DA560C312761}
+ {04ACBF75-CFF2-41AB-B652-776BC0533490} = {59667E4C-0BD2-9F48-FB50-9E55DD8B1011}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {01D48116-37A2-4D33-B9EC-94793C702431}
diff --git a/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props b/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props
index 7776439adc..dfeb60b38c 100644
--- a/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props
+++ b/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props
@@ -9,7 +9,6 @@
true
true
Project
- $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
true
$([System.IO.Path]::Combine('$(IntermediateOutputPath)','$(TargetFramework)','$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension)'))
diff --git a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj
index 0944a4aea0..f4fa41bf45 100644
--- a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj
@@ -46,7 +46,23 @@
-
+
+
+
+
+
+
+
+
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
index 44560401db..d46e4c5f37 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
@@ -1083,6 +1083,22 @@
+
+
+
+
+
+
+
diff --git a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj
index 380a2aa746..e8dbcf7070 100644
--- a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj
@@ -49,5 +49,22 @@
+
+
+
+
+
+
+
+
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj
index 8b4a48c705..0886b0a973 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj
@@ -1059,6 +1059,23 @@
+
+
+
+
+
+
+
+
diff --git a/tools/props/Versions.props b/tools/props/Versions.props
index ad42c4964a..7a3ba3cc9a 100644
--- a/tools/props/Versions.props
+++ b/tools/props/Versions.props
@@ -1,29 +1,12 @@
-
+
+
+
- 7.0.0
0
-
-
- $(MdsVersionDefault).$(BuildNumber)
-
- 7.0.0.0
-
- $(AssemblyFileVersion)
- $(MdsVersionDefault)-dev
- $(NugetPackageVersion)
+
+
@@ -33,8 +16,47 @@
1.0.0-dev
$(SqlServerPackageVersion)
+
+
+
+
+
+
+ 7.0.0
+
+ $(MdsVersionDefault).$(BuildNumber)-dev
+
+
+
+
+ $(MdsVersionDefault).$(BuildNumber)
+
+
+ 7.0.0.0
+
+ $(AssemblyFileVersion)
+
+
+ $(MdsPackageVersion)
+
+
+
- $(NugetPackageVersion)
+ 7.0.0
+ $(AkvVersionDefault).$(BuildNumber)-dev
- $(NugetPackageVersion)
+ $(MdsPackageVersion)
diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec
index fb3fe267fc..78365bd21e 100644
--- a/tools/specs/Microsoft.Data.SqlClient.nuspec
+++ b/tools/specs/Microsoft.Data.SqlClient.nuspec
@@ -32,6 +32,7 @@
+
@@ -48,6 +49,7 @@
+
@@ -62,6 +64,7 @@
+
@@ -76,6 +79,7 @@
+
diff --git a/tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec b/tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec
index 0816fd3086..a313d0af12 100644
--- a/tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec
+++ b/tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec
@@ -25,17 +25,23 @@ Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyStoreProvider.SqlColumnEncrypti
sqlclient microsoft.data.sqlclient azurekeyvaultprovider akvprovider alwaysencrypted
-
+
-
+
+
+
+
+
+
+
@@ -46,22 +52,22 @@ Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyStoreProvider.SqlColumnEncrypti
-
-
-
-
-
+
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
+
+
+
+
+
+
+
+
+
diff --git a/tools/targets/GenerateNugetPackage.targets b/tools/targets/GenerateNugetPackage.targets
deleted file mode 100644
index 4c8cea4159..0000000000
--- a/tools/targets/GenerateNugetPackage.targets
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
- $(NugetPackageVersion)-debug
-
-
-
-
-
-
-
-
-
-
-
-
- $(SqlServerPackageVersion)-debug
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tools/targets/GenerateSqlServerPackage.targets b/tools/targets/GenerateSqlServerPackage.targets
new file mode 100644
index 0000000000..ea6655dcee
--- /dev/null
+++ b/tools/targets/GenerateSqlServerPackage.targets
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/targets/add-ons/GenerateAKVProviderNugetPackage.targets b/tools/targets/add-ons/GenerateAKVProviderNugetPackage.targets
deleted file mode 100644
index 78da74bf32..0000000000
--- a/tools/targets/add-ons/GenerateAKVProviderNugetPackage.targets
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
- $(NugetPackageVersion)-debug
-
-
-
-
-
-
diff --git a/tools/targets/add-ons/GenerateAkvPackage.targets b/tools/targets/add-ons/GenerateAkvPackage.targets
new file mode 100644
index 0000000000..fd822442a2
--- /dev/null
+++ b/tools/targets/add-ons/GenerateAkvPackage.targets
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
From c66066a908e64d175853cebf09aab32bd31faf5d Mon Sep 17 00:00:00 2001
From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com>
Date: Thu, 16 Oct 2025 13:23:37 -0300
Subject: [PATCH 02/16] Abstractions Package - Pipeline Changes (#3628)
---
build.proj | 1 -
eng/pipelines/akv-official-pipeline.yml | 9 +-
.../jobs/build-signed-package-job.yml | 54 ++++-
.../templates/jobs/ci-build-nugets-job.yml | 83 +++++--
.../templates/jobs/ci-run-tests-job.yml | 107 +++++----
.../jobs/run-tests-package-reference-job.yml | 8 +-
.../jobs/validate-signed-package-job.yml | 84 +++----
.../templates/stages/ci-run-tests-stage.yml | 53 +++--
...ld-all-configurations-signed-dlls-step.yml | 37 +--
.../templates/steps/build-all-tests-step.yml | 44 ++--
.../build-and-run-tests-netcore-step.yml | 12 +-
.../steps/build-and-run-tests-netfx-step.yml | 12 +-
.../templates/steps/ci-prebuild-step.yml | 24 +-
.../templates/steps/ci-project-build-step.yml | 39 ++--
.../templates/steps/code-analyze-step.yml | 50 ++--
.../steps/copy-dlls-for-test-step.yml | 4 +-
.../steps/generate-nuget-package-step.yml | 19 +-
.../templates/steps/publish-symbols-step.yml | 2 +-
.../templates/steps/run-all-tests-step.yml | 22 +-
.../update-nuget-config-local-feed-step.yml | 80 +++----
eng/pipelines/dotnet-sqlclient-ci-core.yml | 218 ++++++++++--------
...qlclient-ci-package-reference-pipeline.yml | 84 +++++--
...qlclient-ci-project-reference-pipeline.yml | 74 ++++--
.../dotnet-sqlclient-signing-pipeline.yml | 15 +-
eng/pipelines/jobs/build-akv-official-job.yml | 37 +--
.../jobs/pack-abstractions-package-ci-job.yml | 148 ++++++++++++
eng/pipelines/jobs/stress-tests-ci-job.yml | 2 +-
.../jobs/test-abstractions-package-ci-job.yml | 174 ++++++++++++++
.../libraries/ci-build-variables.yml | 19 +-
eng/pipelines/libraries/common-variables.yml | 51 ++--
.../libraries/mds-validation-variables.yml | 2 +-
.../build-abstractions-package-ci-stage.yml | 119 ++++++++++
.../steps/compound-build-akv-step.yml | 18 +-
.../steps/compound-nuget-pack-step.yml | 38 ++-
.../steps/roslyn-analyzers-akv-step.yml | 15 +-
.../variables/akv-official-variables.yml | 6 +-
.../ref/Microsoft.Data.SqlClient.csproj | 3 -
.../src/Microsoft.Data.SqlClient.csproj | 3 -
.../netfx/ref/Microsoft.Data.SqlClient.csproj | 3 -
.../netfx/src/Microsoft.Data.SqlClient.csproj | 3 -
tools/props/Versions.props | 6 +-
tools/specs/Microsoft.Data.SqlClient.nuspec | 143 ++++++------
...waysEncrypted.AzureKeyVaultProvider.nuspec | 35 ++-
tools/targets/GenerateMdsPackage.targets | 2 +-
.../add-ons/GenerateAkvPackage.targets | 2 +-
45 files changed, 1319 insertions(+), 645 deletions(-)
create mode 100644 eng/pipelines/jobs/pack-abstractions-package-ci-job.yml
create mode 100644 eng/pipelines/jobs/test-abstractions-package-ci-job.yml
create mode 100644 eng/pipelines/stages/build-abstractions-package-ci-stage.yml
diff --git a/build.proj b/build.proj
index af26f1dbfc..2a41791844 100644
--- a/build.proj
+++ b/build.proj
@@ -450,7 +450,6 @@
-
diff --git a/eng/pipelines/akv-official-pipeline.yml b/eng/pipelines/akv-official-pipeline.yml
index d7bc900bb8..316ca9e6ea 100644
--- a/eng/pipelines/akv-official-pipeline.yml
+++ b/eng/pipelines/akv-official-pipeline.yml
@@ -105,7 +105,8 @@ extends:
roslyn:
enabled: ${{ parameters.runSdlTasks }}
break: true
- # Requires RoslynAnalyzers task to be added after build task
+ # Requires RoslynAnalyzers task to be added somewhere in
+ # the build stage.
publishLogs:
enabled: ${{ parameters.runSdlTasks }}
@@ -113,7 +114,7 @@ extends:
sbom:
enabled: ${{ parameters.runSdlTasks }}
packageName: 'Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider'
- packageVersion: ${{ variables.nugetPackageVersion }}
+ packageVersion: ${{ variables.akvPackageVersion }}
tsa:
# OneBranch publishes all sdl results to TSA. If TSA is disabled all SDL tools will
@@ -127,11 +128,11 @@ extends:
jobs:
- template: /eng/pipelines/jobs/build-akv-official-job.yml@self
parameters:
+ akvAssemblyFileVersion: '${{ variables.assemblyFileVersion }}'
+ akvPackageVersion: '${{ variables.akvPackageVersion }}'
apiScanDllPath: '${{ variables.apiScanDllPath }}'
apiScanPdbPath: '${{ variables.apiScanPdbPath }}'
- assemblyFileVersion: '${{ variables.assemblyFileVersion }}'
buildConfiguration: '${{ parameters.buildConfiguration }}'
- nugetPackageVersion: '${{ variables.nugetPackageVersion }}'
mdsPackageVersion: '${{ variables.mdsPackageVersion }}'
publishSymbols: '${{ parameters.publishSymbols }}'
signingAppRegistrationClientId: '$(SigningAppRegistrationClientId)'
diff --git a/eng/pipelines/common/templates/jobs/build-signed-package-job.yml b/eng/pipelines/common/templates/jobs/build-signed-package-job.yml
index 21539540df..b90fe026a8 100644
--- a/eng/pipelines/common/templates/jobs/build-signed-package-job.yml
+++ b/eng/pipelines/common/templates/jobs/build-signed-package-job.yml
@@ -27,8 +27,10 @@ jobs:
variables:
- template: ../../../libraries/variables.yml@self
- ${{ if parameters.isPreview }}:
- - name: NugetPackageVersion
- value: $(PreviewNugetPackageVersion)
+ - name: abstractionsPackageVersion
+ value: $(abstractionsPackagePreviewVersion)
+ - name: mdsPackageVersion
+ value: $(previewMdsPackageVersion)
steps:
- script: SET
@@ -37,20 +39,56 @@ jobs:
- powershell: |
Write-Host "##vso[task.setvariable variable=CDP_BUILD_TYPE_COPY;isOutput=true]$($env:CDP_BUILD_TYPE)"
name: GetBuildType
-
- - template: ../steps/build-all-configurations-signed-dlls-step.yml@self
-
+
+ # Build our tooling, which is required by the analysis step below, but
+ # shouldn't be analyzed itself.
+ - task: MSBuild@1
+ displayName: 'Build Tooling'
+ inputs:
+ solution: '**/build.proj'
+ configuration: $(Configuration)
+ msbuildArguments: -t:BuildTools
+
+ # Perform analysis before building, since this step will clobber build output
- template: ../steps/code-analyze-step.yml@self
+
+ # Update the root NuGet.config to use the packages/ directory as a source.
+ # When we build MDS in Package mode, it depends on the Abstractions package,
+ # which we will build and package into packages/.
+ - template: ../steps/update-nuget-config-local-feed-step.yml
parameters:
- analyzeType: all
+ packagePath: $(REPOROOT)/packages
+ # Build the Abstractions package.
+ - task: MSBuild@1
+ displayName: Build Abstractions
+ inputs:
+ solution: '**/build.proj'
+ configuration: $(Configuration)
+ msbuildArguments: -t:BuildAbstractions
+
+ # Build MDS in Package mode, producing signed DLLs.
+ - template: ../steps/build-all-configurations-signed-dlls-step.yml@self
+ parameters:
+ # These variables are sourced from common-variables.yml.
+ abstractionsAssemblyFileVersion: $(abstractionsAssemblyFileVersion)
+ abstractionsPackageVersion: $(abstractionsPackageVersion)
+ configuration: $(Configuration)
+ mdsAssemblyFileVersion: $(mdsAssemblyFileVersion)
+ mdsPackageVersion: $(mdsPackageVersion)
+ referenceType: Package
+
- template: ../steps/esrp-code-signing-step.yml@self
parameters:
artifactType: dll
- template: ../steps/generate-nuget-package-step.yml@self
parameters:
- OutputDirectory: $(artifactDirectory)
+ nuspecPath: $(nuspecPath)
+ packageVersion: $(mdsPackageVersion)
+ outputDirectory: $(artifactDirectory)
+ displayName: 'Create MDS NuGet Package'
+ referenceType: Package
properties: 'AbstractionsPackageVersion=$(abstractionsPackageVersion)'
- template: ../steps/esrp-code-signing-step.yml@self
@@ -65,4 +103,4 @@ jobs:
- template: ../steps/publish-symbols-step.yml@self
parameters:
publishSymbols: ${{ parameters['PublishSymbols'] }}
- symbolsArtifactName: mds_symbols_$(System.TeamProject)_$(Build.Repository.Name)_$(Build.SourceBranchName)_$(NuGetPackageVersion)_$(System.TimelineId)
+ symbolsArtifactName: mds_symbols_$(System.TeamProject)_$(Build.Repository.Name)_$(Build.SourceBranchName)_$(mdsPackageVersion)_$(System.TimelineId)
diff --git a/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml b/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml
index 5642d5be47..dc68462f1a 100644
--- a/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml
+++ b/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml
@@ -4,6 +4,17 @@
# See the LICENSE file in the project root for more information. #
#################################################################################
parameters:
+
+ - name: 'debug'
+ type: boolean
+ default: false
+
+ - name: referenceType
+ type: string
+ values:
+ - Package
+ - Project
+
- name: poolName
type: string
default: $(ci_var_defaultPoolName)
@@ -12,9 +23,13 @@ parameters:
type: string
default: ADO-MMS22-SQL19
- - name: artifactName
+ - name: abstractionsArtifactName
type: string
- default: Artifacts
+ default: Abstractions.Artifact
+
+ - name: mdsArtifactName
+ type: string
+ default: MDS.Artifact
- name: platform
type: string
@@ -28,8 +43,15 @@ parameters:
type: stepList
default: []
+ - name: abstractionsPackageVersion
+ type: string
+
+ - name: mdsPackageVersion
+ type: string
+
jobs:
-- job: build_nugets
+- job: build_mds_akv_packages_job
+ displayName: Build MDS & AKV Packages
pool:
name: ${{parameters.poolName }}
@@ -44,36 +66,65 @@ jobs:
- ${{ if ne(parameters.prebuildSteps, '') }}:
- ${{ parameters.prebuildSteps }} # extra steps to run before the build like downloading sni and the required configuration
+ # If we're testing in Package mode, download the Abstractions package artifacts into packages/,
+ # and then setup the top-level NuGet.config to look in packages/ for local
+ # NuGet dependencies.
+ - ${{ if eq(parameters.referenceType, 'Package') }}:
+ - task: DownloadPipelineArtifact@2
+ displayName: Download Abstractions Package Artifact
+ inputs:
+ artifactName: ${{ parameters.abstractionsArtifactName }}
+ targetPath: $(packagePath)
+ # Note that packages/ will have been created by the above step, which is a
+ # pre-requisite for configuring NuGet.
+ - template: ../steps/ci-prebuild-step.yml@self
+ parameters:
+ debug: ${{ parameters.debug }}
+ referenceType: ${{ parameters.referenceType }}
+
- template: ../steps/ci-project-build-step.yml@self
parameters:
platform: ${{ parameters.platform }}
configuration: ${{ parameters.configuration }}
+ referenceType: ${{ parameters.referenceType }}
operatingSystem: Windows
- build: all
+ build: MDS
+ abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}}
- template: ../steps/generate-nuget-package-step.yml@self
parameters:
- NugetPackageVersion: $(NugetPackageVersion)
+ packageVersion: ${{ parameters.mdsPackageVersion }}
configuration: $(Configuration)
nuspecPath: 'tools/specs/Microsoft.Data.SqlClient.nuspec'
- OutputDirectory: $(packagePath)
+ outputDirectory: $(packagePath)
generateSymbolsPackage: false
- properties: 'AbstractionsPackageVersion=$(abstractionsPackageVersion)'
- displayName: 'Generate NuGet package M.D.SqlClient'
+ referenceType: ${{ parameters.referenceType }}
+ properties: 'AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}'
+ displayName: 'Create MDS NuGet Package'
+
+ - template: ../steps/ci-project-build-step.yml@self
+ parameters:
+ platform: ${{ parameters.platform }}
+ configuration: ${{ parameters.configuration }}
+ referenceType: ${{ parameters.referenceType }}
+ operatingSystem: Windows
+ build: AKV
+ mdsPackageVersion: ${{parameters.mdsPackageVersion}}
- template: ../steps/generate-nuget-package-step.yml@self
parameters:
- NugetPackageVersion: $(NugetPackageVersion)
+ packageVersion: $(akvPackageVersion)
configuration: $(Configuration)
nuspecPath: 'tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec'
- OutputDirectory: $(packagePath)
+ outputDirectory: $(packagePath)
generateSymbolsPackage: false
- properties: 'MdsPackageVersion=$(mdsPackageVersion)'
+ referenceType: ${{ parameters.referenceType }}
+ properties: 'MdsPackageVersion=${{ parameters.mdsPackageVersion }}'
installNuget: false
- displayName: 'Generate NuGet package AKV Provider'
+ displayName: 'Create AKV NuGet Package'
- - task: PublishBuildArtifacts@1
- displayName: 'Publish Artifact: Artifacts'
+ - task: PublishPipelineArtifact@1
+ displayName: 'Publish Pipeline Artifact'
inputs:
- PathtoPublish: $(packagePath)
- ArtifactName: ${{ parameters.artifactName }}
+ targetPath: $(packagePath)
+ artifactName: ${{ parameters.mdsArtifactName }}
diff --git a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml
index dbf5b10028..06bc31911b 100644
--- a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml
+++ b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml
@@ -4,12 +4,31 @@
# See the LICENSE file in the project root for more information. #
#################################################################################
parameters:
+ - name: abstractionsArtifactName
+ type: string
+
+ - name: abstractionsPackageVersion
+ type: string
+
+ - name: configProperties
+ type: object
+ default: {} # - key: 'value'
+
+ - name: configSqlFor
+ type: string # local, azure, or enclave
+ default: local
+
- name: debug
type: boolean
default: false
- - name: poolName
- type: string
+ - name: enableX64Test
+ type: boolean
+ default: true
+
+ - name: enableX86Test
+ type: boolean
+ default: false
- name: hostedPool
type: boolean
@@ -21,63 +40,51 @@ parameters:
- name: jobDisplayName
type: string
- - name: usemanagedSNI
- type: boolean
- default: false
-
- - name: configProperties
- type: object
- default: {} # - key: 'value'
-
- - name: prebuildSteps
- type: stepList
- default: []
-
- - name: artifactName
+ - name: mdsArtifactName
type: string
- default: Artifacts
- - name: targetFramework
+ - name: mdsPackageVersion
type: string
- name: netcoreVersionTestUtils
type: string
+
+ - name: operatingSystem
+ type: string
+ default: ''
- - name: enableX86Test
- type: boolean
- default: false
-
- - name: enableX64Test
- type: boolean
- default: true
-
- - name: testSet
+ - name: poolName
type: string
+
+ - name: prebuildSteps
+ type: stepList
+ default: []
- name: publishTestResults
type: boolean
default: false
-
- - name: configSqlFor
- type: string # local, azure, or enclave
- default: local
-
- - name: operatingSystem
+
+ - name: referenceType
type: string
- default: ''
-
- - name: buildType
- displayName: 'Build Type'
- default: Project
values:
- Project
- Package
+ - name: targetFramework
+ type: string
+
+ - name: testSet
+ type: string
+
# The timeout, in minutes, for this job.
- name: timeout
type: string
default: 90
+ - name: usemanagedSNI
+ type: boolean
+ default: false
+
jobs:
- job: ${{ format('{0}', coalesce(parameters.jobDisplayName, parameters.image, 'unknown_image')) }}
@@ -98,6 +105,22 @@ jobs:
value: '$(dotnetx86Path)'
steps:
+
+ # If we're testing in Package mode, download the Abstractions and MDS package
+ # artifacts and put them in the packages/ directory in the repo root.
+ - ${{ if eq(parameters.referenceType, 'Package') }}:
+ - task: DownloadPipelineArtifact@2
+ displayName: Download Abstractions Package Artifact
+ inputs:
+ artifactName: ${{ parameters.abstractionsArtifactName }}
+ targetPath: $(Build.SourcesDirectory)/packages
+
+ - task: DownloadPipelineArtifact@2
+ displayName: Download MDS Package Artifact
+ inputs:
+ artifactName: ${{ parameters.mdsArtifactName }}
+ targetPath: $(Build.SourcesDirectory)/packages
+
- ${{ if ne(parameters.prebuildSteps, '') }}:
- ${{ parameters.prebuildSteps }} # extra steps to run before the build like downloading sni and the required configuration
@@ -227,8 +250,10 @@ jobs:
- template: ../steps/build-all-tests-step.yml@self # build tests
parameters:
targetFramework: ${{ parameters.targetFramework }}
- referenceType: ${{ parameters.buildType }}
+ referenceType: ${{ parameters.referenceType }}
testSet: ${{ parameters.testSet }}
+ abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }}
+ mdsPackageVersion: ${{ parameters.mdsPackageVersion }}
${{ if ne(parameters.operatingSystem, 'Windows') }}:
OSGroup: Unix
@@ -237,7 +262,7 @@ jobs:
parameters:
debug: ${{ parameters.debug }}
targetFramework: ${{ parameters.targetFramework }}
- referenceType: ${{ parameters.buildType }}
+ referenceType: ${{ parameters.referenceType }}
testSet: ${{ parameters.testSet }}
operatingSystem: ${{ parameters.operatingSystem }}
@@ -279,13 +304,13 @@ jobs:
parameters:
debug: ${{ parameters.debug }}
targetFramework: ${{ parameters.targetFramework }}
- referenceType: ${{ parameters.buildType }}
+ referenceType: ${{ parameters.referenceType }}
testSet: ${{ parameters.testSet }}
msbuildArchitecture: x86
dotnetx86RootPath: $(dotnetx86RootPath)
operatingSystem: ${{ parameters.operatingSystem }}
- - ${{ if and(eq(parameters.publishTestResults, true), eq(parameters.buildType, 'Project')) }}: # publish test results if build type is project
+ - ${{ if and(eq(parameters.publishTestResults, true), eq(parameters.referenceType, 'Project')) }}: # publish test results if build type is project
- template: ../steps/publish-test-results-step.yml@self
parameters:
debug: ${{ parameters.debug }}
diff --git a/eng/pipelines/common/templates/jobs/run-tests-package-reference-job.yml b/eng/pipelines/common/templates/jobs/run-tests-package-reference-job.yml
index 14aea42411..caa677aa89 100644
--- a/eng/pipelines/common/templates/jobs/run-tests-package-reference-job.yml
+++ b/eng/pipelines/common/templates/jobs/run-tests-package-reference-job.yml
@@ -51,9 +51,7 @@ jobs:
- template: ../steps/update-nuget-config-local-feed-step.yml
parameters:
- downloadedNugetPath: $(Pipeline.Workspace)\${{parameters.packageFolderName }}
- ${{ if parameters.isPreview }}:
- nugetPackageVersion: $(PreviewNugetPackageVersion)
+ packagePath: $(Pipeline.Workspace)\${{parameters.packageFolderName }}
- template: ../steps/update-config-file-step.yml
parameters:
@@ -68,11 +66,11 @@ jobs:
parameters:
referenceType: Package
${{ if parameters.isPreview }}:
- nugetPackageVersion: $(PreviewNugetPackageVersion)
+ mdsPackageVersion: $(previewMdsPackageVersion)
- template: ../steps/build-and-run-tests-netcore-step.yml
parameters:
referenceType: Package
cleanFirst: true
${{ if parameters.isPreview }}:
- nugetPackageVersion: $(PreviewNugetPackageVersion)
+ mdsPackageVersion: $(previewMdsPackageVersion)
diff --git a/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml b/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml
index 009e6f2647..42000da697 100644
--- a/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml
+++ b/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml
@@ -25,14 +25,6 @@ parameters:
- pdb
- both
- - name: assembly_file_version_netfx
- type: string
- default: $(AssemblyFileVersion)
-
- - name: assembly_file_version_core
- type: string
- default: $(AssemblyFileVersion)
-
- name: isPreview
type: boolean
@@ -53,19 +45,14 @@ jobs:
- name: pathToDownloadedNuget # path to the downloaded nuget files
value: $(Pipeline.Workspace)\${{parameters.packageFolderName }}
- - name: ProductVersion #MDS product version (MDS validation)
- value: $(NugetPackageVersion)
-
- name: BuildType
value: $[ stageDependencies.buildMDS.build_signed_package.outputs['GetBuildType.CDP_BUILD_TYPE_COPY'] ]
- ${{ if parameters.isPreview }}:
- name: extractedNugetPath
- value: $(extractedNugetRootPath).$(PreviewNugetPackageVersion)
- - name: NugetPackageVersion
- value: $(PreviewNugetPackageVersion)
- - name: ProductVersion
- value: $(PreviewNugetPackageVersion)
+ value: $(extractedNugetRootPath).$(previewMdsPackageVersion)
+ - name: mdsPackageVersion
+ value: $(previewMdsPackageVersion)
steps:
- script: SET
@@ -75,7 +62,7 @@ jobs:
displayName: 'Use NuGet'
- powershell: |
- #Sets Variables for AssemblyFileVersion, AssemblyVersion and NugetPackageVersion
+ # Sets the pipeline ASSEMBLY_VERSION variable.
[Xml] $versionprops = Get-Content -Path ".\tools\props\Versions.props"
Write-Host $versionprops.Project.PropertyGroup[0].AssemblyFileVersion
@@ -283,60 +270,47 @@ jobs:
displayName: 'Verify all dlls status are Valid'
- powershell: |
- # This will check for ProductVersion and FileVersion.
- #
- # For NetFx we have a different FileVersion, but product versions are all
- # the same. Some may have extra numbering at the end. We only check for
- # the first parts.
+ # This will check each DLL's ProductVersion and FileVersion against
+ # expected values.
+ $failed = 0
foreach ( $pVersion in Get-ChildItem *.dll -Path $(extractedNugetPath) -Recurse | ForEach-Object versioninfo )
{
- if ($pVersion.ProductVersion -Like '$(ProductVersion)*')
+ if ($pVersion.ProductVersion -Like '$(mdsPackageVersion)*')
{
- Write-Host Valid Product Version:"$pVersion.ProductVersion" $pVersion.ProductVersion detected for $pVersion.FileName -ForegroundColor Green
+ Write-Host -ForegroundColor Green "Correct ProductVersion detected for $($pVersion.FileName): $($pVersion.ProductVersion)"
}
else
{
- Write-Host "Wrong ProductVersion detected. Expected: '$(ProductVersion)', but Detected: "$pVersion.ProductVersion""
- Exit -1
+ Write-Host -ForegroundColor Red "Wrong ProductVersion detected for $($pVersion.FileName); expected: $(mdsPackageVersion); found: $($pVersion.ProductVersion)"
+ $failed = 1
}
- if($pVersion.FileName -like '*lib\$(CurrentNetFxVersion)*'){
-
- if($pVersion.FileVersion -eq '${{parameters.assembly_file_version_netfx }}')
- {
- Write-Host 'Correct File version Detected for net46,' $pVersion.FileVersion -ForegroundColor Green
- }
- else
- {
- Write-Host 'Wrong File version Detected for net46,' $pVersion.FileVersion -ForegroundColor Red
- Exit -1
- }
+ if ($pVersion.FileVersion -eq '$(mdsAssemblyFileVersion)')
+ {
+ Write-Host -ForegroundColor Green "Correct FileVersion detected for $($pVersion.FileName): $($pVersion.FileVersion)"
}
else
{
-
- if($pVersion.FileVersion -eq '${{parameters.assembly_file_version_core}}')
- {
- Write-Host 'Correct File version Detected for netcore,' $pVersion.FileVersion -ForegroundColor Green
- }
- else
- {
- Write-Host 'Wrong File version Detected for netcore and ref folder,' $pVersion.FileVersion -ForegroundColor Red
- Exit -1
- }
+ Write-Host -ForegroundColor Red "Wrong FileVersion detected for $($pVersion.FileName); expected $(mdsAssemblyFileVersion); found: $($pVersion.FileVersion)"
+ $failed = 1
}
}
- Get-ChildItem *.dll -Path $(extractedNugetPath) -Recurse | ForEach-Object versioninfo
- displayName: 'Verify "File Version" matches provided pipeline variable "ASSEMBLY_FILE_VERSION" for DLLs'
+ if ($failed -ne 0)
+ {
+ Exit -1
+ }
+
+ Get-ChildItem *.dll -Path $(extractedNugetPath) -Recurse | ForEach-Object VersionInfo | Format-List
+ displayName: 'Verify "File Version" matches expected values for DLLs'
- powershell: |
# Change TestMicrosoftDataSqlClientVersion
[Xml] $versionprops = Get-Content -Path "tools/props/Versions.props"
$versionpropspath = "tools\props\Versions.props"
- $versionprops.Project.PropertyGroup[$versionprops.Project.PropertyGroup.Count-1].TestMicrosoftDataSqlClientVersion ="$(NugetPackageVersion)"
+ $versionprops.Project.PropertyGroup[$versionprops.Project.PropertyGroup.Count-1].TestMicrosoftDataSqlClientVersion ="$(mdsPackageVersion)"
Write-Host "Saving Test nuget version at $rootfolder\props ...." -ForegroundColor Green
$versionprops.Save($versionpropspath)
@@ -344,10 +318,16 @@ jobs:
- powershell: |
# Check assembly versions.
+ #
+ # GOTCHA: This expects the Versions.props file having XML elements in a
+ # certain order. If the order changes, this check will fail!
+ #
+ # TODO: This also isn't checking the versions of the actual assemblies in
+ # the package, so it isn't terribly useful.
[Xml] $versionprops = Get-Content -Path "tools/props/Versions.props"
- $AssemblyFileVersion = $versionprops.Project.PropertyGroup[0].AssemblyFileVersion
- $AssemblyVersion = $versionprops.Project.PropertyGroup[0].AssemblyVersion
+ $AssemblyFileVersion = $versionprops.Project.PropertyGroup[2].AssemblyFileVersion
+ $AssemblyVersion = $versionprops.Project.PropertyGroup[2].AssemblyVersion
if($AssemblyFileVersion -eq $AssemblyVersion)
{
diff --git a/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml b/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml
index e07685407f..46318f8e06 100644
--- a/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml
+++ b/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml
@@ -4,31 +4,43 @@
# See the LICENSE file in the project root for more information. #
#################################################################################
parameters:
+ - name: abstractionsArtifactName
+ type: string
+
+ - name: abstractionsPackageVersion
+ type: string
+
- name: debug
type: boolean
default: false
- - name: testConfigurations
+ - name: dependsOn
type: object
+ default: []
- - name: dependsOn
+ - name: mdsArtifactName
+ type: string
+ default: MDS.Artifact
+
+ - name: mdsPackageVersion
type: string
- default: ''
+
+ - name: postTestJobs
+ type: jobList
+ default: []
- - name: buildType
- displayName: 'Build Type'
+ - name: prebuildSteps
+ type: stepList
+ default: []
+
+ - name: referenceType
default: Project
values:
- Project
- Package
- - name: prebuildSteps
- type: stepList
- default: []
-
- - name: postTestJobs
- type: jobList
- default: []
+ - name: testConfigurations
+ type: object
# The timeout, in minutes, for each test job.
- name: testsTimeout
@@ -39,10 +51,7 @@ stages:
- ${{ each config in parameters.testConfigurations }}:
- ${{ each image in config.value.images }}:
- stage: ${{ image.key }}
- ${{ if ne(parameters.dependsOn, '') }}:
- dependsOn: ${{ parameters.dependsOn }}
- ${{ else }}:
- dependsOn: []
+ dependsOn: ${{ parameters.dependsOn }}
jobs:
- ${{ each targetFramework in config.value.TargetFrameworks }}:
- ${{ each platform in config.value.buildPlatforms }}:
@@ -51,13 +60,17 @@ stages:
- template: ../jobs/ci-run-tests-job.yml@self
parameters:
debug: ${{ parameters.debug }}
- buildType: ${{ parameters.buildType }}
+ referenceType: ${{ parameters.referenceType }}
timeout: ${{ parameters.testsTimeout }}
poolName: ${{ config.value.pool }}
hostedPool: ${{ eq(config.value.hostedPool, true) }}
image: ${{ image.value }}
jobDisplayName: ${{ format('{0}_{1}_{2}', replace(targetFramework, '.', '_'), platform, testSet) }}
configProperties: ${{ config.value.configProperties }}
+ abstractionsArtifactName: ${{ parameters.abstractionsArtifactName }}
+ abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}}
+ mdsArtifactName: ${{ parameters.mdsArtifactName }}
+ mdsPackageVersion: ${{ parameters.mdsPackageVersion }}
prebuildSteps: ${{ parameters.prebuildSteps }}
targetFramework: ${{ targetFramework }}
netcoreVersionTestUtils: ${{config.value.netcoreVersionTestUtils }}
@@ -77,7 +90,7 @@ stages:
- template: ../jobs/ci-run-tests-job.yml@self
parameters:
debug: ${{ parameters.debug }}
- buildType: ${{ parameters.buildType }}
+ referenceType: ${{ parameters.referenceType }}
timeout: ${{ parameters.testsTimeout }}
poolName: ${{ config.value.pool }}
hostedPool: ${{ eq(config.value.hostedPool, true) }}
@@ -88,6 +101,10 @@ stages:
jobDisplayName: ${{ format('{0}_{1}_{2}_{3}', replace(targetFramework, '.', '_'), platform, 'NativeSNI', testSet) }}
configProperties: ${{ config.value.configProperties }}
useManagedSNI: ${{ useManagedSNI }}
+ abstractionsArtifactName: ${{ parameters.abstractionsArtifactName }}
+ abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}}
+ mdsArtifactName: ${{ parameters.mdsArtifactName }}
+ mdsPackageVersion: ${{ parameters.mdsPackageVersion }}
prebuildSteps: ${{ parameters.prebuildSteps }}
targetFramework: ${{ targetFramework }}
netcoreVersionTestUtils: ${{config.value.netcoreVersionTestUtils }}
diff --git a/eng/pipelines/common/templates/steps/build-all-configurations-signed-dlls-step.yml b/eng/pipelines/common/templates/steps/build-all-configurations-signed-dlls-step.yml
index e6a6c0443a..0cfbb3494b 100644
--- a/eng/pipelines/common/templates/steps/build-all-configurations-signed-dlls-step.yml
+++ b/eng/pipelines/common/templates/steps/build-all-configurations-signed-dlls-step.yml
@@ -4,23 +4,27 @@
# See the LICENSE file in the project root for more information. #
#################################################################################
parameters:
- - name: AssemblyFileVersion
+
+ - name: abstractionsAssemblyFileVersion
+ type: string
+
+ - name: abstractionsPackageVersion
type: string
- default: $(AssemblyFileVersion)
- - name: Configuration
+ - name: configuration
type: string
- default: '$(Configuration)'
- - name: packageRefMdsVersion
+ - name: mdsAssemblyFileVersion
type: string
- default: ''
- - name: product
- default: MDS
+ - name: mdsPackageVersion
+ type: string
+
+ - name: referenceType
+ type: string
values:
- - MDS
- - MSS
+ - Package
+ - Project
steps:
- task: DownloadSecureFile@1
@@ -41,10 +45,9 @@ steps:
packageType: runtime
version: '8.x'
-- ${{ if eq(parameters.product, 'MDS') }}:
- - task: MSBuild@1
- displayName: 'BuildAllConfigurations using build.proj'
- inputs:
- solution: '**/build.proj'
- configuration: '${{parameters.Configuration }}'
- msbuildArguments: '-p:AssemblyFileVersion=${{parameters.AssemblyFileVersion }} -t:BuildAllConfigurations -p:GenerateNuget=false -p:SigningKeyPath=$(Agent.TempDirectory)\netfxKeypair.snk'
+- task: MSBuild@1
+ displayName: 'BuildAllConfigurations using build.proj'
+ inputs:
+ solution: '**/build.proj'
+ configuration: '${{ parameters.configuration }}'
+ msbuildArguments: '-t:BuildAllConfigurations -p:ReferenceType=${{ parameters.referenceType }} -p:GenerateNuget=false -p:SigningKeyPath=$(Agent.TempDirectory)\netfxKeypair.snk -p:MdsPackageVersion=${{ parameters.mdsPackageVersion }} -p:AssemblyFileVersion=${{ parameters.mdsAssemblyFileVersion }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }} -p:AbstractionsAssemblyFileVersion=${{ parameters.abstractionsAssemblyFileVersion }}'
diff --git a/eng/pipelines/common/templates/steps/build-all-tests-step.yml b/eng/pipelines/common/templates/steps/build-all-tests-step.yml
index 826be1df8b..43ecb6aafa 100644
--- a/eng/pipelines/common/templates/steps/build-all-tests-step.yml
+++ b/eng/pipelines/common/templates/steps/build-all-tests-step.yml
@@ -4,31 +4,33 @@
# See the LICENSE file in the project root for more information. #
#################################################################################
parameters:
- - name: targetFramework
+ - name: abstractionsPackageVersion
+ type: string
+
+ - name: configuration
+ type: string
+ default: '$(Configuration)'
+
+ - name: mdsPackageVersion
type: string
- - name: nugetPackageVersion
+ - name: osGroup
type: string
- default: $(NugetPackageVersion)
+ default: ''
- name: platform
type: string
default: $(Platform)
-
- - name: configuration
- type: string
- default: '$(Configuration)'
- name: referenceType
- default: Package
+ type: string
values:
- Project
- Package
-
- - name: OSGroup
- type: string
- default: ''
+ - name: targetFramework
+ type: string
+
- name: testSet
type: string
@@ -40,26 +42,16 @@ steps:
solution: build.proj
platform: '${{parameters.platform }}'
configuration: '${{parameters.configuration }}'
- msbuildArguments: '-t:BuildTestsNetFx -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }}'
-
-# - ${{else if contains(parameters.targetFramework, 'netstandard')}}: # .NET Standard
-# - task: MSBuild@1
-# displayName: 'Build Tests NetStandard'
-# inputs:
-# solution: build.proj
-# platform: '${{parameters.platform }}'
-# configuration: '${{parameters.configuration }}'
-# msbuildArguments: '-t:BuildTestsNetCore -p:ReferenceType=NetStandard -p:TargetNetStandardVersion=${{parameters.targetNetStandardVersion }} -p:TF=${{parameters.targetFramework }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }}'
-# condition: and(succeeded(), not(startsWith(variables['TF'], 'net4')), startsWith(variables['TargetNetStandardVersion'], 'netstandard'))
+ msbuildArguments: '-t:BuildTestsNetFx -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}'
-- ${{elseif eq(parameters.OSGroup, '')}}: # .NET on Windows
+- ${{elseif eq(parameters.osGroup, '')}}: # .NET on Windows
- task: MSBuild@1
displayName: 'Build Tests NetCore [Win]'
inputs:
solution: build.proj
platform: '${{parameters.platform }}'
configuration: '${{parameters.configuration }}'
- msbuildArguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }}'
+ msbuildArguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}'
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
- ${{ else }}: # .NET on Unix
@@ -69,7 +61,7 @@ steps:
command: custom
projects: build.proj
custom: msbuild
- arguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:OSGroup=${{parameters.OSGroup }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}'
+ arguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:OSGroup=${{parameters.osGroup }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}'
verbosityRestore: Detailed
verbosityPack: Detailed
condition: and(succeeded(), ne(variables['Agent.OS'], 'Windows_NT'))
diff --git a/eng/pipelines/common/templates/steps/build-and-run-tests-netcore-step.yml b/eng/pipelines/common/templates/steps/build-and-run-tests-netcore-step.yml
index c70fe776a7..43eea4449d 100644
--- a/eng/pipelines/common/templates/steps/build-and-run-tests-netcore-step.yml
+++ b/eng/pipelines/common/templates/steps/build-and-run-tests-netcore-step.yml
@@ -18,9 +18,9 @@ parameters:
- Project
- Package
- - name: NugetPackageVersion
+ - name: mdsPackageVersion
type: string
- default: $(NugetPackageVersion)
+ default: $(mdsPackageVersion)
- name: platform
type: string
@@ -55,14 +55,14 @@ steps:
inputs:
solution: build.proj
msbuildArchitecture: x64
- msbuildArguments: '-p:Configuration=${{parameters.configuration }} -t:BuildAKVNetCore -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }}'
+ msbuildArguments: '-p:Configuration=${{parameters.configuration }} -t:BuildAKVNetCore -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }}'
- task: MSBuild@1
displayName: 'MSBuild Build Tests for ${{parameters.TargetNetCoreVersion }}'
inputs:
solution: build.proj
msbuildArchitecture: x64
- msbuildArguments: '-t:BuildTestsNetCore -p:ReferenceType=${{parameters.referenceType }} -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} -p:Configuration=${{parameters.configuration }}'
+ msbuildArguments: '-t:BuildTestsNetCore -p:ReferenceType=${{parameters.referenceType }} -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:Configuration=${{parameters.configuration }}'
# Don't run unit tests using package reference. Unit tests are only run using project reference.
@@ -71,12 +71,12 @@ steps:
inputs:
command: test
projects: 'src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.FunctionalTests.csproj'
- arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests"'
+ arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests"'
- task: DotNetCoreCLI@2
displayName: 'Run Manual Tests for ${{parameters.TargetNetCoreVersion }}'
inputs:
command: test
projects: 'src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj'
- arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} --no-build -v n --filter category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests --collect "Code Coverage"'
+ arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} --no-build -v n --filter category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests --collect "Code Coverage"'
retryCountOnTaskFailure: ${{parameters.retryCountOnManualTests }}
diff --git a/eng/pipelines/common/templates/steps/build-and-run-tests-netfx-step.yml b/eng/pipelines/common/templates/steps/build-and-run-tests-netfx-step.yml
index 5d9f194c48..e7b35f653e 100644
--- a/eng/pipelines/common/templates/steps/build-and-run-tests-netfx-step.yml
+++ b/eng/pipelines/common/templates/steps/build-and-run-tests-netfx-step.yml
@@ -18,9 +18,9 @@ parameters:
- Project
- Package
- - name: NugetPackageVersion
+ - name: mdsPackageVersion
type: string
- default: $(NugetPackageVersion)
+ default: $(mdsPackageVersion)
- name: platform
type: string
@@ -55,13 +55,13 @@ steps:
inputs:
solution: build.proj
msbuildArchitecture: x64
- msbuildArguments: '-p:Configuration=${{parameters.configuration }} -t:BuildAKVNetFx -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }}'
+ msbuildArguments: '-p:Configuration=${{parameters.configuration }} -t:BuildAKVNetFx -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }}'
- task: MSBuild@1
displayName: 'MSBuild Build Tests for ${{parameters.TargetNetFxVersion }}'
inputs:
solution: build.proj
- msbuildArguments: ' -t:BuildTestsNetFx -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:Configuration=${{parameters.configuration }} -p:Platform=${{parameters.platform }}'
+ msbuildArguments: ' -t:BuildTestsNetFx -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:Configuration=${{parameters.configuration }} -p:Platform=${{parameters.platform }}'
# Don't run unit tests using package reference. Unit tests are only run using project reference.
@@ -70,12 +70,12 @@ steps:
inputs:
command: test
projects: 'src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.FunctionalTests.csproj'
- arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" --collect "Code Coverage"'
+ arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" --collect "Code Coverage"'
- task: DotNetCoreCLI@2
displayName: 'Run Manual Tests for ${{parameters.TargetNetFxVersion }}'
inputs:
command: test
projects: 'src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj'
- arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" --collect "Code Coverage"'
+ arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" --collect "Code Coverage"'
retryCountOnTaskFailure: ${{parameters.retryCountOnManualTests }}
diff --git a/eng/pipelines/common/templates/steps/ci-prebuild-step.yml b/eng/pipelines/common/templates/steps/ci-prebuild-step.yml
index efe17856d8..5f9adface7 100644
--- a/eng/pipelines/common/templates/steps/ci-prebuild-step.yml
+++ b/eng/pipelines/common/templates/steps/ci-prebuild-step.yml
@@ -8,13 +8,8 @@ parameters:
type: boolean
default: false
- - name: artifactName
+ - name: referenceType
type: string
- default: Artifacts
-
- - name: buildType
- displayName: 'Build Type'
- default: Project
values:
- Project
- Package
@@ -37,21 +32,8 @@ steps:
Get-ChildItem env: | Sort-Object Name
displayName: 'List Environment Variables [debug]'
-- ${{if eq(parameters.buildType, 'Package')}}:
- - task: DownloadPipelineArtifact@2
- displayName: 'Download NuGet Package'
- inputs:
- buildType: current
- artifact: ${{parameters.artifactName }}
- patterns: '**/*.nupkg'
- targetPath: $(Pipeline.Workspace)/${{parameters.artifactName }}
-
+- ${{if eq(parameters.referenceType, 'Package')}}:
- template: update-nuget-config-local-feed-step.yml@self
parameters:
- downloadedNugetPath: $(Pipeline.Workspace)\${{parameters.artifactName }}
debug: ${{ parameters.debug }}
-
-- ${{ else }}: # project
- - template: ci-project-build-step.yml@self
- parameters:
- build: allNoDocs
+ packagePath: $(Build.SourcesDirectory)/packages
diff --git a/eng/pipelines/common/templates/steps/ci-project-build-step.yml b/eng/pipelines/common/templates/steps/ci-project-build-step.yml
index e938c909fd..f0dbbf2080 100644
--- a/eng/pipelines/common/templates/steps/ci-project-build-step.yml
+++ b/eng/pipelines/common/templates/steps/ci-project-build-step.yml
@@ -12,6 +12,12 @@ parameters:
type: string
default: $(Configuration)
+ - name: referenceType
+ type: string
+ values:
+ - Package
+ - Project
+
- name: buildNumber
type: string
default: $(BuildNumber)
@@ -34,38 +40,43 @@ parameters:
- all
- allNoDocs
+ # Used when MDS is built with ReferenceType = Package.
+ - name: abstractionsPackageVersion
+ type: string
+ default: ''
+
+ # Used when AKV is built with ReferenceType = Package.
+ - name: mdsPackageVersion
+ type: string
+ default: ''
+
steps:
- template: ./ensure-dotnet-version.yml@self
parameters:
packageType: 'sdk'
version: '9.0'
-- template: ./ensure-dotnet-version.yml@self
- parameters:
- packageType: 'runtime'
- version: '8.0'
-
- ${{ if or(eq(parameters.operatingSystem, 'Windows'), eq(parameters.operatingSystem, 'deferedToRuntime')) }}:
- ${{ if or(eq(parameters.build, 'MDS'), eq(parameters.build, 'all'), eq(parameters.build, 'allNoDocs')) }}:
- task: MSBuild@1
- displayName: 'Restore nugets [Win]'
+ displayName: 'Restore [Win]'
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
inputs:
solution: build.proj
msbuildArchitecture: x64
- msbuildArguments: '-t:restore'
+ msbuildArguments: '-t:restore -p:ReferenceType=${{ parameters.ReferenceType }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}'
retryCountOnTaskFailure: 1
- ${{ if eq(parameters.build, 'allNoDocs') }}:
- task: MSBuild@1
- displayName: 'Build Driver [Win]'
+ displayName: 'Build Driver (no docs) [Win]'
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
inputs:
solution: build.proj
msbuildArchitecture: x64
platform: '${{ parameters.platform }}'
configuration: '${{ parameters.configuration }}'
- msbuildArguments: '-t:BuildAllConfigurations -p:GenerateDocumentationFile=false -p:GenerateNuGet=false -p:BuildNumber=${{ parameters.buildNumber }}'
+ msbuildArguments: '-t:BuildAllConfigurations -p:ReferenceType=${{ parameters.ReferenceType }} -p:GenerateDocumentationFile=false -p:GenerateNuGet=false -p:BuildNumber=${{ parameters.buildNumber }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}'
clean: true
- ${{ if or(eq(parameters.build, 'MDS'), eq(parameters.build, 'all')) }}:
@@ -77,7 +88,7 @@ steps:
msbuildArchitecture: x64
platform: '${{ parameters.platform }}'
configuration: '${{ parameters.configuration }}'
- msbuildArguments: '-t:BuildAllConfigurations -p:GenerateNuGet=false -p:BuildNumber=${{ parameters.buildNumber }}'
+ msbuildArguments: '-t:BuildAllConfigurations -p:ReferenceType=${{ parameters.ReferenceType }} -p:GenerateNuGet=false -p:BuildNumber=${{ parameters.buildNumber }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}'
clean: true
- ${{ if or(eq(parameters.build, 'AKV'), eq(parameters.build, 'all'), eq(parameters.build, 'allNoDocs')) }}:
@@ -89,7 +100,7 @@ steps:
msbuildArchitecture: x64
platform: '${{ parameters.platform }}'
configuration: '${{ parameters.configuration }}'
- msbuildArguments: '-t:BuildAKVNetFx -p:BuildNumber=${{ parameters.buildNumber }}'
+ msbuildArguments: '-t:BuildAKVNetFx -p:ReferenceType=${{ parameters.ReferenceType }} -p:BuildNumber=${{ parameters.buildNumber }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion}}'
- task: MSBuild@1
displayName: 'Build AKV Provider NetCore All OS [Win]'
@@ -99,17 +110,17 @@ steps:
msbuildArchitecture: x64
platform: '${{ parameters.platform }}'
configuration: '${{ parameters.configuration }}'
- msbuildArguments: '-t:BuildAKVNetCoreAllOS -p:BuildNumber=${{ parameters.buildNumber }}'
+ msbuildArguments: '-t:BuildAKVNetCoreAllOS -p:ReferenceType=${{ parameters.ReferenceType }} -p:BuildNumber=${{ parameters.buildNumber }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion}}'
- ${{ if or(eq(parameters.operatingSystem, 'Linux'), eq(parameters.operatingSystem, 'MacOS'), eq(parameters.operatingSystem, 'deferedToRuntime')) }}:
- task: DotNetCoreCLI@2
- displayName: 'Build Driver [non-Win]'
+ displayName: 'Build Driver [${{ parameters.operatingSystem }}]'
condition: and(succeeded(), ne(variables['Agent.OS'], 'Windows_NT'))
inputs:
command: custom
projects: build.proj
custom: msbuild
- arguments: '-t:BuildAll -p:TestEnabled=true -p:GenerateDocumentationFile=false -p:configuration=${{ parameters.configuration }}'
+ arguments: '-t:BuildAll -p:ReferenceType=${{ parameters.ReferenceType }} -p:TestEnabled=true -p:GenerateDocumentationFile=false -p:configuration=${{ parameters.configuration }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}'
verbosityRestore: Detailed
verbosityPack: Detailed
retryCountOnTaskFailure: 1
diff --git a/eng/pipelines/common/templates/steps/code-analyze-step.yml b/eng/pipelines/common/templates/steps/code-analyze-step.yml
index 9807541a70..bad64f55d3 100644
--- a/eng/pipelines/common/templates/steps/code-analyze-step.yml
+++ b/eng/pipelines/common/templates/steps/code-analyze-step.yml
@@ -3,40 +3,30 @@
# The .NET Foundation licenses this file to you under the MIT license. #
# See the LICENSE file in the project root for more information. #
#################################################################################
-parameters:
- - name: analyzeType
- values:
- - roslyn
- - inspect
- - all
+# This template defines a step to run Roslyn Analyzers on the MDS project build.
+# It uses the RoslynAnalyzers@3 task from the Secure Development Team's SDL
+# extension:
+#
+# https://eng.ms/docs/cloud-ai-platform/devdiv/one-engineering-system-1es/1es-mohanb/security-integration/guardian-wiki/sdl-azdo-extension/roslyn-analyzers-build-task
+#
+# GOTCHA: This step will clobber any existing build output. It should be run
+# _before_ any build steps that perform versioning or signing.
+
+# @TODO: This can probably be made generic and pass in the command lines for msbuild
+# BUT, they should be kept separate by now as we rebuild build.proj in parallel, we won't
+# affect >1 project at a time.
+
+parameters:
- name: sourceRoot
type: string
default: $(REPOROOT)
- - name: packageRefMdsVersion
- type: string
- default: ''
-
- - name: product
- default: MDS
- values:
- - MDS
- - MSS
-
steps:
-- ${{ if or(eq(parameters.analyzeType, 'roslyn'), eq(parameters.analyzeType, 'all')) }}:
- - ${{ if eq(parameters.product, 'MDS') }}:
- - task: securedevelopmentteam.vss-secure-development-tools.build-task-roslynanalyzers.RoslynAnalyzers@3
- displayName: 'Guardian Dotnet Analyzers '
- inputs:
- msBuildVersion: 17.0
- msBuildArchitecture: x64
- setupCommandlinePicker: vs2022
- msBuildCommandline: 'msbuild ${{parameters.sourceRoot}}\build.proj -p:configuration=Release -p:GenerateNuget=false -p:BuildTools=false -p:SigningKeyPath=$(Agent.TempDirectory)\netfxKeypair.snk'
-
-- ${{ if or(eq(parameters.analyzeType, 'inspect'), eq(parameters.analyzeType, 'all')) }}:
- - task: securedevelopmentteam.vss-secure-development-tools.build-task-codeinspector.CodeInspector@2
- displayName: 'Run Code Inspector'
+ - task: securedevelopmentteam.vss-secure-development-tools.build-task-roslynanalyzers.RoslynAnalyzers@3
+ displayName: Roslyn Analyzers
inputs:
- LogLevel: Error
+ msBuildVersion: 17.0
+ msBuildArchitecture: x64
+ setupCommandlinePicker: vs2022
+ msBuildCommandline: 'msbuild ${{parameters.sourceRoot}}\build.proj -p:configuration=Release -p:GenerateNuget=false -p:BuildTools=false -p:SigningKeyPath=$(Agent.TempDirectory)\netfxKeypair.snk'
diff --git a/eng/pipelines/common/templates/steps/copy-dlls-for-test-step.yml b/eng/pipelines/common/templates/steps/copy-dlls-for-test-step.yml
index 098286866c..23347ac364 100644
--- a/eng/pipelines/common/templates/steps/copy-dlls-for-test-step.yml
+++ b/eng/pipelines/common/templates/steps/copy-dlls-for-test-step.yml
@@ -83,6 +83,6 @@ steps:
$software = '${{parameters.softwareFolder}}'
$symbols = '${{parameters.symbolsFolder}}'
- Get-ChildItem -recurse "$software\*.dll"
- Get-ChildItem -recurse "$symbols\*.pdb"
+ Get-ChildItem -recurse "$software\*.dll" | ForEach-Object VersionInfo | Format-List
+ Get-ChildItem -recurse "$symbols\*.pdb" | ForEach-Object VersionInfo | Format-List
displayName: 'List the prepared files'
diff --git a/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml b/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml
index 8a8fd00f6f..80a085c502 100644
--- a/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml
+++ b/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml
@@ -6,17 +6,15 @@
parameters:
- name: nuspecPath
type: string
- default: '$(nuspecPath)'
- - name: NugetPackageVersion
+ - name: packageVersion
type: string
- default: '$(NugetPackageVersion)'
- - name: OutputDirectory
+ - name: outputDirectory
type: string
default: '$(Build.SourcesDirectory)/packages'
- - name: Configuration
+ - name: configuration
type: string
default: '$(Configuration)'
@@ -26,12 +24,17 @@ parameters:
- name: displayName
type: string
- default: 'NuGet pack with snupkg'
- name: installNuget
type: boolean
default: true
+ - name: referenceType
+ type: string
+ values:
+ - Package
+ - Project
+
# Semi-colon separated properties to pass to nuget via the -properties
# argument.
- name: properties
@@ -55,6 +58,6 @@ steps:
inputs:
command: custom
${{ if parameters.generateSymbolsPackage }}:
- arguments: 'pack -Symbols -SymbolPackageFormat snupkg ${{parameters.nuspecPath}} -Version ${{parameters.NugetPackageVersion}} -OutputDirectory ${{parameters.OutputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};${{parameters.properties}}"'
+ arguments: 'pack -Symbols -SymbolPackageFormat snupkg ${{parameters.nuspecPath}} -Version ${{parameters.packageVersion}} -OutputDirectory ${{parameters.outputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};ReferenceType=${{ parameters.referenceType }};${{parameters.properties}}"'
${{else }}:
- arguments: 'pack ${{parameters.nuspecPath}} -Version ${{parameters.NugetPackageVersion}} -OutputDirectory ${{parameters.OutputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};${{parameters.properties}}"'
+ arguments: 'pack ${{parameters.nuspecPath}} -Version ${{parameters.packageVersion}} -OutputDirectory ${{parameters.outputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};ReferenceType=${{ parameters.referenceType }};${{parameters.properties}}"'
diff --git a/eng/pipelines/common/templates/steps/publish-symbols-step.yml b/eng/pipelines/common/templates/steps/publish-symbols-step.yml
index 5f8d2e6a7d..8999a6cc1d 100644
--- a/eng/pipelines/common/templates/steps/publish-symbols-step.yml
+++ b/eng/pipelines/common/templates/steps/publish-symbols-step.yml
@@ -15,7 +15,7 @@ parameters:
- name: symbolsVersion
type: string
- default: '$(NuGetPackageVersion)'
+ default: '$(mdsPackageVersion)'
- name: symbolServer
type: string
diff --git a/eng/pipelines/common/templates/steps/run-all-tests-step.yml b/eng/pipelines/common/templates/steps/run-all-tests-step.yml
index b9a870ada4..27da9e4e73 100644
--- a/eng/pipelines/common/templates/steps/run-all-tests-step.yml
+++ b/eng/pipelines/common/templates/steps/run-all-tests-step.yml
@@ -11,9 +11,9 @@ parameters:
- name: targetFramework
type: string
- - name: nugetPackageVersion
+ - name: mdsPackageVersion
type: string
- default: $(NugetPackageVersion)
+ default: $(mdsPackageVersion)
- name: platform
type: string
@@ -62,9 +62,9 @@ steps:
platform: '${{parameters.platform }}'
configuration: '${{parameters.configuration }}'
${{ if eq(parameters.msbuildArchitecture, 'x64') }}:
- msbuildArguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }}'
+ msbuildArguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }}'
${{ else }}: # x86
- msbuildArguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}'
+ msbuildArguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}'
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
retryCountOnTaskFailure: 1
@@ -76,9 +76,9 @@ steps:
platform: '${{parameters.platform }}'
configuration: '${{parameters.configuration }}'
${{ if eq(parameters.msbuildArchitecture, 'x64') }}:
- msbuildArguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }}'
+ msbuildArguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }}'
${{ else }}: # x86
- msbuildArguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}'
+ msbuildArguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}'
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
retryCountOnTaskFailure: 1
@@ -90,9 +90,9 @@ steps:
platform: '${{parameters.platform }}'
configuration: '${{parameters.configuration }}'
${{ if eq(parameters.msbuildArchitecture, 'x64') }}:
- msbuildArguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }}'
+ msbuildArguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }}'
${{ else }}: # x86
- msbuildArguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}'
+ msbuildArguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}'
condition: eq(variables['Agent.OS'], 'Windows_NT')
retryCountOnTaskFailure: 2
@@ -104,7 +104,7 @@ steps:
command: custom
projects: build.proj
custom: msbuild
- arguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}'
+ arguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}'
verbosityRestore: Detailed
verbosityPack: Detailed
retryCountOnTaskFailure: 1
@@ -116,7 +116,7 @@ steps:
command: custom
projects: build.proj
custom: msbuild
- arguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}'
+ arguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}'
verbosityRestore: Detailed
verbosityPack: Detailed
retryCountOnTaskFailure: 1
@@ -128,7 +128,7 @@ steps:
command: custom
projects: build.proj
custom: msbuild
- arguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}'
+ arguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}'
verbosityRestore: Detailed
verbosityPack: Detailed
retryCountOnTaskFailure: 2
diff --git a/eng/pipelines/common/templates/steps/update-nuget-config-local-feed-step.yml b/eng/pipelines/common/templates/steps/update-nuget-config-local-feed-step.yml
index 4eac341108..ac2c517aee 100644
--- a/eng/pipelines/common/templates/steps/update-nuget-config-local-feed-step.yml
+++ b/eng/pipelines/common/templates/steps/update-nuget-config-local-feed-step.yml
@@ -8,76 +8,56 @@ parameters:
type: boolean
default: false
- - name: downloadedNugetPath # path to the downloaded nuget files
+ # The path to add as a NuGet source.
+ - name: packagePath
type: string
- - name: nugetPackageVersion
- type: string
- default: $(NugetPackageVersion)
-
steps:
-- powershell: |
+- pwsh: |
+ # Resolve the path to an absolute path.
+ #
+ # Resolve-Path throws an error if the path doesn't exist yet, which is an
+ # expected scenario here, so we must dance around it.
+ $PackagePath = Resolve-Path "${{ parameters.packagePath }}" -ErrorAction SilentlyContinue -ErrorVariable resolveError
+ if (-Not ($PackagePath))
+ {
+ $PackagePath = $resolveError[0].TargetObject
+ }
+
+ # Ensure the package path exists, for example if we are going to generate
+ # packages in a later step.
+ if (-Not (Test-Path -Path "$PackagePath"))
+ {
+ New-Item -ItemType Directory -Path "$PackagePath" -Force
+ Write-Host "Created package path: $PackagePath"
+ }
+
+ Write-Host "Adding package path: $PackagePath"
+
# Get a list of package sources available
Get-PackageSource
- #Current location
+ # Current location
Get-Location
# Register the local nuget folder to be used by nuget.config
- Register-PackageSource -Name "Package Source" -Location ${{parameters.downloadedNugetPath }} -Force -ProviderName NuGet -Trusted
+ Register-PackageSource -Name "Pipeline Source" -Location "$PackagePath" -Force -ProviderName NuGet -Trusted
# Get a list of package sources available after the change
Get-PackageSource
- #Set the NuGet.config file in the project to use extracted package
+ # Set the NuGet.config file in the project to use extracted package
$rootFolder = Get-location
[Xml] $nugetConfig = Get-Content -Path "NuGet.config"
- $Value = Resolve-Path ${{parameters.downloadedNugetPath }}
$newAdd = $nugetConfig.CreateElement("add")
- $newAdd.SetAttribute("key","Package source")
- $newAdd.SetAttribute("value", "$Value/" )
+ $newAdd.SetAttribute("key","pipeline_source")
+ $newAdd.SetAttribute("value", "$PackagePath" )
$nugetConfig.configuration.packageSources.AppendChild($newAdd)
$nugetConfig.Save("$rootFolder/NuGet.config")
- displayName: 'Update NuGet config file to read from Nuget folder'
+ displayName: 'Add source to NuGet.config'
- ${{ if parameters.debug }}:
- - powershell: |
+ - pwsh: |
# Display the content of the NuGet.config file
Get-Content -Path "NuGet.config"
displayName: 'Read NuGet.config [debug]'
-
-- task: DotNetCoreCLI@2
- displayName: 'Restore NuGets'
- inputs:
- command: 'custom'
- custom: 'msbuild'
- arguments: 'build.proj -t:restore'
- feedsToUse: 'select'
-
-- powershell: |
- $Doc = [xml](Get-Content "./Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj")
- $parent_xpath = '/Project/ItemGroup/ProjectReference'
- $node = $Doc.SelectSingleNode($parent_xpath)
- $parentNode = $node.ParentNode
- while($node -ne $null) {
- $node.ParentNode.RemoveChild($node)
- $node = $Doc.SelectSingleNode($parent_xpath)
- }
-
- $parent_xpath = '/Project/ItemGroup/PackageReference[@Include="Microsoft.Data.SqlClient"]'
- $node = $Doc.SelectSingleNode($parent_xpath)
-
- if($node -eq $null){
- $packagerefnode = $doc.createelement("packagereference")
- $value = $doc.selectsinglenode('/project/itemgroup/projectreference')
- $attrinclude = $doc.createattribute("include")
- $attrinclude.value = "microsoft.data.sqlclient"
- $packagerefnode.attributes.append($attrinclude)
- $parentNode.AppendChild($packageRefNode)
- }
-
- $currentFolder = Get-Location
- $filePath = Join-Path $currentFolder "Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj"
- $Doc.Save($filePath)
- workingDirectory: 'src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider'
- displayName: 'Update AKV Project Ref to Package Ref (.NET Framework/Core)'
diff --git a/eng/pipelines/dotnet-sqlclient-ci-core.yml b/eng/pipelines/dotnet-sqlclient-ci-core.yml
index 353122828b..86987f63e2 100644
--- a/eng/pipelines/dotnet-sqlclient-ci-core.yml
+++ b/eng/pipelines/dotnet-sqlclient-ci-core.yml
@@ -58,9 +58,12 @@ parameters:
type: object
default: [net462, net8.0]
-- name: buildType
- displayName: 'Build Type'
- default: Project
+# The way we will reference sibling projects in the .csproj files:
+# Project - use references.
+# Package - use references to NuGet packages in the
+# packages/ directory.
+- name: referenceType
+ displayName: 'Reference Type'
values:
- Project
- Package
@@ -89,20 +92,48 @@ parameters:
variables:
- template: libraries/ci-build-variables.yml@self
- - name: artifactName
- value: Artifacts
+ - name: abstractionsArtifactName
+ value: Abstractions.Artifact
+
+ - name: mdsArtifactName
+ value: MDS.Artifact
- name: defaultHostedPoolName
value: 'Azure Pipelines'
stages:
- - stage: build_nugets
- displayName: 'Build NuGet Packages'
+
+ # Build the Abstractions package, and publish it to the pipeline artifacts
+ # under the given artifact name.
+ - template: stages/build-abstractions-package-ci-stage.yml@self
+ parameters:
+ buildConfiguration: Release
+ abstractionsPackageVersion: $(abstractionsPackageVersion)
+ artifactName: $(abstractionsArtifactName)
+ ${{if eq(parameters.debug, 'true')}}:
+ verbosity: diagnostic
+
+ # Build MDS and its NuGet packages.
+ - stage: build_mds_akv_packages_stage
+ displayName: 'Build MDS & AKV Packages'
+
+ # When building MDS via packages, we must depend on the Abstractions
+ # package.
+ ${{ if eq(parameters.referenceType, 'Package') }}:
+ dependsOn:
+ - build_abstractions_package_stage
+ ${{ else }}:
+ dependsOn: []
+
jobs:
- template: common/templates/jobs/ci-build-nugets-job.yml@self
parameters:
+ referenceType: ${{ parameters.referenceType }}
configuration: ${{ parameters.buildConfiguration }}
- artifactName: $(artifactName)
+ abstractionsPackageVersion: $(abstractionsPackageVersion)
+ abstractionsArtifactName: $(abstractionsArtifactName)
+ mdsPackageVersion: $(mdsPackageVersion)
+ mdsArtifactName: $(mdsArtifactName)
${{if ne(parameters.SNIVersion, '')}}:
prebuildSteps:
- template: common/templates/steps/override-sni-version.yml@self
@@ -110,44 +141,48 @@ stages:
SNIVersion: ${{parameters.SNIVersion}}
SNIValidationFeed: ${{parameters.SNIValidationFeed}}
+ # Run the stress tests, if desired.
- ${{ if eq(parameters.enableStressTests, true) }}:
- template: stages/stress-tests-ci-stage.yml@self
parameters:
buildConfiguration: ${{ parameters.buildConfiguration }}
- dependsOn: [build_nugets]
+ dependsOn: [build_mds_akv_packages_stage]
pipelineArtifactName: $(artifactName)
- mdsPackageVersion: $(NugetPackageVersion)
+ mdsPackageVersion: $(mdsPackageVersion)
${{ if eq(parameters.debug, 'true') }}:
verbosity: 'detailed'
-
+
+ # Run the MDS and AKV tests.
- template: common/templates/stages/ci-run-tests-stage.yml@self
parameters:
debug: ${{ parameters.debug }}
- buildType: ${{ parameters.buildType }}
+ referenceType: ${{ parameters.referenceType }}
testsTimeout: ${{ parameters.testsTimeout }}
- ${{ if eq(parameters.buildType, 'Package') }}:
- dependsOn: build_nugets
-
- ${{if ne(parameters.SNIVersion, '')}}:
- prebuildSteps: # steps to run prior to building and running tests on each job
+ abstractionsArtifactName: $(abstractionsArtifactName)
+ abstractionsPackageVersion: $(abstractionsPackageVersion)
+ mdsArtifactName: $(mdsArtifactName)
+ mdsPackageVersion: $(mdsPackageVersion)
+
+ # When testing MDS via packages, we must depend on the Abstractions and
+ # MDS packages.
+ ${{ if eq(parameters.referenceType, 'Package') }}:
+ dependsOn:
+ - build_abstractions_package_stage
+ - build_mds_akv_packages_stage
+
+ prebuildSteps: # steps to run prior to building and running tests on each job
+ - ${{if ne(parameters.SNIVersion, '')}}:
- template: common/templates/steps/override-sni-version.yml@self
parameters:
SNIVersion: ${{parameters.SNIVersion}}
SNIValidationFeed: ${{parameters.SNIValidationFeed}}
- - template: common/templates/steps/ci-prebuild-step.yml@self
- parameters:
- debug: ${{ parameters.debug }}
- artifactName: $(artifactName)
- buildType: ${{ parameters.buildType }}
- ${{else}}:
- prebuildSteps: # steps to run prior to building and running tests on each job
- - template: common/templates/steps/ci-prebuild-step.yml@self
- parameters:
- debug: ${{ parameters.debug }}
- artifactName: $(artifactName)
- buildType: ${{ parameters.buildType }}
- ${{ if eq(parameters.buildType, 'Project') }}: # only run the code coverage job if the build type is project
+ - template: common/templates/steps/ci-prebuild-step.yml@self
+ parameters:
+ debug: ${{ parameters.debug }}
+ referenceType: ${{ parameters.referenceType }}
+
+ ${{ if eq(parameters.referenceType, 'Project') }}: # only run the code coverage job if the build type is project
postTestJobs: # jobs to run after the tests are done
- template: common/templates/jobs/ci-code-coverage-job.yml@self
parameters:
@@ -354,9 +389,8 @@ stages:
# ways to detect if they were present) won't run consistently across forks and non-forks.
${{ if eq(variables['system.pullRequest.isFork'], 'False') }}:
AADPasswordConnectionString: $(AAD_PASSWORD_CONN_STR)
- AADServicePrincipalId: $(AADServicePrincipalId)
- ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}:
AADServicePrincipalSecret: $(AADServicePrincipalSecret)
+ AADServicePrincipalId: $(AADServicePrincipalId)
AzureKeyVaultUrl: $(AzureKeyVaultUrl)
AzureKeyVaultTenantId: $(AzureKeyVaultTenantId)
SupportsIntegratedSecurity: false
@@ -383,9 +417,8 @@ stages:
AADAuthorityURL: $(AADAuthorityURL)
${{ if eq(variables['system.pullRequest.isFork'], 'False') }}:
AADPasswordConnectionString: $(AAD_PASSWORD_CONN_STR_eastus)
- AADServicePrincipalId: $(AADServicePrincipalId)
- ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}:
AADServicePrincipalSecret: $(AADServicePrincipalSecret)
+ AADServicePrincipalId: $(AADServicePrincipalId)
AzureKeyVaultUrl: $(AzureKeyVaultUrl)
AzureKeyVaultTenantId: $(AzureKeyVaultTenantId)
SupportsIntegratedSecurity: false
@@ -393,37 +426,6 @@ stages:
LocalDbAppName: $(LocalDbAppName)
LocalDbSharedInstanceName: $(LocalDbSharedInstanceName)
- ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: # only run enclave jobs if the password is available
- windows_enclave_sql:
- pool: ADO-CI-AE-1ES-Pool
- images:
- Win22_Enclave_Sql19: ADO-MMS22-SQL19
- TargetFrameworks: ${{parameters.targetFrameworks }}
- netcoreVersionTestUtils: ${{parameters.netcoreVersionTestUtils }}
- buildPlatforms: ${{parameters.buildPlatforms }}
- testSets: [AE]
- useManagedSNI: ${{parameters.useManagedSNI }}
- codeCovTargetFrameworks: ${{parameters.codeCovTargetFrameworks }}
- configSqlFor: enclave
- operatingSystem: Windows
- configProperties:
- # config.json properties
- TCPConnectionStringHGSVBS: $(SQL_TCP_CONN_STRING_HGSVBS)
- TCPConnectionStringNoneVBS: $(SQL_TCP_CONN_STRING_NoneVBS)
- TCPConnectionStringAASSGX: $(SQL_TCP_CONN_STRING_AASSGX)
- EnclaveEnabled: true
- AADAuthorityURL: $(AADAuthorityURL)
- AADServicePrincipalId: $(AADServicePrincipalId)
- ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}:
- AADServicePrincipalSecret: $(AADServicePrincipalSecret)
- AzureKeyVaultUrl: $(AzureKeyVaultUrl)
- AzureKeyVaultTenantId: $(AzureKeyVaultTenantId)
- SupportsIntegratedSecurity: $(SupportsIntegratedSecurity)
- UserManagedIdentityClientId: $(UserManagedIdentityClientId)
- AliasName: $(SQLAliasName)
- LocalDbAppName: $(LocalDbAppName)
- LocalDbSharedInstanceName: $(LocalDbSharedInstanceName)
-
# self hosted SQL Server on Linux
linux_sql_19_22:
pool: ${{parameters.defaultPoolName }}
@@ -469,9 +471,8 @@ stages:
AADAuthorityURL: $(AADAuthorityURL)
${{ if eq(variables['system.pullRequest.isFork'], 'False') }}:
AADPasswordConnectionString: $(AAD_PASSWORD_CONN_STR)
- AADServicePrincipalId: $(AADServicePrincipalId)
- ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}:
AADServicePrincipalSecret: $(AADServicePrincipalSecret)
+ AADServicePrincipalId: $(AADServicePrincipalId)
AzureKeyVaultUrl: $(AzureKeyVaultUrl)
AzureKeyVaultTenantId: $(AzureKeyVaultTenantId)
SupportsIntegratedSecurity: false
@@ -479,7 +480,65 @@ stages:
LocalDbAppName: $(LocalDbAppName)
LocalDbSharedInstanceName: $(LocalDbSharedInstanceName)
- ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: # only run enclave jobs if the password is available
+ # Self hosted SQL Server on Mac
+ mac_sql_22:
+ pool: $(defaultHostedPoolName)
+ hostedPool: true
+ images:
+ MacOSLatest_Sql22: macos-latest
+ TargetFrameworks: ${{parameters.targetFrameworksLinux }}
+ netcoreVersionTestUtils: ${{parameters.netcoreVersionTestUtils }}
+ buildPlatforms: [AnyCPU]
+ testSets: ${{parameters.testSets }}
+ useManagedSNI: [true]
+ codeCovTargetFrameworks: ${{parameters.codeCovTargetFrameworks }}
+ configSqlFor: local
+ operatingSystem: Mac
+ configProperties:
+ # config.json properties
+ TCPConnectionString: $(SQL_TCP_CONN_STRING)
+ NPConnectionString: $(SQL_NP_CONN_STRING)
+ SupportsIntegratedSecurity: false
+ ManagedIdentitySupported: false
+ LocalDbAppName: $(LocalDbAppName)
+ LocalDbSharedInstanceName: $(LocalDbSharedInstanceName)
+
+ # Enclave tests
+ #
+ # Only run enclave jobs if the password is available, which it won't be
+ # for forked PRs.
+ #
+ ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}:
+ windows_enclave_sql:
+ pool: ADO-CI-AE-1ES-Pool
+ images:
+ Win22_Enclave_Sql19: ADO-MMS22-SQL19
+ TargetFrameworks: ${{parameters.targetFrameworks }}
+ netcoreVersionTestUtils: ${{parameters.netcoreVersionTestUtils }}
+ buildPlatforms: ${{parameters.buildPlatforms }}
+ testSets: [AE]
+ useManagedSNI: ${{parameters.useManagedSNI }}
+ codeCovTargetFrameworks: ${{parameters.codeCovTargetFrameworks }}
+ configSqlFor: enclave
+ operatingSystem: Windows
+ configProperties:
+ # config.json properties
+ TCPConnectionStringHGSVBS: $(SQL_TCP_CONN_STRING_HGSVBS)
+ TCPConnectionStringNoneVBS: $(SQL_TCP_CONN_STRING_NoneVBS)
+ TCPConnectionStringAASSGX: $(SQL_TCP_CONN_STRING_AASSGX)
+ EnclaveEnabled: true
+ AADAuthorityURL: $(AADAuthorityURL)
+ AADServicePrincipalId: $(AADServicePrincipalId)
+ ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}:
+ AADServicePrincipalSecret: $(AADServicePrincipalSecret)
+ AzureKeyVaultUrl: $(AzureKeyVaultUrl)
+ AzureKeyVaultTenantId: $(AzureKeyVaultTenantId)
+ SupportsIntegratedSecurity: $(SupportsIntegratedSecurity)
+ UserManagedIdentityClientId: $(UserManagedIdentityClientId)
+ AliasName: $(SQLAliasName)
+ LocalDbAppName: $(LocalDbAppName)
+ LocalDbSharedInstanceName: $(LocalDbSharedInstanceName)
+
linux_enclave_sql:
pool: ADO-CI-AE-1ES-Pool
images:
@@ -507,26 +566,3 @@ stages:
UserManagedIdentityClientId: $(UserManagedIdentityClientId)
LocalDbAppName: $(LocalDbAppName)
LocalDbSharedInstanceName: $(LocalDbSharedInstanceName)
-
- # Self hosted SQL Server on Mac
- mac_sql_22:
- pool: $(defaultHostedPoolName)
- hostedPool: true
- images:
- MacOSLatest_Sql22: macos-latest
- TargetFrameworks: ${{parameters.targetFrameworksLinux }}
- netcoreVersionTestUtils: ${{parameters.netcoreVersionTestUtils }}
- buildPlatforms: [AnyCPU]
- testSets: ${{parameters.testSets }}
- useManagedSNI: [true]
- codeCovTargetFrameworks: ${{parameters.codeCovTargetFrameworks }}
- configSqlFor: local
- operatingSystem: Mac
- configProperties:
- # config.json properties
- TCPConnectionString: $(SQL_TCP_CONN_STRING)
- NPConnectionString: $(SQL_NP_CONN_STRING)
- SupportsIntegratedSecurity: false
- ManagedIdentitySupported: false
- LocalDbAppName: $(LocalDbAppName)
- LocalDbSharedInstanceName: $(LocalDbSharedInstanceName)
diff --git a/eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml b/eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml
index 336bd97ab5..0e6ee71697 100644
--- a/eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml
+++ b/eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml
@@ -4,37 +4,78 @@
# See the LICENSE file in the project root for more information. #
#################################################################################
+# Use the day of year and a revision number for the build name. This is what
+# appears in the Azure DevOps UI.
name: $(DayOfYear)$(Rev:rr)
-trigger:
- batch: true
+
+# Trigger PR validation runs for all pushes to PRs that target the specified
+# branches.
+#
+# https://learn.microsoft.com/en-us/azure/devops/pipelines/repos/github?view=azure-devops&tabs=yaml#pr-triggers
+#
+pr:
branches:
include:
+ # GitHub repo branch targets that will trigger PR validation builds.
+ - dev/*
+ - feat/*
- main
- - internal/main
+
paths:
include:
- - src\Microsoft.Data.SqlClient\netcore\ref
- - src\Microsoft.Data.SqlClient\netfx\ref
- - src\Microsoft.Data.SqlClient\ref
+ - .azuredevops
+ - .config
+ - src
- eng
- tools
- - .config
- - Nuget.config
+ - azurepipelines-coverage.yml
+ - build.proj
+ - NuGet.config
-schedules:
-- cron: '0 4 * * Fri'
- displayName: Weekly Thursday 9:00 PM (UTC - 7) Build
+# Trigger batched CI runs on pushes to the specified branches.
+#
+# https://learn.microsoft.com/en-us/azure/devops/pipelines/repos/github?view=azure-devops&tabs=yaml#ci-triggers
+#
+trigger:
+ batch: true
branches:
include:
+ # GitHub repo branch targets that will trigger CI builds.
+ - feat/*
+ - main
+
+ # ADO repo branch targets that will trigger CI builds.
- internal/main
- always: true
-- cron: '0 0 * * Mon-Fri'
- displayName: Daily build 5:00 PM (UTC - 7) Build
- branches:
+ paths:
include:
- - main
- always: true
+ - .azuredevops
+ - .config
+ - src
+ - eng
+ - tools
+ - azurepipelines-coverage.yml
+ - build.proj
+ - NuGet.config
+
+# Schedule periodic CI runs for the main branches.
+schedules:
+
+ # ADO internal/main
+ - cron: '0 4 * * Fri'
+ displayName: Weekly Thursday 9:00 PM (UTC - 7) Build
+ branches:
+ include:
+ - internal/main
+ always: true
+
+ # GitHub main
+ - cron: '0 0 * * Mon-Fri'
+ displayName: Daily build 5:00 PM (UTC - 7) Build
+ branches:
+ include:
+ - main
+ always: true
parameters: # parameters are shown up in ADO UI in a build queue time
- name: 'debug'
@@ -74,13 +115,6 @@ parameters: # parameters are shown up in ADO UI in a build queue time
type: object
default: [net462, net8.0]
-- name: buildType
- displayName: 'Build Type'
- default: Package
- values:
- - Project
- - Package
-
- name: buildConfiguration
displayName: 'Build Configuration'
default: Release
@@ -109,7 +143,7 @@ extends:
testSets: ${{ parameters.testSets }}
useManagedSNI: ${{ parameters.useManagedSNI }}
codeCovTargetFrameworks: ${{ parameters.codeCovTargetFrameworks }}
- buildType: ${{ parameters.buildType }}
+ referenceType: Package
buildConfiguration: ${{ parameters.buildConfiguration }}
enableStressTests: ${{ parameters.enableStressTests }}
testsTimeout: ${{ parameters.testsTimeout }}
diff --git a/eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml b/eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml
index 38325d38ca..e63fefdf3d 100644
--- a/eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml
+++ b/eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml
@@ -4,29 +4,78 @@
# See the LICENSE file in the project root for more information. #
#################################################################################
+# Use the day of year and a revision number for the build name. This is what
+# appears in the Azure DevOps UI.
name: $(DayOfYear)$(Rev:rr)
+
+# Trigger PR validation runs for all pushes to PRs that target the specified
+# branches.
+#
+# https://learn.microsoft.com/en-us/azure/devops/pipelines/repos/github?view=azure-devops&tabs=yaml#pr-triggers
+#
+pr:
+ branches:
+ include:
+ # GitHub repo branch targets that will trigger PR validation builds.
+ - dev/*
+ - feat/*
+ - main
+
+ paths:
+ include:
+ - .azuredevops
+ - .config
+ - src
+ - eng
+ - tools
+ - azurepipelines-coverage.yml
+ - build.proj
+ - NuGet.config
+
+# Trigger batched CI runs on pushes to the specified branches.
+#
+# https://learn.microsoft.com/en-us/azure/devops/pipelines/repos/github?view=azure-devops&tabs=yaml#ci-triggers
+#
trigger:
batch: true
branches:
include:
+ # GitHub repo branch targets that will trigger CI builds.
+ - feat/*
- main
+
+ # ADO repo branch targets that will trigger CI builds.
- internal/main
+
paths:
include:
+ - .azuredevops
+ - .config
- src
- eng
- tools
- - .config
+ - azurepipelines-coverage.yml
- build.proj
- - Nuget.config
+ - NuGet.config
+# Schedule periodic CI runs for the main branches.
schedules:
-- cron: '0 5 * * Thu'
- displayName: Weekly Wednesday 10:00 PM (UTC - 7) Build
- branches:
- include:
- - internal/main
- always: true
+
+ # ADO internal/main
+ - cron: '0 4 * * Fri'
+ displayName: Weekly Thursday 9:00 PM (UTC - 7) Build
+ branches:
+ include:
+ - internal/main
+ always: true
+
+ # GitHub main
+ - cron: '0 0 * * Mon-Fri'
+ displayName: Daily build 5:00 PM (UTC - 7) Build
+ branches:
+ include:
+ - main
+ always: true
parameters: # parameters are shown up in ADO UI in a build queue time
- name: 'debug'
@@ -66,13 +115,6 @@ parameters: # parameters are shown up in ADO UI in a build queue time
type: object
default: [net462, net8.0]
-- name: buildType
- displayName: 'Build Type'
- default: Project
- values:
- - Project
- - Package
-
- name: buildConfiguration
displayName: 'Build Configuration'
default: Release
@@ -101,7 +143,7 @@ extends:
testSets: ${{ parameters.testSets }}
useManagedSNI: ${{ parameters.useManagedSNI }}
codeCovTargetFrameworks: ${{ parameters.codeCovTargetFrameworks }}
- buildType: ${{ parameters.buildType }}
+ referenceType: Project
buildConfiguration: ${{ parameters.buildConfiguration }}
enableStressTests: ${{ parameters.enableStressTests }}
testsTimeout: ${{ parameters.testsTimeout }}
diff --git a/eng/pipelines/dotnet-sqlclient-signing-pipeline.yml b/eng/pipelines/dotnet-sqlclient-signing-pipeline.yml
index e104b99193..3a81b58bfd 100644
--- a/eng/pipelines/dotnet-sqlclient-signing-pipeline.yml
+++ b/eng/pipelines/dotnet-sqlclient-signing-pipeline.yml
@@ -8,17 +8,20 @@ name: $(Year:YY)$(DayOfYear)$(Rev:.r)
trigger:
branches:
include:
+
+ # This pipeline is intended to only run against the ADO dotnet-sqlclient
+ # repo.
- internal/main
paths:
include:
+ - .azuredevops
+ - .config
- src
- eng
- tools
- - .config
+ - azurepipelines-coverage.yml
- build.proj
- - Nuget.config
- - '*.cmd'
- - '*.sh'
+ - NuGet.config
schedules:
- cron: '30 4 * * Mon'
@@ -107,14 +110,14 @@ extends:
softwareFolder: $(softwareFolder)
symbolsFolder: $(symbolsFolder)
softwarename: Microsoft.Data.SqlClient
- versionNumber: $(AssemblyFileVersion)
+ versionNumber: $(mdsAssemblyFileVersion)
codeql:
compiled:
enabled: ${{ not(parameters['isPreview']) }}
sbom:
enabled: ${{ not(parameters['isPreview']) }}
packageName: Microsoft.Data.SqlClient
- packageVersion: $(NugetPackageVersion)
+ packageVersion: $(mdsPackageVersion)
policheck:
enabled: ${{ not(parameters['isPreview']) }}
break: true # always break the build on policheck issues. You can disable it by setting to 'false'
diff --git a/eng/pipelines/jobs/build-akv-official-job.yml b/eng/pipelines/jobs/build-akv-official-job.yml
index a4374b773b..bad8758f6e 100644
--- a/eng/pipelines/jobs/build-akv-official-job.yml
+++ b/eng/pipelines/jobs/build-akv-official-job.yml
@@ -5,21 +5,21 @@
#################################################################################
parameters:
+ - name: akvAssemblyFileVersion
+ type: string
+
+ - name: akvPackageVersion
+ type: string
+
- name: apiScanDllPath
type: string
- name: apiScanPdbPath
type: string
-
- - name: assemblyFileVersion
- type: string
- name: buildConfiguration
type: string
- - name: nugetPackageVersion
- type: string
-
- name: mdsPackageVersion
type: string
@@ -86,9 +86,18 @@ jobs:
$jsonParams | ConvertFrom-Json | Format-List
displayName: 'Output Job Parameters'
+ # Perform analysis before building, since this step will clobber build
+ # output
+ - template: ../steps/roslyn-analyzers-akv-step.yml@self
+ parameters:
+ akvPackageVersion: '${{ parameters.akvPackageVersion }}'
+ buildConfiguration: '${{ parameters.buildConfiguration }}'
+ mdsPackageVersion: '${{ parameters.mdsPackageVersion }}'
+
- template: ../steps/compound-build-akv-step.yml@self
parameters:
- assemblyFileVersion: '${{ parameters.assemblyFileVersion }}'
+ akvAssemblyFileVersion: '${{ parameters.akvAssemblyFileVersion }}'
+ akvPackageVersion: '${{ parameters.akvPackageVersion }}'
buildConfiguration: '${{ parameters.buildConfiguration }}'
mdsPackageVersion: '${{ parameters.mdsPackageVersion }}'
@@ -101,11 +110,6 @@ jobs:
referenceType: Package
targetFramework: '${{ targetFramework }}'
- - template: ../steps/roslyn-analyzers-akv-step.yml@self
- parameters:
- buildConfiguration: '${{ parameters.buildConfiguration }}'
- mdsPackageVersion: '${{ parameters.mdsPackageVersion }}'
-
- template: ../steps/compound-esrp-code-signing-step.yml@self
parameters:
appRegistrationClientId: '${{ parameters.signingAppRegistrationClientId }}'
@@ -120,10 +124,11 @@ jobs:
parameters:
buildConfiguration: '${{ parameters.buildConfiguration }}'
generateSymbolsPackage: true # Always generate symbols, even if they are not published
- packageVersion: '${{ parameters.nugetPackageVersion }}'
+ packageVersion: '${{ parameters.akvPackageVersion }}'
nuspecPath: '$(REPO_ROOT)/tools/specs/add-ons/$(PACKAGE_NAME).nuspec'
outputDirectory: '$(ARTIFACT_PATH)'
- referenceType: 'Package'
+ referenceType: Package
+ properties: MdsPackageVersion=${{ parameters.mdsPackageVersion }}
- template: ../steps/compound-esrp-code-signing-step.yml@self
parameters:
@@ -138,7 +143,7 @@ jobs:
- ${{ if parameters.publishSymbols }}:
- template: ../steps/compound-publish-symbols-step.yml@self
parameters:
- artifactName: 'akv_symbols_$(System.TeamProject)_$(Build.Repository.Name)_$(Build.SourceBranchName)_${{ parameters.nugetPackageVersion }}_$(System.TimelineId)'
+ artifactName: 'akv_symbols_$(System.TeamProject)_$(Build.Repository.Name)_$(Build.SourceBranchName)_${{ parameters.akvPackageVersion }}_$(System.TimelineId)'
azureSubscription: '${{ parameters.symbolsAzureSubscription }}'
publishProjectName: '${{ parameters.symbolsPublishProjectName }}'
packageName: '$(PACKAGE_NAME)'
@@ -151,4 +156,4 @@ jobs:
Windows_NT/${{ parameters.buildConfiguration }}.AnyCPU/AzureKeyVaultProvider/**/$(PACKAGE_NAME).pdb
AnyOS/${{ parameters.buildConfiguration }}.AnyCPU/AzureKeyVaultProvider/**/$(PACKAGE_NAME).pdb
uploadAccount: '${{ parameters.symbolsUploadAccount }}'
- version: '${{ parameters.nugetPackageVersion }}'
+ version: '${{ parameters.akvPackageVersion }}'
diff --git a/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml b/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml
new file mode 100644
index 0000000000..13bf3618fb
--- /dev/null
+++ b/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml
@@ -0,0 +1,148 @@
+################################################################################
+# Licensed to the .NET Foundation under one or more agreements. The .NET
+# Foundation licenses this file to you under the MIT license. See the LICENSE
+# file in the project root for more information.
+################################################################################
+
+# This job packs the Abstractions package into NuGet and symbols packages and
+# publishes them as a named pipeline artifact.
+#
+# This template defines a job named 'pack_abstractions_package_job' that can be
+# depended on by downstream jobs.
+
+parameters:
+
+ # The version to apply to the Abstractions NuGet package and its assemblies.
+ - name: abstractionsPackageVersion
+ type: string
+
+ # The name to apply to the published pipeline artifact.
+ - name: artifactName
+ type: string
+ default: Abstractions.Artifact
+
+ # The type of build to test (Release or Debug)
+ - name: buildConfiguration
+ type: string
+ values:
+ - Release
+ - Debug
+
+ # The list of upstream jobs to depend on.
+ - name: dependsOn
+ type: object
+ default: []
+
+ # The verbosity level for the dotnet CLI commands.
+ - name: verbosity
+ type: string
+ default: normal
+ values:
+ - quiet
+ - minimal
+ - normal
+ - detailed
+ - diagnostic
+
+jobs:
+
+ - job: pack_abstractions_package_job
+ displayName: 'Pack Abstractions Package'
+
+ dependsOn: ${{ parameters.dependsOn }}
+
+ pool:
+ name: Azure Pipelines
+ vmImage: ubuntu-latest
+
+ variables:
+
+ # The Abstractions project file to use for all dotnet CLI commands.
+ - name: project
+ value: src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj
+
+ # The directory where the NuGet packages will be staged before being
+ # published as pipeline artifacts.
+ - name: dotnetPackagesDir
+ value: $(Build.StagingDirectory)/dotnetPackages
+
+ # dotnet CLI arguments common to all commands.
+ - name: commonArguments
+ value: >-
+ --verbosity ${{ parameters.verbosity }}
+
+ # dotnet CLI arguments for build/test/pack commands
+ - name: buildArguments
+ value: >-
+ $(commonArguments)
+ --configuration ${{ parameters.buildConfiguration }}
+ -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}
+
+ # Explicitly unset the $PLATFORM environment variable that is set by the
+ # 'ADO Build properties' Library in the ADO SqlClientDrivers public project.
+ # This is defined with a non-standard Platform of 'AnyCPU', and will fail
+ # the builds if left defined. The stress tests solution does not require
+ # any specific Platform, and so its solution file doesn't support any
+ # non-standard platforms.
+ #
+ # Note that Azure Pipelines will inject this variable as PLATFORM into the
+ # environment of all tasks in this job.
+ #
+ # See:
+ # https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch
+ #
+ - name: Platform
+ value: ''
+
+ # Do the same for $CONFIGURATION since we explicitly set it using our
+ # 'buildConfiguration' parameter, and we don't want the environment to
+ # override us.
+ - name: Configuration
+ value: ''
+
+ steps:
+
+ # Install the .NET 9.0 SDK.
+ - task: UseDotNet@2
+ displayName: Install .NET 9.0 SDK
+ inputs:
+ packageType: sdk
+ version: 9.x
+
+ # We use the 'custom' command because the DotNetCoreCLI@2 task doesn't
+ # support all of our argument combinations for the different build steps.
+
+ # Restore the solution.
+ - task: DotNetCoreCLI@2
+ displayName: Restore Solution
+ inputs:
+ command: custom
+ custom: restore
+ projects: $(project)
+ arguments: $(commonArguments)
+
+ # Build the solution.
+ - task: DotNetCoreCLI@2
+ displayName: Build Solution
+ inputs:
+ command: custom
+ custom: build
+ projects: $(project)
+ arguments: $(buildArguments) --no-restore
+
+ # Create the NuGet packages.
+ - task: DotNetCoreCLI@2
+ displayName: Create NuGet Package
+ inputs:
+ command: custom
+ custom: pack
+ projects: $(project)
+ arguments: $(buildArguments) --no-build -o $(dotnetPackagesDir)
+
+ # Publish the NuGet packages as a named pipeline artifact.
+ - task: PublishPipelineArtifact@1
+ displayName: Publish Pipeline Artifact
+ inputs:
+ targetPath: $(dotnetPackagesDir)
+ artifactName: ${{ parameters.artifactName }}
+ publishLocation: pipeline
diff --git a/eng/pipelines/jobs/stress-tests-ci-job.yml b/eng/pipelines/jobs/stress-tests-ci-job.yml
index 2e01470fe5..cc2913c367 100644
--- a/eng/pipelines/jobs/stress-tests-ci-job.yml
+++ b/eng/pipelines/jobs/stress-tests-ci-job.yml
@@ -4,7 +4,7 @@
# file in the project root for more information.
################################################################################
-# This stage builds and runs stress tests against an MDS NuGet package available
+# This job builds and runs stress tests against an MDS NuGet package available
# as a pipeline artifact.
#
# The stress tests are located here:
diff --git a/eng/pipelines/jobs/test-abstractions-package-ci-job.yml b/eng/pipelines/jobs/test-abstractions-package-ci-job.yml
new file mode 100644
index 0000000000..a5e0f98978
--- /dev/null
+++ b/eng/pipelines/jobs/test-abstractions-package-ci-job.yml
@@ -0,0 +1,174 @@
+################################################################################
+# Licensed to the .NET Foundation under one or more agreements. The .NET
+# Foundation licenses this file to you under the MIT license. See the LICENSE
+# file in the project root for more information.
+################################################################################
+
+# This job builds the Abstractions package and runs its tests for a set of .NET
+# runtimes.
+#
+# This template defines a job named 'test_abstractions_package_job_'
+# that can be depended on by downstream jobs.
+
+parameters:
+
+ # The type of build to test (Release or Debug)
+ - name: buildConfiguration
+ type: string
+ values:
+ - Release
+ - Debug
+
+ # The prefix to prepend to the job's display name:
+ #
+ # [] Run Stress Tests
+ #
+ - name: displayNamePrefix
+ type: string
+
+ # The suffix to append to the job name.
+ - name: jobNameSuffix
+ type: string
+
+ # The list of .NET Framework runtimes to test against.
+ - name: netFrameworkRuntimes
+ type: object
+ default: []
+
+ # The list of .NET runtimes to test against.
+ - name: netRuntimes
+ type: object
+ default: []
+
+ # The name of the Azure Pipelines pool to use.
+ - name: poolName
+ type: string
+
+ # The verbosity level for the dotnet CLI commands.
+ - name: verbosity
+ type: string
+ default: normal
+ values:
+ - quiet
+ - minimal
+ - normal
+ - detailed
+ - diagnostic
+
+ # The pool VM image to use.
+ - name: vmImage
+ type: string
+
+jobs:
+
+ - job: test_abstractions_package_job_${{ parameters.jobNameSuffix }}
+ displayName: '[${{ parameters.displayNamePrefix }}] Test Abstractions Package'
+ pool:
+ name: ${{ parameters.poolName }}
+
+ # Images provided by Azure Pipelines must be selected using 'vmImage'.
+ ${{ if eq(parameters.poolName, 'Azure Pipelines') }}:
+ vmImage: ${{ parameters.vmImage }}
+ # Images provided by 1ES must be selected using a demand.
+ ${{ else }}:
+ demands:
+ - imageOverride -equals ${{ parameters.vmImage }}
+
+ variables:
+
+ # The Abstractions test project file to use for all dotnet CLI commands.
+ - name: project
+ value: src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj
+
+ # dotnet CLI arguments common to all commands.
+ - name: commonArguments
+ value: >-
+ --verbosity ${{ parameters.verbosity }}
+
+ # dotnet CLI arguments for build/test/pack commands
+ - name: buildArguments
+ value: >-
+ $(commonArguments)
+ --configuration ${{ parameters.buildConfiguration }}
+
+ # Explicitly unset the $PLATFORM environment variable that is set by the
+ # 'ADO Build properties' Library in the ADO SqlClientDrivers public project.
+ # This is defined with a non-standard Platform of 'AnyCPU', and will fail
+ # the builds if left defined. The stress tests solution does not require
+ # any specific Platform, and so its solution file doesn't support any
+ # non-standard platforms.
+ #
+ # Note that Azure Pipelines will inject this variable as PLATFORM into the
+ # environment of all tasks in this job.
+ #
+ # See:
+ # https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch
+ #
+ - name: Platform
+ value: ''
+
+ # Do the same for $CONFIGURATION since we explicitly set it using our
+ # 'buildConfiguration' parameter, and we don't want the environment to
+ # override us.
+ - name: Configuration
+ value: ''
+
+ steps:
+
+ # Install the .NET 9.0 SDK.
+ - task: UseDotNet@2
+ displayName: Install .NET 9.0 SDK
+ inputs:
+ packageType: sdk
+ version: 9.x
+
+ # Install the .NET 8.0 runtime.
+ - task: UseDotNet@2
+ displayName: Install .NET 8.0 Runtime
+ inputs:
+ packageType: runtime
+ version: 8.x
+
+ # The Windows agent images include a suitable .NET Framework runtime, so
+ # we don't have to install one explicitly.
+
+ # We use the 'custom' command because the DotNetCoreCLI@2 task doesn't
+ # support all of our argument combinations for the different build steps.
+
+ # Restore the solution.
+ - task: DotNetCoreCLI@2
+ displayName: Restore Solution
+ inputs:
+ command: custom
+ custom: restore
+ projects: $(project)
+ arguments: $(commonArguments)
+
+ # Build the solution.
+ - task: DotNetCoreCLI@2
+ displayName: Build Solution
+ inputs:
+ command: custom
+ custom: build
+ projects: $(project)
+ arguments: $(buildArguments) --no-restore
+
+ # Run the tests for each .NET runtime.
+ - ${{ each runtime in parameters.netRuntimes }}:
+ - task: DotNetCoreCLI@2
+ displayName: Test [${{ runtime }}]
+ inputs:
+ command: custom
+ custom: test
+ projects: $(project)
+ arguments: $(buildArguments) --no-build -f ${{ runtime }}
+
+ # Run the tests for each .NET Framework runtime.
+ - ${{ each runtime in parameters.netFrameworkRuntimes }}:
+ - task: DotNetCoreCLI@2
+ displayName: Test [${{ runtime }}]
+ inputs:
+ command: custom
+ custom: test
+ projects: $(project)
+ arguments: $(buildArguments) --no-build -f ${{ runtime }}
diff --git a/eng/pipelines/libraries/ci-build-variables.yml b/eng/pipelines/libraries/ci-build-variables.yml
index d3ae6fcbc3..6b6ac2a825 100644
--- a/eng/pipelines/libraries/ci-build-variables.yml
+++ b/eng/pipelines/libraries/ci-build-variables.yml
@@ -6,7 +6,6 @@
variables:
- group: 'ADO Build properties'
- - group: 'ADO CI Packaging'
- group: 'ADO Test Configuration Properties'
- name: buildNumber
@@ -15,21 +14,15 @@ variables:
value: 'net8.0'
- name: SQLTarget
value: 'localhost'
- - name: NugetPackageVersion
- value: $(Major).$(Minor)$(Patch)-pull.1$(buildnumber)
+ - name: abstractionsPackageVersion
+ value: 1.0.0.$(buildNumber)-ci
+ - name: akvPackageVersion
+ value: 7.0.0.$(buildNumber)-ci
+ - name: mdsPackageVersion
+ value: 7.0.0.$(buildNumber)-ci
- name: skipComponentGovernanceDetection
value: true
- name: runCodesignValidationInjection
value: false
- name: packagePath
value: '$(Build.SourcesDirectory)/packages'
-
- # TODO(ADO-38703): Remove these when the other pipeline changes arrive.
- - name: baseBuildNumber
- value: $[ split(variables['Build.BuildNumber'], '.')[0] ]
- - name: abstractionsPackageVersion
- value: 1.0.0.$(baseBuildNumber)
- - name: mdsPackageVersion
- value: $(NugetPackageVersion)
- - name: akvPackageVersion
- value: $(NugetPackageVersion)
diff --git a/eng/pipelines/libraries/common-variables.yml b/eng/pipelines/libraries/common-variables.yml
index a986c714af..e03e239f3b 100644
--- a/eng/pipelines/libraries/common-variables.yml
+++ b/eng/pipelines/libraries/common-variables.yml
@@ -26,6 +26,39 @@ variables:
- name: artifactDirectory
value: '$(REPOROOT)/packages'
+ # C# assembly versions must be in the format: Major.Minor.Build.Revision, but
+ # $(Build.BuildNumber) has the format XXX.YY. Additionally, each version part
+ # must be a positive 16-bit integer less than 65535. Simply concatenating
+ # both parts of $(Build.BuildNumber) could produce values larger than 65534,
+ # so we must omit the second part entirely. Unfortunately, this may result
+ # in multiple subsequent pipline builds using the same C# assembly versions.
+ # The package versions will not be affected and will show the complete
+ # $(Build.BuildNumber) values.
+ - name: assemblyBuildNumber
+ value: $[ split(variables['Build.BuildNumber'], '.')[0] ]
+
+ # ----------------------------------------------------------------------------
+ # Abstractions Package Versions
+ #
+ # These are version values that will be used by the official build. They
+ # should be updated after each release to reflect the next release's versions.
+
+ # The NuGet package version for GA releases (non-preview).
+ - name: abstractionsPackageVersion
+ value: '1.0.0'
+
+ # The NuGet package version for preview releases.
+ - name: abstractionsPackagePreviewVersion
+ value: 1.0.0-preview1.$(Build.BuildNumber)
+
+ # The AssemblyFileVersion for all assemblies in the Abstractions package.
+ #
+ - name: abstractionsAssemblyFileVersion
+ value: 1.0.0.$(assemblyBuildNumber)
+
+ # ----------------------------------------------------------------------------
+ # MDS Package Versions
+
# Update this after every release. This is used to generate the MDS NuGet package version.
- name: Major
value: '7'
@@ -40,21 +73,11 @@ variables:
- name: Revision
value: '2'
- - name: NugetPackageVersion
+ - name: mdsPackageVersion
value: $(Major).$(Minor).$(Patch)
- - name: PreviewNugetPackageVersion
+ - name: previewMdsPackageVersion
value: $(Major).$(Minor).$(Patch)$(Preview)$(Revision).$(Build.BuildNumber)
- - name: AssemblyFileVersion
- value: '$(Major).$(Minor)$(Patch).$(Build.BuildNumber)'
+ - name: mdsAssemblyFileVersion
+ value: $(Major).$(Minor).$(Patch).$(assemblyBuildNumber)
- name: nuspecPath
value: '$(REPOROOT)/tools/specs/Microsoft.Data.SqlClient.nuspec'
-
- # TODO(ADO-38703): Remove these when the other pipeline changes arrive.
- - name: baseBuildNumber
- value: $[ split(variables['Build.BuildNumber'], '.')[0] ]
- - name: abstractionsPackageVersion
- value: 1.0.0.$(baseBuildNumber)
- - name: mdsPackageVersion
- value: $(NugetPackageVersion)
- - name: akvPackageVersion
- value: $(NugetPackageVersion)
diff --git a/eng/pipelines/libraries/mds-validation-variables.yml b/eng/pipelines/libraries/mds-validation-variables.yml
index d7723a059f..93dc0804ff 100644
--- a/eng/pipelines/libraries/mds-validation-variables.yml
+++ b/eng/pipelines/libraries/mds-validation-variables.yml
@@ -13,7 +13,7 @@ variables:
- name: extractedNugetRootPath
value: $(Build.SourcesDirectory)\$(TempFolderName)\Microsoft.Data.SqlClient
- name: extractedNugetPath
- value: $(extractedNugetRootPath).$(NugetPackageVersion)
+ value: $(extractedNugetRootPath).$(mdsPackageVersion)
- name: expectedFolderNames
value: lib,ref,runtimes
- name: expectedDotnetVersions
diff --git a/eng/pipelines/stages/build-abstractions-package-ci-stage.yml b/eng/pipelines/stages/build-abstractions-package-ci-stage.yml
new file mode 100644
index 0000000000..2a9268e737
--- /dev/null
+++ b/eng/pipelines/stages/build-abstractions-package-ci-stage.yml
@@ -0,0 +1,119 @@
+################################################################################
+# Licensed to the .NET Foundation under one or more agreements. The .NET
+# Foundation licenses this file to you under the MIT license. See the LICENSE
+# file in the project root for more information.
+################################################################################
+
+# This stage builds the Abstractions package, runs tests, and publishes the
+# resulting NuGet packages as pipeline artifacts.
+#
+# The NuGet packages have the following properties:
+#
+# Name: Microsoft.Data.SqlClient.Extensions.Abstractions
+# Version: ${{ abstractionsPackageVersion }} (from parameter)
+#
+# The following NuGet packages are published:
+#
+# Microsoft.Data.SqlClient.Extensions.Abstractions..nupkg
+# Microsoft.Data.SqlClient.Extensions.Abstractions..snupkg (symbols)
+#
+# The packages are published to pipeline artifacts with the name specified by
+# the ${{ artifactName }} parameter.
+#
+# This template defines a stage named 'build_abstractions_package_stage' that
+# can be depended on by downstream stages.
+
+parameters:
+
+ # The version to apply to the NuGet package and DLLs.
+ - name: abstractionsPackageVersion
+ type: string
+
+ # The name of the pipeline artifact to publish.
+ - name: artifactName
+ type: string
+ default: Abstractions.Artifact
+
+ # The type of build to produce (Release or Debug)
+ - name: buildConfiguration
+ type: string
+ default: Release
+ values:
+ - Release
+ - Debug
+
+ # The verbosity level for the dotnet CLI commands.
+ - name: verbosity
+ type: string
+ default: normal
+ values:
+ - quiet
+ - minimal
+ - normal
+ - detailed
+ - diagnostic
+
+stages:
+
+ - stage: build_abstractions_package_stage
+ displayName: Build Abstractions Package
+
+ jobs:
+
+ # ------------------------------------------------------------------------
+ # Build and test on Linux.
+
+ - template: ../jobs/test-abstractions-package-ci-job.yml@self
+ parameters:
+ jobNameSuffix: linux
+ displayNamePrefix: Linux
+ poolName: Azure Pipelines
+ vmImage: ubuntu-latest
+ buildConfiguration: ${{ parameters.buildConfiguration }}
+ netRuntimes: [net8.0, net9.0]
+ netFrameworkRuntimes: []
+ verbosity: ${{ parameters.verbosity }}
+
+ # ------------------------------------------------------------------------
+ # Build and test on Windows
+
+ - template: ../jobs/test-abstractions-package-ci-job.yml@self
+ parameters:
+ jobNameSuffix: windows
+ displayNamePrefix: Win
+ poolName: Azure Pipelines
+ vmImage: windows-latest
+ buildConfiguration: ${{ parameters.buildConfiguration }}
+ netRuntimes: [net8.0, net9.0]
+ netFrameworkRuntimes: [net462, net47, net471, net472, net48, net481]
+ verbosity: ${{ parameters.verbosity }}
+
+ # ------------------------------------------------------------------------
+ # Build and test on macOS.
+
+ - template: ../jobs/test-abstractions-package-ci-job.yml
+ parameters:
+ jobNameSuffix: macos
+ displayNamePrefix: macOS
+ poolName: Azure Pipelines
+ vmImage: macos-latest
+ buildConfiguration: ${{ parameters.buildConfiguration }}
+ netRuntimes: [net8.0, net9.0]
+ netFrameworkRuntimes: []
+ verbosity: ${{ parameters.verbosity }}
+
+ # ------------------------------------------------------------------------
+ # Create and publish the NuGet package.
+
+ - template: ../jobs/pack-abstractions-package-ci-job.yml@self
+ parameters:
+ artifactName: ${{ parameters.artifactName }}
+ buildConfiguration: ${{ parameters.buildConfiguration }}
+ abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }}
+ verbosity: ${{ parameters.verbosity }}
+ dependsOn:
+ # We depend on all of the test jobs to ensure the tests pass before
+ # producing the NuGet package.
+ - test_abstractions_package_job_linux
+ - test_abstractions_package_job_windows
+ - test_abstractions_package_job_macos
diff --git a/eng/pipelines/steps/compound-build-akv-step.yml b/eng/pipelines/steps/compound-build-akv-step.yml
index 906dcfaf72..75e6e00e3d 100644
--- a/eng/pipelines/steps/compound-build-akv-step.yml
+++ b/eng/pipelines/steps/compound-build-akv-step.yml
@@ -7,10 +7,13 @@
# @TODO: This can probably be made generic and pass in the command lines for msbuild
# BUT, they should be kept separate by now as we rebuild build.proj in parallel, we won't
# affect >1 project at a time.
-# @TODO: NugetPackageVersion should not be used for MDS package version
+# @TODO: mdsPackageVersion should not be used for MDS package version
parameters:
- - name: assemblyFileVersion
+ - name: akvAssemblyFileVersion
+ type: string
+
+ - name: akvPackageVersion
type: string
- name: buildConfiguration
@@ -32,12 +35,6 @@ steps:
packageType: 'sdk'
version: '9.x'
- - task: UseDotNet@2
- displayName: 'Install .NET 8.x Runtime'
- inputs:
- packageType: 'runtime'
- version: '8.x'
-
- task: MSBuild@1
displayName: 'Build.proj - BuildAkv'
inputs:
@@ -45,8 +42,9 @@ steps:
configuration: '${{ parameters.buildConfiguration }}'
msbuildArguments: >-
-t:BuildAkv
- -p:AssemblyFileVersion=${{ parameters.assemblyFileVersion }}
- -p:NugetPackageVersion=${{ parameters.mdsPackageVersion }}
+ -p:AssemblyFileVersion=${{ parameters.akvAssemblyFileVersion }}
+ -p:AkvPackageVersion=${{ parameters.akvPackageVersion }}
+ -p:MdsPackageVersion=${{ parameters.mdsPackageVersion }}
-p:ReferenceType=Package
-p:SigningKeyPath=$(Agent.TempDirectory)/netfxKeypair.snk
diff --git a/eng/pipelines/steps/compound-nuget-pack-step.yml b/eng/pipelines/steps/compound-nuget-pack-step.yml
index 888078ed30..d645a361c3 100644
--- a/eng/pipelines/steps/compound-nuget-pack-step.yml
+++ b/eng/pipelines/steps/compound-nuget-pack-step.yml
@@ -23,14 +23,36 @@ parameters:
- name: referenceType
type: string
values:
- - Package
- - Project
+ - Package
+ - Project
+
+ # Semi-colon separated properties to pass to nuget via the -properties
+ # argument.
+ - name: properties
+ type: string
+ default: ''
steps:
- - task: NuGetToolInstaller@1
- displayName: 'Install Latest Nuget'
- inputs:
- checkLatest: true
+ # This tool is failing on OneBranch pipelines, possibly due to new
+ # network isolation rules:
+ #
+ # ERR:Client network socket disconnected before secure TLS connection was established
+ #
+ # Our AKV Official build uses this 1ES image:
+ #
+ # Image: 1ES-OB-2022-D8-Netlock-V2_westus2_1_image
+ #
+ # An ICM for this issue exists:
+ #
+ # https://portal.microsofticm.com/imp/v5/incidents/details/690355343/summary
+ #
+ # Recommendation is to remove this step since NuGet is already present on
+ # the 1ES images.
+ #
+ # - task: NuGetToolInstaller@1
+ # displayName: 'Install Latest Nuget'
+ # inputs:
+ # checkLatest: true
- ${{ if parameters.generateSymbolsPackage }}:
- task: NuGetCommand@2
@@ -44,7 +66,7 @@ steps:
-SymbolPackageFormat snupkg
-Version ${{ parameters.packageVersion }}
-OutputDirectory ${{ parameters.outputDirectory }}
- -Properties "COMMITID=$(Build.SourceVersion);Configuration=${{ parameters.buildConfiguration }};ReferenceType=${{ parameters.referenceType }}"
+ -Properties "COMMITID=$(Build.SourceVersion);Configuration=${{ parameters.buildConfiguration }};ReferenceType=${{ parameters.referenceType }};${{ parameters.properties }}"
- ${{ else }}:
- task: NuGetCommand@2
displayName: 'Generate NuGet Package'
@@ -55,4 +77,4 @@ steps:
${{ parameters.nuspecPath }}
-Version ${{ parameters.packageVersion }}
-OutputDirectory ${{ parameters.outputDirectory }}
- -Properties "COMMITID=$(Build.SourceVersion);Configuration=${{ parameters.buildConfiguration }};ReferenceType=${{ parameters.referenceType }}"
+ -Properties "COMMITID=$(Build.SourceVersion);Configuration=${{ parameters.buildConfiguration }};ReferenceType=${{ parameters.referenceType }};${{ parameters.properties }}"
diff --git a/eng/pipelines/steps/roslyn-analyzers-akv-step.yml b/eng/pipelines/steps/roslyn-analyzers-akv-step.yml
index 0e05177d5a..909241e4b3 100644
--- a/eng/pipelines/steps/roslyn-analyzers-akv-step.yml
+++ b/eng/pipelines/steps/roslyn-analyzers-akv-step.yml
@@ -4,11 +4,23 @@
# See the LICENSE file in the project root for more information. #
#################################################################################
+# This template defines a step to run Roslyn Analyzers on the AKV project build.
+# It uses the RoslynAnalyzers@3 task from the Secure Development Team's SDL
+# extension:
+#
+# https://eng.ms/docs/cloud-ai-platform/devdiv/one-engineering-system-1es/1es-mohanb/security-integration/guardian-wiki/sdl-azdo-extension/roslyn-analyzers-build-task
+#
+# GOTCHA: This step will clobber any existing build output. It should be run
+# _before_ any build steps that perform versioning or signing.
+
# @TODO: This can probably be made generic and pass in the command lines for msbuild
# BUT, they should be kept separate by now as we rebuild build.proj in parallel, we won't
# affect >1 project at a time.
parameters:
+ - name: akvPackageVersion
+ type: string
+
- name: buildConfiguration
type: string
@@ -25,7 +37,8 @@ steps:
$(REPO_ROOT)/build.proj
-t:BuildAkv
-p:Configuration=${{ parameters.buildConfiguration }}
- -p:NugetPackageVersion=${{ parameters.mdsPackageVersion }}
+ -p:AkvPackageVersion=${{ parameters.akvPackageVersion }}
+ -p:MdsPackageVersion=${{ parameters.mdsPackageVersion }}
-p:ReferenceType=Package
msBuildVersion: 17.0
setupCommandLinePicker: vs2022
diff --git a/eng/pipelines/variables/akv-official-variables.yml b/eng/pipelines/variables/akv-official-variables.yml
index aaf8de7c5e..591a562686 100644
--- a/eng/pipelines/variables/akv-official-variables.yml
+++ b/eng/pipelines/variables/akv-official-variables.yml
@@ -35,9 +35,7 @@ variables:
value: '-preview1'
# Compound Variables ---------------------------------------------------
- - name: assemblyFileVersion
+ - name: akvAssemblyFileVersion
value: '${{ variables.versionMajor }}.${{ variables.versionMinor }}${{ variables.versionPatch }}.$(Build.BuildNumber)'
- - name: nugetPackageVersion
+ - name: akvPackageVersion
value: '${{ variables.versionMajor }}.${{ variables.versionMinor }}.${{ variables.versionPatch }}${{ variables.versionPreview }}'
-
-
diff --git a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj
index f4fa41bf45..4b658f409a 100644
--- a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj
@@ -55,12 +55,9 @@
-
-
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
index d46e4c5f37..fff624a59a 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
@@ -1091,12 +1091,9 @@
-
-
diff --git a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj
index e8dbcf7070..f73b8682a0 100644
--- a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj
@@ -58,12 +58,9 @@
-
-
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj
index 0886b0a973..3729377928 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj
@@ -1068,12 +1068,9 @@
-
-
diff --git a/tools/props/Versions.props b/tools/props/Versions.props
index 7a3ba3cc9a..d82a04cce2 100644
--- a/tools/props/Versions.props
+++ b/tools/props/Versions.props
@@ -31,10 +31,14 @@
specific to MDS, and then used in the MDS project. As-is, these names are
used by the build tooling and may be unintentionally included in other
(non-MDS) projects.
+
+ For example, the AKV package uses the AssemblyVersion, FileVersion, and
+ Version as its own. It currently isn't possible to build/package both
+ MDS and AKV at the same time.
-->
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
diff --git a/tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec b/tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec
index a313d0af12..e55fb4e7cb 100644
--- a/tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec
+++ b/tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec
@@ -36,12 +36,6 @@ Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyStoreProvider.SqlColumnEncrypti
-
-
-
-
-
-
@@ -51,23 +45,28 @@ Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyStoreProvider.SqlColumnEncrypti
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build.proj b/build.proj
index 2a41791844..d5cdcf73ef 100644
--- a/build.proj
+++ b/build.proj
@@ -28,10 +28,13 @@
$(TF)
$(TF)
true
- Configuration=$(Configuration);AssemblyVersion=$(SqlServerAssemblyVersion);AssemblyFileVersion=$(SqlServerAssemblyFileVersion);Version=$(SqlServerPackageVersion);
- Configuration=$(Configuration);AssemblyFileVersion=$(AssemblyFileVersion);TargetsWindows=$(TargetsWindows);TargetsUnix=$(TargetsUnix);
+
+ Configuration=$(Configuration);ReferenceType=$(ReferenceType)
+ $(CommonProperties);AssemblyVersion=$(SqlServerAssemblyVersion);AssemblyFileVersion=$(SqlServerAssemblyFileVersion);Version=$(SqlServerPackageVersion);
+ $(CommonProperties);AssemblyFileVersion=$(AssemblyFileVersion);TargetsWindows=$(TargetsWindows);TargetsUnix=$(TargetsUnix);
$(ProjectProperties);BuildForRelease=false;TargetNetCoreVersion=$(TargetNetCoreVersion);TargetNetFxVersion=$(TargetNetFxVersion)
TestResults
+
+
+
+
@@ -101,6 +107,8 @@
+ $(CommonProperties)
+
- AbstractionsPackageVersion=$(AbstractionsPackageVersion)
+ $(AbstractionsProperties);AbstractionsPackageVersion=$(AbstractionsPackageVersion)
@@ -133,7 +141,7 @@
Properties="$(AbstractionsProperties)" />
-
+
-
+
+
+
+ $(CommonProperties)
+
+
+
+ $(AzureProperties);AzurePackageVersion=$(AzurePackageVersion)
+
+
+
+
+ $(AzureProperties);AzureAssemblyFileVersion=$(AzureAssemblyFileVersion)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
@@ -175,7 +239,7 @@
Name="RestoreNetFx"
DependsOnTargets="RestoreSqlServerLib;RestoreAbstractions"
Condition="'$(IsEnabledWindows)' == 'true'">
-
+
-
-
- dotnet build -c Release -p:ReferenceType=$(ReferenceType)
-
-
+
+
+
+
+
+
-
+
-
+
@@ -238,29 +303,29 @@
Name="BuildUnitTestsNetCore"
DependsOnTargets="RestoreTestsNetCore;BuildNetCore"
Condition="$(ReferenceType.Contains('Project'))">
-
+
-
+
-
+
-
+
-
+
diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationProviderManager.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationProviderManager.xml
new file mode 100644
index 0000000000..f79488fd08
--- /dev/null
+++ b/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationProviderManager.xml
@@ -0,0 +1,20 @@
+
+
+
+ Manages which authentication provider is used for each authentication method.
+
+
+ The authentication method.
+ Gets an authentication provider by method.
+ The authentication provider or if not found.
+
+
+ The authentication method.
+ The authentication provider.
+ Sets an authentication provider by method.
+
+ if the operation succeeded; otherwise, (for example, the existing provider disallows overriding).
+
+
+
+
diff --git a/eng/pipelines/common/templates/jobs/build-signed-package-job.yml b/eng/pipelines/common/templates/jobs/build-signed-package-job.yml
index b90fe026a8..a77ee79146 100644
--- a/eng/pipelines/common/templates/jobs/build-signed-package-job.yml
+++ b/eng/pipelines/common/templates/jobs/build-signed-package-job.yml
@@ -49,7 +49,7 @@ jobs:
configuration: $(Configuration)
msbuildArguments: -t:BuildTools
- # Perform analysis before building, since this step will clobber build output
+ # Perform analysis before building, since this step will clobber build output.
- template: ../steps/code-analyze-step.yml@self
# Update the root NuGet.config to use the packages/ directory as a source.
diff --git a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml
index 06bc31911b..ceab63eb61 100644
--- a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml
+++ b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml
@@ -10,6 +10,12 @@ parameters:
- name: abstractionsPackageVersion
type: string
+ - name: azureArtifactName
+ type: string
+
+ - name: azurePackageVersion
+ type: string
+
- name: configProperties
type: object
default: {} # - key: 'value'
@@ -121,6 +127,12 @@ jobs:
artifactName: ${{ parameters.mdsArtifactName }}
targetPath: $(Build.SourcesDirectory)/packages
+ - task: DownloadPipelineArtifact@2
+ displayName: Download Azure Package Artifact
+ inputs:
+ artifactName: ${{ parameters.azureArtifactName }}
+ targetPath: $(Build.SourcesDirectory)/packages
+
- ${{ if ne(parameters.prebuildSteps, '') }}:
- ${{ parameters.prebuildSteps }} # extra steps to run before the build like downloading sni and the required configuration
@@ -253,6 +265,7 @@ jobs:
referenceType: ${{ parameters.referenceType }}
testSet: ${{ parameters.testSet }}
abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }}
+ azurePackageVersion: ${{ parameters.azurePackageVersion }}
mdsPackageVersion: ${{ parameters.mdsPackageVersion }}
${{ if ne(parameters.operatingSystem, 'Windows') }}:
OSGroup: Unix
diff --git a/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml b/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml
index 42000da697..030199e72b 100644
--- a/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml
+++ b/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml
@@ -305,17 +305,6 @@ jobs:
Get-ChildItem *.dll -Path $(extractedNugetPath) -Recurse | ForEach-Object VersionInfo | Format-List
displayName: 'Verify "File Version" matches expected values for DLLs'
- - powershell: |
- # Change TestMicrosoftDataSqlClientVersion
-
- [Xml] $versionprops = Get-Content -Path "tools/props/Versions.props"
- $versionpropspath = "tools\props\Versions.props"
- $versionprops.Project.PropertyGroup[$versionprops.Project.PropertyGroup.Count-1].TestMicrosoftDataSqlClientVersion ="$(mdsPackageVersion)"
- Write-Host "Saving Test nuget version at $rootfolder\props ...." -ForegroundColor Green
- $versionprops.Save($versionpropspath)
-
- displayName: 'Modify TestMicrosoftDataSqlClientVersion'
-
- powershell: |
# Check assembly versions.
#
diff --git a/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml b/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml
index 46318f8e06..d9c7148c82 100644
--- a/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml
+++ b/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml
@@ -10,6 +10,12 @@ parameters:
- name: abstractionsPackageVersion
type: string
+ - name: azureArtifactName
+ type: string
+
+ - name: azurePackageVersion
+ type: string
+
- name: debug
type: boolean
default: false
@@ -68,7 +74,9 @@ stages:
jobDisplayName: ${{ format('{0}_{1}_{2}', replace(targetFramework, '.', '_'), platform, testSet) }}
configProperties: ${{ config.value.configProperties }}
abstractionsArtifactName: ${{ parameters.abstractionsArtifactName }}
- abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}}
+ abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }}
+ azureArtifactName: ${{ parameters.azureArtifactName }}
+ azurePackageVersion: ${{ parameters.azurePackageVersion }}
mdsArtifactName: ${{ parameters.mdsArtifactName }}
mdsPackageVersion: ${{ parameters.mdsPackageVersion }}
prebuildSteps: ${{ parameters.prebuildSteps }}
@@ -102,7 +110,9 @@ stages:
configProperties: ${{ config.value.configProperties }}
useManagedSNI: ${{ useManagedSNI }}
abstractionsArtifactName: ${{ parameters.abstractionsArtifactName }}
- abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}}
+ abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }}
+ azureArtifactName: ${{ parameters.azureArtifactName }}
+ azurePackageVersion: ${{ parameters.azurePackageVersion }}
mdsArtifactName: ${{ parameters.mdsArtifactName }}
mdsPackageVersion: ${{ parameters.mdsPackageVersion }}
prebuildSteps: ${{ parameters.prebuildSteps }}
diff --git a/eng/pipelines/common/templates/steps/build-all-tests-step.yml b/eng/pipelines/common/templates/steps/build-all-tests-step.yml
index 43ecb6aafa..36aa703f28 100644
--- a/eng/pipelines/common/templates/steps/build-all-tests-step.yml
+++ b/eng/pipelines/common/templates/steps/build-all-tests-step.yml
@@ -7,6 +7,9 @@ parameters:
- name: abstractionsPackageVersion
type: string
+ - name: azurePackageVersion
+ type: string
+
- name: configuration
type: string
default: '$(Configuration)'
@@ -42,7 +45,7 @@ steps:
solution: build.proj
platform: '${{parameters.platform }}'
configuration: '${{parameters.configuration }}'
- msbuildArguments: '-t:BuildTestsNetFx -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}'
+ msbuildArguments: '-t:BuildTestsNetFx -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }} -p:AzurePackageVersion=${{ parameters.azurePackageVersion }}'
- ${{elseif eq(parameters.osGroup, '')}}: # .NET on Windows
- task: MSBuild@1
@@ -51,7 +54,7 @@ steps:
solution: build.proj
platform: '${{parameters.platform }}'
configuration: '${{parameters.configuration }}'
- msbuildArguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}'
+ msbuildArguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }} -p:AzurePackageVersion=${{ parameters.azurePackageVersion }}'
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
- ${{ else }}: # .NET on Unix
@@ -61,7 +64,7 @@ steps:
command: custom
projects: build.proj
custom: msbuild
- arguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:OSGroup=${{parameters.osGroup }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}'
+ arguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion }} -p:OSGroup=${{parameters.osGroup }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }} -p:AzurePackageVersion=${{ parameters.azurePackageVersion }}'
verbosityRestore: Detailed
verbosityPack: Detailed
condition: and(succeeded(), ne(variables['Agent.OS'], 'Windows_NT'))
diff --git a/eng/pipelines/common/templates/steps/build-and-run-tests-netcore-step.yml b/eng/pipelines/common/templates/steps/build-and-run-tests-netcore-step.yml
index 43eea4449d..c23e7d310a 100644
--- a/eng/pipelines/common/templates/steps/build-and-run-tests-netcore-step.yml
+++ b/eng/pipelines/common/templates/steps/build-and-run-tests-netcore-step.yml
@@ -55,14 +55,14 @@ steps:
inputs:
solution: build.proj
msbuildArchitecture: x64
- msbuildArguments: '-p:Configuration=${{parameters.configuration }} -t:BuildAKVNetCore -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }}'
+ msbuildArguments: '-p:Configuration=${{parameters.configuration }} -t:BuildAKVNetCore -p:ReferenceType=${{parameters.referenceType }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion }}'
- task: MSBuild@1
displayName: 'MSBuild Build Tests for ${{parameters.TargetNetCoreVersion }}'
inputs:
solution: build.proj
msbuildArchitecture: x64
- msbuildArguments: '-t:BuildTestsNetCore -p:ReferenceType=${{parameters.referenceType }} -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:Configuration=${{parameters.configuration }}'
+ msbuildArguments: '-t:BuildTestsNetCore -p:ReferenceType=${{parameters.referenceType }} -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion }} -p:Configuration=${{parameters.configuration }}'
# Don't run unit tests using package reference. Unit tests are only run using project reference.
@@ -71,12 +71,12 @@ steps:
inputs:
command: test
projects: 'src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.FunctionalTests.csproj'
- arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests"'
+ arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion }} --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests"'
- task: DotNetCoreCLI@2
displayName: 'Run Manual Tests for ${{parameters.TargetNetCoreVersion }}'
inputs:
command: test
projects: 'src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj'
- arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} --no-build -v n --filter category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests --collect "Code Coverage"'
+ arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion }} --no-build -v n --filter category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests --collect "Code Coverage"'
retryCountOnTaskFailure: ${{parameters.retryCountOnManualTests }}
diff --git a/eng/pipelines/common/templates/steps/build-and-run-tests-netfx-step.yml b/eng/pipelines/common/templates/steps/build-and-run-tests-netfx-step.yml
index e7b35f653e..8d2a57872b 100644
--- a/eng/pipelines/common/templates/steps/build-and-run-tests-netfx-step.yml
+++ b/eng/pipelines/common/templates/steps/build-and-run-tests-netfx-step.yml
@@ -55,13 +55,13 @@ steps:
inputs:
solution: build.proj
msbuildArchitecture: x64
- msbuildArguments: '-p:Configuration=${{parameters.configuration }} -t:BuildAKVNetFx -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }}'
+ msbuildArguments: '-p:Configuration=${{parameters.configuration }} -t:BuildAKVNetFx -p:ReferenceType=${{parameters.referenceType }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion }}'
- task: MSBuild@1
displayName: 'MSBuild Build Tests for ${{parameters.TargetNetFxVersion }}'
inputs:
solution: build.proj
- msbuildArguments: ' -t:BuildTestsNetFx -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:Configuration=${{parameters.configuration }} -p:Platform=${{parameters.platform }}'
+ msbuildArguments: ' -t:BuildTestsNetFx -p:ReferenceType=${{parameters.referenceType }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion }} -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:Configuration=${{parameters.configuration }} -p:Platform=${{parameters.platform }}'
# Don't run unit tests using package reference. Unit tests are only run using project reference.
@@ -70,12 +70,12 @@ steps:
inputs:
command: test
projects: 'src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.FunctionalTests.csproj'
- arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" --collect "Code Coverage"'
+ arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion }} --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" --collect "Code Coverage"'
- task: DotNetCoreCLI@2
displayName: 'Run Manual Tests for ${{parameters.TargetNetFxVersion }}'
inputs:
command: test
projects: 'src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj'
- arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" --collect "Code Coverage"'
+ arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion }} --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" --collect "Code Coverage"'
retryCountOnTaskFailure: ${{parameters.retryCountOnManualTests }}
diff --git a/eng/pipelines/common/templates/steps/run-all-tests-step.yml b/eng/pipelines/common/templates/steps/run-all-tests-step.yml
index 27da9e4e73..9b3289e300 100644
--- a/eng/pipelines/common/templates/steps/run-all-tests-step.yml
+++ b/eng/pipelines/common/templates/steps/run-all-tests-step.yml
@@ -62,9 +62,9 @@ steps:
platform: '${{parameters.platform }}'
configuration: '${{parameters.configuration }}'
${{ if eq(parameters.msbuildArchitecture, 'x64') }}:
- msbuildArguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }}'
+ msbuildArguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion }}'
${{ else }}: # x86
- msbuildArguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}'
+ msbuildArguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}'
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
retryCountOnTaskFailure: 1
@@ -76,9 +76,9 @@ steps:
platform: '${{parameters.platform }}'
configuration: '${{parameters.configuration }}'
${{ if eq(parameters.msbuildArchitecture, 'x64') }}:
- msbuildArguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }}'
+ msbuildArguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion }}'
${{ else }}: # x86
- msbuildArguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}'
+ msbuildArguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}'
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
retryCountOnTaskFailure: 1
@@ -90,9 +90,9 @@ steps:
platform: '${{parameters.platform }}'
configuration: '${{parameters.configuration }}'
${{ if eq(parameters.msbuildArchitecture, 'x64') }}:
- msbuildArguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }}'
+ msbuildArguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion }}'
${{ else }}: # x86
- msbuildArguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}'
+ msbuildArguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}'
condition: eq(variables['Agent.OS'], 'Windows_NT')
retryCountOnTaskFailure: 2
@@ -104,7 +104,7 @@ steps:
command: custom
projects: build.proj
custom: msbuild
- arguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}'
+ arguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}'
verbosityRestore: Detailed
verbosityPack: Detailed
retryCountOnTaskFailure: 1
@@ -116,7 +116,7 @@ steps:
command: custom
projects: build.proj
custom: msbuild
- arguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}'
+ arguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}'
verbosityRestore: Detailed
verbosityPack: Detailed
retryCountOnTaskFailure: 1
@@ -128,7 +128,7 @@ steps:
command: custom
projects: build.proj
custom: msbuild
- arguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}'
+ arguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:MdsPackageVersion=${{parameters.mdsPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}'
verbosityRestore: Detailed
verbosityPack: Detailed
retryCountOnTaskFailure: 2
diff --git a/eng/pipelines/dotnet-sqlclient-ci-core.yml b/eng/pipelines/dotnet-sqlclient-ci-core.yml
index 86987f63e2..9c13159a14 100644
--- a/eng/pipelines/dotnet-sqlclient-ci-core.yml
+++ b/eng/pipelines/dotnet-sqlclient-ci-core.yml
@@ -94,6 +94,9 @@ variables:
- name: abstractionsArtifactName
value: Abstractions.Artifact
+
+ - name: azureArtifactName
+ value: Azure.Artifact
- name: mdsArtifactName
value: MDS.Artifact
@@ -107,7 +110,7 @@ stages:
# under the given artifact name.
- template: stages/build-abstractions-package-ci-stage.yml@self
parameters:
- buildConfiguration: Release
+ buildConfiguration: ${{ parameters.buildConfiguration }}
abstractionsPackageVersion: $(abstractionsPackageVersion)
artifactName: $(abstractionsArtifactName)
${{if eq(parameters.debug, 'true')}}:
@@ -141,6 +144,24 @@ stages:
SNIVersion: ${{parameters.SNIVersion}}
SNIValidationFeed: ${{parameters.SNIValidationFeed}}
+ # Build the Azure package, and publish it to the pipeline artifacts under the
+ # given artifact name.
+ - template: stages/build-azure-package-ci-stage.yml@self
+ parameters:
+ abstractionsArtifactName: $(abstractionsArtifactName)
+ abstractionsPackageVersion: $(abstractionsPackageVersion)
+ azureArtifactName: $(azureArtifactName)
+ azurePackageVersion: $(azurePackageVersion)
+ buildConfiguration: ${{ parameters.buildConfiguration }}
+ # When building via package references, we must depend on the Abstractions
+ # package.
+ ${{ if eq(parameters.referenceType, 'Package') }}:
+ dependsOn:
+ - build_abstractions_package_stage
+ referenceType: ${{ parameters.referenceType }}
+ ${{if eq(parameters.debug, 'true')}}:
+ verbosity: diagnostic
+
# Run the stress tests, if desired.
- ${{ if eq(parameters.enableStressTests, true) }}:
- template: stages/stress-tests-ci-stage.yml@self
@@ -160,14 +181,17 @@ stages:
testsTimeout: ${{ parameters.testsTimeout }}
abstractionsArtifactName: $(abstractionsArtifactName)
abstractionsPackageVersion: $(abstractionsPackageVersion)
+ azureArtifactName: $(azureArtifactName)
+ azurePackageVersion: $(azurePackageVersion)
mdsArtifactName: $(mdsArtifactName)
mdsPackageVersion: $(mdsPackageVersion)
- # When testing MDS via packages, we must depend on the Abstractions and
- # MDS packages.
+ # When testing MDS via packages, we must depend on the Abstractions,
+ # Azure, and MDS packages.
${{ if eq(parameters.referenceType, 'Package') }}:
dependsOn:
- build_abstractions_package_stage
+ - build_azure_package_stage
- build_mds_akv_packages_stage
prebuildSteps: # steps to run prior to building and running tests on each job
diff --git a/eng/pipelines/jobs/build-akv-official-job.yml b/eng/pipelines/jobs/build-akv-official-job.yml
index bad8758f6e..55ebff9f79 100644
--- a/eng/pipelines/jobs/build-akv-official-job.yml
+++ b/eng/pipelines/jobs/build-akv-official-job.yml
@@ -87,7 +87,7 @@ jobs:
displayName: 'Output Job Parameters'
# Perform analysis before building, since this step will clobber build
- # output
+ # output.
- template: ../steps/roslyn-analyzers-akv-step.yml@self
parameters:
akvPackageVersion: '${{ parameters.akvPackageVersion }}'
diff --git a/eng/pipelines/jobs/pack-azure-package-ci-job.yml b/eng/pipelines/jobs/pack-azure-package-ci-job.yml
new file mode 100644
index 0000000000..9cc33eadb1
--- /dev/null
+++ b/eng/pipelines/jobs/pack-azure-package-ci-job.yml
@@ -0,0 +1,188 @@
+################################################################################
+# Licensed to the .NET Foundation under one or more agreements. The .NET
+# Foundation licenses this file to you under the MIT license. See the LICENSE
+# file in the project root for more information.
+################################################################################
+
+# This job packs the Azure package into NuGet and symbols packages and publishes
+# them as a named pipeline artifact.
+#
+# This template defines a job named 'pack_azure_package_job' that can be
+# depended on by downstream jobs.
+
+parameters:
+
+ # The name of the Abstractions pipeline artifact to download.
+ #
+ # This is used when the referenceType is 'Package'.
+ - name: abstractionsArtifactName
+ type: string
+ default: Abstractions.Artifact
+
+ # The Abstractions package verion to depend on.
+ #
+ # This is used when the referenceType is 'Package'.
+ - name: abstractionsPackageVersion
+ type: string
+
+ # The name of the pipeline artifact to publish.
+ - name: azureArtifactName
+ type: string
+ default: Azure.Artifact
+
+ # The version to apply to the NuGet package and DLLs.
+ - name: azurePackageVersion
+ type: string
+
+ # The type of build to test (Release or Debug)
+ - name: buildConfiguration
+ type: string
+ values:
+ - Release
+ - Debug
+
+ # The list of upstream jobs to depend on.
+ - name: dependsOn
+ type: object
+ default: []
+
+ # The reference type to use:
+ #
+ # Project - dependent projects are referenced directly.
+ # Package - dependent projects are referenced via NuGet packages.
+ #
+ - name: referenceType
+ type: string
+ values:
+ - Package
+ - Project
+
+ # The verbosity level for the dotnet CLI commands.
+ - name: verbosity
+ type: string
+ default: normal
+ values:
+ - quiet
+ - minimal
+ - normal
+ - detailed
+ - diagnostic
+
+jobs:
+
+ - job: pack_azure_package_job
+ displayName: 'Pack Azure Package'
+
+ dependsOn: ${{ parameters.dependsOn }}
+
+ pool:
+ name: Azure Pipelines
+ vmImage: ubuntu-latest
+
+ variables:
+
+ # The Azure project file to use for all dotnet CLI commands.
+ - name: project
+ value: src/Microsoft.Data.SqlClient.Extensions/Azure/src/Azure.csproj
+
+ # The directory where the NuGet packages will be staged before being
+ # published as pipeline artifacts.
+ - name: dotnetPackagesDir
+ value: $(Build.StagingDirectory)/dotnetPackages
+
+ # dotnet CLI arguments common to all commands.
+ - name: commonArguments
+ value: >-
+ --verbosity ${{ parameters.verbosity }}
+ -p:ReferenceType=${{ parameters.referenceType }}
+ -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}
+
+ # dotnet CLI arguments for build/test/pack commands
+ - name: buildArguments
+ value: >-
+ $(commonArguments)
+ --configuration ${{ parameters.buildConfiguration }}
+ -p:AzurePackageVersion=${{ parameters.azurePackageVersion }}
+
+ # Explicitly unset the $PLATFORM environment variable that is set by the
+ # 'ADO Build properties' Library in the ADO SqlClientDrivers public
+ # project. This is defined with a non-standard Platform of 'AnyCPU', and
+ # will fail the builds if left defined. The stress tests solution does
+ # not require any specific Platform, and so its solution file doesn't
+ # support any non-standard platforms.
+ #
+ # Note that Azure Pipelines will inject this variable as PLATFORM into the
+ # environment of all tasks in this job.
+ #
+ # See:
+ # https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch
+ #
+ - name: Platform
+ value: ''
+
+ # Do the same for $CONFIGURATION since we explicitly set it using our
+ # 'buildConfiguration' parameter, and we don't want the environment to
+ # override us.
+ - name: Configuration
+ value: ''
+
+ steps:
+
+ # We have a few extra steps for Package reference builds.
+ - ${{ if eq(parameters.referenceType, 'Package') }}:
+
+ # Download the Abstractions package artifacts into packages/.
+ - task: DownloadPipelineArtifact@2
+ displayName: Download Abstractions Package Artifact
+ inputs:
+ artifactName: ${{ parameters.abstractionsArtifactName }}
+ targetPath: $(Build.SourcesDirectory)/packages
+
+ # Use the local NuGet.config that references the packages/ directory.
+ - pwsh: cp $(Build.SourcesDirectory)/NuGet.config.local $(Build.SourcesDirectory)/NuGet.config
+ displayName: Use local NuGet.config
+
+ # Install the .NET 9.0 SDK.
+ - task: UseDotNet@2
+ displayName: Install .NET 9.0 SDK
+ inputs:
+ packageType: sdk
+ version: 9.x
+
+ # We use the 'custom' command because the DotNetCoreCLI@2 task doesn't
+ # support all of our argument combinations for the different build steps.
+
+ # Restore the solution.
+ - task: DotNetCoreCLI@2
+ displayName: Restore Solution
+ inputs:
+ command: custom
+ custom: restore
+ projects: $(project)
+ arguments: $(commonArguments)
+
+ # Build the solution.
+ - task: DotNetCoreCLI@2
+ displayName: Build Solution
+ inputs:
+ command: custom
+ custom: build
+ projects: $(project)
+ arguments: $(buildArguments) --no-restore
+
+ # Create the NuGet packages.
+ - task: DotNetCoreCLI@2
+ displayName: Create NuGet Package
+ inputs:
+ command: custom
+ custom: pack
+ projects: $(project)
+ arguments: $(buildArguments) --no-build -o $(dotnetPackagesDir)
+
+ # Publish the NuGet packages as a named pipeline artifact.
+ - task: PublishPipelineArtifact@1
+ displayName: Publish Pipeline Artifact
+ inputs:
+ targetPath: $(dotnetPackagesDir)
+ artifactName: ${{ parameters.azureArtifactName }}
+ publishLocation: pipeline
diff --git a/eng/pipelines/jobs/test-azure-package-ci-job.yml b/eng/pipelines/jobs/test-azure-package-ci-job.yml
new file mode 100644
index 0000000000..8e1b8fc6db
--- /dev/null
+++ b/eng/pipelines/jobs/test-azure-package-ci-job.yml
@@ -0,0 +1,214 @@
+################################################################################
+# Licensed to the .NET Foundation under one or more agreements. The .NET
+# Foundation licenses this file to you under the MIT license. See the LICENSE
+# file in the project root for more information.
+################################################################################
+
+# This job builds the Azure package and runs its tests for a set of .NET
+# runtimes.
+#
+# This template defines a job named 'test_azure_package_job_' that can
+# be depended on by downstream jobs.
+
+parameters:
+
+ # The name of the Abstractions pipeline artifact to download.
+ #
+ # This is used when the referenceType is 'Package'.
+ - name: abstractionsArtifactName
+ type: string
+ default: Abstractions.Artifact
+
+ # The Abstractions package verion to depend on.
+ #
+ # This is used when the referenceType is 'Package'.
+ - name: abstractionsPackageVersion
+ type: string
+
+ # The type of build to test (Release or Debug)
+ - name: buildConfiguration
+ type: string
+ values:
+ - Release
+ - Debug
+
+ # The prefix to prepend to the job's display name:
+ #
+ # [] Run Stress Tests
+ #
+ - name: displayNamePrefix
+ type: string
+
+ # The suffix to append to the job name.
+ - name: jobNameSuffix
+ type: string
+
+ # The list of .NET Framework runtimes to test against.
+ - name: netFrameworkRuntimes
+ type: object
+ default: []
+
+ # The list of .NET runtimes to test against.
+ - name: netRuntimes
+ type: object
+ default: []
+
+ # The name of the Azure Pipelines pool to use.
+ - name: poolName
+ type: string
+
+ # The reference type to use:
+ #
+ # Project - dependent projects are referenced directly.
+ # Package - dependent projects are referenced via NuGet packages.
+ #
+ - name: referenceType
+ type: string
+ values:
+ - Package
+ - Project
+
+ # The verbosity level for the dotnet CLI commands.
+ - name: verbosity
+ type: string
+ default: normal
+ values:
+ - quiet
+ - minimal
+ - normal
+ - detailed
+ - diagnostic
+
+ # The pool VM image to use.
+ - name: vmImage
+ type: string
+
+jobs:
+
+ - job: test_azure_package_job_${{ parameters.jobNameSuffix }}
+ displayName: '[${{ parameters.displayNamePrefix }}] Test Azure Package'
+ pool:
+ name: ${{ parameters.poolName }}
+
+ # Images provided by Azure Pipelines must be selected using 'vmImage'.
+ ${{ if eq(parameters.poolName, 'Azure Pipelines') }}:
+ vmImage: ${{ parameters.vmImage }}
+ # Images provided by 1ES must be selected using a demand.
+ ${{ else }}:
+ demands:
+ - imageOverride -equals ${{ parameters.vmImage }}
+
+ variables:
+
+ # The Azure test project file to use for all dotnet CLI commands.
+ - name: project
+ value: src/Microsoft.Data.SqlClient.Extensions/Azure/test/Azure.Test.csproj
+
+ # dotnet CLI arguments common to all commands.
+ - name: commonArguments
+ value: >-
+ --verbosity ${{ parameters.verbosity }}
+ -p:ReferenceType=${{ parameters.referenceType }}
+ -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}
+
+ # dotnet CLI arguments for build/test/pack commands
+ - name: buildArguments
+ value: >-
+ $(commonArguments)
+ --configuration ${{ parameters.buildConfiguration }}
+
+ # Explicitly unset the $PLATFORM environment variable that is set by the
+ # 'ADO Build properties' Library in the ADO SqlClientDrivers public
+ # project. This is defined with a non-standard Platform of 'AnyCPU', and
+ # will fail the builds if left defined. The stress tests solution does
+ # not require any specific Platform, and so its solution file doesn't
+ # support any non-standard platforms.
+ #
+ # Note that Azure Pipelines will inject this variable as PLATFORM into the
+ # environment of all tasks in this job.
+ #
+ # See:
+ # https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch
+ #
+ - name: Platform
+ value: ''
+
+ # Do the same for $CONFIGURATION since we explicitly set it using our
+ # 'buildConfiguration' parameter, and we don't want the environment to
+ # override us.
+ - name: Configuration
+ value: ''
+
+ steps:
+
+ # We have a few extra steps for Package reference builds.
+ - ${{ if eq(parameters.referenceType, 'Package') }}:
+
+ # Download the Abstractions package artifacts into packages/.
+ - task: DownloadPipelineArtifact@2
+ displayName: Download Abstractions Package Artifact
+ inputs:
+ artifactName: ${{ parameters.abstractionsArtifactName }}
+ targetPath: $(Build.SourcesDirectory)/packages
+
+ # Use the local NuGet.config that references the packages/ directory.
+ - pwsh: cp $(Build.SourcesDirectory)/NuGet.config.local $(Build.SourcesDirectory)/NuGet.config
+ displayName: Use local NuGet.config
+
+ # Install the .NET 9.0 SDK.
+ - task: UseDotNet@2
+ displayName: Install .NET 9.0 SDK
+ inputs:
+ packageType: sdk
+ version: 9.x
+
+ # Install the .NET 8.0 runtime.
+ - task: UseDotNet@2
+ displayName: Install .NET 8.0 Runtime
+ inputs:
+ packageType: runtime
+ version: 8.x
+
+ # The Windows agent images include a suitable .NET Framework runtime, so
+ # we don't have to install one explicitly.
+
+ # We use the 'custom' command because the DotNetCoreCLI@2 task doesn't
+ # support all of our argument combinations for the different build steps.
+
+ # Restore the solution.
+ - task: DotNetCoreCLI@2
+ displayName: Restore Solution
+ inputs:
+ command: custom
+ custom: restore
+ projects: $(project)
+ arguments: $(commonArguments)
+
+ # Build the solution.
+ - task: DotNetCoreCLI@2
+ displayName: Build Solution
+ inputs:
+ command: custom
+ custom: build
+ projects: $(project)
+ arguments: $(buildArguments) --no-restore
+
+ # Run the tests for each .NET runtime.
+ - ${{ each runtime in parameters.netRuntimes }}:
+ - task: DotNetCoreCLI@2
+ displayName: Test [${{ runtime }}]
+ inputs:
+ command: custom
+ custom: test
+ projects: $(project)
+ arguments: $(buildArguments) --no-build -f ${{ runtime }}
+
+ # Run the tests for each .NET Framework runtime.
+ - ${{ each runtime in parameters.netFrameworkRuntimes }}:
+ - task: DotNetCoreCLI@2
+ displayName: Test [${{ runtime }}]
+ inputs:
+ command: custom
+ custom: test
+ projects: $(project)
+ arguments: $(buildArguments) --no-build -f ${{ runtime }}
diff --git a/eng/pipelines/libraries/ci-build-variables.yml b/eng/pipelines/libraries/ci-build-variables.yml
index 6b6ac2a825..79ec983027 100644
--- a/eng/pipelines/libraries/ci-build-variables.yml
+++ b/eng/pipelines/libraries/ci-build-variables.yml
@@ -18,6 +18,8 @@ variables:
value: 1.0.0.$(buildNumber)-ci
- name: akvPackageVersion
value: 7.0.0.$(buildNumber)-ci
+ - name: azurePackageVersion
+ value: 1.0.0.$(buildNumber)-ci
- name: mdsPackageVersion
value: 7.0.0.$(buildNumber)-ci
- name: skipComponentGovernanceDetection
diff --git a/eng/pipelines/stages/build-azure-package-ci-stage.yml b/eng/pipelines/stages/build-azure-package-ci-stage.yml
new file mode 100644
index 0000000000..c88a2f5db5
--- /dev/null
+++ b/eng/pipelines/stages/build-azure-package-ci-stage.yml
@@ -0,0 +1,162 @@
+################################################################################
+# Licensed to the .NET Foundation under one or more agreements. The .NET
+# Foundation licenses this file to you under the MIT license. See the LICENSE
+# file in the project root for more information.
+################################################################################
+
+# This stage builds the Azure package, runs tests, and publishes the resulting
+# NuGet packages as pipeline artifacts.
+#
+# The NuGet packages have the following properties:
+#
+# Name: Microsoft.Data.SqlClient.Extensions.Azure
+# Version: azurePackageVersion (from parameters)
+#
+# The following NuGet packages are published:
+#
+# Microsoft.Data.SqlClient.Extensions.Azure..nupkg
+# Microsoft.Data.SqlClient.Extensions.Azure..snupkg (symbols)
+#
+# The packages are published to pipeline artifacts with the name specified by
+# the azureArtifactName parameter.
+#
+# This template defines a stage named 'build_azure_package_stage' that
+# can be depended on by downstream stages.
+
+parameters:
+
+ # The name of the Abstractions pipeline artifact to download.
+ #
+ # This is used when the referenceType is 'Package'.
+ - name: abstractionsArtifactName
+ type: string
+ default: Abstractions.Artifact
+
+ # The Abstractions package verion to depend on.
+ #
+ # This is used when the referenceType is 'Package'.
+ - name: abstractionsPackageVersion
+ type: string
+
+ # The name of the pipeline artifact to publish.
+ - name: azureArtifactName
+ type: string
+ default: Azure.Artifact
+
+ # The version to apply to the NuGet package and DLLs.
+ - name: azurePackageVersion
+ type: string
+
+ # The type of build to produce (Release or Debug)
+ - name: buildConfiguration
+ type: string
+ default: Release
+ values:
+ - Release
+ - Debug
+
+ # The stages we depend on, if any.
+ - name: dependsOn
+ type: object
+ default: []
+
+ # The reference type to use:
+ #
+ # Project - dependent projects are referenced directly.
+ # Package - dependent projects are referenced via NuGet packages.
+ #
+ - name: referenceType
+ type: string
+ values:
+ - Package
+ - Project
+
+ # The dotnet CLI verbosity to use.
+ - name: verbosity
+ type: string
+ default: normal
+ values:
+ - quiet
+ - minimal
+ - normal
+ - detailed
+ - diagnostic
+
+stages:
+
+ - stage: build_azure_package_stage
+ displayName: Build Azure Package
+
+ dependsOn: ${{ parameters.dependsOn }}
+
+ jobs:
+
+ # ------------------------------------------------------------------------
+ # Build and test on Linux.
+
+ - template: ../jobs/test-azure-package-ci-job.yml@self
+ parameters:
+ abstractionsArtifactName: ${{ parameters.abstractionsArtifactName }}
+ abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }}
+ buildConfiguration: ${{ parameters.buildConfiguration }}
+ displayNamePrefix: Linux
+ jobNameSuffix: linux
+ netFrameworkRuntimes: []
+ netRuntimes: [net8.0, net9.0]
+ poolName: Azure Pipelines
+ referenceType: ${{ parameters.referenceType }}
+ verbosity: ${{ parameters.verbosity }}
+ vmImage: ubuntu-latest
+
+ # ------------------------------------------------------------------------
+ # Build and test on Windows
+
+ - template: ../jobs/test-azure-package-ci-job.yml@self
+ parameters:
+ abstractionsArtifactName: ${{ parameters.abstractionsArtifactName }}
+ abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }}
+ buildConfiguration: ${{ parameters.buildConfiguration }}
+ displayNamePrefix: Win
+ jobNameSuffix: windows
+ netFrameworkRuntimes: [net462, net47, net471, net472, net48, net481]
+ netRuntimes: [net8.0, net9.0]
+ poolName: Azure Pipelines
+ referenceType: ${{ parameters.referenceType }}
+ verbosity: ${{ parameters.verbosity }}
+ vmImage: windows-latest
+
+ # ------------------------------------------------------------------------
+ # Build and test on macOS.
+
+ - template: ../jobs/test-azure-package-ci-job.yml
+ parameters:
+ abstractionsArtifactName: ${{ parameters.abstractionsArtifactName }}
+ abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }}
+ buildConfiguration: ${{ parameters.buildConfiguration }}
+ displayNamePrefix: macOS
+ jobNameSuffix: macos
+ netFrameworkRuntimes: []
+ netRuntimes: [net8.0, net9.0]
+ poolName: Azure Pipelines
+ referenceType: ${{ parameters.referenceType }}
+ verbosity: ${{ parameters.verbosity }}
+ vmImage: macos-latest
+
+ # ------------------------------------------------------------------------
+ # Create and publish the NuGet package.
+
+ - template: ../jobs/pack-azure-package-ci-job.yml@self
+ parameters:
+ abstractionsArtifactName: ${{ parameters.abstractionsArtifactName }}
+ abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }}
+ azureArtifactName: ${{ parameters.azureArtifactName }}
+ azurePackageVersion: ${{ parameters.abstractionsPackageVersion }}
+ buildConfiguration: ${{ parameters.buildConfiguration }}
+ dependsOn:
+ # We depend on all of the test jobs to ensure the tests pass before
+ # producing the NuGet package.
+ - test_azure_package_job_linux
+ - test_azure_package_job_windows
+ - test_azure_package_job_macos
+ referenceType: ${{ parameters.referenceType }}
+ verbosity: ${{ parameters.verbosity }}
diff --git a/eng/pipelines/steps/compound-build-akv-step.yml b/eng/pipelines/steps/compound-build-akv-step.yml
index 75e6e00e3d..393c51362f 100644
--- a/eng/pipelines/steps/compound-build-akv-step.yml
+++ b/eng/pipelines/steps/compound-build-akv-step.yml
@@ -18,7 +18,7 @@ parameters:
- name: buildConfiguration
type: string
-
+
- name: mdsPackageVersion
type: string
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 86f3529cbb..705daf092a 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -12,12 +12,10 @@
Project
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index c01b28e57e..03ea8a9942 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -5,22 +5,33 @@
-
-
-
+
+
+
+
+
+
+
+
-
+
-
+
@@ -30,7 +41,7 @@
-
+
@@ -52,7 +63,7 @@
-
+
@@ -67,12 +78,16 @@
+
+
+
+
+
-
@@ -109,16 +124,22 @@
-
+
-
+
+
+
+
+
+
+
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/Sample.xml b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/Sample.xml
deleted file mode 100644
index 8d5f5c44d5..0000000000
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/Sample.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
- Sample class to demonstrate packaging and pipelines.
-
-
-
- Construct with a name.
- The name.
-
-
- Gets the name.
- The name.
-
-
-
diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationMethod.xml b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationMethod.xml
similarity index 100%
rename from doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationMethod.xml
rename to src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationMethod.xml
diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationParameters.xml b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationParameters.xml
similarity index 67%
rename from doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationParameters.xml
rename to src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationParameters.xml
index 7c409cdc5c..759919e48f 100644
--- a/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationParameters.xml
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationParameters.xml
@@ -6,23 +6,31 @@
- One of the enumeration values that specifies the authentication method.
+
+ Construct with values for all properties.
+
+ The authentication method.
The server name.
The database name.
The resource URI.
The authority URI.
- The user login name/ID.
- The user password.
+ The user login name/ID, or null if not applicable.
+ The user password, or null if not applicable.
The connection ID.
- The connection timeout value in seconds.
-
- Initializes a new instance of the class using the specified authentication method, server name, database name, resource URI, authority URI, user login name/ID, user password, connection ID and connection timeout value.
-
+ The connection timeout, in seconds.
Gets the authentication method.
The authentication method.
+
+ Gets the server name.
+ The server name.
+
+
+ Gets the database name.
+ The database name.
+
The resource URIs.
The resource URI.
@@ -33,27 +41,19 @@
Gets the user login name/ID.
- The user login name/ID.
+ The user login name/ID, or null if not applicable.
Gets the user password.
- The user password.
+ The user password, or null if not applicable.
Gets the connection ID.
The connection ID.
-
- Gets the server name.
- The server name.
-
-
- Gets the database name.
- The database name.
-
Gets the connection timeout value.
- The connection timeout value to be passed to Cancellation Token Source.
+ The connection timeout, in seconds.
diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationProvider.xml b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationProvider.xml
similarity index 88%
rename from doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationProvider.xml
rename to src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationProvider.xml
index 75cc752d76..66c7f1a5bc 100644
--- a/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationProvider.xml
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationProvider.xml
@@ -89,48 +89,36 @@
-
-
- Called from constructors in derived classes to initialize the class.
-
-
-
- The authentication method.
- Gets an authentication provider by method.
- The authentication provider or if not found.
-
-
- The authentication method.
- The authentication provider.
- Sets an authentication provider by method.
-
- if the operation succeeded; otherwise, (for example, the existing provider disallows overriding).
-
-
- The authentication method.
This method is called immediately before the provider is added to the SQL authentication provider registry.
Avoid performing long-waiting tasks in this method, since it can block other threads from accessing the provider registry.
+
+ This method must not throw.
+ The authentication method.
- The authentication method.
This method is called immediately before the provider is removed from the SQL authentication provider registry.
For example, this method is called when a different provider with the same authentication method overrides this provider in the SQL authentication provider registry. Avoid performing long-waiting task in this method, since it can block other threads from accessing the provider registry.
+
+ This method must not throw.
+ The authentication method.
- The authentication method.
Indicates whether the specified authentication method is supported.
+ This method must not throw.
if the specified authentication method is supported; otherwise, .
+ The authentication method.
- The Active Directory authentication parameters passed by the driver to authentication providers.
Acquires a security token from the authority.
+ The Active Directory authentication parameters passed by the driver to authentication providers.
+ If any errors occur.
Represents an asynchronous operation that returns the AD authentication token.
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationProviderException.xml b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationProviderException.xml
new file mode 100644
index 0000000000..dbdf2966f9
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationProviderException.xml
@@ -0,0 +1,77 @@
+
+
+
+
+ This exception is thrown for any errors that occur during the
+ authentication process.
+
+
+
+
+ Protected construction for derived classes to supply a minimal set of
+ values.
+
+ Method will be NotSpecified.
+ FailureCode will be "Unknown".
+ ShouldRetry will be false.
+ RetryPeriod will be 0.
+
+ The error message.
+ The exception that caused this exception, if any.
+
+
+
+ Protected construction for derived classes to supply values for all
+ public properties.
+
+
+ The authentication method that failed, or NotSpecified if not known.
+
+
+ The failure code, or "Unknown" if not known.
+
+
+ True if the action should be retried, false otherwise.
+
+
+ The period of time, in milliseconds, to wait before retrying the action.
+ Specify 0 if no retry period is suggested. Ignored if negative. Not
+ used when ShouldRetry is false, in which cases 0 is assumed.
+
+
+ The error message.
+
+
+ The exception that caused this exception, if any.
+
+
+
+
+ The authentication method that failed, or NotSpecified if not known.
+
+
+
+
+ The failure code, or "Unknown" if not known.
+
+
+
+
+ True if the action should be retried, false otherwise.
+
+
+
+
+ The period of time, in milliseconds, to wait before retrying the action.
+ 0 if no retry period is suggested. Never negative. Always 0 when
+ ShouldRetry is false.
+
+
+
+
+ A string that includes the base exception information along with all
+ property values.
+
+
+
+
diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationToken.xml b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationToken.xml
similarity index 63%
rename from doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationToken.xml
rename to src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationToken.xml
index 52f79dd535..11ce14db28 100644
--- a/doc/snippets/Microsoft.Data.SqlClient/SqlAuthenticationToken.xml
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationToken.xml
@@ -4,22 +4,22 @@
Represents an authentication token.
- The access token.
- The token expiration time.
- Initializes a new instance of the class.
+ Construct with values for all properties.
-
- The parameter is or empty.
-
+ The token string.
+ The token expiration time.
+
+ is null or empty.
+
-
- Gets the token expiration time.
- The token expiration time.
-
Gets the token string.
The token string.
+
+ Gets the token expiration time.
+ The token expiration time.
+
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj
index 485a3de83a..802a80068e 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj
@@ -23,17 +23,19 @@
Microsoft.Data.SqlClient.Extensions.Abstractions
- Microsoft.Data.SqlClient.Extensions.Abstractions
+ $(AssemblyName)
- $(_DefaultMajorVersion).0.0.0
+ $(AbstractionsDefaultMajorVersion).0.0.0
$(AbstractionsAssemblyFileVersion)
$(AbstractionsAssemblyFileVersion)
$(AbstractionsPackageVersion)
+
+ $(Artifacts)/doc/$(TargetFramework)/$(AssemblyName).xml
@@ -42,7 +44,7 @@
-
+
- <_DefaultMajorVersion>1
+ 1
<_OurPackageVersion Condition="'$(AbstractionsPackageVersion)' != ''">$(AbstractionsPackageVersion)
- <_OurPackageVersion Condition="'$(AbstractionsPackageVersion)' == ''">$(_DefaultMajorVersion).0.0.$(BuildNumber)-dev
+ <_OurPackageVersion Condition="'$(AbstractionsPackageVersion)' == ''">$(AbstractionsDefaultMajorVersion).0.0.$(BuildNumber)-dev
@@ -56,7 +56,7 @@
<_OurAssemblyFileVersion Condition="'$(AbstractionsAssemblyFileVersion)' == '' and '$(AbstractionsPackageVersion)' != ''">$(AbstractionsPackageVersion.Split('-')[0])
- <_OurAssemblyFileVersion Condition="'$(AbstractionsAssemblyFileVersion)' == '' and '$(AbstractionsPackageVersion)' == ''">$(_DefaultMajorVersion).0.0.$(BuildNumber)
+ <_OurAssemblyFileVersion Condition="'$(AbstractionsAssemblyFileVersion)' == '' and '$(AbstractionsPackageVersion)' == ''">$(AbstractionsDefaultMajorVersion).0.0.$(BuildNumber)
+
+
+
+ netstandard2.0
+
+
+
+
+ enable
+ enable
+
+
+
+
+ Microsoft.Data.SqlClient.Extensions.Azure
+ $(AssemblyName)
+
+
+ $(AzureDefaultMajorVersion).0.0.0
+
+ $(AzureAssemblyFileVersion)
+ $(AzureAssemblyFileVersion)
+ $(AzurePackageVersion)
+
+ $(Artifacts)/doc/$(TargetFramework)/$(AssemblyName).xml
+
+
+
+
+ <_Parameter1>true
+
+
+
+
+
+
+
+
+ $(AssemblyName)
+ $(AbstractionsPackageVersion)
+ $(PackagesDir)
+ true
+ snupkg
+
+ Microsoft Corporation
+ Microsoft Corporation
+ Microsoft.Data.SqlClient Extensions Azure
+ https://github.com/dotnet/SqlClient
+ MIT
+ dotnet.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+ $(AssemblyName)
+
+
+
+
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Azure/src/AzureVersions.props b/src/Microsoft.Data.SqlClient.Extensions/Azure/src/AzureVersions.props
new file mode 100644
index 0000000000..8c9d16969e
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient.Extensions/Azure/src/AzureVersions.props
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+ <_OurPackageVersion Condition="'$(AzurePackageVersion)' != ''">$(AzurePackageVersion)
+ <_OurPackageVersion Condition="'$(AzurePackageVersion)' == ''">$(AzureDefaultMajorVersion).0.0.$(BuildNumber)-dev
+
+
+
+ <_OurAssemblyFileVersion Condition="'$(AzureAssemblyFileVersion)' != ''">$(AzureAssemblyFileVersion)
+
+ <_OurAssemblyFileVersion Condition="'$(AzureAssemblyFileVersion)' == '' and '$(AzurePackageVersion)' != ''">$(AzurePackageVersion.Split('-')[0])
+
+ <_OurAssemblyFileVersion Condition="'$(AzureAssemblyFileVersion)' == '' and '$(AzurePackageVersion)' == ''">$(AzureDefaultMajorVersion).0.0.$(BuildNumber)
+
+
+ $(_OurPackageVersion)
+ $(_OurAssemblyFileVersion)
+
+
+
+
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Azure/test/Azure.Test.csproj b/src/Microsoft.Data.SqlClient.Extensions/Azure/test/Azure.Test.csproj
new file mode 100644
index 0000000000..f391b7393c
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient.Extensions/Azure/test/Azure.Test.csproj
@@ -0,0 +1,26 @@
+
+
+
+ net462;net47;net471;net472;net48;net481;net8.0;net9.0
+ enable
+ enable
+ false
+ true
+ Microsoft.Data.SqlClient.Extensions.Azure.Test
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Microsoft.Data.SqlClient.sln b/src/Microsoft.Data.SqlClient.sln
index d7a2f70689..d5efe9e4b9 100644
--- a/src/Microsoft.Data.SqlClient.sln
+++ b/src/Microsoft.Data.SqlClient.sln
@@ -327,6 +327,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{59667E4C-0
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Abstractions.Test", "Microsoft.Data.SqlClient.Extensions\Abstractions\test\Abstractions.Test.csproj", "{04ACBF75-CFF2-41AB-B652-776BC0533490}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Azure", "Azure", "{A20114E1-82D8-903A-C389-726EB4FD943F}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0D2F834B-6D91-18D0-3F09-672D448751BD}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure", "Microsoft.Data.SqlClient.Extensions\Azure\src\Azure.csproj", "{20C16035-7293-45AC-8217-9B86A389E571}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{5AF52CDD-DF78-3712-7516-5B49F94F9491}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Test", "Microsoft.Data.SqlClient.Extensions\Azure\test\Azure.Test.csproj", "{A7C0B6C7-A4B2-43CA-921B-D4FAEE86ACBC}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -679,6 +689,30 @@ Global
{04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|x64.Build.0 = Release|Any CPU
{04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|x86.ActiveCfg = Release|Any CPU
{04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|x86.Build.0 = Release|Any CPU
+ {20C16035-7293-45AC-8217-9B86A389E571}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {20C16035-7293-45AC-8217-9B86A389E571}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {20C16035-7293-45AC-8217-9B86A389E571}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {20C16035-7293-45AC-8217-9B86A389E571}.Debug|x64.Build.0 = Debug|Any CPU
+ {20C16035-7293-45AC-8217-9B86A389E571}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {20C16035-7293-45AC-8217-9B86A389E571}.Debug|x86.Build.0 = Debug|Any CPU
+ {20C16035-7293-45AC-8217-9B86A389E571}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {20C16035-7293-45AC-8217-9B86A389E571}.Release|Any CPU.Build.0 = Release|Any CPU
+ {20C16035-7293-45AC-8217-9B86A389E571}.Release|x64.ActiveCfg = Release|Any CPU
+ {20C16035-7293-45AC-8217-9B86A389E571}.Release|x64.Build.0 = Release|Any CPU
+ {20C16035-7293-45AC-8217-9B86A389E571}.Release|x86.ActiveCfg = Release|Any CPU
+ {20C16035-7293-45AC-8217-9B86A389E571}.Release|x86.Build.0 = Release|Any CPU
+ {A7C0B6C7-A4B2-43CA-921B-D4FAEE86ACBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A7C0B6C7-A4B2-43CA-921B-D4FAEE86ACBC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A7C0B6C7-A4B2-43CA-921B-D4FAEE86ACBC}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {A7C0B6C7-A4B2-43CA-921B-D4FAEE86ACBC}.Debug|x64.Build.0 = Debug|Any CPU
+ {A7C0B6C7-A4B2-43CA-921B-D4FAEE86ACBC}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A7C0B6C7-A4B2-43CA-921B-D4FAEE86ACBC}.Debug|x86.Build.0 = Debug|Any CPU
+ {A7C0B6C7-A4B2-43CA-921B-D4FAEE86ACBC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A7C0B6C7-A4B2-43CA-921B-D4FAEE86ACBC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A7C0B6C7-A4B2-43CA-921B-D4FAEE86ACBC}.Release|x64.ActiveCfg = Release|Any CPU
+ {A7C0B6C7-A4B2-43CA-921B-D4FAEE86ACBC}.Release|x64.Build.0 = Release|Any CPU
+ {A7C0B6C7-A4B2-43CA-921B-D4FAEE86ACBC}.Release|x86.ActiveCfg = Release|Any CPU
+ {A7C0B6C7-A4B2-43CA-921B-D4FAEE86ACBC}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -740,6 +774,11 @@ Global
{B21E7C94-D805-427E-928A-8DE8EA2F08CC} = {210228A5-979A-DE06-EE1F-B35C65E1583C}
{59667E4C-0BD2-9F48-FB50-9E55DD8B1011} = {556B486E-F9B0-7EA9-6A25-DA560C312761}
{04ACBF75-CFF2-41AB-B652-776BC0533490} = {59667E4C-0BD2-9F48-FB50-9E55DD8B1011}
+ {A20114E1-82D8-903A-C389-726EB4FD943F} = {19F1F1E5-3013-7660-661A-2A15F7D606C1}
+ {0D2F834B-6D91-18D0-3F09-672D448751BD} = {A20114E1-82D8-903A-C389-726EB4FD943F}
+ {20C16035-7293-45AC-8217-9B86A389E571} = {0D2F834B-6D91-18D0-3F09-672D448751BD}
+ {5AF52CDD-DF78-3712-7516-5B49F94F9491} = {A20114E1-82D8-903A-C389-726EB4FD943F}
+ {A7C0B6C7-A4B2-43CA-921B-D4FAEE86ACBC} = {5AF52CDD-DF78-3712-7516-5B49F94F9491}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {01D48116-37A2-4D33-B9EC-94793C702431}
diff --git a/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj b/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj
index 51af5632e3..b3e100b36c 100644
--- a/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj
+++ b/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj
@@ -33,15 +33,22 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props b/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props
index dfeb60b38c..d5bd53f012 100644
--- a/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props
+++ b/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props
@@ -8,7 +8,6 @@
$(OS)
true
true
- Project
true
$([System.IO.Path]::Combine('$(IntermediateOutputPath)','$(TargetFramework)','$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension)'))
diff --git a/src/Microsoft.Data.SqlClient/add-ons/Directory.Packages.props b/src/Microsoft.Data.SqlClient/add-ons/Directory.Packages.props
deleted file mode 100644
index 4a24bb25ae..0000000000
--- a/src/Microsoft.Data.SqlClient/add-ons/Directory.Packages.props
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs
index 0a04d047f8..0e5b501d41 100644
--- a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs
@@ -142,30 +142,6 @@ public SqlVector(System.ReadOnlyMemory memory) { }
}
namespace Microsoft.Data.SqlClient
{
- ///
- public sealed partial class ActiveDirectoryAuthenticationProvider : SqlAuthenticationProvider
- {
- ///
- public ActiveDirectoryAuthenticationProvider() { }
- ///
- public ActiveDirectoryAuthenticationProvider(string applicationClientId) { }
- ///
- public static void ClearUserTokenCache() { }
- ///
- public ActiveDirectoryAuthenticationProvider(System.Func deviceCodeFlowCallbackMethod, string applicationClientId = null) { }
- ///
- public override System.Threading.Tasks.Task AcquireTokenAsync(SqlAuthenticationParameters parameters) { throw null; }
- ///
- public void SetDeviceCodeFlowCallback(System.Func deviceCodeFlowCallbackMethod) { }
- ///
- public void SetAcquireAuthorizationCodeAsyncCallback(System.Func> acquireAuthorizationCodeAsyncCallback) { }
- ///
- public override bool IsSupported(SqlAuthenticationMethod authentication) { throw null; }
- ///
- public override void BeforeLoad(SqlAuthenticationMethod authentication) { }
- ///
- public override void BeforeUnload(SqlAuthenticationMethod authentication) { }
- }
///
public enum ApplicationIntent
{
@@ -204,85 +180,14 @@ protected SqlAuthenticationInitializer() { }
///
public abstract void Initialize();
}
- ///
- public enum SqlAuthenticationMethod
+ ///
+ public sealed partial class SqlAuthenticationProviderManager
{
- ///
- NotSpecified = 0,
- ///
- SqlPassword = 1,
- ///
- [System.Obsolete("ActiveDirectoryPassword is deprecated, use a more secure authentication method. See https://aka.ms/SqlClientEntraIDAuthentication for more details.")]
- ActiveDirectoryPassword = 2,
- ///
- ActiveDirectoryIntegrated = 3,
- ///
- ActiveDirectoryInteractive = 4,
- ///
- ActiveDirectoryServicePrincipal = 5,
- ///
- ActiveDirectoryDeviceCodeFlow = 6,
- ///
- ActiveDirectoryManagedIdentity = 7,
- ///
- ActiveDirectoryMSI = 8,
- ///
- ActiveDirectoryDefault = 9,
- ///
- ActiveDirectoryWorkloadIdentity = 10
- }
- ///
- public class SqlAuthenticationParameters
- {
- ///
- protected SqlAuthenticationParameters(Microsoft.Data.SqlClient.SqlAuthenticationMethod authenticationMethod, string serverName, string databaseName, string resource, string authority, string userId, string password, System.Guid connectionId, int connectionTimeout) { }
- ///
- public Microsoft.Data.SqlClient.SqlAuthenticationMethod AuthenticationMethod { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
- ///
- public string Authority { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
- ///
- public System.Guid ConnectionId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
- ///
- public string DatabaseName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
- ///
- public string Password { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
- ///
- public string Resource { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
- ///
- public string ServerName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
- ///
- public string UserId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
- ///
- public int ConnectionTimeout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
- }
- ///
- public abstract partial class SqlAuthenticationProvider
- {
- ///
- protected SqlAuthenticationProvider() { }
- ///
- public abstract System.Threading.Tasks.Task AcquireTokenAsync(Microsoft.Data.SqlClient.SqlAuthenticationParameters parameters);
- ///
- public virtual void BeforeLoad(Microsoft.Data.SqlClient.SqlAuthenticationMethod authenticationMethod) { }
- ///
- public virtual void BeforeUnload(Microsoft.Data.SqlClient.SqlAuthenticationMethod authenticationMethod) { }
- ///
+ ///
public static Microsoft.Data.SqlClient.SqlAuthenticationProvider GetProvider(Microsoft.Data.SqlClient.SqlAuthenticationMethod authenticationMethod) { throw null; }
- ///
- public abstract bool IsSupported(Microsoft.Data.SqlClient.SqlAuthenticationMethod authenticationMethod);
- ///
+ ///
public static bool SetProvider(Microsoft.Data.SqlClient.SqlAuthenticationMethod authenticationMethod, Microsoft.Data.SqlClient.SqlAuthenticationProvider provider) { throw null; }
}
- ///
- public partial class SqlAuthenticationToken
- {
- ///
- public SqlAuthenticationToken(string accessToken, System.DateTimeOffset expiresOn) { }
- ///
- public string AccessToken { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
- ///
- public System.DateTimeOffset ExpiresOn { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
- }
///
public sealed partial class SqlBulkCopy : System.IDisposable
{
diff --git a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj
index 4b658f409a..7632098f89 100644
--- a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj
@@ -32,8 +32,6 @@
-
-
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
index fff624a59a..64580fa70e 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
@@ -177,9 +177,6 @@
Microsoft\Data\SqlClient\AAsyncCallContext.cs
-
- Microsoft\Data\SqlClient\ActiveDirectoryAuthenticationProvider.cs
-
Microsoft\Data\SqlClient\ActiveDirectoryAuthenticationTimeoutRetryHelper.cs
@@ -489,18 +486,12 @@
Microsoft\Data\SqlClient\SqlAppContextSwitchManager.netcore.cs
-
- Microsoft\Data\SqlClient\SqlAuthenticationParameters.cs
-
-
- Microsoft\Data\SqlClient\SqlAuthenticationProvider.cs
+
+ Microsoft\Data\SqlClient\SqlAuthenticationParametersBuilder.cs
Microsoft\Data\SqlClient\SqlAuthenticationProviderManager.cs
-
- Microsoft\Data\SqlClient\SqlAuthenticationToken.cs
-
Microsoft\Data\SqlClient\SqlBatch.cs
@@ -1068,8 +1059,6 @@
-
-
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
index 06736ab693..983f36693c 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
@@ -18,7 +18,6 @@
using Microsoft.Data.Common.ConnectionString;
using Microsoft.Data.ProviderBase;
using Microsoft.Data.SqlClient.ConnectionPool;
-using Microsoft.Identity.Client;
namespace Microsoft.Data.SqlClient
{
@@ -106,8 +105,6 @@ public void AssertUnrecoverableStateCountIsCorrect()
internal sealed class SqlInternalConnectionTds : SqlInternalConnection, IDisposable
{
- // https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/retry-after#simple-retry-for-errors-with-http-error-codes-500-600
- internal const int MsalHttpRetryStatusCode = 429;
// Connection re-route limit
internal const int MaxNumberOfRedirectRoute = 10;
@@ -134,7 +131,8 @@ internal sealed class SqlInternalConnectionTds : SqlInternalConnection, IDisposa
internal bool _federatedAuthenticationInfoReceived;
// The Federated Authentication returned by TryGetFedAuthTokenLocked or GetFedAuthToken.
- SqlFedAuthToken _fedAuthToken = null;
+ private SqlFedAuthToken _fedAuthToken = null;
+
internal byte[] _accessTokenInBytes;
internal readonly Func> _accessTokenCallback;
internal readonly SspiContextProvider _sspiContextProvider;
@@ -232,17 +230,6 @@ internal bool IsDNSCachingBeforeRedirectSupported
private DbConnectionPoolAuthenticationContextKey _dbConnectionPoolAuthenticationContextKey;
#if DEBUG
- // This is a test hook to enable testing of the retry paths for MSAL get access token.
- // Sample code to enable:
- //
- // Type type = typeof(SqlConnection).Assembly.GetType("Microsoft.Data.SqlClient.SQLInternalConnectionTds");
- // System.Reflection.FieldInfo field = type.GetField("_forceMsalRetry", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
- // if (field != null) {
- // field.SetValue(null, true);
- // }
- //
- internal static bool _forceMsalRetry = false;
-
// This is a test hook to simulate a token expiring within the next 45 minutes.
private static bool _forceExpiryLocked = false;
@@ -763,7 +750,7 @@ protected override bool UnbindOnTransactionCompletion
///
/// Validates if federated authentication is used, Access Token used by this connection is active for the value of 'accessTokenExpirationBufferTime'.
///
- internal override bool IsAccessTokenExpired => _federatedAuthenticationInfoRequested && DateTime.FromFileTimeUtc(_fedAuthToken.expirationFileTime) < DateTime.UtcNow.AddSeconds(accessTokenExpirationBufferTime);
+ internal override bool IsAccessTokenExpired => _federatedAuthenticationInfoRequested && DateTime.FromFileTimeUtc(_fedAuthToken.ExpirationFileTime) < DateTime.UtcNow.AddSeconds(accessTokenExpirationBufferTime);
////////////////////////////////////////////////////////////////////////////////////////
// GENERAL METHODS
@@ -2338,7 +2325,7 @@ internal void OnFedAuthInfo(SqlFedAuthInfo fedAuthInfo)
Debug.Assert(_dbConnectionPool.AuthenticationContexts != null);
// Construct the dbAuthenticationContextKey with information from FedAuthInfo and store for later use, when inserting in to the token cache.
- _dbConnectionPoolAuthenticationContextKey = new DbConnectionPoolAuthenticationContextKey(fedAuthInfo.stsurl, fedAuthInfo.spn);
+ _dbConnectionPoolAuthenticationContextKey = new DbConnectionPoolAuthenticationContextKey(fedAuthInfo.StsUrl, fedAuthInfo.Spn);
// Try to retrieve the authentication context from the pool, if one does exist for this key.
if (_dbConnectionPool.AuthenticationContexts.TryGetValue(_dbConnectionPoolAuthenticationContextKey, out dbConnectionPoolAuthenticationContext))
@@ -2427,15 +2414,14 @@ internal void OnFedAuthInfo(SqlFedAuthInfo fedAuthInfo)
Debug.Assert(_fedAuthToken == null, "_fedAuthToken should be null in this case.");
Debug.Assert(_newDbConnectionPoolAuthenticationContext == null, "_newDbConnectionPoolAuthenticationContext should be null.");
- _fedAuthToken = new SqlFedAuthToken();
-
// If the code flow is here, then we are re-using the context from the cache for this connection attempt and not
// generating a new access token on this thread.
- _fedAuthToken.accessToken = dbConnectionPoolAuthenticationContext.AccessToken;
- _fedAuthToken.expirationFileTime = dbConnectionPoolAuthenticationContext.ExpirationTime.ToFileTime();
+ _fedAuthToken = new(
+ dbConnectionPoolAuthenticationContext.AccessToken,
+ dbConnectionPoolAuthenticationContext.ExpirationTime.ToFileTime());
}
- Debug.Assert(_fedAuthToken != null && _fedAuthToken.accessToken != null, "_fedAuthToken and _fedAuthToken.accessToken cannot be null.");
+ Debug.Assert(_fedAuthToken != null && _fedAuthToken.AccessToken != null, "_fedAuthToken and _fedAuthToken.AccessToken cannot be null.");
_parser.SendFedAuthToken(_fedAuthToken);
}
@@ -2495,6 +2481,8 @@ internal bool TryGetFedAuthTokenLocked(SqlFedAuthInfo fedAuthInfo, DbConnectionP
return authenticationContextLocked;
}
+ #nullable enable
+
///
/// Get the Federated Authentication Token.
///
@@ -2502,37 +2490,32 @@ internal bool TryGetFedAuthTokenLocked(SqlFedAuthInfo fedAuthInfo, DbConnectionP
/// SqlFedAuthToken
internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
{
- Debug.Assert(fedAuthInfo != null, "fedAuthInfo should not be null.");
-
- // No:of milliseconds to sleep for the inital back off.
- int sleepInterval = 100;
-
- // No:of attempts, for tracing purposes, if we underwent retries.
- int numberOfAttempts = 0;
+ // Number of milliseconds to sleep for the initial back off, if a
+ // retry period is not specified by the provider.
+ const int defaultRetryPeriod = 100;
- // Object that will be returned to the caller, containing all required data about the token.
- _fedAuthToken = new SqlFedAuthToken();
+ // Number of retry attempts we are willing to perform.
+ const int maxRetryAttempts = 1;
// Username to use in error messages.
- string username = null;
+ string? username = null;
- SqlAuthenticationProvider authProvider = SqlAuthenticationProvider.GetProvider(ConnectionOptions.Authentication);
+ SqlAuthenticationProvider? authProvider = SqlAuthenticationProviderManager.GetProvider(ConnectionOptions.Authentication);
if (authProvider == null && _accessTokenCallback == null)
{
throw SQL.CannotFindAuthProvider(ConnectionOptions.Authentication.ToString());
}
- // retry getting access token once if MsalException.error_code is unknown_error.
- // extra logic to deal with HTTP 429 (Retry after).
- while (numberOfAttempts <= 1)
+ // We will perform retries if the provider indicates an error that
+ // is retryable.
+ for (int retryAttempt = 0; retryAttempt <= maxRetryAttempts; ++retryAttempt)
{
- numberOfAttempts++;
try
{
- var authParamsBuilder = new SqlAuthenticationParameters.Builder(
+ var authParamsBuilder = new SqlAuthenticationParametersBuilder(
authenticationMethod: ConnectionOptions.Authentication,
- resource: fedAuthInfo.spn,
- authority: fedAuthInfo.stsurl,
+ resource: fedAuthInfo.Spn,
+ authority: fedAuthInfo.StsUrl,
serverName: ConnectionOptions.DataSource,
databaseName: ConnectionOptions.InitialCatalog)
.WithConnectionId(_clientConnectionId)
@@ -2560,7 +2543,8 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
{
// We use Task.Run here in all places to execute task synchronously in the same context.
// Fixes block-over-async deadlock possibilities https://github.com/dotnet/SqlClient/issues/1209
- _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken();
+ _fedAuthToken = new(Task.Run(async () => await authProvider!.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult());
+
_activeDirectoryAuthTimeoutRetryHelper.CachedToken = _fedAuthToken;
}
break;
@@ -2577,7 +2561,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
else
{
authParamsBuilder.WithUserId(ConnectionOptions.UserID);
- _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken();
+ _fedAuthToken = new(Task.Run(async () => await authProvider!.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult());
_activeDirectoryAuthTimeoutRetryHelper.CachedToken = _fedAuthToken;
}
break;
@@ -2595,13 +2579,13 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
{
username = _credential.UserId;
authParamsBuilder.WithUserId(username).WithPassword(_credential.Password);
- _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken();
+ _fedAuthToken = new(Task.Run(async () => await authProvider!.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult());
}
else
{
username = ConnectionOptions.UserID;
authParamsBuilder.WithUserId(username).WithPassword(ConnectionOptions.Password);
- _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken();
+ _fedAuthToken = new(Task.Run(async () => await authProvider!.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult());
}
_activeDirectoryAuthTimeoutRetryHelper.CachedToken = _fedAuthToken;
}
@@ -2635,105 +2619,80 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
{
cts.CancelAfter((int)_timeout.MillisecondsRemaining);
}
- _fedAuthToken = Task.Run(async () => await _accessTokenCallback(parameters, cts.Token)).GetAwaiter().GetResult().ToSqlFedAuthToken();
+ _fedAuthToken = new(Task.Run(async () => await _accessTokenCallback(parameters, cts.Token)).GetAwaiter().GetResult());
_activeDirectoryAuthTimeoutRetryHelper.CachedToken = _fedAuthToken;
}
break;
}
- Debug.Assert(_fedAuthToken.accessToken != null, "AccessToken should not be null.");
-#if DEBUG
- if (_forceMsalRetry)
- {
- // 3399614468 is 0xCAA20004L just for testing.
- throw new MsalServiceException(MsalError.UnknownError, "Force retry in GetFedAuthToken");
- }
-#endif
+ Debug.Assert(_fedAuthToken.AccessToken != null, "AccessToken should not be null.");
+
// Break out of the retry loop in successful case.
break;
}
- // Deal with Msal service exceptions first, retry if 429 received.
- catch (MsalServiceException serviceException)
+ catch (SqlAuthenticationProviderException ex)
{
- if (serviceException.StatusCode == MsalHttpRetryStatusCode)
+ // Is the error fatal or retryable?
+ if (!ex.ShouldRetry)
{
- RetryConditionHeaderValue retryAfter = serviceException.Headers.RetryAfter;
- if (retryAfter.Delta.HasValue)
- {
- sleepInterval = retryAfter.Delta.Value.Milliseconds;
- }
- else if (retryAfter.Date.HasValue)
- {
- sleepInterval = Convert.ToInt32(retryAfter.Date.Value.Offset.TotalMilliseconds);
- }
-
- // if there's enough time to retry before timeout, then retry, otherwise break out the retry loop.
- if (sleepInterval < _timeout.MillisecondsRemaining)
- {
- Thread.Sleep(sleepInterval);
- }
- else
- {
- SqlClientEventSource.Log.TryTraceEvent(" Timeout: {0}", serviceException.ErrorCode);
- throw SQL.ActiveDirectoryTokenRetrievingTimeout(Enum.GetName(typeof(SqlAuthenticationMethod), ConnectionOptions.Authentication), serviceException.ErrorCode, serviceException);
- }
+ // It's fatal, so translate into a SqlException.
+ throw ADP.CreateSqlException(ex, ConnectionOptions, this, username);
}
- else
+
+ // We should retry.
+
+ // Could we retry if we wanted to?
+ if (_timeout.IsExpired || _timeout.MillisecondsRemaining <= 0)
{
- SqlClientEventSource.Log.TryTraceEvent(" {0}", serviceException.ErrorCode);
- throw ADP.CreateSqlException(serviceException, ConnectionOptions, this, username);
+ // No, so we throw.
+ SqlClientEventSource.Log.TryTraceEvent(" Retry Attempt: {0}, Timeout: {1}", retryAttempt, ex.FailureCode);
+ throw SQL.ActiveDirectoryTokenRetrievingTimeout(Enum.GetName(typeof(SqlAuthenticationMethod), ConnectionOptions.Authentication), ex.FailureCode, ex);
}
- }
- // Deal with normal MsalExceptions.
- catch (MsalException msalException)
- {
- if (MsalError.UnknownError != msalException.ErrorCode || _timeout.IsExpired || _timeout.MillisecondsRemaining <= sleepInterval)
- {
- SqlClientEventSource.Log.TryTraceEvent(" {0}", msalException.ErrorCode);
- throw ADP.CreateSqlException(msalException, ConnectionOptions, this, username);
- }
+ // We use a doubling backoff if the provider didn't provide
+ // a retry period.
+ int retryPeriod =
+ ex.RetryPeriod > 0
+ ? ex.RetryPeriod
+ : defaultRetryPeriod * (2 ^ retryAttempt);
- SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, sleeping {1}[Milliseconds]", ObjectID, sleepInterval);
- SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, remaining {1}[Milliseconds]", ObjectID, _timeout.MillisecondsRemaining);
+ SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, Retry Attempt: {1}, sleeping {2}[Milliseconds]", ObjectID, retryAttempt, retryPeriod);
+ SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, Retry Attempt: {1}, remaining {2}[Milliseconds]", ObjectID, retryAttempt, _timeout.MillisecondsRemaining);
- Thread.Sleep(sleepInterval);
- sleepInterval *= 2;
- }
- // All other exceptions from MSAL/Azure Identity APIs
- catch (Exception e)
- {
- throw SqlException.CreateException(
- new()
- {
- new(
- 0,
- (byte)0x00,
- (byte)TdsEnums.FATAL_ERROR_CLASS,
- ConnectionOptions.DataSource,
- e.Message,
- ActiveDirectoryAuthentication.MSALGetAccessTokenFunctionName,
- 0)
- },
- "",
- this,
- e);
+ // Sleep for the desired period.
+ Thread.Sleep(retryPeriod);
+
+ // Fall through to retry...
}
}
- Debug.Assert(_fedAuthToken != null, "fedAuthToken should not be null.");
- Debug.Assert(_fedAuthToken.accessToken != null && _fedAuthToken.accessToken.Length > 0, "fedAuthToken.accessToken should not be null or empty.");
+ // Nullable context has exposed that _fedAuthToken may be null here,
+ // which the existing code didn't handle.
+ if (_fedAuthToken is null)
+ {
+ // We failed to acquire a token, so use a default one.
+ //
+ // TODO: The old code actually allowed the AccessToken byte
+ // array to be null, and then had Debug.Assert()s to verify it
+ // wasn't null. We never test in debug, so those were never
+ // firing, and we were happily using a _fedAuthToken with a null
+ // AccessToken. Now that SqlFedAuthToken doesn't allow a null
+ // AccessToken, we just create an empty one instead.
+ _fedAuthToken = new SqlFedAuthToken([], 0);
+ }
// Store the newly generated token in _newDbConnectionPoolAuthenticationContext, only if using pooling.
if (_dbConnectionPool != null)
{
- DateTime expirationTime = DateTime.FromFileTimeUtc(_fedAuthToken.expirationFileTime);
- _newDbConnectionPoolAuthenticationContext = new DbConnectionPoolAuthenticationContext(_fedAuthToken.accessToken, expirationTime);
+ DateTime expirationTime = DateTime.FromFileTimeUtc(_fedAuthToken.ExpirationFileTime);
+ _newDbConnectionPoolAuthenticationContext = new DbConnectionPoolAuthenticationContext(_fedAuthToken.AccessToken, expirationTime);
}
SqlClientEventSource.Log.TryTraceEvent(" {0}, Finished generating federated authentication token.", ObjectID);
return _fedAuthToken;
}
+ #nullable disable
+
internal void OnFeatureExtAck(int featureId, byte[] data)
{
if (RoutingInfo != null && featureId != TdsEnums.FEATUREEXT_SQLDNSCACHING)
diff --git a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs
index e662fc0560..a929c01bd4 100644
--- a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs
@@ -57,32 +57,6 @@ public sealed class SqlDataSourceEnumerator : System.Data.Common.DbDataSourceEnu
namespace Microsoft.Data.SqlClient
{
- ///
- public sealed class ActiveDirectoryAuthenticationProvider : SqlAuthenticationProvider
- {
- ///
- public ActiveDirectoryAuthenticationProvider() { }
- ///
- public ActiveDirectoryAuthenticationProvider(string applicationClientId) { }
- ///
- public static void ClearUserTokenCache() { }
- ///
- public ActiveDirectoryAuthenticationProvider(System.Func deviceCodeFlowCallbackMethod, string applicationClientId = null) { }
- ///
- public override System.Threading.Tasks.Task AcquireTokenAsync(SqlAuthenticationParameters parameters) { throw null; }
- ///
- public void SetDeviceCodeFlowCallback(System.Func deviceCodeFlowCallbackMethod) { }
- ///
- public void SetAcquireAuthorizationCodeAsyncCallback(System.Func> acquireAuthorizationCodeAsyncCallback) { }
- ///
- public void SetIWin32WindowFunc(System.Func iWin32WindowFunc) { }
- ///
- public override bool IsSupported(SqlAuthenticationMethod authentication) { throw null; }
- ///
- public override void BeforeLoad(SqlAuthenticationMethod authentication) { }
- ///
- public override void BeforeUnload(SqlAuthenticationMethod authentication) { }
- }
///
public enum ApplicationIntent
{
@@ -122,84 +96,13 @@ protected SqlAuthenticationInitializer() { }
///
public abstract void Initialize();
}
- ///
- public enum SqlAuthenticationMethod
+ ///
+ public sealed partial class SqlAuthenticationProviderManager
{
- ///
- NotSpecified = 0,
- ///
- SqlPassword = 1,
- ///
- [System.ObsoleteAttribute("ActiveDirectoryPassword is deprecated, use a more secure authentication method. See https://aka.ms/SqlClientEntraIDAuthentication for more details.")]
- ActiveDirectoryPassword = 2,
- ///
- ActiveDirectoryIntegrated = 3,
- ///
- ActiveDirectoryInteractive = 4,
- ///
- ActiveDirectoryServicePrincipal = 5,
- ///
- ActiveDirectoryDeviceCodeFlow = 6,
- ///
- ActiveDirectoryManagedIdentity = 7,
- ///
- ActiveDirectoryMSI = 8,
- ///
- ActiveDirectoryDefault = 9,
- ///
- ActiveDirectoryWorkloadIdentity = 10
- }
- ///
- public class SqlAuthenticationParameters
- {
- ///
- protected SqlAuthenticationParameters(Microsoft.Data.SqlClient.SqlAuthenticationMethod authenticationMethod, string serverName, string databaseName, string resource, string authority, string userId, string password, System.Guid connectionId, int connectionTimeout) { }
- ///
- public Microsoft.Data.SqlClient.SqlAuthenticationMethod AuthenticationMethod { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
- ///
- public string Authority { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
- ///
- public System.Guid ConnectionId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
- ///
- public string DatabaseName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
- ///
- public string Password { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
- ///
- public string Resource { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
- ///
- public string ServerName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
- ///
- public string UserId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
- ///
- public int ConnectionTimeout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
- }
- ///
- public abstract partial class SqlAuthenticationProvider
- {
- ///
- protected SqlAuthenticationProvider() { }
- ///
- public abstract System.Threading.Tasks.Task AcquireTokenAsync(Microsoft.Data.SqlClient.SqlAuthenticationParameters parameters);
- ///
- public virtual void BeforeLoad(Microsoft.Data.SqlClient.SqlAuthenticationMethod authenticationMethod) { }
- ///
- public virtual void BeforeUnload(Microsoft.Data.SqlClient.SqlAuthenticationMethod authenticationMethod) { }
- ///
+ ///
public static Microsoft.Data.SqlClient.SqlAuthenticationProvider GetProvider(Microsoft.Data.SqlClient.SqlAuthenticationMethod authenticationMethod) { throw null; }
- ///
- public abstract bool IsSupported(Microsoft.Data.SqlClient.SqlAuthenticationMethod authenticationMethod);
- ///
- public static bool SetProvider(Microsoft.Data.SqlClient.SqlAuthenticationMethod authenticationMethod, Microsoft.Data.SqlClient.SqlAuthenticationProvider provider) { throw null; }
- }
- ///
- public partial class SqlAuthenticationToken
- {
- ///
- public SqlAuthenticationToken(string accessToken, System.DateTimeOffset expiresOn) { }
- ///
- public string AccessToken { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
- ///
- public System.DateTimeOffset ExpiresOn { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
+ ///
+ public static bool SetProvider(Microsoft.Data.SqlClient.SqlAuthenticationMethod authenticationMethod, Microsoft.Data.SqlClient.SqlAuthenticationProvider provider) { throw null; }
}
///
public sealed partial class SqlBulkCopy : System.IDisposable
diff --git a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj
index f73b8682a0..b0bb14a9b7 100644
--- a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj
@@ -32,8 +32,6 @@
-
-
All
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj
index 3729377928..78b39dbe6b 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj
@@ -459,9 +459,6 @@
Microsoft\Data\SqlClient\AssemblyRef.cs
-
- Microsoft\Data\SqlClient\ActiveDirectoryAuthenticationProvider.cs
-
Microsoft\Data\SqlClient\AlwaysEncryptedEnclaveProviderUtils.cs
@@ -660,11 +657,8 @@
Microsoft\Data\SqlClient\SqlAeadAes256CbcHmac256Factory.cs
-
- Microsoft\Data\SqlClient\SqlAuthenticationParameters.cs
-
-
- Microsoft\Data\SqlClient\SqlAuthenticationProvider.cs
+
+ Microsoft\Data\SqlClient\SqlAuthenticationParametersBuilder.cs
Microsoft\Data\SqlClient\SqlAuthenticationProviderManager.cs
@@ -675,9 +669,6 @@
Microsoft\Data\SqlClient\SqlBulkCopy.cs
-
- Microsoft\Data\SqlClient\SqlAuthenticationToken.cs
-
Microsoft\Data\SqlClient\SqlBatchCommand.cs
@@ -1041,8 +1032,6 @@
-
-
All
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
index 9f4a612951..bc6e9c13de 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
@@ -19,7 +19,6 @@
using Microsoft.Data.Common.ConnectionString;
using Microsoft.Data.ProviderBase;
using Microsoft.Data.SqlClient.ConnectionPool;
-using Microsoft.Identity.Client;
namespace Microsoft.Data.SqlClient
{
@@ -107,8 +106,6 @@ public void AssertUnrecoverableStateCountIsCorrect()
internal sealed class SqlInternalConnectionTds : SqlInternalConnection, IDisposable
{
- // https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/retry-after#simple-retry-for-errors-with-http-error-codes-500-600
- internal const int MsalHttpRetryStatusCode = 429;
// Connection re-route limit
internal const int MaxNumberOfRedirectRoute = 10;
@@ -233,17 +230,6 @@ internal bool IsDNSCachingBeforeRedirectSupported
private DbConnectionPoolAuthenticationContextKey _dbConnectionPoolAuthenticationContextKey;
#if DEBUG
- // This is a test hook to enable testing of the retry paths for MSAL get access token.
- // Sample code to enable:
- //
- // Type type = typeof(SqlConnection).Assembly.GetType("Microsoft.Data.SqlClient.SQLInternalConnectionTds");
- // System.Reflection.FieldInfo field = type.GetField("_forceMsalRetry", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
- // if (field != null) {
- // field.SetValue(null, true);
- // }
- //
- internal static bool _forceMsalRetry = false;
-
// This is a test hook to simulate a token expiring within the next 45 minutes.
private static bool _forceExpiryLocked = false;
@@ -773,7 +759,7 @@ protected override bool UnbindOnTransactionCompletion
///
/// Validates if federated authentication is used, Access Token used by this connection is active for the value of 'accessTokenExpirationBufferTime'.
///
- internal override bool IsAccessTokenExpired => _federatedAuthenticationInfoRequested && DateTime.FromFileTimeUtc(_fedAuthToken.expirationFileTime) < DateTime.UtcNow.AddSeconds(accessTokenExpirationBufferTime);
+ internal override bool IsAccessTokenExpired => _federatedAuthenticationInfoRequested && DateTime.FromFileTimeUtc(_fedAuthToken.ExpirationFileTime) < DateTime.UtcNow.AddSeconds(accessTokenExpirationBufferTime);
////////////////////////////////////////////////////////////////////////////////////////
// GENERAL METHODS
@@ -2394,7 +2380,7 @@ internal void OnFedAuthInfo(SqlFedAuthInfo fedAuthInfo)
Debug.Assert(_dbConnectionPool.AuthenticationContexts != null);
// Construct the dbAuthenticationContextKey with information from FedAuthInfo and store for later use, when inserting in to the token cache.
- _dbConnectionPoolAuthenticationContextKey = new DbConnectionPoolAuthenticationContextKey(fedAuthInfo.stsurl, fedAuthInfo.spn);
+ _dbConnectionPoolAuthenticationContextKey = new DbConnectionPoolAuthenticationContextKey(fedAuthInfo.StsUrl, fedAuthInfo.Spn);
// Try to retrieve the authentication context from the pool, if one does exist for this key.
if (_dbConnectionPool.AuthenticationContexts.TryGetValue(_dbConnectionPoolAuthenticationContextKey, out dbConnectionPoolAuthenticationContext))
@@ -2483,15 +2469,14 @@ internal void OnFedAuthInfo(SqlFedAuthInfo fedAuthInfo)
Debug.Assert(_fedAuthToken == null, "_fedAuthToken should be null in this case.");
Debug.Assert(_newDbConnectionPoolAuthenticationContext == null, "_newDbConnectionPoolAuthenticationContext should be null.");
- _fedAuthToken = new SqlFedAuthToken();
-
// If the code flow is here, then we are re-using the context from the cache for this connection attempt and not
// generating a new access token on this thread.
- _fedAuthToken.accessToken = dbConnectionPoolAuthenticationContext.AccessToken;
- _fedAuthToken.expirationFileTime = dbConnectionPoolAuthenticationContext.ExpirationTime.ToFileTime();
+ _fedAuthToken = new(
+ dbConnectionPoolAuthenticationContext.AccessToken,
+ dbConnectionPoolAuthenticationContext.ExpirationTime.ToFileTime());
}
- Debug.Assert(_fedAuthToken != null && _fedAuthToken.accessToken != null, "_fedAuthToken and _fedAuthToken.accessToken cannot be null.");
+ Debug.Assert(_fedAuthToken != null && _fedAuthToken.AccessToken != null, "_fedAuthToken and _fedAuthToken.AccessToken cannot be null.");
_parser.SendFedAuthToken(_fedAuthToken);
}
@@ -2551,6 +2536,8 @@ internal bool TryGetFedAuthTokenLocked(SqlFedAuthInfo fedAuthInfo, DbConnectionP
return authenticationContextLocked;
}
+ #nullable enable
+
///
/// Get the Federated Authentication Token.
///
@@ -2558,37 +2545,32 @@ internal bool TryGetFedAuthTokenLocked(SqlFedAuthInfo fedAuthInfo, DbConnectionP
/// SqlFedAuthToken
internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
{
- Debug.Assert(fedAuthInfo != null, "fedAuthInfo should not be null.");
-
- // No:of milliseconds to sleep for the inital back off.
- int sleepInterval = 100;
-
- // No:of attempts, for tracing purposes, if we underwent retries.
- int numberOfAttempts = 0;
+ // Number of milliseconds to sleep for the initial back off, if a
+ // retry period is not specified by the provider.
+ const int defaultRetryPeriod = 100;
- // Object that will be returned to the caller, containing all required data about the token.
- _fedAuthToken = new SqlFedAuthToken();
+ // Number of retry attempts we are willing to perform.
+ const int maxRetryAttempts = 1;
// Username to use in error messages.
- string username = null;
+ string? username = null;
- SqlAuthenticationProvider authProvider = SqlAuthenticationProvider.GetProvider(ConnectionOptions.Authentication);
+ SqlAuthenticationProvider? authProvider = SqlAuthenticationProviderManager.GetProvider(ConnectionOptions.Authentication);
if (authProvider == null && _accessTokenCallback == null)
{
throw SQL.CannotFindAuthProvider(ConnectionOptions.Authentication.ToString());
}
- // retry getting access token once if MsalException.error_code is unknown_error.
- // extra logic to deal with HTTP 429 (Retry after).
- while (numberOfAttempts <= 1 && sleepInterval <= _timeout.MillisecondsRemaining)
+ // We will perform retries if the provider indicates an error that
+ // is retryable.
+ for (int retryAttempt = 0; retryAttempt < maxRetryAttempts; ++retryAttempt)
{
- numberOfAttempts++;
try
{
- var authParamsBuilder = new SqlAuthenticationParameters.Builder(
+ var authParamsBuilder = new SqlAuthenticationParametersBuilder(
authenticationMethod: ConnectionOptions.Authentication,
- resource: fedAuthInfo.spn,
- authority: fedAuthInfo.stsurl,
+ resource: fedAuthInfo.Spn,
+ authority: fedAuthInfo.StsUrl,
serverName: ConnectionOptions.DataSource,
databaseName: ConnectionOptions.InitialCatalog)
.WithConnectionId(_clientConnectionId)
@@ -2605,7 +2587,10 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
{
// We use Task.Run here in all places to execute task synchronously in the same context.
// Fixes block-over-async deadlock possibilities https://github.com/dotnet/SqlClient/issues/1209
- _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken();
+ //
+ // TODO: Remove this async stuff and the '!'
+ // when we have a sync API on the auth provider.
+ _fedAuthToken = new(Task.Run(async () => await authProvider!.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult());
_activeDirectoryAuthTimeoutRetryHelper.CachedToken = _fedAuthToken;
}
break;
@@ -2622,7 +2607,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
else
{
authParamsBuilder.WithUserId(ConnectionOptions.UserID);
- _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken();
+ _fedAuthToken = new(Task.Run(async () => await authProvider!.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult());
_activeDirectoryAuthTimeoutRetryHelper.CachedToken = _fedAuthToken;
}
break;
@@ -2640,13 +2625,13 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
{
username = _credential.UserId;
authParamsBuilder.WithUserId(username).WithPassword(_credential.Password);
- _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken();
+ _fedAuthToken = new(Task.Run(async () => await authProvider!.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult());
}
else
{
username = ConnectionOptions.UserID;
authParamsBuilder.WithUserId(username).WithPassword(ConnectionOptions.Password);
- _fedAuthToken = Task.Run(async () => await authProvider.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult().ToSqlFedAuthToken();
+ _fedAuthToken = new(Task.Run(async () => await authProvider!.AcquireTokenAsync(authParamsBuilder)).GetAwaiter().GetResult());
}
_activeDirectoryAuthTimeoutRetryHelper.CachedToken = _fedAuthToken;
}
@@ -2680,105 +2665,80 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
{
cts.CancelAfter((int)_timeout.MillisecondsRemaining);
}
- _fedAuthToken = Task.Run(async () => await _accessTokenCallback(parameters, cts.Token)).GetAwaiter().GetResult().ToSqlFedAuthToken();
+ _fedAuthToken = new(Task.Run(async () => await _accessTokenCallback(parameters, cts.Token)).GetAwaiter().GetResult());
_activeDirectoryAuthTimeoutRetryHelper.CachedToken = _fedAuthToken;
}
break;
}
- Debug.Assert(_fedAuthToken.accessToken != null, "AccessToken should not be null.");
-#if DEBUG
- if (_forceMsalRetry)
- {
- // 3399614468 is 0xCAA20004L just for testing.
- throw new MsalServiceException(MsalError.UnknownError, "Force retry in GetFedAuthToken");
- }
-#endif
+ Debug.Assert(_fedAuthToken.AccessToken != null, "AccessToken should not be null.");
+
// Break out of the retry loop in successful case.
break;
}
- // Deal with Msal service exceptions first, retry if 429 received.
- catch (MsalServiceException serviceException)
+ catch (SqlAuthenticationProviderException ex)
{
- if (serviceException.StatusCode == MsalHttpRetryStatusCode)
+ // Is the error fatal or retryable?
+ if (!ex.ShouldRetry)
{
- RetryConditionHeaderValue retryAfter = serviceException.Headers.RetryAfter;
- if (retryAfter.Delta.HasValue)
- {
- sleepInterval = retryAfter.Delta.Value.Milliseconds;
- }
- else if (retryAfter.Date.HasValue)
- {
- sleepInterval = Convert.ToInt32(retryAfter.Date.Value.Offset.TotalMilliseconds);
- }
-
- // if there's enough time to retry before timeout, then retry, otherwise break out the retry loop.
- if (sleepInterval < _timeout.MillisecondsRemaining)
- {
- Thread.Sleep(sleepInterval);
- }
- else
- {
- SqlClientEventSource.Log.TryTraceEvent(" Timeout: {0}", serviceException.ErrorCode);
- throw SQL.ActiveDirectoryTokenRetrievingTimeout(Enum.GetName(typeof(SqlAuthenticationMethod), ConnectionOptions.Authentication), serviceException.ErrorCode, serviceException);
- }
+ // It's fatal, so translate into a SqlException.
+ throw ADP.CreateSqlException(ex, ConnectionOptions, this, username);
}
- else
+
+ // We should retry.
+
+ // Could we retry if we wanted to?
+ if (_timeout.IsExpired || _timeout.MillisecondsRemaining <= 0)
{
- SqlClientEventSource.Log.TryTraceEvent(" {0}", serviceException.ErrorCode);
- throw ADP.CreateSqlException(serviceException, ConnectionOptions, this, username);
+ // No, so we throw.
+ SqlClientEventSource.Log.TryTraceEvent(" Retry Attempt: {0}, Timeout: {1}", retryAttempt, ex.FailureCode);
+ throw SQL.ActiveDirectoryTokenRetrievingTimeout(Enum.GetName(typeof(SqlAuthenticationMethod), ConnectionOptions.Authentication), ex.FailureCode, ex);
}
- }
- // Deal with normal MsalExceptions.
- catch (MsalException msalException)
- {
- if (MsalError.UnknownError != msalException.ErrorCode || _timeout.IsExpired || _timeout.MillisecondsRemaining <= sleepInterval)
- {
- SqlClientEventSource.Log.TryTraceEvent(" {0}", msalException.ErrorCode);
- throw ADP.CreateSqlException(msalException, ConnectionOptions, this, username);
- }
+ // We use a doubling backoff if the provider didn't provide
+ // a retry period.
+ int retryPeriod =
+ ex.RetryPeriod > 0
+ ? ex.RetryPeriod
+ : defaultRetryPeriod * (2 ^ retryAttempt);
- SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, sleeping {1}[Milliseconds]", ObjectID, sleepInterval);
- SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, remaining {1}[Milliseconds]", ObjectID, _timeout.MillisecondsRemaining);
+ SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, Retry Attempt: {1}, sleeping {2}[Milliseconds]", ObjectID, retryAttempt, retryPeriod);
+ SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, Retry Attempt: {1}, remaining {2}[Milliseconds]", ObjectID, retryAttempt, _timeout.MillisecondsRemaining);
- Thread.Sleep(sleepInterval);
- sleepInterval *= 2;
- }
- // All other exceptions from MSAL/Azure Identity APIs
- catch (Exception e)
- {
- throw SqlException.CreateException(
- new()
- {
- new(
- 0,
- (byte)0x00,
- (byte)TdsEnums.FATAL_ERROR_CLASS,
- ConnectionOptions.DataSource,
- e.Message,
- ActiveDirectoryAuthentication.MSALGetAccessTokenFunctionName,
- 0)
- },
- "",
- this,
- e);
+ // Sleep for the desired period.
+ Thread.Sleep(retryPeriod);
+
+ // Fall through to retry...
}
}
- Debug.Assert(_fedAuthToken != null, "fedAuthToken should not be null.");
- Debug.Assert(_fedAuthToken.accessToken != null && _fedAuthToken.accessToken.Length > 0, "fedAuthToken.accessToken should not be null or empty.");
+ // Nullable context has exposed that _fedAuthToken may be null here,
+ // which the existing code didn't handle.
+ if (_fedAuthToken is null)
+ {
+ // We failed to acquire a token, so use a default one.
+ //
+ // TODO: The old code actually allowed the AccessToken byte
+ // array to be null, and then had Debug.Assert()s to verify it
+ // wasn't null. We never test in debug, so those were never
+ // firing, and we were happily using a _fedAuthToken with a null
+ // AccessToken. Now that SqlFedAuthToken doesn't allow a null
+ // AccessToken, we just create an empty one instead.
+ _fedAuthToken = new SqlFedAuthToken([], 0);
+ }
// Store the newly generated token in _newDbConnectionPoolAuthenticationContext, only if using pooling.
if (_dbConnectionPool != null)
{
- DateTime expirationTime = DateTime.FromFileTimeUtc(_fedAuthToken.expirationFileTime);
- _newDbConnectionPoolAuthenticationContext = new DbConnectionPoolAuthenticationContext(_fedAuthToken.accessToken, expirationTime);
+ DateTime expirationTime = DateTime.FromFileTimeUtc(_fedAuthToken.ExpirationFileTime);
+ _newDbConnectionPoolAuthenticationContext = new DbConnectionPoolAuthenticationContext(_fedAuthToken.AccessToken, expirationTime);
}
SqlClientEventSource.Log.TryTraceEvent(" {0}, Finished generating federated authentication token.", ObjectID);
return _fedAuthToken;
}
+ #nullable disable
+
internal void OnFeatureExtAck(int featureId, byte[] data)
{
if (RoutingInfo != null && featureId != TdsEnums.FEATUREEXT_SQLDNSCACHING)
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj
index df4ca44714..9aaef4560f 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj
@@ -8,8 +8,6 @@
-
-
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs
index b37f97ac17..961c50e9ed 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs
@@ -21,7 +21,6 @@
using Microsoft.Data.Common.ConnectionString;
using Microsoft.Data.SqlClient;
using IsolationLevel = System.Data.IsolationLevel;
-using Microsoft.Identity.Client;
using Microsoft.SqlServer.Server;
using System.Security.Authentication;
using System.Collections.Generic;
@@ -465,7 +464,7 @@ internal static ArgumentException InvalidArgumentLength(string argumentName, int
internal static ArgumentException MustBeReadOnly(string argumentName) => Argument(StringsHelper.GetString(Strings.ADP_MustBeReadOnly, argumentName));
- internal static Exception CreateSqlException(MsalException msalException, SqlConnectionString connectionOptions, SqlInternalConnectionTds sender, string username)
+ internal static Exception CreateSqlException(SqlAuthenticationProviderException authException, SqlConnectionString connectionOptions, SqlInternalConnectionTds sender, string username)
{
// Error[0]
SqlErrorCollection sqlErs = new();
@@ -473,20 +472,20 @@ internal static Exception CreateSqlException(MsalException msalException, SqlCon
sqlErs.Add(new SqlError(0, (byte)0x00, (byte)TdsEnums.MIN_ERROR_CLASS,
connectionOptions.DataSource,
StringsHelper.GetString(Strings.SQL_MSALFailure, username, connectionOptions.Authentication.ToString("G")),
- ActiveDirectoryAuthentication.MSALGetAccessTokenFunctionName, 0));
+ authException.Method.ToString(), 0));
// Error[1]
- string errorMessage1 = StringsHelper.GetString(Strings.SQL_MSALInnerException, msalException.ErrorCode);
+ string errorMessage1 = StringsHelper.GetString(Strings.SQL_MSALInnerException, authException.FailureCode);
sqlErs.Add(new SqlError(0, (byte)0x00, (byte)TdsEnums.MIN_ERROR_CLASS,
- connectionOptions.DataSource, errorMessage1,
- ActiveDirectoryAuthentication.MSALGetAccessTokenFunctionName, 0));
+ connectionOptions.DataSource, errorMessage1,
+ authException.Method.ToString(), 0));
// Error[2]
- if (!string.IsNullOrEmpty(msalException.Message))
+ if (!string.IsNullOrEmpty(authException.Message))
{
sqlErs.Add(new SqlError(0, (byte)0x00, (byte)TdsEnums.MIN_ERROR_CLASS,
- connectionOptions.DataSource, msalException.Message,
- ActiveDirectoryAuthentication.MSALGetAccessTokenFunctionName, 0));
+ connectionOptions.DataSource, authException.Message,
+ authException.Method.ToString(), 0));
}
return SqlException.CreateException(sqlErs, "", sender, innerException: null, batchCommand: null);
}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs
deleted file mode 100644
index 0393de9beb..0000000000
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs
+++ /dev/null
@@ -1,743 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Concurrent;
-using System.Security.Cryptography;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Azure.Core;
-using Azure.Identity;
-using Microsoft.Data.Common.ConnectionString;
-using Microsoft.Extensions.Caching.Memory;
-using Microsoft.Identity.Client;
-using Microsoft.Identity.Client.Extensibility;
-
-namespace Microsoft.Data.SqlClient
-{
- ///
- public sealed class ActiveDirectoryAuthenticationProvider : SqlAuthenticationProvider
- {
- ///
- /// This is a static cache instance meant to hold instances of "PublicClientApplication" mapping to information available in PublicClientAppKey.
- /// The purpose of this cache is to allow re-use of Access Tokens fetched for a user interactively or with any other mode
- /// to avoid interactive authentication request every-time, within application scope making use of MSAL's userTokenCache.
- ///
- private static readonly ConcurrentDictionary s_pcaMap = new();
- private static readonly ConcurrentDictionary s_tokenCredentialMap = new();
- private static SemaphoreSlim s_pcaMapModifierSemaphore = new(1, 1);
- private static SemaphoreSlim s_tokenCredentialMapModifierSemaphore = new(1, 1);
- private static readonly MemoryCache s_accountPwCache = new MemoryCache(new MemoryCacheOptions());
- private static readonly int s_accountPwCacheTtlInHours = 2;
- private static readonly string s_nativeClientRedirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient";
- private static readonly string s_defaultScopeSuffix = "/.default";
- private readonly string _type = typeof(ActiveDirectoryAuthenticationProvider).Name;
- private readonly SqlClientLogger _logger = new();
- private Func _deviceCodeFlowCallback;
- private ICustomWebUi _customWebUI = null;
- private readonly string _applicationClientId = ActiveDirectoryAuthentication.AdoClientId;
-
- ///
- public ActiveDirectoryAuthenticationProvider()
- : this(DefaultDeviceFlowCallback)
- {
- }
-
- ///
- public ActiveDirectoryAuthenticationProvider(string applicationClientId)
- : this(DefaultDeviceFlowCallback, applicationClientId)
- {
- }
-
- ///
- public ActiveDirectoryAuthenticationProvider(Func deviceCodeFlowCallbackMethod, string applicationClientId = null)
- {
- if (applicationClientId != null)
- {
- _applicationClientId = applicationClientId;
- }
- SetDeviceCodeFlowCallback(deviceCodeFlowCallbackMethod);
- }
-
- ///
- public static void ClearUserTokenCache()
- {
- if (!s_pcaMap.IsEmpty)
- {
- s_pcaMap.Clear();
- }
-
- if (!s_tokenCredentialMap.IsEmpty)
- {
- s_tokenCredentialMap.Clear();
- }
- }
-
- ///
- public void SetDeviceCodeFlowCallback(Func deviceCodeFlowCallbackMethod) => _deviceCodeFlowCallback = deviceCodeFlowCallbackMethod;
-
- ///
- public void SetAcquireAuthorizationCodeAsyncCallback(Func> acquireAuthorizationCodeAsyncCallback) => _customWebUI = new CustomWebUi(acquireAuthorizationCodeAsyncCallback);
-
- ///
- public override bool IsSupported(SqlAuthenticationMethod authentication)
- {
- return authentication == SqlAuthenticationMethod.ActiveDirectoryIntegrated
- #pragma warning disable 0618 // Type or member is obsolete
- || authentication == SqlAuthenticationMethod.ActiveDirectoryPassword
- #pragma warning restore 0618 // Type or member is obsolete
- || authentication == SqlAuthenticationMethod.ActiveDirectoryInteractive
- || authentication == SqlAuthenticationMethod.ActiveDirectoryServicePrincipal
- || authentication == SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow
- || authentication == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity
- || authentication == SqlAuthenticationMethod.ActiveDirectoryMSI
- || authentication == SqlAuthenticationMethod.ActiveDirectoryDefault
- || authentication == SqlAuthenticationMethod.ActiveDirectoryWorkloadIdentity;
- }
-
- ///
- public override void BeforeLoad(SqlAuthenticationMethod authentication)
- {
- _logger.LogInfo(_type, "BeforeLoad", $"being loaded into SqlAuthProviders for {authentication}.");
- }
-
- ///
- public override void BeforeUnload(SqlAuthenticationMethod authentication)
- {
- _logger.LogInfo(_type, "BeforeUnload", $"being unloaded from SqlAuthProviders for {authentication}.");
- }
-
-#if NETFRAMEWORK
- private Func _iWin32WindowFunc = null;
-
- ///
- public void SetIWin32WindowFunc(Func iWin32WindowFunc) => this._iWin32WindowFunc = iWin32WindowFunc;
-#endif
-
- ///
-
- public override async Task AcquireTokenAsync(SqlAuthenticationParameters parameters)
- {
- using CancellationTokenSource cts = new();
-
- // Use Connection timeout value to cancel token acquire request after certain period of time.
- int timeout = parameters.ConnectionTimeout * 1000; // Convert to milliseconds
- if (timeout > 0) // if ConnectionTimeout is 0 or the millis overflows an int, no need to set CancelAfter
- {
- cts.CancelAfter(timeout);
- }
-
- string scope = parameters.Resource.EndsWith(s_defaultScopeSuffix, StringComparison.Ordinal) ? parameters.Resource : parameters.Resource + s_defaultScopeSuffix;
- string[] scopes = new string[] { scope };
- TokenRequestContext tokenRequestContext = new(scopes);
-
- /* We split audience from Authority URL here. Audience can be one of the following:
- * The Azure AD authority audience enumeration
- * The tenant ID, which can be:
- * - A GUID (the ID of your Azure AD instance), for single-tenant applications
- * - A domain name associated with your Azure AD instance (also for single-tenant applications)
- * One of these placeholders as a tenant ID in place of the Azure AD authority audience enumeration:
- * - `organizations` for a multitenant application
- * - `consumers` to sign in users only with their personal accounts
- * - `common` to sign in users with their work and school accounts or their personal Microsoft accounts
- *
- * MSAL will throw a meaningful exception if you specify both the Azure AD authority audience and the tenant ID.
- * If you don't specify an audience, your app will target Azure AD and personal Microsoft accounts as an audience. (That is, it will behave as though `common` were specified.)
- * More information: https://docs.microsoft.com/azure/active-directory/develop/msal-client-application-configuration
- **/
-
- int separatorIndex = parameters.Authority.LastIndexOf('/');
- string authority = parameters.Authority.Remove(separatorIndex + 1);
- string audience = parameters.Authority.Substring(separatorIndex + 1);
- string clientId = string.IsNullOrWhiteSpace(parameters.UserId) ? null : parameters.UserId;
-
- if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryDefault)
- {
- // Cache DefaultAzureCredenial based on scope, authority, audience, and clientId
- TokenCredentialKey tokenCredentialKey = new(typeof(DefaultAzureCredential), authority, scope, audience, clientId);
- AccessToken accessToken = await GetTokenAsync(tokenCredentialKey, string.Empty, tokenRequestContext, cts.Token).ConfigureAwait(false);
- SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Default auth mode. Expiry Time: {0}", accessToken.ExpiresOn);
- return new SqlAuthenticationToken(accessToken.Token, accessToken.ExpiresOn);
- }
-
- TokenCredentialOptions tokenCredentialOptions = new() { AuthorityHost = new Uri(authority) };
-
- if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity || parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryMSI)
- {
- // Cache ManagedIdentityCredential based on scope, authority, and clientId
- TokenCredentialKey tokenCredentialKey = new(typeof(ManagedIdentityCredential), authority, scope, string.Empty, clientId);
- AccessToken accessToken = await GetTokenAsync(tokenCredentialKey, string.Empty, tokenRequestContext, cts.Token).ConfigureAwait(false);
- SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Managed Identity auth mode. Expiry Time: {0}", accessToken.ExpiresOn);
- return new SqlAuthenticationToken(accessToken.Token, accessToken.ExpiresOn);
- }
-
- if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryServicePrincipal)
- {
- // Cache ClientSecretCredential based on scope, authority, audience, and clientId
- TokenCredentialKey tokenCredentialKey = new(typeof(ClientSecretCredential), authority, scope, audience, clientId);
- AccessToken accessToken = await GetTokenAsync(tokenCredentialKey, parameters.Password, tokenRequestContext, cts.Token).ConfigureAwait(false);
- SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Active Directory Service Principal auth mode. Expiry Time: {0}", accessToken.ExpiresOn);
- return new SqlAuthenticationToken(accessToken.Token, accessToken.ExpiresOn);
- }
-
- if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryWorkloadIdentity)
- {
- // Cache WorkloadIdentityCredential based on authority and clientId
- TokenCredentialKey tokenCredentialKey = new(typeof(WorkloadIdentityCredential), authority, string.Empty, string.Empty, clientId);
- // If either tenant id, client id, or the token file path are not specified when fetching the token,
- // a CredentialUnavailableException will be thrown instead
- AccessToken accessToken = await GetTokenAsync(tokenCredentialKey, string.Empty, tokenRequestContext, cts.Token).ConfigureAwait(false);
- SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Workload Identity auth mode. Expiry Time: {0}", accessToken.ExpiresOn);
- return new SqlAuthenticationToken(accessToken.Token, accessToken.ExpiresOn);
- }
-
- /*
- * Today, MSAL.NET uses another redirect URI by default in desktop applications that run on Windows
- * (urn:ietf:wg:oauth:2.0:oob). In the future, we'll want to change this default, so we recommend
- * that you use https://login.microsoftonline.com/common/oauth2/nativeclient.
- *
- * https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-desktop-app-registration#redirect-uris
- */
- string redirectUri = s_nativeClientRedirectUri;
-
-#if NET
- if (parameters.AuthenticationMethod != SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow)
- {
- redirectUri = "http://localhost";
- }
-#endif
- PublicClientAppKey pcaKey = new(parameters.Authority, redirectUri, _applicationClientId
-#if NETFRAMEWORK
- , _iWin32WindowFunc
-#endif
- );
-
- AuthenticationResult result = null;
- IPublicClientApplication app = await GetPublicClientAppInstanceAsync(pcaKey, cts.Token).ConfigureAwait(false);
-
- if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryIntegrated)
- {
- result = await TryAcquireTokenSilent(app, parameters, scopes, cts).ConfigureAwait(false);
-
- if (result == null)
- {
- if (!string.IsNullOrEmpty(parameters.UserId))
- {
- // The AcquireTokenByIntegratedWindowsAuth method is marked as obsolete in MSAL.NET
- // but it is still a supported way to acquire tokens for Active Directory Integrated authentication.
-#pragma warning disable CS0618 // Type or member is obsolete
- result = await app.AcquireTokenByIntegratedWindowsAuth(scopes)
-#pragma warning restore CS0618 // Type or member is obsolete
- .WithCorrelationId(parameters.ConnectionId)
- .WithUsername(parameters.UserId)
- .ExecuteAsync(cancellationToken: cts.Token)
- .ConfigureAwait(false);
- }
- else
- {
-#pragma warning disable CS0618 // Type or member is obsolete
- result = await app.AcquireTokenByIntegratedWindowsAuth(scopes)
-#pragma warning restore CS0618 // Type or member is obsolete
- .WithCorrelationId(parameters.ConnectionId)
- .ExecuteAsync(cancellationToken: cts.Token)
- .ConfigureAwait(false);
- }
- SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Active Directory Integrated auth mode. Expiry Time: {0}", result?.ExpiresOn);
- }
- }
- #pragma warning disable 0618 // Type or member is obsolete
- else if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryPassword)
- #pragma warning restore 0618 // Type or member is obsolete
- {
- string pwCacheKey = GetAccountPwCacheKey(parameters);
- object previousPw = s_accountPwCache.Get(pwCacheKey);
- byte[] currPwHash = GetHash(parameters.Password);
-
- if (previousPw != null &&
- previousPw is byte[] previousPwBytes &&
- // Only get the cached token if the current password hash matches the previously used password hash
- AreEqual(currPwHash, previousPwBytes))
- {
- result = await TryAcquireTokenSilent(app, parameters, scopes, cts).ConfigureAwait(false);
- }
-
- if (result == null)
- {
-#pragma warning disable CS0618 // Type or member is obsolete
- result = await app.AcquireTokenByUsernamePassword(scopes, parameters.UserId, parameters.Password)
-#pragma warning restore CS0618 // Type or member is obsolete
- .WithCorrelationId(parameters.ConnectionId)
- .ExecuteAsync(cancellationToken: cts.Token)
- .ConfigureAwait(false);
-
- // We cache the password hash to ensure future connection requests include a validated password
- // when we check for a cached MSAL account. Otherwise, a connection request with the same username
- // against the same tenant could succeed with an invalid password when we re-use the cached token.
- using (ICacheEntry entry = s_accountPwCache.CreateEntry(pwCacheKey))
- {
- entry.Value = GetHash(parameters.Password);
- entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(s_accountPwCacheTtlInHours);
- }
- SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Active Directory Password auth mode. Expiry Time: {0}", result?.ExpiresOn);
- }
- }
- else if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryInteractive ||
- parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow)
- {
- try
- {
- result = await TryAcquireTokenSilent(app, parameters, scopes, cts).ConfigureAwait(false);
- SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token (silent) for {0} auth mode. Expiry Time: {1}", parameters.AuthenticationMethod, result?.ExpiresOn);
- }
- catch (MsalUiRequiredException)
- {
- // An 'MsalUiRequiredException' is thrown in the case where an interaction is required with the end user of the application,
- // for instance, if no refresh token was in the cache, or the user needs to consent, or re-sign-in (for instance if the password expired),
- // or the user needs to perform two factor authentication.
- result = await AcquireTokenInteractiveDeviceFlowAsync(app, scopes, parameters.ConnectionId, parameters.UserId, parameters.AuthenticationMethod, cts, _customWebUI, _deviceCodeFlowCallback).ConfigureAwait(false);
- SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token (interactive) for {0} auth mode. Expiry Time: {1}", parameters.AuthenticationMethod, result?.ExpiresOn);
- }
-
- if (result == null)
- {
- // If no existing 'account' is found, we request user to sign in interactively.
- result = await AcquireTokenInteractiveDeviceFlowAsync(app, scopes, parameters.ConnectionId, parameters.UserId, parameters.AuthenticationMethod, cts, _customWebUI, _deviceCodeFlowCallback).ConfigureAwait(false);
- SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token (interactive) for {0} auth mode. Expiry Time: {1}", parameters.AuthenticationMethod, result?.ExpiresOn);
- }
- }
- else
- {
- SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | {0} authentication mode not supported by ActiveDirectoryAuthenticationProvider class.", parameters.AuthenticationMethod);
- throw SQL.UnsupportedAuthenticationSpecified(parameters.AuthenticationMethod);
- }
-
- return new SqlAuthenticationToken(result.AccessToken, result.ExpiresOn);
- }
-
- private static async Task TryAcquireTokenSilent(IPublicClientApplication app, SqlAuthenticationParameters parameters,
- string[] scopes, CancellationTokenSource cts)
- {
- AuthenticationResult result = null;
-
- // Fetch available accounts from 'app' instance
- System.Collections.Generic.IEnumerator accounts = (await app.GetAccountsAsync().ConfigureAwait(false)).GetEnumerator();
-
- IAccount account = default;
- if (accounts.MoveNext())
- {
- if (!string.IsNullOrEmpty(parameters.UserId))
- {
- do
- {
- IAccount currentVal = accounts.Current;
- if (string.Compare(parameters.UserId, currentVal.Username, StringComparison.InvariantCultureIgnoreCase) == 0)
- {
- account = currentVal;
- break;
- }
- }
- while (accounts.MoveNext());
- }
- else
- {
- account = accounts.Current;
- }
- }
-
- if (account != null)
- {
- // If 'account' is available in 'app', we use the same to acquire token silently.
- // Read More on API docs: https://docs.microsoft.com/dotnet/api/microsoft.identity.client.clientapplicationbase.acquiretokensilent
- result = await app.AcquireTokenSilent(scopes, account).ExecuteAsync(cancellationToken: cts.Token).ConfigureAwait(false);
- SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token (silent) for {0} auth mode. Expiry Time: {1}", parameters.AuthenticationMethod, result?.ExpiresOn);
- }
-
- return result;
- }
-
- private static async Task AcquireTokenInteractiveDeviceFlowAsync(IPublicClientApplication app, string[] scopes, Guid connectionId, string userId,
- SqlAuthenticationMethod authenticationMethod, CancellationTokenSource cts, ICustomWebUi customWebUI, Func deviceCodeFlowCallback)
- {
- try
- {
- if (authenticationMethod == SqlAuthenticationMethod.ActiveDirectoryInteractive)
- {
- CancellationTokenSource ctsInteractive = new();
-#if NET
- /*
- * On .NET Core, MSAL will start the system browser as a separate process. MSAL does not have control over this browser,
- * but once the user finishes authentication, the web page is redirected in such a way that MSAL can intercept the Uri.
- * MSAL cannot detect if the user navigates away or simply closes the browser. Apps using this technique are encouraged
- * to define a timeout (via CancellationToken). We recommend a timeout of at least a few minutes, to take into account
- * cases where the user is prompted to change password or perform 2FA.
- *
- * https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/System-Browser-on-.Net-Core#system-browser-experience
- */
- ctsInteractive.CancelAfter(180000);
-#endif
- if (customWebUI != null)
- {
- return await app.AcquireTokenInteractive(scopes)
- .WithCorrelationId(connectionId)
- .WithCustomWebUi(customWebUI)
- .WithLoginHint(userId)
- .ExecuteAsync(ctsInteractive.Token)
- .ConfigureAwait(false);
- }
- else
- {
- /*
- * We will use the MSAL Embedded or System web browser which changes by Default in MSAL according to this table:
- *
- * Framework Embedded System Default
- * -------------------------------------------
- * .NET Classic Yes Yes^ Embedded
- * .NET Core No Yes^ System
- * .NET Standard No No NONE
- * UWP Yes No Embedded
- * Xamarin.Android Yes Yes System
- * Xamarin.iOS Yes Yes System
- * Xamarin.Mac Yes No Embedded
- *
- * ^ Requires "http://localhost" redirect URI
- *
- * https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/MSAL.NET-uses-web-browser#at-a-glance
- */
- return await app.AcquireTokenInteractive(scopes)
- .WithCorrelationId(connectionId)
- .WithLoginHint(userId)
- .ExecuteAsync(ctsInteractive.Token)
- .ConfigureAwait(false);
- }
- }
- else
- {
- AuthenticationResult result = await app.AcquireTokenWithDeviceCode(scopes,
- deviceCodeResult => deviceCodeFlowCallback(deviceCodeResult))
- .WithCorrelationId(connectionId)
- .ExecuteAsync(cancellationToken: cts.Token)
- .ConfigureAwait(false);
- return result;
- }
- }
- catch (OperationCanceledException)
- {
- SqlClientEventSource.Log.TryTraceEvent("AcquireTokenInteractiveDeviceFlowAsync | Operation timed out while acquiring access token.");
- throw (authenticationMethod == SqlAuthenticationMethod.ActiveDirectoryInteractive) ?
- SQL.ActiveDirectoryInteractiveTimeout() :
- SQL.ActiveDirectoryDeviceFlowTimeout();
- }
- }
-
- private static Task DefaultDeviceFlowCallback(DeviceCodeResult result)
- {
- // This will print the message on the console which tells the user where to go sign-in using
- // a separate browser and the code to enter once they sign in.
- // The AcquireTokenWithDeviceCode() method will poll the server after firing this
- // device code callback to look for the successful login of the user via that browser.
- // This background polling (whose interval and timeout data is also provided as fields in the
- // deviceCodeCallback class) will occur until:
- // * The user has successfully logged in via browser and entered the proper code
- // * The timeout specified by the server for the lifetime of this code (typically ~15 minutes) has been reached
- // * The developing application calls the Cancel() method on a CancellationToken sent into the method.
- // If this occurs, an OperationCanceledException will be thrown (see catch below for more details).
- SqlClientEventSource.Log.TryTraceEvent("AcquireTokenInteractiveDeviceFlowAsync | Callback triggered with Device Code Result: {0}", result.Message);
- Console.WriteLine(result.Message);
- return Task.FromResult(0);
- }
-
- private class CustomWebUi : ICustomWebUi
- {
- private readonly Func> _acquireAuthorizationCodeAsyncCallback;
-
- internal CustomWebUi(Func> acquireAuthorizationCodeAsyncCallback) => _acquireAuthorizationCodeAsyncCallback = acquireAuthorizationCodeAsyncCallback;
-
- public Task AcquireAuthorizationCodeAsync(Uri authorizationUri, Uri redirectUri, CancellationToken cancellationToken)
- => _acquireAuthorizationCodeAsyncCallback.Invoke(authorizationUri, redirectUri, cancellationToken);
- }
-
- private async Task GetPublicClientAppInstanceAsync(PublicClientAppKey publicClientAppKey, CancellationToken cancellationToken)
- {
- if (!s_pcaMap.TryGetValue(publicClientAppKey, out IPublicClientApplication clientApplicationInstance))
- {
- await s_pcaMapModifierSemaphore.WaitAsync(cancellationToken);
- try
- {
- // Double-check in case another thread added it while we waited for the semaphore
- if (!s_pcaMap.TryGetValue(publicClientAppKey, out clientApplicationInstance))
- {
- clientApplicationInstance = CreateClientAppInstance(publicClientAppKey);
- s_pcaMap.TryAdd(publicClientAppKey, clientApplicationInstance);
- }
- }
- finally
- {
- s_pcaMapModifierSemaphore.Release();
- }
- }
-
- return clientApplicationInstance;
- }
-
- private static async Task GetTokenAsync(TokenCredentialKey tokenCredentialKey, string secret,
- TokenRequestContext tokenRequestContext, CancellationToken cancellationToken)
- {
- if (!s_tokenCredentialMap.TryGetValue(tokenCredentialKey, out TokenCredentialData tokenCredentialInstance))
- {
- await s_tokenCredentialMapModifierSemaphore.WaitAsync(cancellationToken);
- try
- {
- // Double-check in case another thread added it while we waited for the semaphore
- if (!s_tokenCredentialMap.TryGetValue(tokenCredentialKey, out tokenCredentialInstance))
- {
- tokenCredentialInstance = CreateTokenCredentialInstance(tokenCredentialKey, secret);
- s_tokenCredentialMap.TryAdd(tokenCredentialKey, tokenCredentialInstance);
- }
- }
- finally
- {
- s_tokenCredentialMapModifierSemaphore.Release();
- }
- }
-
- if (!AreEqual(tokenCredentialInstance._secretHash, GetHash(secret)))
- {
- // If the secret hash has changed, we need to remove the old token credential instance and create a new one.
- await s_tokenCredentialMapModifierSemaphore.WaitAsync(cancellationToken);
- try
- {
- s_tokenCredentialMap.TryRemove(tokenCredentialKey, out _);
- tokenCredentialInstance = CreateTokenCredentialInstance(tokenCredentialKey, secret);
- s_tokenCredentialMap.TryAdd(tokenCredentialKey, tokenCredentialInstance);
- }
- finally
- {
- s_tokenCredentialMapModifierSemaphore.Release();
- }
- }
-
- return await tokenCredentialInstance._tokenCredential.GetTokenAsync(tokenRequestContext, cancellationToken);
- }
-
- private static string GetAccountPwCacheKey(SqlAuthenticationParameters parameters)
- {
- return parameters.Authority + "+" + parameters.UserId;
- }
-
- private static byte[] GetHash(string input)
- {
- byte[] unhashedBytes = Encoding.Unicode.GetBytes(input);
- SHA256 sha256 = SHA256.Create();
- byte[] hashedBytes = sha256.ComputeHash(unhashedBytes);
- return hashedBytes;
- }
-
- private static bool AreEqual(byte[] a1, byte[] a2)
- {
- if (ReferenceEquals(a1, a2))
- {
- return true;
- }
- else if (a1 is null || a2 is null)
- {
- return false;
- }
- else if (a1.Length != a2.Length)
- {
- return false;
- }
-
- return a1.AsSpan().SequenceEqual(a2.AsSpan());
- }
-
- private IPublicClientApplication CreateClientAppInstance(PublicClientAppKey publicClientAppKey)
- {
- PublicClientApplicationBuilder builder = PublicClientApplicationBuilder
- .CreateWithApplicationOptions(new PublicClientApplicationOptions
- {
- ClientId = publicClientAppKey._applicationClientId,
- ClientName = DbConnectionStringDefaults.ApplicationName,
- ClientVersion = Common.ADP.GetAssemblyVersion().ToString(),
- RedirectUri = publicClientAppKey._redirectUri,
- })
- .WithAuthority(publicClientAppKey._authority);
-
- #if NETFRAMEWORK
- if (_iWin32WindowFunc is not null)
- {
- builder.WithParentActivityOrWindow(_iWin32WindowFunc);
- }
- #endif
-
- return builder.Build();
- }
-
- private static TokenCredentialData CreateTokenCredentialInstance(TokenCredentialKey tokenCredentialKey, string secret)
- {
- if (tokenCredentialKey._tokenCredentialType == typeof(DefaultAzureCredential))
- {
- DefaultAzureCredentialOptions defaultAzureCredentialOptions = new()
- {
- AuthorityHost = new Uri(tokenCredentialKey._authority),
- TenantId = tokenCredentialKey._audience,
- ExcludeInteractiveBrowserCredential = true // Force disabled, even though it's disabled by default to respect driver specifications.
- };
-
- // Optionally set clientId when available
- if (tokenCredentialKey._clientId is not null)
- {
- defaultAzureCredentialOptions.ManagedIdentityClientId = tokenCredentialKey._clientId;
-#pragma warning disable CS0618 // Type or member is obsolete
- defaultAzureCredentialOptions.SharedTokenCacheUsername = tokenCredentialKey._clientId;
-#pragma warning restore CS0618 // Type or member is obsolete
- defaultAzureCredentialOptions.WorkloadIdentityClientId = tokenCredentialKey._clientId;
- }
-
- // SqlClient is a library and provides support to acquire access
- // token using 'DefaultAzureCredential' on user demand when they
- // specify 'Authentication = Active Directory Default' in
- // connection string.
- //
- // Default Azure Credential is instantiated by the calling
- // application when using "Active Directory Default"
- // authentication code to connect to Azure SQL instance.
- // SqlClient is a library, doesn't instantiate the credential
- // without running application instructions.
- //
- // Note that CodeQL suppression support can only detect
- // suppression comments that appear immediately above the
- // flagged statement, or appended to the end of the statement.
- // Multi-line justifications are not supported.
- //
- // https://eng.ms/docs/cloud-ai-platform/devdiv/one-engineering-system-1es/1es-docs/codeql/codeql-semmle#guidance-on-suppressions
- //
- // CodeQL [SM05137] See above for justification.
- DefaultAzureCredential cred = new(defaultAzureCredentialOptions);
-
- return new TokenCredentialData(cred, GetHash(secret));
- }
-
- TokenCredentialOptions tokenCredentialOptions = new() { AuthorityHost = new Uri(tokenCredentialKey._authority) };
-
- if (tokenCredentialKey._tokenCredentialType == typeof(ManagedIdentityCredential))
- {
- return new TokenCredentialData(new ManagedIdentityCredential(tokenCredentialKey._clientId, tokenCredentialOptions), GetHash(secret));
- }
- else if (tokenCredentialKey._tokenCredentialType == typeof(ClientSecretCredential))
- {
- return new TokenCredentialData(new ClientSecretCredential(tokenCredentialKey._audience, tokenCredentialKey._clientId, secret, tokenCredentialOptions), GetHash(secret));
- }
- else if (tokenCredentialKey._tokenCredentialType == typeof(WorkloadIdentityCredential))
- {
- // The WorkloadIdentityCredentialOptions object initialization populates its instance members
- // from the environment variables AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_FEDERATED_TOKEN_FILE,
- // and AZURE_ADDITIONALLY_ALLOWED_TENANTS. AZURE_CLIENT_ID may be overridden by the User Id.
- WorkloadIdentityCredentialOptions options = new() { AuthorityHost = new Uri(tokenCredentialKey._authority) };
-
- if (tokenCredentialKey._clientId is not null)
- {
- options.ClientId = tokenCredentialKey._clientId;
- }
-
- return new TokenCredentialData(new WorkloadIdentityCredential(options), GetHash(secret));
- }
-
- // This should never be reached, but if it is, throw an exception that will be noticed during development
- throw new ArgumentException(nameof(ActiveDirectoryAuthenticationProvider));
- }
-
- internal class PublicClientAppKey
- {
- public readonly string _authority;
- public readonly string _redirectUri;
- public readonly string _applicationClientId;
-#if NETFRAMEWORK
- public readonly Func _iWin32WindowFunc;
-#endif
-
- public PublicClientAppKey(string authority, string redirectUri, string applicationClientId
-#if NETFRAMEWORK
- , Func iWin32WindowFunc
-#endif
- )
- {
- _authority = authority;
- _redirectUri = redirectUri;
- _applicationClientId = applicationClientId;
-#if NETFRAMEWORK
- _iWin32WindowFunc = iWin32WindowFunc;
-#endif
- }
-
- public override bool Equals(object obj)
- {
- if (obj != null && obj is PublicClientAppKey pcaKey)
- {
- return (string.CompareOrdinal(_authority, pcaKey._authority) == 0
- && string.CompareOrdinal(_redirectUri, pcaKey._redirectUri) == 0
- && string.CompareOrdinal(_applicationClientId, pcaKey._applicationClientId) == 0
-#if NETFRAMEWORK
- && pcaKey._iWin32WindowFunc == _iWin32WindowFunc
-#endif
- );
- }
- return false;
- }
-
- public override int GetHashCode() => Tuple.Create(_authority, _redirectUri, _applicationClientId
-#if NETFRAMEWORK
- , _iWin32WindowFunc
-#endif
- ).GetHashCode();
- }
-
- internal class TokenCredentialData
- {
- public TokenCredential _tokenCredential;
- public byte[] _secretHash;
-
- public TokenCredentialData(TokenCredential tokenCredential, byte[] secretHash)
- {
- _tokenCredential = tokenCredential;
- _secretHash = secretHash;
- }
- }
-
- internal class TokenCredentialKey
- {
- public readonly Type _tokenCredentialType;
- public readonly string _authority;
- public readonly string _scope;
- public readonly string _audience;
- public readonly string _clientId;
-
- public TokenCredentialKey(Type tokenCredentialType, string authority, string scope, string audience, string clientId)
- {
- _tokenCredentialType = tokenCredentialType;
- _authority = authority;
- _scope = scope;
- _audience = audience;
- _clientId = clientId;
- }
-
- public override bool Equals(object obj)
- {
- if (obj != null && obj is TokenCredentialKey tcKey)
- {
- return string.CompareOrdinal(nameof(_tokenCredentialType), nameof(tcKey._tokenCredentialType)) == 0
- && string.CompareOrdinal(_authority, tcKey._authority) == 0
- && string.CompareOrdinal(_scope, tcKey._scope) == 0
- && string.CompareOrdinal(_audience, tcKey._audience) == 0
- && string.CompareOrdinal(_clientId, tcKey._clientId) == 0
- ;
- }
- return false;
- }
-
- public override int GetHashCode() => Tuple.Create(_tokenCredentialType, _authority, _scope, _audience, _clientId).GetHashCode();
- }
-
- }
-}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationTimeoutRetryHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationTimeoutRetryHelper.cs
index e972102260..721e31ca6f 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationTimeoutRetryHelper.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationTimeoutRetryHelper.cs
@@ -132,7 +132,8 @@ private static string GetTokenHash(SqlFedAuthToken token)
}
// Here we mimic how ADAL calculates hash for token. They use UTF8 instead of Unicode.
- var originalTokenString = SqlAuthenticationToken.AccessTokenStringFromBytes(token.accessToken);
+ var originalTokenString = Encoding.Unicode.GetString(token.AccessToken);
+
var bytesInUtf8 = Encoding.UTF8.GetBytes(originalTokenString);
using (var sha256 = SHA256.Create())
{
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationParameters.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationParameters.cs
deleted file mode 100644
index 9c74b937b8..0000000000
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationParameters.cs
+++ /dev/null
@@ -1,162 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Runtime.InteropServices;
-using System.Security;
-using Microsoft.Data.Common;
-
-namespace Microsoft.Data.SqlClient
-{
-
- ///
- public class SqlAuthenticationParameters
- {
- ///
- public SqlAuthenticationMethod AuthenticationMethod { get; }
-
- ///
- public string Resource { get; }
-
- ///
- public string Authority { get; }
-
- ///
- public string UserId { get; }
-
- ///
- public string Password { get; }
-
- ///
- public Guid ConnectionId { get; }
-
- ///
- public string ServerName { get; }
-
- ///
- public string DatabaseName { get; }
-
- ///
- public int ConnectionTimeout { get; } = ADP.DefaultConnectionTimeout;
-
- ///
- protected SqlAuthenticationParameters(
- SqlAuthenticationMethod authenticationMethod,
- string serverName,
- string databaseName,
- string resource,
- string authority,
- string userId,
- string password,
- Guid connectionId,
- int connectionTimeout)
- {
- AuthenticationMethod = authenticationMethod;
- ServerName = serverName;
- DatabaseName = databaseName;
- Resource = resource;
- Authority = authority;
- UserId = userId;
- Password = password;
- ConnectionId = connectionId;
- ConnectionTimeout = connectionTimeout;
- }
-
- ///
- /// AD authentication parameter builder.
- ///
- internal class Builder
- {
- private readonly SqlAuthenticationMethod _authenticationMethod;
- private readonly string _serverName;
- private readonly string _databaseName;
- private readonly string _resource;
- private readonly string _authority;
- private string _userId;
- private string _password;
- private Guid _connectionId = Guid.NewGuid();
- private int _connectionTimeout = ADP.DefaultConnectionTimeout;
-
- ///
- /// Implicitly converts to .
- ///
- public static implicit operator SqlAuthenticationParameters(Builder builder)
- {
- return new SqlAuthenticationParameters(
- authenticationMethod: builder._authenticationMethod,
- serverName: builder._serverName,
- databaseName: builder._databaseName,
- resource: builder._resource,
- authority: builder._authority,
- userId: builder._userId,
- password: builder._password,
- connectionId: builder._connectionId,
- connectionTimeout: builder._connectionTimeout);
- }
-
- ///
- /// Set user id.
- ///
- public Builder WithUserId(string userId)
- {
- _userId = userId;
- return this;
- }
-
- ///
- /// Set password.
- ///
- public Builder WithPassword(string password)
- {
- _password = password;
- return this;
- }
-
- ///
- /// Set password.
- ///
- public Builder WithPassword(SecureString password)
- {
- IntPtr valuePtr = IntPtr.Zero;
- try
- {
- valuePtr = Marshal.SecureStringToGlobalAllocUnicode(password);
- _password = Marshal.PtrToStringUni(valuePtr);
- }
- finally
- {
- Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
- }
- return this;
- }
-
- ///
- /// Set a specific connection id instead of using a random one.
- ///
- public Builder WithConnectionId(Guid connectionId)
- {
- _connectionId = connectionId;
- return this;
- }
-
- ///
- /// Set connection timeout.
- ///
- public Builder WithConnectionTimeout(int timeout)
- {
- _connectionTimeout = timeout;
- return this;
- }
-
- internal Builder(SqlAuthenticationMethod authenticationMethod, string resource, string authority, string serverName, string databaseName)
- {
- _authenticationMethod = authenticationMethod;
- _serverName = serverName;
- _databaseName = databaseName;
- _resource = resource;
- _authority = authority;
- }
- }
- }
-}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationParametersBuilder.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationParametersBuilder.cs
new file mode 100644
index 0000000000..5fdd7f020e
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationParametersBuilder.cs
@@ -0,0 +1,104 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+using System.Security;
+using Microsoft.Data.Common;
+
+namespace Microsoft.Data.SqlClient
+{
+ internal sealed class SqlAuthenticationParametersBuilder
+ {
+ private readonly SqlAuthenticationMethod _authenticationMethod;
+ private readonly string _serverName;
+ private readonly string _databaseName;
+ private readonly string _resource;
+ private readonly string _authority;
+ private string _userId;
+ private string _password;
+ private Guid _connectionId = Guid.NewGuid();
+ private int _connectionTimeout = ADP.DefaultConnectionTimeout;
+
+ ///
+ /// Implicitly converts to .
+ ///
+ public static implicit operator SqlAuthenticationParameters(SqlAuthenticationParametersBuilder builder)
+ {
+ return new SqlAuthenticationParameters(
+ authenticationMethod: builder._authenticationMethod,
+ serverName: builder._serverName,
+ databaseName: builder._databaseName,
+ resource: builder._resource,
+ authority: builder._authority,
+ userId: builder._userId,
+ password: builder._password,
+ connectionId: builder._connectionId,
+ connectionTimeout: builder._connectionTimeout);
+ }
+
+ ///
+ /// Set user id.
+ ///
+ public SqlAuthenticationParametersBuilder WithUserId(string userId)
+ {
+ _userId = userId;
+ return this;
+ }
+
+ ///
+ /// Set password.
+ ///
+ public SqlAuthenticationParametersBuilder WithPassword(string password)
+ {
+ _password = password;
+ return this;
+ }
+
+ ///
+ /// Set password.
+ ///
+ public SqlAuthenticationParametersBuilder WithPassword(SecureString password)
+ {
+ IntPtr valuePtr = IntPtr.Zero;
+ try
+ {
+ valuePtr = Marshal.SecureStringToGlobalAllocUnicode(password);
+ _password = Marshal.PtrToStringUni(valuePtr);
+ }
+ finally
+ {
+ Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
+ }
+ return this;
+ }
+
+ ///
+ /// Set a specific connection id instead of using a random one.
+ ///
+ public SqlAuthenticationParametersBuilder WithConnectionId(Guid connectionId)
+ {
+ _connectionId = connectionId;
+ return this;
+ }
+
+ ///
+ /// Set connection timeout.
+ ///
+ public SqlAuthenticationParametersBuilder WithConnectionTimeout(int timeout)
+ {
+ _connectionTimeout = timeout;
+ return this;
+ }
+
+ internal SqlAuthenticationParametersBuilder(SqlAuthenticationMethod authenticationMethod, string resource, string authority, string serverName, string databaseName)
+ {
+ _authenticationMethod = authenticationMethod;
+ _serverName = serverName;
+ _databaseName = databaseName;
+ _resource = resource;
+ _authority = authority;
+ }
+ }
+}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationProvider.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationProvider.cs
deleted file mode 100644
index 25e1cf006e..0000000000
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationProvider.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Threading.Tasks;
-
-namespace Microsoft.Data.SqlClient
-{
-
- ///
- public abstract class SqlAuthenticationProvider
- {
- ///
- public static SqlAuthenticationProvider GetProvider(SqlAuthenticationMethod authenticationMethod)
- {
- return SqlAuthenticationProviderManager.Instance.GetProvider(authenticationMethod);
- }
-
- ///
- public static bool SetProvider(SqlAuthenticationMethod authenticationMethod, SqlAuthenticationProvider provider)
- {
- return SqlAuthenticationProviderManager.Instance.SetProvider(authenticationMethod, provider);
- }
-
- ///
- public virtual void BeforeLoad(SqlAuthenticationMethod authenticationMethod) { }
-
- ///
- public virtual void BeforeUnload(SqlAuthenticationMethod authenticationMethod) { }
-
- ///
- public abstract bool IsSupported(SqlAuthenticationMethod authenticationMethod);
-
- ///
- public abstract Task AcquireTokenAsync(SqlAuthenticationParameters parameters);
- }
-}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.cs
index 447ea0e9c5..ab3614a751 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.cs
@@ -6,13 +6,15 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Configuration;
+using System.IO;
+using System.Reflection;
+
+#nullable enable
namespace Microsoft.Data.SqlClient
{
- ///
- /// Authentication provider manager.
- ///
- internal sealed class SqlAuthenticationProviderManager
+ ///
+ public sealed class SqlAuthenticationProviderManager
{
[Obsolete("ActiveDirectoryPassword is deprecated, use a more secure authentication method. See https://aka.ms/SqlClientEntraIDAuthentication for more details.")]
private const string ActiveDirectoryPassword = "active directory password";
@@ -27,7 +29,7 @@ internal sealed class SqlAuthenticationProviderManager
static SqlAuthenticationProviderManager()
{
- SqlAuthenticationProviderConfigurationSection configurationSection = null;
+ SqlAuthenticationProviderConfigurationSection? configurationSection = null;
try
{
@@ -46,49 +48,116 @@ static SqlAuthenticationProviderManager()
}
Instance = new SqlAuthenticationProviderManager(configurationSection);
- SetDefaultAuthProviders(Instance);
- }
- ///
- /// Sets default supported Active Directory Authentication providers by the driver
- /// on the SqlAuthenticationProviderManager instance.
- ///
- private static void SetDefaultAuthProviders(SqlAuthenticationProviderManager instance)
- {
- if (instance != null)
+ // If our Azure extensions package is present, use its
+ // authentication provider as our default.
+ const string assemblyName = "Microsoft.Data.SqlClient.Extensions.Azure";
+
+ try
{
- var activeDirectoryAuthProvider = new ActiveDirectoryAuthenticationProvider(instance._applicationClientId);
- instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryIntegrated, activeDirectoryAuthProvider);
+ // Try to load our Azure extension.
+ var assembly = Assembly.Load(assemblyName);
+
+ // TODO: Verify the assembly is signed by us?
+
+ SqlClientEventSource.Log.TryTraceEvent(
+ nameof(SqlAuthenticationProviderManager) +
+ $": Azure extension assembly={assemblyName} found; " +
+ "attempting to set as default provider for all Active " +
+ "Directory authentication methods");
+
+ // Look for the authentication provider class.
+ const string className = "Microsoft.Data.SqlClient.ActiveDirectoryAuthenticationProvider";
+ var type = assembly.GetType(className);
+
+ if (type is null)
+ {
+ SqlClientEventSource.Log.TryTraceEvent(
+ nameof(SqlAuthenticationProviderManager) +
+ $": Azure extension does not contain class={className}; " +
+ "no default Active Directory provider installed");
+
+ return;
+ }
+
+ // Try to instantiate it.
+ var instance = Activator.CreateInstance(
+ type,
+ [Instance._applicationClientId])
+ as SqlAuthenticationProvider;
+
+ if (instance is null)
+ {
+ SqlClientEventSource.Log.TryTraceEvent(
+ nameof(SqlAuthenticationProviderManager) +
+ $": Failed to instantiate Azure extension class={className}; " +
+ "no default Active Directory provider installed");
+
+ return;
+ }
+
+ // We successfully instantiated the provider, so set it as the
+ // default for all Active Directory authentication methods.
+ //
+ // Note that SetProvider() will refuse to clobber an application
+ // specified provider, so these defaults will only be applied
+ // for methods that do not already have a provider.
+ SetProvider(SqlAuthenticationMethod.ActiveDirectoryIntegrated, instance);
#pragma warning disable 0618 // Type or member is obsolete
- instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryPassword, activeDirectoryAuthProvider);
+ SetProvider(SqlAuthenticationMethod.ActiveDirectoryPassword, instance);
#pragma warning restore 0618 // Type or member is obsolete
- instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive, activeDirectoryAuthProvider);
- instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryServicePrincipal, activeDirectoryAuthProvider);
- instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, activeDirectoryAuthProvider);
- instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryManagedIdentity, activeDirectoryAuthProvider);
- instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryMSI, activeDirectoryAuthProvider);
- instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDefault, activeDirectoryAuthProvider);
- instance.SetProvider(SqlAuthenticationMethod.ActiveDirectoryWorkloadIdentity, activeDirectoryAuthProvider);
+ SetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive, instance);
+ SetProvider(SqlAuthenticationMethod.ActiveDirectoryServicePrincipal, instance);
+ SetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, instance);
+ SetProvider(SqlAuthenticationMethod.ActiveDirectoryManagedIdentity, instance);
+ SetProvider(SqlAuthenticationMethod.ActiveDirectoryMSI, instance);
+ SetProvider(SqlAuthenticationMethod.ActiveDirectoryDefault, instance);
+ SetProvider(SqlAuthenticationMethod.ActiveDirectoryWorkloadIdentity, instance);
+
+ SqlClientEventSource.Log.TryTraceEvent(
+ nameof(SqlAuthenticationProviderManager) +
+ $": Azure extension class={className} installed as " +
+ "provider for all Active Directory authentication methods");
+ }
+ // All of these exceptions mean we couldn't find or instantiate the
+ // Azure extension's authentication provider, in which case we
+ // simply have no default and the app must provide one if they
+ // attempt to use Active Directory authentication.
+ catch (Exception ex)
+ when (ex is ArgumentNullException ||
+ ex is ArgumentException ||
+ ex is BadImageFormatException ||
+ ex is FileLoadException ||
+ ex is FileNotFoundException ||
+ ex is MemberAccessException ||
+ ex is MethodAccessException ||
+ ex is MissingMethodException ||
+ ex is NotSupportedException ||
+ ex is TargetInvocationException ||
+ ex is TypeLoadException)
+ {
+ SqlClientEventSource.Log.TryTraceEvent(
+ nameof(SqlAuthenticationProviderManager) +
+ $": Azure extension assembly={assemblyName} not found or " +
+ "not usable; no default provider installed; " +
+ $"{ex.GetType().Name}: {ex.Message}");
}
+ // Any other exceptions are fatal.
}
- public static readonly SqlAuthenticationProviderManager Instance;
+ private static readonly SqlAuthenticationProviderManager Instance;
- private readonly SqlAuthenticationInitializer _initializer;
- private readonly IReadOnlyCollection _authenticationsWithAppSpecifiedProvider;
- private readonly ConcurrentDictionary _providers;
+ private readonly HashSet _authenticationsWithAppSpecifiedProvider = new();
+ private readonly ConcurrentDictionary _providers = new();
private readonly SqlClientLogger _sqlAuthLogger = new SqlClientLogger();
- private readonly string _applicationClientId = ActiveDirectoryAuthentication.AdoClientId;
+ private readonly string? _applicationClientId = null;
///
/// Constructor.
///
- public SqlAuthenticationProviderManager(SqlAuthenticationProviderConfigurationSection configSection = null)
+ private SqlAuthenticationProviderManager(SqlAuthenticationProviderConfigurationSection? configSection)
{
var methodName = "Ctor";
- _providers = new ConcurrentDictionary();
- var authenticationsWithAppSpecifiedProvider = new HashSet();
- _authenticationsWithAppSpecifiedProvider = authenticationsWithAppSpecifiedProvider;
if (configSection == null)
{
@@ -112,8 +181,14 @@ public SqlAuthenticationProviderManager(SqlAuthenticationProviderConfigurationSe
try
{
var initializerType = Type.GetType(configSection.InitializerType, true);
- _initializer = (SqlAuthenticationInitializer)Activator.CreateInstance(initializerType);
- _initializer.Initialize();
+ if (initializerType is not null)
+ {
+ var initializer = (SqlAuthenticationInitializer?)Activator.CreateInstance(initializerType);
+ if (initializer is not null)
+ {
+ initializer.Initialize();
+ }
+ }
}
catch (Exception e)
{
@@ -132,23 +207,31 @@ public SqlAuthenticationProviderManager(SqlAuthenticationProviderConfigurationSe
foreach (ProviderSettings providerSettings in configSection.Providers)
{
SqlAuthenticationMethod authentication = AuthenticationEnumFromString(providerSettings.Name);
- SqlAuthenticationProvider provider;
+ SqlAuthenticationProvider? provider;
try
{
var providerType = Type.GetType(providerSettings.Type, true);
- provider = (SqlAuthenticationProvider)Activator.CreateInstance(providerType);
+ if (providerType is null)
+ {
+ continue;
+ }
+ provider = (SqlAuthenticationProvider?)Activator.CreateInstance(providerType);
}
catch (Exception e)
{
throw SQL.CannotCreateAuthProvider(authentication.ToString(), providerSettings.Type, e);
}
+ if (provider is null)
+ {
+ continue;
+ }
if (!provider.IsSupported(authentication))
{
throw SQL.UnsupportedAuthenticationByProvider(authentication.ToString(), providerSettings.Type);
}
_providers[authentication] = provider;
- authenticationsWithAppSpecifiedProvider.Add(authentication);
+ _authenticationsWithAppSpecifiedProvider.Add(authentication);
_sqlAuthLogger.LogInfo(nameof(SqlAuthenticationProviderManager), methodName, string.Format("Added user-defined auth provider: {0} for authentication {1}.", providerSettings?.Type, authentication));
}
}
@@ -158,54 +241,50 @@ public SqlAuthenticationProviderManager(SqlAuthenticationProviderConfigurationSe
}
}
- ///
- /// Get an authentication provider by method.
- ///
- /// Authentication method.
- /// Authentication provider or null if not found.
- public SqlAuthenticationProvider GetProvider(SqlAuthenticationMethod authenticationMethod)
+ ///
+ public static SqlAuthenticationProvider? GetProvider(SqlAuthenticationMethod authenticationMethod)
{
- SqlAuthenticationProvider value;
- return _providers.TryGetValue(authenticationMethod, out value) ? value : null;
+ SqlAuthenticationProvider? value;
+ return Instance._providers.TryGetValue(authenticationMethod, out value) ? value : null;
}
- ///
- /// Set an authentication provider by method.
- ///
- /// Authentication method.
- /// Authentication provider.
- /// True if succeeded, false otherwise, e.g., the existing provider disallows overriding.
- public bool SetProvider(SqlAuthenticationMethod authenticationMethod, SqlAuthenticationProvider provider)
+ ///
+ public static bool SetProvider(SqlAuthenticationMethod authenticationMethod, SqlAuthenticationProvider provider)
{
if (!provider.IsSupported(authenticationMethod))
{
throw SQL.UnsupportedAuthenticationByProvider(authenticationMethod.ToString(), provider.GetType().Name);
}
var methodName = "SetProvider";
- if (_authenticationsWithAppSpecifiedProvider.Count > 0)
+ if (Instance._authenticationsWithAppSpecifiedProvider.Count > 0)
{
- foreach (SqlAuthenticationMethod candidateMethod in _authenticationsWithAppSpecifiedProvider)
+ foreach (SqlAuthenticationMethod candidateMethod in Instance._authenticationsWithAppSpecifiedProvider)
{
if (candidateMethod == authenticationMethod)
{
- _sqlAuthLogger.LogError(nameof(SqlAuthenticationProviderManager), methodName, $"Failed to add provider {GetProviderType(provider)} because a user-defined provider with type {GetProviderType(_providers[authenticationMethod])} already existed for authentication {authenticationMethod}.");
- return false; // return here to avoid replacing user-defined provider
+ Instance._sqlAuthLogger.LogError(nameof(SqlAuthenticationProviderManager), methodName, $"Failed to add provider {GetProviderType(provider)} because a user-defined provider with type {GetProviderType(Instance._providers[authenticationMethod])} already existed for authentication {authenticationMethod}.");
+
+ // The app has already specified a Provider for this
+ // authentication method, so we won't override it.
+ return false;
}
}
}
- _providers.AddOrUpdate(authenticationMethod, provider, (key, oldProvider) =>
- {
- if (oldProvider != null)
- {
- oldProvider.BeforeUnload(authenticationMethod);
- }
- if (provider != null)
+ Instance._providers.AddOrUpdate(
+ authenticationMethod,
+ provider,
+ (SqlAuthenticationMethod key, SqlAuthenticationProvider oldProvider) =>
{
+ if (oldProvider != null)
+ {
+ oldProvider.BeforeUnload(authenticationMethod);
+ }
+
provider.BeforeLoad(authenticationMethod);
- }
- _sqlAuthLogger.LogInfo(nameof(SqlAuthenticationProviderManager), methodName, $"Added auth provider {GetProviderType(provider)}, overriding existed provider {GetProviderType(oldProvider)} for authentication {authenticationMethod}.");
- return provider;
- });
+
+ Instance._sqlAuthLogger.LogInfo(nameof(SqlAuthenticationProviderManager), methodName, $"Added auth provider {GetProviderType(provider)}, overriding existed provider {GetProviderType(oldProvider)} for authentication {authenticationMethod}.");
+ return provider;
+ });
return true;
}
@@ -216,7 +295,7 @@ public bool SetProvider(SqlAuthenticationMethod authenticationMethod, SqlAuthent
///
///
///
- private static T FetchConfigurationSection(string name)
+ private static T? FetchConfigurationSection(string name) where T : class
{
Type t = typeof(T);
@@ -265,14 +344,13 @@ private static SqlAuthenticationMethod AuthenticationEnumFromString(string authe
}
}
- private static string GetProviderType(SqlAuthenticationProvider provider)
+ private static string GetProviderType(SqlAuthenticationProvider? provider)
{
- if (provider == null)
+ if (provider is null)
{
return "null";
}
-
- return provider.GetType().FullName;
+ return provider.GetType().FullName ?? "unknown";
}
}
@@ -293,13 +371,13 @@ internal class SqlAuthenticationProviderConfigurationSection : ConfigurationSect
/// User-defined initializer.
///
[ConfigurationProperty("initializerType")]
- public string InitializerType => this["initializerType"] as string;
+ public string InitializerType => this["initializerType"] as string ?? string.Empty;
///
/// Application Client Id
///
[ConfigurationProperty("applicationClientId", IsRequired = false)]
- public string ApplicationClientId => this["applicationClientId"] as string;
+ public string ApplicationClientId => this["applicationClientId"] as string ?? string.Empty;
}
///
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationToken.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationToken.cs
deleted file mode 100644
index c405cac2cb..0000000000
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationToken.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Text;
-
-namespace Microsoft.Data.SqlClient
-{
- ///
- public class SqlAuthenticationToken
- {
- ///
- public DateTimeOffset ExpiresOn { get; }
-
- ///
- public string AccessToken { get; }
-
- ///
- public SqlAuthenticationToken(string accessToken, DateTimeOffset expiresOn)
- {
- if (string.IsNullOrEmpty(accessToken))
- {
- throw SQL.ParameterCannotBeEmpty("AccessToken");
- }
-
- AccessToken = accessToken;
- ExpiresOn = expiresOn;
- }
-
- ///
- /// Constructor.
- ///
- internal SqlAuthenticationToken(byte[] accessToken, DateTimeOffset expiresOn)
- : this(AccessTokenStringFromBytes(accessToken), expiresOn) { }
-
- ///
- /// Convert to driver's internal token class.
- ///
- internal SqlFedAuthToken ToSqlFedAuthToken()
- {
- var tokenBytes = AccessTokenBytesFromString(AccessToken);
- return new SqlFedAuthToken
- {
- accessToken = tokenBytes,
- dataLen = (uint)tokenBytes.Length,
- expirationFileTime = ExpiresOn.ToFileTime()
- };
- }
-
- ///
- /// Convert token bytes to string.
- ///
- internal static string AccessTokenStringFromBytes(byte[] bytes)
- {
- return Encoding.Unicode.GetString(bytes);
- }
-
- ///
- /// Convert token string to bytes.
- ///
- internal static byte[] AccessTokenBytesFromString(string token)
- {
- return Encoding.Unicode.GetBytes(token);
- }
- }
-}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlErrorCollection.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlErrorCollection.cs
index 4684747627..fe20d0d2e5 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlErrorCollection.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlErrorCollection.cs
@@ -45,6 +45,11 @@ internal SqlErrorCollection() { }
///
public IEnumerator GetEnumerator() => _errors.GetEnumerator();
- internal void Add(SqlError error) => _errors.Add(error);
+ // Append the error to our list, and return ourselves for chaining.
+ internal SqlErrorCollection Add(SqlError error)
+ {
+ _errors.Add(error);
+ return this;
+ }
}
}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlException.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlException.cs
index 80c810e748..dcaa8b55dd 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlException.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlException.cs
@@ -205,8 +205,6 @@ internal static SqlException CreateException(SqlErrorCollection errorCollection,
internal static SqlException CreateException(SqlErrorCollection errorCollection, string serverVersion, Guid conId, Exception innerException = null, SqlBatchCommand batchCommand = null)
{
- Debug.Assert(errorCollection != null && errorCollection.Count > 0, "no errorCollection?");
-
StringBuilder message = new();
for (int i = 0; i < errorCollection.Count; i++)
{
@@ -217,7 +215,11 @@ internal static SqlException CreateException(SqlErrorCollection errorCollection,
message.Append(errorCollection[i].Message);
}
- if (innerException == null && errorCollection[0].Win32ErrorCode != 0 && errorCollection[0].Win32ErrorCode != -1)
+ if (innerException is null &&
+ errorCollection is not null &&
+ errorCollection.Count > 0 &&
+ errorCollection[0].Win32ErrorCode != 0 &&
+ errorCollection[0].Win32ErrorCode != -1)
{
innerException = new Win32Exception(errorCollection[0].Win32ErrorCode);
}
@@ -230,7 +232,10 @@ internal static SqlException CreateException(SqlErrorCollection errorCollection,
exception.Data.Add("HelpLink.ProdVer", serverVersion);
}
exception.Data.Add("HelpLink.EvtSrc", "MSSQLServer");
- exception.Data.Add("HelpLink.EvtID", errorCollection[0].Number.ToString(CultureInfo.InvariantCulture));
+ if (errorCollection is not null && errorCollection.Count > 0)
+ {
+ exception.Data.Add("HelpLink.EvtID", errorCollection[0].Number.ToString(CultureInfo.InvariantCulture));
+ }
exception.Data.Add("HelpLink.BaseHelpUrl", "https://go.microsoft.com/fwlink");
exception.Data.Add("HelpLink.LinkId", "20476");
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs
index e13a77bd73..9b0361a008 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs
@@ -1382,17 +1382,6 @@ internal static Exception UnsupportedFeatureAndToken(SqlInternalConnectionTds in
return exc;
}
- internal static Exception Azure_ManagedIdentityException(string msg)
- {
- SqlErrorCollection errors = new SqlErrorCollection
- {
- new SqlError(0, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, null, msg, "", 0)
- };
- SqlException exc = SqlException.CreateException(errors, null);
- exc._doNotReconnect = true; // disable open retry logic on this error
- return exc;
- }
-
#region Always Encrypted Errors
#region Always Encrypted - Certificate Store Provider Errors
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs
index 53aaf8295b..1a77fbf19a 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs
@@ -1133,44 +1133,6 @@ public enum SqlCommandColumnEncryptionSetting
///
Disabled,
}
-
- ///
- public enum SqlAuthenticationMethod
- {
- ///
- NotSpecified = 0,
-
- ///
- SqlPassword,
-
- ///
- [Obsolete("ActiveDirectoryPassword is deprecated, use a more secure authentication method. See https://aka.ms/SqlClientEntraIDAuthentication for more details.")]
- ActiveDirectoryPassword,
-
- ///
- ActiveDirectoryIntegrated,
-
- ///
- ActiveDirectoryInteractive,
-
- ///
- ActiveDirectoryServicePrincipal,
-
- ///
- ActiveDirectoryDeviceCodeFlow,
-
- ///
- ActiveDirectoryManagedIdentity,
-
- ///
- ActiveDirectoryMSI,
-
- ///
- ActiveDirectoryDefault,
-
- ///
- ActiveDirectoryWorkloadIdentity
- }
// This enum indicates the state of TransparentNetworkIPResolution
// The first attempt when TNIR is on should be sequential. If the first attempt fails next attempts should be parallel.
internal enum TransparentNetworkResolutionState
@@ -1180,12 +1142,6 @@ internal enum TransparentNetworkResolutionState
ParallelMode
};
- internal class ActiveDirectoryAuthentication
- {
- internal const string AdoClientId = "2fd908ad-0664-4344-b9be-cd3e8b574c38";
- internal const string MSALGetAccessTokenFunctionName = "AcquireToken";
- }
-
// Fields in the first resultset of "sp_describe_parameter_encryption".
// We expect the server to return the fields in the resultset in the same order as mentioned below.
// If the server changes the below order, then transparent parameter encryption will break.
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParser.cs
index d88bf218f6..deb44f44b8 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParser.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParser.cs
@@ -4297,7 +4297,8 @@ private TdsOperationStatus TryProcessLoginAck(TdsParserStateObject stateObj, out
private TdsOperationStatus TryProcessFedAuthInfo(TdsParserStateObject stateObj, int tokenLen, out SqlFedAuthInfo sqlFedAuthInfo)
{
sqlFedAuthInfo = null;
- SqlFedAuthInfo tempFedAuthInfo = new SqlFedAuthInfo();
+ string spn = null;
+ string stsUrl = null;
// Skip reading token length, since it has already been read in caller
SqlClientEventSource.Log.TryAdvancedTraceEvent(" FEDAUTHINFO token stream length = {0}", tokenLen);
@@ -4390,15 +4391,15 @@ private TdsOperationStatus TryProcessFedAuthInfo(TdsParserStateObject stateObj,
}
SqlClientEventSource.Log.TryAdvancedTraceEvent(" FedAuthInfoData: {0}", data);
- // store data in tempFedAuthInfo
+ // Store data in temporaries.
switch ((TdsEnums.FedAuthInfoId)id)
{
case TdsEnums.FedAuthInfoId.Spn:
- tempFedAuthInfo.spn = data;
+ spn = data;
break;
case TdsEnums.FedAuthInfoId.Stsurl:
- tempFedAuthInfo.stsurl = data;
+ stsUrl = data;
break;
default:
@@ -4413,15 +4414,16 @@ private TdsOperationStatus TryProcessFedAuthInfo(TdsParserStateObject stateObj,
throw SQL.ParsingErrorLength(ParsingErrorState.FedAuthInfoLengthTooShortForData, tokenLen);
}
- SqlClientEventSource.Log.TryTraceEvent(" Processed FEDAUTHINFO token stream: {0}", tempFedAuthInfo);
- if (string.IsNullOrWhiteSpace(tempFedAuthInfo.stsurl) || string.IsNullOrWhiteSpace(tempFedAuthInfo.spn))
+ if (string.IsNullOrWhiteSpace(spn) || string.IsNullOrWhiteSpace(stsUrl))
{
// We should be receiving both stsurl and spn
SqlClientEventSource.Log.TryTraceEvent(" FEDAUTHINFO token stream does not contain both STSURL and SPN.");
throw SQL.ParsingError(ParsingErrorState.FedAuthInfoDoesNotContainStsurlAndSpn);
}
- sqlFedAuthInfo = tempFedAuthInfo;
+ sqlFedAuthInfo = new(spn, stsUrl);
+ SqlClientEventSource.Log.TryTraceEvent(" Processed FEDAUTHINFO token stream: {0}", sqlFedAuthInfo);
+
return TdsOperationStatus.Done;
}
@@ -9539,11 +9541,11 @@ private int ApplyFeatureExData(TdsEnums.FeatureExtension requestedFeatures,
internal void SendFedAuthToken(SqlFedAuthToken fedAuthToken)
{
Debug.Assert(fedAuthToken != null, "fedAuthToken cannot be null");
- Debug.Assert(fedAuthToken.accessToken != null, "fedAuthToken.accessToken cannot be null");
+ Debug.Assert(fedAuthToken.AccessToken != null, "fedAuthToken.AccessToken cannot be null");
SqlClientEventSource.Log.TryTraceEvent(" Sending federated authentication token");
_physicalStateObj._outputMessageType = TdsEnums.MT_FEDAUTH;
- byte[] accessToken = fedAuthToken.accessToken;
+ byte[] accessToken = fedAuthToken.AccessToken;
// Send total length (length of token plus 4 bytes for the token length field)
// If we were sending a nonce, this would include that length as well
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs
index 8f0bb915c0..16386e1d9d 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs
@@ -13,6 +13,7 @@
using System.Security;
using System.Security.Authentication;
using System.Text;
+using System.Text.Encodings;
using Microsoft.Data.Common;
using Microsoft.Data.Common.ConnectionString;
@@ -128,23 +129,53 @@ internal sealed class SqlLoginAck
internal uint tdsVersion;
}
+ #nullable enable
+
internal sealed class SqlFedAuthInfo
{
- internal string spn;
- internal string stsurl;
+ internal string Spn { get; }
+ internal string StsUrl { get; }
+
+ internal SqlFedAuthInfo(string spn, string stsurl)
+ {
+ Spn = spn;
+ StsUrl = stsurl;
+ }
+
public override string ToString()
{
- return $"STSURL: {stsurl}, SPN: {spn}";
+ return $"SPN: {Spn}, STSURL: {StsUrl}";
}
}
internal sealed class SqlFedAuthToken
{
- internal uint dataLen;
- internal byte[] accessToken;
- internal long expirationFileTime;
+ internal byte[] AccessToken { get; }
+ internal uint DataLen { get; }
+ internal long ExpirationFileTime { get; }
+
+ internal SqlFedAuthToken(
+ byte[] accessToken,
+ long expirationFileTime)
+ {
+ AccessToken = accessToken;
+ DataLen = (uint)AccessToken.Length;
+ ExpirationFileTime = expirationFileTime;
+ }
+
+ ///
+ /// Convert from a SqlAuthenticationToken.
+ ///
+ internal SqlFedAuthToken(SqlAuthenticationToken token)
+ {
+ AccessToken = Encoding.Unicode.GetBytes(token.AccessToken);
+ DataLen = (uint)AccessToken.Length;
+ ExpirationFileTime = token.ExpiresOn.ToFileTime();
+ }
}
+ #nullable disable
+
internal sealed class _SqlMetaData : SqlMetaDataPriv
{
[Flags]
diff --git a/src/Microsoft.Data.SqlClient/tests/CustomConfigurableRetryLogic/CustomRetryLogicProvider.csproj b/src/Microsoft.Data.SqlClient/tests/CustomConfigurableRetryLogic/CustomRetryLogicProvider.csproj
index 1b35e8f80d..f420579f9e 100644
--- a/src/Microsoft.Data.SqlClient/tests/CustomConfigurableRetryLogic/CustomRetryLogicProvider.csproj
+++ b/src/Microsoft.Data.SqlClient/tests/CustomConfigurableRetryLogic/CustomRetryLogicProvider.csproj
@@ -10,9 +10,15 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Microsoft.Data.SqlClient/tests/Directory.Build.props b/src/Microsoft.Data.SqlClient/tests/Directory.Build.props
index b470f899e1..a23f3f03a4 100644
--- a/src/Microsoft.Data.SqlClient/tests/Directory.Build.props
+++ b/src/Microsoft.Data.SqlClient/tests/Directory.Build.props
@@ -11,7 +11,6 @@
true
Debug;Release;
AnyCPU;x86;x64
- Project
diff --git a/src/Microsoft.Data.SqlClient/tests/Directory.Packages.props b/src/Microsoft.Data.SqlClient/tests/Directory.Packages.props
index db17cb1e48..f03010f23a 100644
--- a/src/Microsoft.Data.SqlClient/tests/Directory.Packages.props
+++ b/src/Microsoft.Data.SqlClient/tests/Directory.Packages.props
@@ -14,9 +14,4 @@
-
-
-
-
-
diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AADAuthenticationTests.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AADAuthenticationTests.cs
index f354e6f806..208ddacd92 100644
--- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AADAuthenticationTests.cs
+++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AADAuthenticationTests.cs
@@ -61,7 +61,7 @@ private void InvalidCombinationCheck(SqlCredential credential)
[Fact]
public async Task IsDummySqlAuthenticationProviderSetByDefault()
{
- var provider = SqlAuthenticationProvider.GetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive);
+ var provider = SqlAuthenticationProviderManager.GetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive);
Assert.NotNull(provider);
Assert.Equal(typeof(DummySqlAuthenticationProvider), provider.GetType());
@@ -75,24 +75,24 @@ public async Task IsDummySqlAuthenticationProviderSetByDefault()
public void CustomActiveDirectoryProviderTest()
{
SqlAuthenticationProvider authProvider = new ActiveDirectoryAuthenticationProvider(static (result) => Task.CompletedTask);
- SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, authProvider);
- Assert.Equal(authProvider, SqlAuthenticationProvider.GetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow));
+ SqlAuthenticationProviderManager.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, authProvider);
+ Assert.Same(authProvider, SqlAuthenticationProviderManager.GetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow));
}
[Fact]
public void CustomActiveDirectoryProviderTest_AppClientId()
{
SqlAuthenticationProvider authProvider = new ActiveDirectoryAuthenticationProvider(Guid.NewGuid().ToString());
- SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, authProvider);
- Assert.Equal(authProvider, SqlAuthenticationProvider.GetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow));
+ SqlAuthenticationProviderManager.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, authProvider);
+ Assert.Same(authProvider, SqlAuthenticationProviderManager.GetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow));
}
[Fact]
public void CustomActiveDirectoryProviderTest_AppClientId_DeviceFlowCallback()
{
SqlAuthenticationProvider authProvider = new ActiveDirectoryAuthenticationProvider(static (result) => Task.CompletedTask, Guid.NewGuid().ToString());
- SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, authProvider);
- Assert.Equal(authProvider, SqlAuthenticationProvider.GetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow));
+ SqlAuthenticationProviderManager.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, authProvider);
+ Assert.Same(authProvider, SqlAuthenticationProviderManager.GetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow));
}
}
}
diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.FunctionalTests.csproj b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.FunctionalTests.csproj
index 7f6d8abd2c..7c54891ff4 100644
--- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.FunctionalTests.csproj
+++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.FunctionalTests.csproj
@@ -111,6 +111,8 @@
+
+
Common
@@ -128,12 +130,31 @@
TDS
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
PreserveNewest
diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlAuthenticationProviderTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlAuthenticationProviderTest.cs
index 8168c26f8e..503b5468b9 100644
--- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlAuthenticationProviderTest.cs
+++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlAuthenticationProviderTest.cs
@@ -22,7 +22,7 @@ public class SqlAuthenticationProviderTest
[InlineData(SqlAuthenticationMethod.ActiveDirectoryWorkloadIdentity)]
public void DefaultAuthenticationProviders(SqlAuthenticationMethod method)
{
- Assert.IsType(SqlAuthenticationProvider.GetProvider(method));
+ Assert.IsType(SqlAuthenticationProviderManager.GetProvider(method));
}
#if NETFRAMEWORK
@@ -33,7 +33,7 @@ public void DefaultAuthenticationProviders(SqlAuthenticationMethod method)
[InlineData(SqlAuthenticationMethod.ActiveDirectoryInteractive)]
public void DefaultAuthenticationProviders_Interactive(SqlAuthenticationMethod method)
{
- Assert.IsType(SqlAuthenticationProvider.GetProvider(method));
+ Assert.IsType(SqlAuthenticationProviderManager.GetProvider(method));
}
#endif
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj
index fbaf55db72..3b46cce657 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj
@@ -303,6 +303,8 @@
+
+
Common
@@ -323,11 +325,32 @@
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -346,7 +369,6 @@
-
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs
index 608c34c977..1cb7ac6cbf 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs
@@ -8,7 +8,6 @@
using System.Threading;
using System.Threading.Tasks;
using Azure.Core;
-using Azure.Identity;
using Microsoft.Identity.Client;
using Xunit;
@@ -263,7 +262,7 @@ public static void TestADPasswordAuthentication()
public static void TestCustomProviderAuthentication()
{
#pragma warning disable 0618 // Type or member is obsolete
- SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryPassword, new CustomSqlAuthenticationProvider(DataTestUtility.ApplicationClientId));
+ SqlAuthenticationProviderManager.SetProvider(SqlAuthenticationMethod.ActiveDirectoryPassword, new CustomSqlAuthenticationProvider(DataTestUtility.ApplicationClientId));
#pragma warning restore 0618 // Type or member is obsolete
// Connect to Azure DB with password and retrieve user name using custom authentication provider
using (SqlConnection conn = new SqlConnection(DataTestUtility.AADPasswordConnectionString))
@@ -283,7 +282,7 @@ public static void TestCustomProviderAuthentication()
}
// Reset to driver internal provider.
#pragma warning disable 0618 // Type or member is obsolete
- SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryPassword, new ActiveDirectoryAuthenticationProvider(DataTestUtility.ApplicationClientId));
+ SqlAuthenticationProviderManager.SetProvider(SqlAuthenticationMethod.ActiveDirectoryPassword, new ActiveDirectoryAuthenticationProvider(DataTestUtility.ApplicationClientId));
#pragma warning restore 0618 // Type or member is obsolete
}
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataClassificationTest/DataClassificationTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataClassificationTest/DataClassificationTest.cs
index 3e7076d52d..9a6b4c7552 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataClassificationTest/DataClassificationTest.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataClassificationTest/DataClassificationTest.cs
@@ -25,7 +25,6 @@ public static void TestDataClassificationResultSetRank()
try
{
sqlConnection.Open();
- Assert.True(DataTestUtility.IsSupportedDataClassification());
CreateTable(sqlCommand);
AddSensitivity(sqlCommand, rankEnabled: true);
InsertData(sqlCommand);
@@ -48,7 +47,6 @@ public static void TestDataClassificationResultSet()
try
{
sqlConnection.Open();
- Assert.True(DataTestUtility.IsSupportedDataClassification());
CreateTable(sqlCommand);
AddSensitivity(sqlCommand);
InsertData(sqlCommand);
diff --git a/src/Microsoft.Data.SqlClient/tests/PerformanceTests/Microsoft.Data.SqlClient.PerformanceTests.csproj b/src/Microsoft.Data.SqlClient/tests/PerformanceTests/Microsoft.Data.SqlClient.PerformanceTests.csproj
index 24bcaab242..4b9a8d99f4 100644
--- a/src/Microsoft.Data.SqlClient/tests/PerformanceTests/Microsoft.Data.SqlClient.PerformanceTests.csproj
+++ b/src/Microsoft.Data.SqlClient/tests/PerformanceTests/Microsoft.Data.SqlClient.PerformanceTests.csproj
@@ -15,12 +15,22 @@
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs
index bf47188b34..72ed2e63a0 100644
--- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs
+++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs
@@ -45,6 +45,9 @@ public class Config
public static Config Load(string configPath = @"config.json")
{
+ // Allow an override of the config path via an environment variable.
+ configPath = Environment.GetEnvironmentVariable("MDS_TEST_CONFIG") ?? configPath;
+
try
{
using (StreamReader r = new StreamReader(configPath))
diff --git a/tools/props/Versions.props b/tools/props/Versions.props
index d82a04cce2..51e16268a7 100644
--- a/tools/props/Versions.props
+++ b/tools/props/Versions.props
@@ -57,19 +57,12 @@
$(MdsPackageVersion)
+
+
+
7.0.0
$(AkvVersionDefault).$(BuildNumber)-dev
-
-
- $(MdsPackageVersion)
diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec
index 2e15d7076d..57cf2ae755 100644
--- a/tools/specs/Microsoft.Data.SqlClient.nuspec
+++ b/tools/specs/Microsoft.Data.SqlClient.nuspec
@@ -29,8 +29,6 @@
sqlclient microsoft.data.sqlclient
-
-
@@ -46,8 +44,6 @@
-
-
@@ -61,8 +57,6 @@
-
-
@@ -76,8 +70,6 @@
-
-
diff --git a/tools/specs/Microsoft.SqlServer.Server.nuspec b/tools/specs/Microsoft.SqlServer.Server.nuspec
index eec275b292..df75137b92 100644
--- a/tools/specs/Microsoft.SqlServer.Server.nuspec
+++ b/tools/specs/Microsoft.SqlServer.Server.nuspec
@@ -36,15 +36,20 @@ Microsoft.SqlServer.Server.Format
+
+
-
-
-
+
+
+
-
-
-
+
+
+
diff --git a/tools/targets/GenerateSqlServerPackage.targets b/tools/targets/GenerateSqlServerPackage.targets
index ea6655dcee..909c0da6e0 100644
--- a/tools/targets/GenerateSqlServerPackage.targets
+++ b/tools/targets/GenerateSqlServerPackage.targets
@@ -8,6 +8,6 @@
-
+
diff --git a/tools/targets/GenerateThisAssemblyCs.targets b/tools/targets/GenerateThisAssemblyCs.targets
index 6230af8ae7..86e896013c 100644
--- a/tools/targets/GenerateThisAssemblyCs.targets
+++ b/tools/targets/GenerateThisAssemblyCs.targets
@@ -4,18 +4,31 @@
+
+
+
+[assembly: System.CLSCompliant(true)]
+
+
+
+ System
+
+
-[assembly: System.CLSCompliant(true)]
-namespace System
+$(ThisAssemblyClsCompliantContent)
+namespace $(ThisAssemblyNamespace)
{
-internal static class ThisAssembly
-{
-internal const string InformationalVersion = "$(AssemblyFileVersion)"%3B
-internal const string NuGetPackageVersion = "$(Version)"%3B
-}
+ internal static class ThisAssembly
+ {
+ internal const string InformationalVersion = "$(AssemblyFileVersion)"%3B
+ internal const string NuGetPackageVersion = "$(Version)"%3B
+ }
}
From bdd1c133bf17f96d521d587fd63e26c4ee81de69 Mon Sep 17 00:00:00 2001
From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com>
Date: Tue, 21 Oct 2025 12:25:24 -0300
Subject: [PATCH 04/16] - Added obsolete Get/Set Provider methods on
SqlAuthenticationProvider to maintain API for now. - Addressed review
comments.
---
.../build-abstractions-package-ci-stage.yml | 2 +-
.../stages/build-azure-package-ci-stage.yml | 2 +-
src/Directory.Packages.props | 2 +-
.../doc/SqlAuthenticationMethod.xml | 5 +
.../doc/SqlAuthenticationParameters.xml | 17 +-
.../doc/SqlAuthenticationProvider.xml | 34 +++-
.../SqlAuthenticationProviderException.xml | 5 +
.../doc/SqlAuthenticationToken.xml | 7 +-
.../Abstractions/src/Abstractions.csproj | 9 +-
.../src/SqlAuthenticationParameters.cs | 12 +-
.../src/SqlAuthenticationProvider.cs | 26 ++-
.../src/SqlAuthenticationProviderInternal.cs | 150 ++++++++++++++++++
.../test/Abstractions.Test.csproj | 2 +-
.../test/SqlAuthenticationMethodTest.cs | 4 +
.../test/SqlAuthenticationParametersTest.cs | 10 ++
.../SqlAuthenticationProviderExceptionTest.cs | 8 +-
.../test/SqlAuthenticationProviderTest.cs | 43 +++++
.../test/SqlAuthenticationTokenTest.cs | 8 +-
.../ActiveDirectoryAuthenticationProvider.xml | 7 +-
.../ActiveDirectoryAuthenticationProvider.cs | 12 +-
.../Azure/src/AuthenticationException.cs | 4 +
.../Azure/src/Azure.csproj | 9 +-
.../Azure/test/Azure.Test.csproj | 2 +-
.../SqlClient/SqlInternalConnectionTds.cs | 2 +-
.../SqlClient/SqlInternalConnectionTds.cs | 2 +-
.../SqlAuthenticationParametersBuilder.cs | 10 +-
.../SqlAuthenticationProviderManager.cs | 11 +-
.../FunctionalTests/AADAuthenticationTests.cs | 57 ++++++-
.../ConnectivityTests/AADConnectionTest.cs | 2 +-
29 files changed, 425 insertions(+), 39 deletions(-)
create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProviderInternal.cs
create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationProviderTest.cs
diff --git a/eng/pipelines/stages/build-abstractions-package-ci-stage.yml b/eng/pipelines/stages/build-abstractions-package-ci-stage.yml
index 2a9268e737..0d84dc6ccb 100644
--- a/eng/pipelines/stages/build-abstractions-package-ci-stage.yml
+++ b/eng/pipelines/stages/build-abstractions-package-ci-stage.yml
@@ -85,7 +85,7 @@ stages:
vmImage: windows-latest
buildConfiguration: ${{ parameters.buildConfiguration }}
netRuntimes: [net8.0, net9.0]
- netFrameworkRuntimes: [net462, net47, net471, net472, net48, net481]
+ netFrameworkRuntimes: [net462]
verbosity: ${{ parameters.verbosity }}
# ------------------------------------------------------------------------
diff --git a/eng/pipelines/stages/build-azure-package-ci-stage.yml b/eng/pipelines/stages/build-azure-package-ci-stage.yml
index c88a2f5db5..90beb30caf 100644
--- a/eng/pipelines/stages/build-azure-package-ci-stage.yml
+++ b/eng/pipelines/stages/build-azure-package-ci-stage.yml
@@ -118,7 +118,7 @@ stages:
buildConfiguration: ${{ parameters.buildConfiguration }}
displayNamePrefix: Win
jobNameSuffix: windows
- netFrameworkRuntimes: [net462, net47, net471, net472, net48, net481]
+ netFrameworkRuntimes: [net462]
netRuntimes: [net8.0, net9.0]
poolName: Azure Pipelines
referenceType: ${{ parameters.referenceType }}
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index 03ea8a9942..4d877d6deb 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -140,6 +140,6 @@
-
+
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationMethod.xml b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationMethod.xml
index cd15a65ec2..c804a8fb3a 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationMethod.xml
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationMethod.xml
@@ -1,3 +1,8 @@
+
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationParameters.xml b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationParameters.xml
index 759919e48f..dfc2ca27da 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationParameters.xml
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationParameters.xml
@@ -1,4 +1,9 @@
-
+
+
@@ -17,7 +22,7 @@
The user login name/ID, or null if not applicable.
The user password, or null if not applicable.
The connection ID.
- The connection timeout, in seconds.
+ The authentication timeout, in seconds.
Gets the authentication method.
@@ -51,8 +56,16 @@
Gets the connection ID.
The connection ID.
+
+ Gets the authentication timeout value.
+ The authentication timeout, in seconds.
+
Gets the connection timeout value.
+
+ This property is deprecated and will be removed in future versions. Use
+ AuthenticationTimeout instead.
+
The connection timeout, in seconds.
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationProvider.xml b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationProvider.xml
index 66c7f1a5bc..52cdba787a 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationProvider.xml
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationProvider.xml
@@ -1,4 +1,9 @@
-
+
+
Defines the core behavior of authentication providers and provides a base class for derived classes.
@@ -116,10 +121,33 @@
The authentication method.
- Acquires a security token from the authority.
- The Active Directory authentication parameters passed by the driver to authentication providers.
+ Acquires an access token from the authority.
+ The parameters passed to the provider by the driver.
If any errors occur.
Represents an asynchronous operation that returns the AD authentication token.
+
+ Gets an authentication provider by method.
+
+ This method is obsolete and will be removed in future versions. Use
+ the SqlAuthenticationProviderManager.GetProvider() method in the
+ Microsoft.Data.SqlClient package instead.
+
+ The authentication method.
+ The authentication provider or if not found.
+
+
+ Sets an authentication provider by method.
+
+ This method is obsolete and will be removed in future versions. Use
+ the SqlAuthenticationProviderManager.SetProvider() method in the
+ Microsoft.Data.SqlClient package instead.
+
+ The authentication method.
+ The authentication provider.
+
+ if the operation succeeded; otherwise, (for example, the existing provider disallows overriding).
+
+
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationProviderException.xml b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationProviderException.xml
index dbdf2966f9..648e4a7e2f 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationProviderException.xml
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationProviderException.xml
@@ -1,3 +1,8 @@
+
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationToken.xml b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationToken.xml
index 11ce14db28..4eb9a78f52 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationToken.xml
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationToken.xml
@@ -1,4 +1,9 @@
-
+
+
Represents an authentication token.
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj
index 802a80068e..c1725ee867 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj
@@ -42,8 +42,15 @@
<_Parameter1>true
+
+
+ CDP_BUILD_TYPE is a OneBranch governed pipeline variable.
+ -->
+
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationParameters.cs b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationParameters.cs
index c3d6dc4a2b..f0759fa94e 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationParameters.cs
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationParameters.cs
@@ -31,8 +31,14 @@ public sealed class SqlAuthenticationParameters
///
public string DatabaseName { get; }
+ ///
+ public int AuthenticationTimeout { get; }
+
///
- public int ConnectionTimeout { get; }
+ [Obsolete(
+ "This property is deprecated and will be removed in future versions. " +
+ "Use AuthenticationTimeout instead.")]
+ public int ConnectionTimeout { get { return AuthenticationTimeout; } }
///
public SqlAuthenticationParameters(
@@ -44,7 +50,7 @@ public SqlAuthenticationParameters(
string? userId,
string? password,
Guid connectionId,
- int connectionTimeout)
+ int authenticationTimeout)
{
AuthenticationMethod = authenticationMethod;
ServerName = serverName;
@@ -54,6 +60,6 @@ public SqlAuthenticationParameters(
UserId = userId;
Password = password;
ConnectionId = connectionId;
- ConnectionTimeout = connectionTimeout;
+ AuthenticationTimeout = authenticationTimeout;
}
}
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProvider.cs b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProvider.cs
index 36d9bce99e..20d76f4342 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProvider.cs
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProvider.cs
@@ -5,7 +5,7 @@
namespace Microsoft.Data.SqlClient;
///
-public abstract class SqlAuthenticationProvider
+public abstract partial class SqlAuthenticationProvider
{
///
public virtual void BeforeLoad(SqlAuthenticationMethod authenticationMethod) { }
@@ -18,4 +18,28 @@ public virtual void BeforeUnload(SqlAuthenticationMethod authenticationMethod) {
///
public abstract Task AcquireTokenAsync(SqlAuthenticationParameters parameters);
+
+
+ ///
+ [Obsolete(
+ "This method is deprecated and will be removed in future versions. " +
+ "Use SqlAuthenticationProviderManager.GetProvider() from the " +
+ "Microsoft.Data.SqlClient package instead.")]
+ public static SqlAuthenticationProvider? GetProvider(
+ SqlAuthenticationMethod authenticationMethod)
+ {
+ return Internal.GetProvider(authenticationMethod);
+ }
+
+ ///
+ [Obsolete(
+ "This method is deprecated and will be removed in future versions. " +
+ "Use SqlAuthenticationProviderManager.SetProvider() from the " +
+ "Microsoft.Data.SqlClient package instead.")]
+ public static bool SetProvider(
+ SqlAuthenticationMethod authenticationMethod,
+ SqlAuthenticationProvider provider)
+ {
+ return Internal.SetProvider(authenticationMethod, provider);
+ }
}
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProviderInternal.cs b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProviderInternal.cs
new file mode 100644
index 0000000000..8db0c86c54
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProviderInternal.cs
@@ -0,0 +1,150 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Reflection;
+
+namespace Microsoft.Data.SqlClient;
+
+///
+public abstract partial class SqlAuthenticationProvider
+{
+ private static class Internal
+ {
+ private static MethodInfo? _getProvider = null;
+ private static MethodInfo? _setProvider = null;
+
+ static Internal()
+ {
+ // If the MDS package is present, load its
+ // SqlAuthenticationProviderManager class and get/set methods.
+ const string assemblyName = "Microsoft.Data.SqlClient";
+
+ try
+ {
+ // Try to load the MDS assembly.
+ var assembly = Assembly.Load(assemblyName);
+
+ if (assembly is null)
+ {
+ // TODO: Logging
+ // SqlClientEventSource.Log.TryTraceEvent(
+ // nameof(SqlAuthenticationProviderManager) +
+ // $": Azure extension assembly={assemblyName} not found; " +
+ // "no default provider installed");
+ return;
+ }
+
+ // TODO(ADO-39845): Verify the assembly is signed by us?
+
+ // TODO: Logging
+ // SqlClientEventSource.Log.TryTraceEvent(
+ // nameof(SqlAuthenticationProviderManager) +
+ // $": Azure extension assembly={assemblyName} found; " +
+ // "attempting to set as default provider for all Active " +
+ // "Directory authentication methods");
+
+ // Look for the manager class.
+ const string className = "Microsoft.Data.SqlClient.SqlAuthenticationProviderManager";
+ var manager = assembly.GetType(className);
+
+ if (manager is null)
+ {
+ // TODO: Logging
+ // SqlClientEventSource.Log.TryTraceEvent(
+ // nameof(SqlAuthenticationProviderManager) +
+ // $": Azure extension does not contain class={className}; " +
+ // "no default Active Directory provider installed");
+
+ return;
+ }
+
+ // Get handles to the get/set static methods.
+ _getProvider = manager.GetMethod(
+ "GetProvider",
+ BindingFlags.Public | BindingFlags.Static);
+ _setProvider = manager.GetMethod(
+ "SetProvider",
+ BindingFlags.Public | BindingFlags.Static);
+
+ // TODO: Logging
+ // SqlClientEventSource.Log.TryTraceEvent(
+ // nameof(SqlAuthenticationProviderManager) +
+ // $": Azure extension class={className} installed as " +
+ // "provider for all Active Directory authentication methods");
+ }
+ // All of these exceptions mean we couldn't find the get/set
+ // methods.
+ catch (Exception ex)
+ when (ex is AmbiguousMatchException ||
+ ex is BadImageFormatException ||
+ ex is FileLoadException ||
+ ex is FileNotFoundException)
+ {
+ // SqlClientEventSource.Log.TryTraceEvent(
+ // nameof(SqlAuthenticationProviderManager) +
+ // $": Azure extension assembly={assemblyName} not found or " +
+ // "not usable; no default provider installed; " +
+ // $"{ex.GetType().Name}: {ex.Message}");
+ }
+ // Any other exceptions are fatal.
+ }
+
+ public static SqlAuthenticationProvider? GetProvider(
+ SqlAuthenticationMethod authenticationMethod)
+ {
+ if (_getProvider is null)
+ {
+ return null;
+ }
+
+ try
+ {
+ return _getProvider.Invoke(null, [authenticationMethod])
+ as SqlAuthenticationProvider;
+ }
+ catch (Exception ex)
+ when (ex is InvalidOperationException ||
+ ex is MemberAccessException ||
+ ex is MethodAccessException ||
+ ex is NotSupportedException ||
+ ex is TargetInvocationException)
+ {
+ return null;
+ }
+ }
+
+ public static bool SetProvider(
+ SqlAuthenticationMethod authenticationMethod,
+ SqlAuthenticationProvider provider)
+ {
+ if (_setProvider is null)
+ {
+ return false;
+ }
+
+ try
+ {
+ bool? result =
+ _setProvider.Invoke(null, [authenticationMethod, provider])
+ as bool?;
+
+ if (!result.HasValue)
+ {
+ return false;
+ }
+
+ return result.Value;
+ }
+ catch (Exception ex)
+ when (ex is InvalidOperationException ||
+ ex is MemberAccessException ||
+ ex is MethodAccessException ||
+ ex is NotSupportedException ||
+ ex is TargetInvocationException)
+ {
+ return false;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj
index 118b215737..ddc3ae6fad 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj
@@ -1,7 +1,7 @@
- net462;net47;net471;net472;net48;net481;net8.0;net9.0
+ net462;net8.0;net9.0
enable
enable
false
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationMethodTest.cs b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationMethodTest.cs
index da8739ac9f..434ad94177 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationMethodTest.cs
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationMethodTest.cs
@@ -1,3 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
namespace Microsoft.Data.SqlClient.Extensions.Abstractions.Test;
public class SqlAuthenticationMethodTest
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationParametersTest.cs b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationParametersTest.cs
index 87a442f798..feecbbd831 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationParametersTest.cs
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationParametersTest.cs
@@ -1,3 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
namespace Microsoft.Data.SqlClient.Extensions.Abstractions.Test;
public class SqlAuthenticationParametersTest
@@ -36,7 +40,10 @@ public void Constructor_WithNulls()
Assert.Null(parameters.UserId);
Assert.Null(parameters.Password);
Assert.Equal(id, parameters.ConnectionId);
+ Assert.Equal(timeout, parameters.AuthenticationTimeout);
+ #pragma warning disable CS0618 // Type or member is obsolete
Assert.Equal(timeout, parameters.ConnectionTimeout);
+ #pragma warning restore CS0618 // Type or member is obsolete
}
// Verify that the properties are set correctly when nullable arguments
@@ -73,6 +80,9 @@ public void Constructor_WithoutNulls()
Assert.Equal(user, parameters.UserId);
Assert.Equal(pass, parameters.Password);
Assert.Equal(id, parameters.ConnectionId);
+ Assert.Equal(timeout, parameters.AuthenticationTimeout);
+ #pragma warning disable CS0618 // Type or member is obsolete
Assert.Equal(timeout, parameters.ConnectionTimeout);
+ #pragma warning restore CS0618 // Type or member is obsolete
}
}
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationProviderExceptionTest.cs b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationProviderExceptionTest.cs
index 13a9798dc7..d8a5ecaa03 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationProviderExceptionTest.cs
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationProviderExceptionTest.cs
@@ -1,3 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
namespace Microsoft.Data.SqlClient.Extensions.Abstractions.Test;
public class SqlAuthenticationProviderExceptionTest
@@ -57,7 +61,7 @@ public void Constructor_Minimal_WithCausedBy()
Assert.False(ex.ShouldRetry);
Assert.Equal(0, ex.RetryPeriod);
Assert.Equal(message, ex.Message);
- Assert.Equal(causedBy, ex.InnerException);
+ Assert.Same(causedBy, ex.InnerException);
}
// Verify that all properties are set correctly. The causedBy argument is
@@ -112,6 +116,6 @@ public void Constructor_All_WithCausedBy()
Assert.Equal(shouldRetry, ex.ShouldRetry);
Assert.Equal(retryPeriod, ex.RetryPeriod);
Assert.Equal(message, ex.Message);
- Assert.Equal(causedBy, ex.InnerException);
+ Assert.Same(causedBy, ex.InnerException);
}
}
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationProviderTest.cs b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationProviderTest.cs
new file mode 100644
index 0000000000..950f03ca8b
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationProviderTest.cs
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.Data.SqlClient.Extensions.Abstractions.Test;
+
+public class SqlAuthenticationProviderTest
+{
+ [Fact]
+ public void GetProvider()
+ {
+ #pragma warning disable CS0618 // Type or member is obsolete
+ Assert.Null(
+ SqlAuthenticationProvider.GetProvider(
+ SqlAuthenticationMethod.ActiveDirectoryInteractive));
+ #pragma warning restore CS0618 // Type or member is obsolete
+ }
+
+ private sealed class Provider : SqlAuthenticationProvider
+ {
+ public override bool IsSupported(
+ SqlAuthenticationMethod authenticationMethod)
+ {
+ return true;
+ }
+
+ public override Task AcquireTokenAsync(SqlAuthenticationParameters parameters)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ [Fact]
+ public void SetProvider()
+ {
+ #pragma warning disable CS0618 // Type or member is obsolete
+ Assert.False(
+ SqlAuthenticationProvider.SetProvider(
+ SqlAuthenticationMethod.ActiveDirectoryIntegrated,
+ new Provider()));
+ #pragma warning restore CS0618 // Type or member is obsolete
+ }
+}
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationTokenTest.cs b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationTokenTest.cs
index d90d25407b..6c419576db 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationTokenTest.cs
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationTokenTest.cs
@@ -1,3 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
namespace Microsoft.Data.SqlClient.Extensions.Abstractions.Test;
public class SqlAuthenticationTokenTest
@@ -22,7 +26,7 @@ public void Constructor_NullToken()
string? token = null;
var expiry = DateTimeOffset.UtcNow.AddHours(1);
- var ex = Assert.Throws(() =>
+ var ex = Assert.ThrowsAny(() =>
{
new SqlAuthenticationToken(token!, expiry);
});
@@ -37,7 +41,7 @@ public void Constructor_EmptyToken()
string token = string.Empty;
var expiry = DateTimeOffset.UtcNow.AddHours(1);
- var ex = Assert.Throws(() =>
+ var ex = Assert.ThrowsAny(() =>
{
new SqlAuthenticationToken(token, expiry);
});
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Azure/doc/ActiveDirectoryAuthenticationProvider.xml b/src/Microsoft.Data.SqlClient.Extensions/Azure/doc/ActiveDirectoryAuthenticationProvider.xml
index a940011eb3..c680d0dd8b 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Azure/doc/ActiveDirectoryAuthenticationProvider.xml
+++ b/src/Microsoft.Data.SqlClient.Extensions/Azure/doc/ActiveDirectoryAuthenticationProvider.xml
@@ -1,4 +1,9 @@
-
+
+
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Azure/src/ActiveDirectoryAuthenticationProvider.cs b/src/Microsoft.Data.SqlClient.Extensions/Azure/src/ActiveDirectoryAuthenticationProvider.cs
index 7208fe3b06..cd9e2704bc 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Azure/src/ActiveDirectoryAuthenticationProvider.cs
+++ b/src/Microsoft.Data.SqlClient.Extensions/Azure/src/ActiveDirectoryAuthenticationProvider.cs
@@ -125,18 +125,18 @@ public override async Task AcquireTokenAsync(SqlAuthenti
{
using CancellationTokenSource cts = new();
- // Use Connection timeout value to cancel token acquire request
- // after certain period of time.
- if (parameters.ConnectionTimeout > 0)
+ // Use the authentication timeout value to cancel token acquire
+ // request after certain period of time.
+ if (parameters.AuthenticationTimeout > 0)
{
// Safely convert to milliseconds.
- if (int.MaxValue / 1000 > parameters.ConnectionTimeout)
+ if (int.MaxValue / 1000 > parameters.AuthenticationTimeout)
{
cts.CancelAfter(int.MaxValue);
}
else
{
- cts.CancelAfter(parameters.ConnectionTimeout * 1000);
+ cts.CancelAfter(parameters.AuthenticationTimeout * 1000);
}
}
@@ -291,7 +291,9 @@ previousPw is byte[] previousPwBytes &&
if (result == null)
{
+ #pragma warning disable CS0618 // Type or member is obsolete
result = await app.AcquireTokenByUsernamePassword(scopes, parameters.UserId, parameters.Password)
+ #pragma warning disable CS0618 // Type or member is obsolete
.WithCorrelationId(parameters.ConnectionId)
.ExecuteAsync(cancellationToken: cts.Token)
.ConfigureAwait(false);
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Azure/src/AuthenticationException.cs b/src/Microsoft.Data.SqlClient.Extensions/Azure/src/AuthenticationException.cs
index 55a7abf2d2..b8d1eb5b5c 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Azure/src/AuthenticationException.cs
+++ b/src/Microsoft.Data.SqlClient.Extensions/Azure/src/AuthenticationException.cs
@@ -1,3 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
namespace Microsoft.Data.SqlClient.Extensions.Azure;
// This exception is used internally by authentication providers to signal
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Azure/src/Azure.csproj b/src/Microsoft.Data.SqlClient.Extensions/Azure/src/Azure.csproj
index 52f2966c2b..50d70d3228 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Azure/src/Azure.csproj
+++ b/src/Microsoft.Data.SqlClient.Extensions/Azure/src/Azure.csproj
@@ -42,8 +42,15 @@
<_Parameter1>true
+
+
+ CDP_BUILD_TYPE is a OneBranch governed pipeline variable.
+ -->
+
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Azure/test/Azure.Test.csproj b/src/Microsoft.Data.SqlClient.Extensions/Azure/test/Azure.Test.csproj
index f391b7393c..72459b823e 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Azure/test/Azure.Test.csproj
+++ b/src/Microsoft.Data.SqlClient.Extensions/Azure/test/Azure.Test.csproj
@@ -1,7 +1,7 @@
- net462;net47;net471;net472;net48;net481;net8.0;net9.0
+ net462;net8.0;net9.0
enable
enable
false
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
index 983f36693c..f7cb28bc57 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
@@ -2519,7 +2519,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
serverName: ConnectionOptions.DataSource,
databaseName: ConnectionOptions.InitialCatalog)
.WithConnectionId(_clientConnectionId)
- .WithConnectionTimeout(ConnectionOptions.ConnectTimeout);
+ .WithAuthenticationTimeout(ConnectionOptions.ConnectTimeout);
switch (ConnectionOptions.Authentication)
{
case SqlAuthenticationMethod.ActiveDirectoryIntegrated:
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
index bc6e9c13de..5585690736 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
@@ -2574,7 +2574,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
serverName: ConnectionOptions.DataSource,
databaseName: ConnectionOptions.InitialCatalog)
.WithConnectionId(_clientConnectionId)
- .WithConnectionTimeout(ConnectionOptions.ConnectTimeout);
+ .WithAuthenticationTimeout(ConnectionOptions.ConnectTimeout);
switch (ConnectionOptions.Authentication)
{
case SqlAuthenticationMethod.ActiveDirectoryIntegrated:
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationParametersBuilder.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationParametersBuilder.cs
index 5fdd7f020e..d95427d052 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationParametersBuilder.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationParametersBuilder.cs
@@ -19,7 +19,7 @@ internal sealed class SqlAuthenticationParametersBuilder
private string _userId;
private string _password;
private Guid _connectionId = Guid.NewGuid();
- private int _connectionTimeout = ADP.DefaultConnectionTimeout;
+ private int _authenticationTimeout = ADP.DefaultConnectionTimeout;
///
/// Implicitly converts to .
@@ -35,7 +35,7 @@ public static implicit operator SqlAuthenticationParameters(SqlAuthenticationPar
userId: builder._userId,
password: builder._password,
connectionId: builder._connectionId,
- connectionTimeout: builder._connectionTimeout);
+ authenticationTimeout: builder._authenticationTimeout);
}
///
@@ -84,11 +84,11 @@ public SqlAuthenticationParametersBuilder WithConnectionId(Guid connectionId)
}
///
- /// Set connection timeout.
+ /// Set authentication timeout.
///
- public SqlAuthenticationParametersBuilder WithConnectionTimeout(int timeout)
+ public SqlAuthenticationParametersBuilder WithAuthenticationTimeout(int timeout)
{
- _connectionTimeout = timeout;
+ _authenticationTimeout = timeout;
return this;
}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.cs
index ab3614a751..e2db8ed6fc 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.cs
@@ -58,7 +58,16 @@ static SqlAuthenticationProviderManager()
// Try to load our Azure extension.
var assembly = Assembly.Load(assemblyName);
- // TODO: Verify the assembly is signed by us?
+ if (assembly is null)
+ {
+ SqlClientEventSource.Log.TryTraceEvent(
+ nameof(SqlAuthenticationProviderManager) +
+ $": Azure extension assembly={assemblyName} not found; " +
+ "no default Active Directory provider installed");
+ return;
+ }
+
+ // TODO(ADO-39845): Verify the assembly is signed by us?
SqlClientEventSource.Log.TryTraceEvent(
nameof(SqlAuthenticationProviderManager) +
diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AADAuthenticationTests.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AADAuthenticationTests.cs
index 208ddacd92..3215c17049 100644
--- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AADAuthenticationTests.cs
+++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AADAuthenticationTests.cs
@@ -49,8 +49,8 @@ private void InvalidCombinationCheck(SqlCredential credential)
Assert.Throws(() => connection.AccessToken = "SampleAccessToken");
}
}
-
- #if NETFRAMEWORK
+
+#if NETFRAMEWORK
// This test is only valid for .NET Framework
///
@@ -69,7 +69,58 @@ public async Task IsDummySqlAuthenticationProviderSetByDefault()
var token = await provider.AcquireTokenAsync(null);
Assert.Equal(token.AccessToken, DummySqlAuthenticationProvider.DUMMY_TOKEN_STR);
}
- #endif
+#endif
+
+ // Verify that we can get and set providers via both the Abstractions
+ // package and Manager class interchangeably.
+ //
+ // This tests the dynamic assembly loading code in the Abstractions
+ // package.
+ [Fact]
+ public void Abstractions_And_Manager_GetSetProvider_Equivalent()
+ {
+ // Set via Manager, get via both.
+ DummySqlAuthenticationProvider provider1 = new();
+
+ Assert.True(
+ SqlAuthenticationProviderManager.SetProvider(
+ SqlAuthenticationMethod.ActiveDirectoryInteractive,
+ provider1));
+
+ Assert.Same(
+ provider1,
+ SqlAuthenticationProviderManager.GetProvider(
+ SqlAuthenticationMethod.ActiveDirectoryInteractive));
+
+ Assert.Same(
+ provider1,
+ #pragma warning disable CS0618 // Type or member is obsolete
+ SqlAuthenticationProvider.GetProvider(
+ SqlAuthenticationMethod.ActiveDirectoryInteractive));
+ #pragma warning restore CS0618 // Type or member is obsolete
+
+ // Set via Abstractions, get via both.
+ DummySqlAuthenticationProvider provider2 = new();
+
+ Assert.True(
+ #pragma warning disable CS0618 // Type or member is obsolete
+ SqlAuthenticationProvider.SetProvider(
+ SqlAuthenticationMethod.ActiveDirectoryInteractive,
+ provider2));
+ #pragma warning restore CS0618 // Type or member is obsolete
+
+ Assert.Same(
+ provider2,
+ SqlAuthenticationProviderManager.GetProvider(
+ SqlAuthenticationMethod.ActiveDirectoryInteractive));
+
+ Assert.Same(
+ provider2,
+ #pragma warning disable CS0618 // Type or member is obsolete
+ SqlAuthenticationProvider.GetProvider(
+ SqlAuthenticationMethod.ActiveDirectoryInteractive));
+ #pragma warning restore CS0618 // Type or member is obsolete
+ }
[Fact]
public void CustomActiveDirectoryProviderTest()
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs
index 1cb7ac6cbf..2221148d59 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs
@@ -34,7 +34,7 @@ public override async Task AcquireTokenAsync(SqlAuthenti
_ = parameters.ConnectionId;
var cts = new CancellationTokenSource();
- cts.CancelAfter(parameters.ConnectionTimeout * 1000);
+ cts.CancelAfter(parameters.AuthenticationTimeout * 1000);
string[] scopes = new string[] { scope };
SecureString password = new SecureString();
From 522e5a45830cf91f864e3123cb07f865772187c9 Mon Sep 17 00:00:00 2001
From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com>
Date: Tue, 21 Oct 2025 13:34:36 -0300
Subject: [PATCH 05/16] - Fixed dummy auth provider tests on .NET Framework. -
Added some config improvements to xUnit runners.
---
.../FunctionalTests/AADAuthenticationTests.cs | 15 ++++++-----
.../DummySqlAuthenticationProvider.cs | 25 +++++++++++++++++--
.../tests/FunctionalTests/app.config | 1 +
.../xunit.runner.json | 5 +++-
4 files changed, 37 insertions(+), 9 deletions(-)
diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AADAuthenticationTests.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AADAuthenticationTests.cs
index 3215c17049..83f6dc921f 100644
--- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AADAuthenticationTests.cs
+++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AADAuthenticationTests.cs
@@ -84,19 +84,22 @@ public void Abstractions_And_Manager_GetSetProvider_Equivalent()
Assert.True(
SqlAuthenticationProviderManager.SetProvider(
- SqlAuthenticationMethod.ActiveDirectoryInteractive,
+ // GOTCHA: On .NET Framework, the dummy provider is already
+ // registered as the default provider for Interactive, so we
+ // use DeviceCodeFlow instead.
+ SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow,
provider1));
Assert.Same(
provider1,
SqlAuthenticationProviderManager.GetProvider(
- SqlAuthenticationMethod.ActiveDirectoryInteractive));
+ SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow));
Assert.Same(
provider1,
#pragma warning disable CS0618 // Type or member is obsolete
SqlAuthenticationProvider.GetProvider(
- SqlAuthenticationMethod.ActiveDirectoryInteractive));
+ SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow));
#pragma warning restore CS0618 // Type or member is obsolete
// Set via Abstractions, get via both.
@@ -105,20 +108,20 @@ public void Abstractions_And_Manager_GetSetProvider_Equivalent()
Assert.True(
#pragma warning disable CS0618 // Type or member is obsolete
SqlAuthenticationProvider.SetProvider(
- SqlAuthenticationMethod.ActiveDirectoryInteractive,
+ SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow,
provider2));
#pragma warning restore CS0618 // Type or member is obsolete
Assert.Same(
provider2,
SqlAuthenticationProviderManager.GetProvider(
- SqlAuthenticationMethod.ActiveDirectoryInteractive));
+ SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow));
Assert.Same(
provider2,
#pragma warning disable CS0618 // Type or member is obsolete
SqlAuthenticationProvider.GetProvider(
- SqlAuthenticationMethod.ActiveDirectoryInteractive));
+ SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow));
#pragma warning restore CS0618 // Type or member is obsolete
}
diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/DataCommon/DummySqlAuthenticationProvider.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/DataCommon/DummySqlAuthenticationProvider.cs
index bb5e2e2e52..b924b33e5e 100644
--- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/DataCommon/DummySqlAuthenticationProvider.cs
+++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/DataCommon/DummySqlAuthenticationProvider.cs
@@ -20,8 +20,29 @@ public class DummySqlAuthenticationProvider : SqlAuthenticationProvider
public override Task AcquireTokenAsync(SqlAuthenticationParameters parameters)
=> Task.FromResult(new SqlAuthenticationToken(DUMMY_TOKEN_STR, new DateTimeOffset(DateTime.Now.AddHours(2))));
- // Supported authentication modes don't matter for dummy test, but added to demonstrate config file usage.
+ // We support two methods:
+ //
+ // ActiveDirectoryInteractive:
+ // We are installed as a default provider for this method by the
+ // app.config file for .NET Framework only. Default providers
+ // cannot be overridden by application code.
+ //
+ // ActiveDirectoryDeviceCodeFlow:
+ // We support this method, but are not installed as a default
+ // provider for it. This allows the tests to explicitly set us
+ // as the provider.
+ //
public override bool IsSupported(SqlAuthenticationMethod authenticationMethod)
- => authenticationMethod == SqlAuthenticationMethod.ActiveDirectoryInteractive;
+ {
+ switch (authenticationMethod)
+ {
+ case SqlAuthenticationMethod.ActiveDirectoryInteractive:
+ case SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow:
+ return true;
+
+ default:
+ return false;
+ }
+ }
}
}
diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/app.config b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/app.config
index fb7f63f65f..9fc08c65a7 100644
--- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/app.config
+++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/app.config
@@ -7,6 +7,7 @@
+
diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/xunit.runner.json b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/xunit.runner.json
index 8faf1479cc..42755c93ec 100644
--- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/xunit.runner.json
+++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/xunit.runner.json
@@ -2,5 +2,8 @@
"$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
"diagnosticMessages": true,
"parallelizeAssembly": true,
- "shadowCopy": false
+ "shadowCopy": false,
+ "printMaxEnumerableLength": 0,
+ "printMaxStringLength": 0,
+ "showLiveOutput": false
}
From d4c681a16ea46329d7d6c7601ccb8719005da16d Mon Sep 17 00:00:00 2001
From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com>
Date: Tue, 21 Oct 2025 17:05:51 -0300
Subject: [PATCH 06/16] - Attempt to fix sensitive diagnostics tests having
trouble with CI-SqlClient-Package runs.
---
.../TracingTests/DiagnosticTest.cs | 61 +++++++++----------
1 file changed, 30 insertions(+), 31 deletions(-)
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs
index 29272784a7..462c780634 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs
@@ -246,9 +246,9 @@ public void ExecuteXmlReaderErrorTest()
[Fact]
public void ExecuteScalarAsyncTest()
{
- RemoteExecutor.Invoke(() =>
+ RemoteExecutor.Invoke(async () =>
{
- CollectStatisticsDiagnosticsAsync(async connectionString =>
+ await CollectStatisticsDiagnosticsAsync(async connectionString =>
{
#if NET
await using (SqlConnection conn = new SqlConnection(connectionString))
@@ -264,7 +264,7 @@ public void ExecuteScalarAsyncTest()
conn.Open();
await cmd.ExecuteScalarAsync();
}
- }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]).Wait();
+ }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]);
return RemoteExecutor.SuccessExitCode;
}).Dispose();
}
@@ -272,9 +272,9 @@ public void ExecuteScalarAsyncTest()
[Fact]
public void ExecuteScalarAsyncErrorTest()
{
- RemoteExecutor.Invoke(() =>
+ RemoteExecutor.Invoke(async () =>
{
- CollectStatisticsDiagnosticsAsync(async connectionString =>
+ await CollectStatisticsDiagnosticsAsync(async connectionString =>
{
#if NET
await using (SqlConnection conn = new SqlConnection(connectionString))
@@ -290,7 +290,7 @@ public void ExecuteScalarAsyncErrorTest()
conn.Open();
await Assert.ThrowsAsync(() => cmd.ExecuteScalarAsync());
}
- }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandError, WriteConnectionCloseBefore, WriteConnectionCloseAfter]).Wait();
+ }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandError, WriteConnectionCloseBefore, WriteConnectionCloseAfter]);
return RemoteExecutor.SuccessExitCode;
}).Dispose();
}
@@ -298,9 +298,9 @@ public void ExecuteScalarAsyncErrorTest()
[Fact]
public void ExecuteNonQueryAsyncTest()
{
- RemoteExecutor.Invoke(() =>
+ RemoteExecutor.Invoke(async () =>
{
- CollectStatisticsDiagnosticsAsync(async connectionString =>
+ await CollectStatisticsDiagnosticsAsync(async connectionString =>
{
#if NET
await using (SqlConnection conn = new SqlConnection(connectionString))
@@ -316,7 +316,7 @@ public void ExecuteNonQueryAsyncTest()
conn.Open();
await cmd.ExecuteNonQueryAsync();
}
- }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]).Wait();
+ }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]);
return RemoteExecutor.SuccessExitCode;
}).Dispose();
}
@@ -324,9 +324,9 @@ public void ExecuteNonQueryAsyncTest()
[Fact]
public void ExecuteNonQueryAsyncErrorTest()
{
- RemoteExecutor.Invoke(() =>
+ RemoteExecutor.Invoke(async () =>
{
- CollectStatisticsDiagnosticsAsync(async connectionString =>
+ await CollectStatisticsDiagnosticsAsync(async connectionString =>
{
#if NET
await using (SqlConnection conn = new SqlConnection(connectionString))
@@ -342,7 +342,7 @@ public void ExecuteNonQueryAsyncErrorTest()
conn.Open();
await Assert.ThrowsAsync(() => cmd.ExecuteNonQueryAsync());
}
- }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandError, WriteConnectionCloseBefore, WriteConnectionCloseAfter]).Wait();
+ }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandError, WriteConnectionCloseBefore, WriteConnectionCloseAfter]);
return RemoteExecutor.SuccessExitCode;
}).Dispose();
}
@@ -350,9 +350,9 @@ public void ExecuteNonQueryAsyncErrorTest()
[Fact]
public void ExecuteReaderAsyncTest()
{
- RemoteExecutor.Invoke(() =>
+ RemoteExecutor.Invoke(async () =>
{
- CollectStatisticsDiagnosticsAsync(async connectionString =>
+ await CollectStatisticsDiagnosticsAsync(async connectionString =>
{
#if NET
await using (SqlConnection conn = new SqlConnection(connectionString))
@@ -372,7 +372,7 @@ public void ExecuteReaderAsyncTest()
// Read to end
}
}
- }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]).Wait();
+ }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]);
return RemoteExecutor.SuccessExitCode;
}).Dispose();
}
@@ -380,9 +380,9 @@ public void ExecuteReaderAsyncTest()
[Fact]
public void ExecuteReaderAsyncErrorTest()
{
- RemoteExecutor.Invoke(() =>
+ RemoteExecutor.Invoke(async () =>
{
- CollectStatisticsDiagnosticsAsync(async connectionString =>
+ await CollectStatisticsDiagnosticsAsync(async connectionString =>
{
#if NET
await using (SqlConnection conn = new SqlConnection(connectionString))
@@ -399,7 +399,7 @@ public void ExecuteReaderAsyncErrorTest()
// @TODO: TestTdsServer should not throw on ExecuteReader, should throw on reader.Read
await Assert.ThrowsAsync(() => cmd.ExecuteReaderAsync());
}
- }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandError, WriteConnectionCloseBefore, WriteConnectionCloseAfter]).Wait();
+ }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandError, WriteConnectionCloseBefore, WriteConnectionCloseAfter]);
return RemoteExecutor.SuccessExitCode;
}).Dispose();
}
@@ -409,9 +409,9 @@ public void ExecuteReaderAsyncErrorTest()
public void ExecuteXmlReaderAsyncTest()
{
// @TODO: TestTdsServer does not handle xml reader, so connect to a real server as a workaround
- RemoteExecutor.Invoke(() =>
+ RemoteExecutor.Invoke(async () =>
{
- CollectStatisticsDiagnosticsAsync(async _ =>
+ await CollectStatisticsDiagnosticsAsync(async _ =>
{
#if NET
await using (SqlConnection conn = new SqlConnection(DataTestUtility.TCPConnectionString))
@@ -431,7 +431,7 @@ public void ExecuteXmlReaderAsyncTest()
// Read to end
}
}
- }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]).Wait();
+ }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]);
return RemoteExecutor.SuccessExitCode;
}).Dispose();
}
@@ -440,10 +440,9 @@ public void ExecuteXmlReaderAsyncTest()
public void ExecuteXmlReaderAsyncErrorTest()
{
// @TODO: TestTdsServer does not handle xml reader, so connect to a real server as a workaround
- RemoteExecutor.Invoke(() =>
+ RemoteExecutor.Invoke(async () =>
{
-
- CollectStatisticsDiagnosticsAsync(async _ =>
+ await CollectStatisticsDiagnosticsAsync(async _ =>
{
#if NET
await using (SqlConnection conn = new SqlConnection(DataTestUtility.TCPConnectionString))
@@ -466,7 +465,7 @@ public void ExecuteXmlReaderAsyncErrorTest()
XmlReader reader = await cmd.ExecuteXmlReaderAsync();
await Assert.ThrowsAsync(() => reader.ReadAsync());
}
- }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]).Wait();
+ }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]);
return RemoteExecutor.SuccessExitCode;
}).Dispose();
}
@@ -506,9 +505,9 @@ public void ConnectionOpenErrorTest()
[Fact]
public void ConnectionOpenAsyncTest()
{
- RemoteExecutor.Invoke(() =>
+ RemoteExecutor.Invoke(async () =>
{
- CollectStatisticsDiagnosticsAsync(async connectionString =>
+ await CollectStatisticsDiagnosticsAsync(async connectionString =>
{
#if NET
await using (SqlConnection sqlConnection = new SqlConnection(connectionString))
@@ -518,7 +517,7 @@ public void ConnectionOpenAsyncTest()
{
await sqlConnection.OpenAsync();
}
- }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]).Wait();
+ }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]);
return RemoteExecutor.SuccessExitCode;
}).Dispose();
}
@@ -526,9 +525,9 @@ public void ConnectionOpenAsyncTest()
[Fact]
public void ConnectionOpenAsyncErrorTest()
{
- RemoteExecutor.Invoke(() =>
+ RemoteExecutor.Invoke(async () =>
{
- CollectStatisticsDiagnosticsAsync(async _ =>
+ await CollectStatisticsDiagnosticsAsync(async _ =>
{
#if NET
await using (SqlConnection sqlConnection = new SqlConnection(BadConnectionString))
@@ -538,7 +537,7 @@ public void ConnectionOpenAsyncErrorTest()
{
await Assert.ThrowsAsync(() => sqlConnection.OpenAsync());
}
- }, [WriteConnectionOpenBefore, WriteConnectionOpenError]).Wait();
+ }, [WriteConnectionOpenBefore, WriteConnectionOpenError]);
return RemoteExecutor.SuccessExitCode;
}).Dispose();
}
From 807bfa702da4c681047dbdda235cb5754a4610b1 Mon Sep 17 00:00:00 2001
From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com>
Date: Wed, 22 Oct 2025 09:38:44 -0300
Subject: [PATCH 07/16] - Replaced Console output with xUnit output to avoid
confusing interleaved output.
---
.../TracingTests/DiagnosticTest.cs | 44 ++++++++++++-------
1 file changed, 27 insertions(+), 17 deletions(-)
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs
index 462c780634..4c9d16e297 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs
@@ -14,11 +14,14 @@
using Microsoft.SqlServer.TDS.Servers;
using Microsoft.SqlServer.TDS.SQLBatch;
using Xunit;
+using Xunit.Abstractions;
using System.Runtime.CompilerServices;
using System;
using System.Data;
using Microsoft.DotNet.RemoteExecutor;
+#nullable enable
+
namespace Microsoft.Data.SqlClient.ManualTesting.Tests
{
public class DiagnosticTest
@@ -35,6 +38,13 @@ public class DiagnosticTest
private const string WriteConnectionCloseAfter = "Microsoft.Data.SqlClient.WriteConnectionCloseAfter";
private const string WriteConnectionCloseError = "Microsoft.Data.SqlClient.WriteConnectionCloseError";
+ private readonly ITestOutputHelper _output;
+
+ public DiagnosticTest(ITestOutputHelper output)
+ {
+ _output = output;
+ }
+
[Fact]
public void ExecuteScalarTest()
{
@@ -542,7 +552,7 @@ await CollectStatisticsDiagnosticsAsync(async _ =>
}).Dispose();
}
- private static void CollectStatisticsDiagnostics(Action sqlOperation, string[] expectedDiagnostics, [CallerMemberName] string methodName = "")
+ private void CollectStatisticsDiagnostics(Action sqlOperation, string[] expectedDiagnostics, [CallerMemberName] string methodName = "")
{
bool statsLogged = false;
bool operationHasError = false;
@@ -730,12 +740,12 @@ private static void CollectStatisticsDiagnostics(Action sqlOperation, st
using (DiagnosticListener.AllListeners.Subscribe(diagnosticListenerObserver))
{
- Console.WriteLine(string.Format("Test: {0} Enabled Listeners", methodName));
+ _output.WriteLine(string.Format("Test: {0} Enabled Listeners", methodName));
using (var server = new TdsServer(new DiagnosticsQueryEngine(), new TdsServerArguments()))
{
server.Start(methodName);
- Console.WriteLine(string.Format("Test: {0} Started Server", methodName));
+ _output.WriteLine(string.Format("Test: {0} Started Server", methodName));
var connectionString = new SqlConnectionStringBuilder
{
@@ -745,7 +755,7 @@ private static void CollectStatisticsDiagnostics(Action sqlOperation, st
sqlOperation(connectionString);
- Console.WriteLine(string.Format("Test: {0} SqlOperation Successful", methodName));
+ _output.WriteLine(string.Format("Test: {0} SqlOperation Successful", methodName));
Assert.True(statsLogged);
@@ -755,14 +765,14 @@ private static void CollectStatisticsDiagnostics(Action sqlOperation, st
Assert.True(diagnosticListenerObserver.HasReceivedDiagnostic(expected), $"Missing diagnostic '{expected}'");
}
- Console.WriteLine(string.Format("Test: {0} Listeners Disabled", methodName));
+ _output.WriteLine(string.Format("Test: {0} Listeners Disabled", methodName));
}
- Console.WriteLine(string.Format("Test: {0} Server Disposed", methodName));
+ _output.WriteLine(string.Format("Test: {0} Server Disposed", methodName));
}
- Console.WriteLine(string.Format("Test: {0} Listeners Disposed Successfully", methodName));
+ _output.WriteLine(string.Format("Test: {0} Listeners Disposed Successfully", methodName));
}
- private static async Task CollectStatisticsDiagnosticsAsync(Func sqlOperation, string[] expectedDiagnostics, [CallerMemberName] string methodName = "")
+ private async Task CollectStatisticsDiagnosticsAsync(Func sqlOperation, string[] expectedDiagnostics, [CallerMemberName] string methodName = "")
{
bool statsLogged = false;
bool operationHasError = false;
@@ -934,11 +944,11 @@ private static async Task CollectStatisticsDiagnosticsAsync(Func s
diagnosticListenerObserver.Enable();
using (DiagnosticListener.AllListeners.Subscribe(diagnosticListenerObserver))
{
- Console.WriteLine(string.Format("Test: {0} Enabled Listeners", methodName));
+ _output.WriteLine(string.Format("Test: {0} Enabled Listeners", methodName));
using (var server = new TdsServer(new DiagnosticsQueryEngine(), new TdsServerArguments()))
{
server.Start(methodName);
- Console.WriteLine(string.Format("Test: {0} Started Server", methodName));
+ _output.WriteLine(string.Format("Test: {0} Started Server", methodName));
var connectionString = new SqlConnectionStringBuilder
{
@@ -947,7 +957,7 @@ private static async Task CollectStatisticsDiagnosticsAsync(Func s
}.ConnectionString;
await sqlOperation(connectionString);
- Console.WriteLine(string.Format("Test: {0} SqlOperation Successful", methodName));
+ _output.WriteLine(string.Format("Test: {0} SqlOperation Successful", methodName));
Assert.True(statsLogged);
@@ -957,20 +967,20 @@ private static async Task CollectStatisticsDiagnosticsAsync(Func s
Assert.True(diagnosticListenerObserver.HasReceivedDiagnostic(expected), $"Missing diagnostic '{expected}'");
}
- Console.WriteLine(string.Format("Test: {0} Listeners Disabled", methodName));
+ _output.WriteLine(string.Format("Test: {0} Listeners Disabled", methodName));
}
- Console.WriteLine(string.Format("Test: {0} Server Disposed", methodName));
+ _output.WriteLine(string.Format("Test: {0} Server Disposed", methodName));
}
- Console.WriteLine(string.Format("Test: {0} Listeners Disposed Successfully", methodName));
+ _output.WriteLine(string.Format("Test: {0} Listeners Disposed Successfully", methodName));
}
private static T GetPropertyValueFromType(object obj, string propName)
{
Type type = obj.GetType();
- PropertyInfo pi = type.GetRuntimeProperty(propName);
+ PropertyInfo? pi = type.GetRuntimeProperty(propName);
- var propertyValue = pi.GetValue(obj);
- return (T)propertyValue;
+ var propertyValue = pi?.GetValue(obj);
+ return (T)propertyValue!;
}
}
From 39d2d10aff9f9abed7cc9bce7070eee68b9b3a91 Mon Sep 17 00:00:00 2001
From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com>
Date: Wed, 22 Oct 2025 11:45:33 -0300
Subject: [PATCH 08/16] Revert "- Replaced Console output with xUnit output to
avoid confusing interleaved output."
This reverts commit 807bfa702da4c681047dbdda235cb5754a4610b1.
---
.../TracingTests/DiagnosticTest.cs | 44 +++++++------------
1 file changed, 17 insertions(+), 27 deletions(-)
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs
index 4c9d16e297..462c780634 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs
@@ -14,14 +14,11 @@
using Microsoft.SqlServer.TDS.Servers;
using Microsoft.SqlServer.TDS.SQLBatch;
using Xunit;
-using Xunit.Abstractions;
using System.Runtime.CompilerServices;
using System;
using System.Data;
using Microsoft.DotNet.RemoteExecutor;
-#nullable enable
-
namespace Microsoft.Data.SqlClient.ManualTesting.Tests
{
public class DiagnosticTest
@@ -38,13 +35,6 @@ public class DiagnosticTest
private const string WriteConnectionCloseAfter = "Microsoft.Data.SqlClient.WriteConnectionCloseAfter";
private const string WriteConnectionCloseError = "Microsoft.Data.SqlClient.WriteConnectionCloseError";
- private readonly ITestOutputHelper _output;
-
- public DiagnosticTest(ITestOutputHelper output)
- {
- _output = output;
- }
-
[Fact]
public void ExecuteScalarTest()
{
@@ -552,7 +542,7 @@ await CollectStatisticsDiagnosticsAsync(async _ =>
}).Dispose();
}
- private void CollectStatisticsDiagnostics(Action sqlOperation, string[] expectedDiagnostics, [CallerMemberName] string methodName = "")
+ private static void CollectStatisticsDiagnostics(Action sqlOperation, string[] expectedDiagnostics, [CallerMemberName] string methodName = "")
{
bool statsLogged = false;
bool operationHasError = false;
@@ -740,12 +730,12 @@ private void CollectStatisticsDiagnostics(Action sqlOperation, string[]
using (DiagnosticListener.AllListeners.Subscribe(diagnosticListenerObserver))
{
- _output.WriteLine(string.Format("Test: {0} Enabled Listeners", methodName));
+ Console.WriteLine(string.Format("Test: {0} Enabled Listeners", methodName));
using (var server = new TdsServer(new DiagnosticsQueryEngine(), new TdsServerArguments()))
{
server.Start(methodName);
- _output.WriteLine(string.Format("Test: {0} Started Server", methodName));
+ Console.WriteLine(string.Format("Test: {0} Started Server", methodName));
var connectionString = new SqlConnectionStringBuilder
{
@@ -755,7 +745,7 @@ private void CollectStatisticsDiagnostics(Action sqlOperation, string[]
sqlOperation(connectionString);
- _output.WriteLine(string.Format("Test: {0} SqlOperation Successful", methodName));
+ Console.WriteLine(string.Format("Test: {0} SqlOperation Successful", methodName));
Assert.True(statsLogged);
@@ -765,14 +755,14 @@ private void CollectStatisticsDiagnostics(Action sqlOperation, string[]
Assert.True(diagnosticListenerObserver.HasReceivedDiagnostic(expected), $"Missing diagnostic '{expected}'");
}
- _output.WriteLine(string.Format("Test: {0} Listeners Disabled", methodName));
+ Console.WriteLine(string.Format("Test: {0} Listeners Disabled", methodName));
}
- _output.WriteLine(string.Format("Test: {0} Server Disposed", methodName));
+ Console.WriteLine(string.Format("Test: {0} Server Disposed", methodName));
}
- _output.WriteLine(string.Format("Test: {0} Listeners Disposed Successfully", methodName));
+ Console.WriteLine(string.Format("Test: {0} Listeners Disposed Successfully", methodName));
}
- private async Task CollectStatisticsDiagnosticsAsync(Func sqlOperation, string[] expectedDiagnostics, [CallerMemberName] string methodName = "")
+ private static async Task CollectStatisticsDiagnosticsAsync(Func sqlOperation, string[] expectedDiagnostics, [CallerMemberName] string methodName = "")
{
bool statsLogged = false;
bool operationHasError = false;
@@ -944,11 +934,11 @@ private async Task CollectStatisticsDiagnosticsAsync(Func sqlOpera
diagnosticListenerObserver.Enable();
using (DiagnosticListener.AllListeners.Subscribe(diagnosticListenerObserver))
{
- _output.WriteLine(string.Format("Test: {0} Enabled Listeners", methodName));
+ Console.WriteLine(string.Format("Test: {0} Enabled Listeners", methodName));
using (var server = new TdsServer(new DiagnosticsQueryEngine(), new TdsServerArguments()))
{
server.Start(methodName);
- _output.WriteLine(string.Format("Test: {0} Started Server", methodName));
+ Console.WriteLine(string.Format("Test: {0} Started Server", methodName));
var connectionString = new SqlConnectionStringBuilder
{
@@ -957,7 +947,7 @@ private async Task CollectStatisticsDiagnosticsAsync(Func sqlOpera
}.ConnectionString;
await sqlOperation(connectionString);
- _output.WriteLine(string.Format("Test: {0} SqlOperation Successful", methodName));
+ Console.WriteLine(string.Format("Test: {0} SqlOperation Successful", methodName));
Assert.True(statsLogged);
@@ -967,20 +957,20 @@ private async Task CollectStatisticsDiagnosticsAsync(Func sqlOpera
Assert.True(diagnosticListenerObserver.HasReceivedDiagnostic(expected), $"Missing diagnostic '{expected}'");
}
- _output.WriteLine(string.Format("Test: {0} Listeners Disabled", methodName));
+ Console.WriteLine(string.Format("Test: {0} Listeners Disabled", methodName));
}
- _output.WriteLine(string.Format("Test: {0} Server Disposed", methodName));
+ Console.WriteLine(string.Format("Test: {0} Server Disposed", methodName));
}
- _output.WriteLine(string.Format("Test: {0} Listeners Disposed Successfully", methodName));
+ Console.WriteLine(string.Format("Test: {0} Listeners Disposed Successfully", methodName));
}
private static T GetPropertyValueFromType(object obj, string propName)
{
Type type = obj.GetType();
- PropertyInfo? pi = type.GetRuntimeProperty(propName);
+ PropertyInfo pi = type.GetRuntimeProperty(propName);
- var propertyValue = pi?.GetValue(obj);
- return (T)propertyValue!;
+ var propertyValue = pi.GetValue(obj);
+ return (T)propertyValue;
}
}
From 278c87279373f5805a9ae157806d27fd6a21d011 Mon Sep 17 00:00:00 2001
From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com>
Date: Wed, 22 Oct 2025 11:45:50 -0300
Subject: [PATCH 09/16] Revert "- Attempt to fix sensitive diagnostics tests
having trouble with CI-SqlClient-Package runs."
This reverts commit d4c681a16ea46329d7d6c7601ccb8719005da16d.
---
.../TracingTests/DiagnosticTest.cs | 61 ++++++++++---------
1 file changed, 31 insertions(+), 30 deletions(-)
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs
index 462c780634..29272784a7 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs
@@ -246,9 +246,9 @@ public void ExecuteXmlReaderErrorTest()
[Fact]
public void ExecuteScalarAsyncTest()
{
- RemoteExecutor.Invoke(async () =>
+ RemoteExecutor.Invoke(() =>
{
- await CollectStatisticsDiagnosticsAsync(async connectionString =>
+ CollectStatisticsDiagnosticsAsync(async connectionString =>
{
#if NET
await using (SqlConnection conn = new SqlConnection(connectionString))
@@ -264,7 +264,7 @@ await CollectStatisticsDiagnosticsAsync(async connectionString =>
conn.Open();
await cmd.ExecuteScalarAsync();
}
- }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]);
+ }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]).Wait();
return RemoteExecutor.SuccessExitCode;
}).Dispose();
}
@@ -272,9 +272,9 @@ await CollectStatisticsDiagnosticsAsync(async connectionString =>
[Fact]
public void ExecuteScalarAsyncErrorTest()
{
- RemoteExecutor.Invoke(async () =>
+ RemoteExecutor.Invoke(() =>
{
- await CollectStatisticsDiagnosticsAsync(async connectionString =>
+ CollectStatisticsDiagnosticsAsync(async connectionString =>
{
#if NET
await using (SqlConnection conn = new SqlConnection(connectionString))
@@ -290,7 +290,7 @@ await CollectStatisticsDiagnosticsAsync(async connectionString =>
conn.Open();
await Assert.ThrowsAsync(() => cmd.ExecuteScalarAsync());
}
- }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandError, WriteConnectionCloseBefore, WriteConnectionCloseAfter]);
+ }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandError, WriteConnectionCloseBefore, WriteConnectionCloseAfter]).Wait();
return RemoteExecutor.SuccessExitCode;
}).Dispose();
}
@@ -298,9 +298,9 @@ await CollectStatisticsDiagnosticsAsync(async connectionString =>
[Fact]
public void ExecuteNonQueryAsyncTest()
{
- RemoteExecutor.Invoke(async () =>
+ RemoteExecutor.Invoke(() =>
{
- await CollectStatisticsDiagnosticsAsync(async connectionString =>
+ CollectStatisticsDiagnosticsAsync(async connectionString =>
{
#if NET
await using (SqlConnection conn = new SqlConnection(connectionString))
@@ -316,7 +316,7 @@ await CollectStatisticsDiagnosticsAsync(async connectionString =>
conn.Open();
await cmd.ExecuteNonQueryAsync();
}
- }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]);
+ }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]).Wait();
return RemoteExecutor.SuccessExitCode;
}).Dispose();
}
@@ -324,9 +324,9 @@ await CollectStatisticsDiagnosticsAsync(async connectionString =>
[Fact]
public void ExecuteNonQueryAsyncErrorTest()
{
- RemoteExecutor.Invoke(async () =>
+ RemoteExecutor.Invoke(() =>
{
- await CollectStatisticsDiagnosticsAsync(async connectionString =>
+ CollectStatisticsDiagnosticsAsync(async connectionString =>
{
#if NET
await using (SqlConnection conn = new SqlConnection(connectionString))
@@ -342,7 +342,7 @@ await CollectStatisticsDiagnosticsAsync(async connectionString =>
conn.Open();
await Assert.ThrowsAsync(() => cmd.ExecuteNonQueryAsync());
}
- }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandError, WriteConnectionCloseBefore, WriteConnectionCloseAfter]);
+ }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandError, WriteConnectionCloseBefore, WriteConnectionCloseAfter]).Wait();
return RemoteExecutor.SuccessExitCode;
}).Dispose();
}
@@ -350,9 +350,9 @@ await CollectStatisticsDiagnosticsAsync(async connectionString =>
[Fact]
public void ExecuteReaderAsyncTest()
{
- RemoteExecutor.Invoke(async () =>
+ RemoteExecutor.Invoke(() =>
{
- await CollectStatisticsDiagnosticsAsync(async connectionString =>
+ CollectStatisticsDiagnosticsAsync(async connectionString =>
{
#if NET
await using (SqlConnection conn = new SqlConnection(connectionString))
@@ -372,7 +372,7 @@ await CollectStatisticsDiagnosticsAsync(async connectionString =>
// Read to end
}
}
- }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]);
+ }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]).Wait();
return RemoteExecutor.SuccessExitCode;
}).Dispose();
}
@@ -380,9 +380,9 @@ await CollectStatisticsDiagnosticsAsync(async connectionString =>
[Fact]
public void ExecuteReaderAsyncErrorTest()
{
- RemoteExecutor.Invoke(async () =>
+ RemoteExecutor.Invoke(() =>
{
- await CollectStatisticsDiagnosticsAsync(async connectionString =>
+ CollectStatisticsDiagnosticsAsync(async connectionString =>
{
#if NET
await using (SqlConnection conn = new SqlConnection(connectionString))
@@ -399,7 +399,7 @@ await CollectStatisticsDiagnosticsAsync(async connectionString =>
// @TODO: TestTdsServer should not throw on ExecuteReader, should throw on reader.Read
await Assert.ThrowsAsync(() => cmd.ExecuteReaderAsync());
}
- }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandError, WriteConnectionCloseBefore, WriteConnectionCloseAfter]);
+ }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandError, WriteConnectionCloseBefore, WriteConnectionCloseAfter]).Wait();
return RemoteExecutor.SuccessExitCode;
}).Dispose();
}
@@ -409,9 +409,9 @@ await CollectStatisticsDiagnosticsAsync(async connectionString =>
public void ExecuteXmlReaderAsyncTest()
{
// @TODO: TestTdsServer does not handle xml reader, so connect to a real server as a workaround
- RemoteExecutor.Invoke(async () =>
+ RemoteExecutor.Invoke(() =>
{
- await CollectStatisticsDiagnosticsAsync(async _ =>
+ CollectStatisticsDiagnosticsAsync(async _ =>
{
#if NET
await using (SqlConnection conn = new SqlConnection(DataTestUtility.TCPConnectionString))
@@ -431,7 +431,7 @@ await CollectStatisticsDiagnosticsAsync(async _ =>
// Read to end
}
}
- }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]);
+ }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]).Wait();
return RemoteExecutor.SuccessExitCode;
}).Dispose();
}
@@ -440,9 +440,10 @@ await CollectStatisticsDiagnosticsAsync(async _ =>
public void ExecuteXmlReaderAsyncErrorTest()
{
// @TODO: TestTdsServer does not handle xml reader, so connect to a real server as a workaround
- RemoteExecutor.Invoke(async () =>
+ RemoteExecutor.Invoke(() =>
{
- await CollectStatisticsDiagnosticsAsync(async _ =>
+
+ CollectStatisticsDiagnosticsAsync(async _ =>
{
#if NET
await using (SqlConnection conn = new SqlConnection(DataTestUtility.TCPConnectionString))
@@ -465,7 +466,7 @@ await CollectStatisticsDiagnosticsAsync(async _ =>
XmlReader reader = await cmd.ExecuteXmlReaderAsync();
await Assert.ThrowsAsync(() => reader.ReadAsync());
}
- }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]);
+ }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]).Wait();
return RemoteExecutor.SuccessExitCode;
}).Dispose();
}
@@ -505,9 +506,9 @@ public void ConnectionOpenErrorTest()
[Fact]
public void ConnectionOpenAsyncTest()
{
- RemoteExecutor.Invoke(async () =>
+ RemoteExecutor.Invoke(() =>
{
- await CollectStatisticsDiagnosticsAsync(async connectionString =>
+ CollectStatisticsDiagnosticsAsync(async connectionString =>
{
#if NET
await using (SqlConnection sqlConnection = new SqlConnection(connectionString))
@@ -517,7 +518,7 @@ await CollectStatisticsDiagnosticsAsync(async connectionString =>
{
await sqlConnection.OpenAsync();
}
- }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]);
+ }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]).Wait();
return RemoteExecutor.SuccessExitCode;
}).Dispose();
}
@@ -525,9 +526,9 @@ await CollectStatisticsDiagnosticsAsync(async connectionString =>
[Fact]
public void ConnectionOpenAsyncErrorTest()
{
- RemoteExecutor.Invoke(async () =>
+ RemoteExecutor.Invoke(() =>
{
- await CollectStatisticsDiagnosticsAsync(async _ =>
+ CollectStatisticsDiagnosticsAsync(async _ =>
{
#if NET
await using (SqlConnection sqlConnection = new SqlConnection(BadConnectionString))
@@ -537,7 +538,7 @@ await CollectStatisticsDiagnosticsAsync(async _ =>
{
await Assert.ThrowsAsync(() => sqlConnection.OpenAsync());
}
- }, [WriteConnectionOpenBefore, WriteConnectionOpenError]);
+ }, [WriteConnectionOpenBefore, WriteConnectionOpenError]).Wait();
return RemoteExecutor.SuccessExitCode;
}).Dispose();
}
From 5d5fa8440cefa1f2dc12fee9b82d3716008a56df Mon Sep 17 00:00:00 2001
From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com>
Date: Thu, 23 Oct 2025 12:03:48 -0300
Subject: [PATCH 10/16] - Addressed review comments. - Reverted
SqlAuthenticationParameters authenticationTimeout constructor argument to its
original name connectionTimeout and added docs explaining why.
---
.../doc/SqlAuthenticationParameters.xml | 16 +++++--
.../src/SqlAuthenticationMethod.cs | 1 +
.../src/SqlAuthenticationParameters.cs | 8 +++-
.../src/SqlAuthenticationProvider.cs | 2 +
.../src/SqlAuthenticationProviderInternal.cs | 19 +++++++-
.../test/Abstractions.Test.csproj | 1 +
.../test/SqlAuthenticationProviderTest.cs | 44 +++++++++++++------
.../Azure/test/Azure.Test.csproj | 1 +
.../SqlClient/SqlInternalConnectionTds.cs | 14 +++---
.../SqlClient/SqlInternalConnectionTds.cs | 12 ++---
10 files changed, 86 insertions(+), 32 deletions(-)
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationParameters.xml b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationParameters.xml
index dfc2ca27da..731fd316e7 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationParameters.xml
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/SqlAuthenticationParameters.xml
@@ -22,7 +22,18 @@ See the LICENSE file in the project root for more information.
The user login name/ID, or null if not applicable.
The user password, or null if not applicable.
The connection ID.
- The authentication timeout, in seconds.
+
+ The authentication timeout, in seconds. The overall connection timeout
+ is managed by the driver; this timeout only applies to authentication.
+
+ The value supplied here is used to set the AuthenticationTimeout
+ property.
+
+ Note that C# doesn't have a mechanism to deprecate constructor parameter
+ names in a backwards-compatible fashion, so we must keep the old name
+ (connectionTimeout) even though this parameter should really be named
+ authenticationTimeout
+
Gets the authentication method.
@@ -61,12 +72,11 @@ See the LICENSE file in the project root for more information.
The authentication timeout, in seconds.
- Gets the connection timeout value.
+ Gets the AuthenticationTimeout property value.
This property is deprecated and will be removed in future versions. Use
AuthenticationTimeout instead.
- The connection timeout, in seconds.
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationMethod.cs b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationMethod.cs
index a5b6708400..e5413110ae 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationMethod.cs
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationMethod.cs
@@ -15,6 +15,7 @@ public enum SqlAuthenticationMethod : int
///
[Obsolete("ActiveDirectoryPassword is deprecated, use a more secure authentication method. See https://aka.ms/SqlClientEntraIDAuthentication for more details.")]
+ // Obsoleted with MDS 7.0.0; to be removed at least 2 major versions later.
ActiveDirectoryPassword,
///
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationParameters.cs b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationParameters.cs
index f0759fa94e..04bd5aa939 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationParameters.cs
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationParameters.cs
@@ -38,6 +38,7 @@ public sealed class SqlAuthenticationParameters
[Obsolete(
"This property is deprecated and will be removed in future versions. " +
"Use AuthenticationTimeout instead.")]
+ // Obsoleted with MDS 7.0.0; to be removed at least 2 major versions later.
public int ConnectionTimeout { get { return AuthenticationTimeout; } }
///
@@ -50,7 +51,10 @@ public SqlAuthenticationParameters(
string? userId,
string? password,
Guid connectionId,
- int authenticationTimeout)
+ // This parameter should really be named authenticationTimeout, but we
+ // must keep the old name for backwards compatibility. The value
+ // supplied here is used to set the AuthenticationTimeout property.
+ int connectionTimeout)
{
AuthenticationMethod = authenticationMethod;
ServerName = serverName;
@@ -60,6 +64,6 @@ public SqlAuthenticationParameters(
UserId = userId;
Password = password;
ConnectionId = connectionId;
- AuthenticationTimeout = authenticationTimeout;
+ AuthenticationTimeout = connectionTimeout;
}
}
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProvider.cs b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProvider.cs
index 20d76f4342..c7df239f38 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProvider.cs
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProvider.cs
@@ -25,6 +25,7 @@ public virtual void BeforeUnload(SqlAuthenticationMethod authenticationMethod) {
"This method is deprecated and will be removed in future versions. " +
"Use SqlAuthenticationProviderManager.GetProvider() from the " +
"Microsoft.Data.SqlClient package instead.")]
+ // Obsoleted with MDS 7.0.0; to be removed at least 2 major versions later.
public static SqlAuthenticationProvider? GetProvider(
SqlAuthenticationMethod authenticationMethod)
{
@@ -36,6 +37,7 @@ public virtual void BeforeUnload(SqlAuthenticationMethod authenticationMethod) {
"This method is deprecated and will be removed in future versions. " +
"Use SqlAuthenticationProviderManager.SetProvider() from the " +
"Microsoft.Data.SqlClient package instead.")]
+ // Obsoleted with MDS 7.0.0; to be removed at least 2 major versions later.
public static bool SetProvider(
SqlAuthenticationMethod authenticationMethod,
SqlAuthenticationProvider provider)
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProviderInternal.cs b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProviderInternal.cs
index 8db0c86c54..2423b2e384 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProviderInternal.cs
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProviderInternal.cs
@@ -9,11 +9,17 @@ namespace Microsoft.Data.SqlClient;
///
public abstract partial class SqlAuthenticationProvider
{
+ // This class implements the obsolete static GetProvider and SetProvider
+ // methods by using reflection to call into the Microsoft.Data.SqlClient
+ // package's SqlAuthenticationProviderManager class, if that assembly is
+ // present.
private static class Internal
{
+ // Handles to the reflected get/set methods.
private static MethodInfo? _getProvider = null;
private static MethodInfo? _setProvider = null;
+ // Static construction performs the reflection lookups.
static Internal()
{
// If the MDS package is present, load its
@@ -66,7 +72,7 @@ static Internal()
_setProvider = manager.GetMethod(
"SetProvider",
BindingFlags.Public | BindingFlags.Static);
-
+
// TODO: Logging
// SqlClientEventSource.Log.TryTraceEvent(
// nameof(SqlAuthenticationProviderManager) +
@@ -90,6 +96,11 @@ ex is FileLoadException ||
// Any other exceptions are fatal.
}
+ // Call the reflected GetProvider method.
+ //
+ // Returns null if reflection failed or any exceptions occur.
+ // Otherwise, returns as the reflected method does.
+ //
public static SqlAuthenticationProvider? GetProvider(
SqlAuthenticationMethod authenticationMethod)
{
@@ -114,6 +125,12 @@ ex is NotSupportedException ||
}
}
+
+ // Call the reflected SetProvider method.
+ //
+ // Returns false if reflection failed, invocation fails, or any
+ // exceptions occur. Otherwise, returns as the reflected method does.
+ //
public static bool SetProvider(
SqlAuthenticationMethod authenticationMethod,
SqlAuthenticationProvider provider)
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj
index ddc3ae6fad..053804342e 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj
@@ -17,6 +17,7 @@
+
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationProviderTest.cs b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationProviderTest.cs
index 950f03ca8b..6dada18678 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationProviderTest.cs
+++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SqlAuthenticationProviderTest.cs
@@ -2,20 +2,15 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Reflection;
+
namespace Microsoft.Data.SqlClient.Extensions.Abstractions.Test;
+// Tests for the obsolete SqlAuthenticationProvider.GetProvider and SetProvider
+// methods.
public class SqlAuthenticationProviderTest
{
- [Fact]
- public void GetProvider()
- {
- #pragma warning disable CS0618 // Type or member is obsolete
- Assert.Null(
- SqlAuthenticationProvider.GetProvider(
- SqlAuthenticationMethod.ActiveDirectoryInteractive));
- #pragma warning restore CS0618 // Type or member is obsolete
- }
-
+ // A dummy provider that supports all authentication methods.
private sealed class Provider : SqlAuthenticationProvider
{
public override bool IsSupported(
@@ -24,20 +19,43 @@ public override bool IsSupported(
return true;
}
- public override Task AcquireTokenAsync(SqlAuthenticationParameters parameters)
+ public override Task AcquireTokenAsync(
+ SqlAuthenticationParameters parameters)
{
throw new NotImplementedException();
}
}
+ // Test that GetProvider fails predictably when the MDS assembly can't be
+ // found.
+ [Fact]
+ public void GetProvider()
+ {
+ // Confirm that the MDS assembly is indeed not present.
+ Assert.Throws(
+ () => Assembly.Load("Microsoft.Data.SqlClient"));
+
+#pragma warning disable CS0618 // Type or member is obsolete
+ Assert.Null(
+ SqlAuthenticationProvider.GetProvider(
+ SqlAuthenticationMethod.ActiveDirectoryInteractive));
+#pragma warning restore CS0618 // Type or member is obsolete
+ }
+
+ // Test that SetProvider fails predictably when the MDS assembly can't be
+ // found.
[Fact]
public void SetProvider()
{
- #pragma warning disable CS0618 // Type or member is obsolete
+ // Confirm that the MDS assembly is indeed not present.
+ Assert.Throws(
+ () => Assembly.Load("Microsoft.Data.SqlClient"));
+
+#pragma warning disable CS0618 // Type or member is obsolete
Assert.False(
SqlAuthenticationProvider.SetProvider(
SqlAuthenticationMethod.ActiveDirectoryIntegrated,
new Provider()));
- #pragma warning restore CS0618 // Type or member is obsolete
+#pragma warning restore CS0618 // Type or member is obsolete
}
}
diff --git a/src/Microsoft.Data.SqlClient.Extensions/Azure/test/Azure.Test.csproj b/src/Microsoft.Data.SqlClient.Extensions/Azure/test/Azure.Test.csproj
index 72459b823e..ad94e9b4b1 100644
--- a/src/Microsoft.Data.SqlClient.Extensions/Azure/test/Azure.Test.csproj
+++ b/src/Microsoft.Data.SqlClient.Extensions/Azure/test/Azure.Test.csproj
@@ -17,6 +17,7 @@
+
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
index 347c400545..3f8eed9dea 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
@@ -2488,8 +2488,8 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
// retry period is not specified by the provider.
const int defaultRetryPeriod = 100;
- // Number of retry attempts we are willing to perform.
- const int maxRetryAttempts = 1;
+ // Number of attempts we are willing to perform.
+ const int maxAttempts = 1;
// Username to use in error messages.
string? username = null;
@@ -2502,7 +2502,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
// We will perform retries if the provider indicates an error that
// is retryable.
- for (int retryAttempt = 0; retryAttempt <= maxRetryAttempts; ++retryAttempt)
+ for (int attempt = 0; attempt <= maxAttempts; ++attempt)
{
try
{
@@ -2639,7 +2639,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
if (_timeout.IsExpired || _timeout.MillisecondsRemaining <= 0)
{
// No, so we throw.
- SqlClientEventSource.Log.TryTraceEvent(" Retry Attempt: {0}, Timeout: {1}", retryAttempt, ex.FailureCode);
+ SqlClientEventSource.Log.TryTraceEvent(" Attempt: {0}, Timeout: {1}", attempt, ex.FailureCode);
throw SQL.ActiveDirectoryTokenRetrievingTimeout(Enum.GetName(typeof(SqlAuthenticationMethod), ConnectionOptions.Authentication), ex.FailureCode, ex);
}
@@ -2648,10 +2648,10 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
int retryPeriod =
ex.RetryPeriod > 0
? ex.RetryPeriod
- : defaultRetryPeriod * (2 ^ retryAttempt);
+ : defaultRetryPeriod * (2 ^ attempt);
- SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, Retry Attempt: {1}, sleeping {2}[Milliseconds]", ObjectID, retryAttempt, retryPeriod);
- SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, Retry Attempt: {1}, remaining {2}[Milliseconds]", ObjectID, retryAttempt, _timeout.MillisecondsRemaining);
+ SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, Attempt: {1}, sleeping {2}[Milliseconds]", ObjectID, attempt, retryPeriod);
+ SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, Attempt: {1}, remaining {2}[Milliseconds]", ObjectID, attempt, _timeout.MillisecondsRemaining);
// Sleep for the desired period.
Thread.Sleep(retryPeriod);
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
index e63376f7ab..8b8e7e4f88 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs
@@ -2545,7 +2545,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
const int defaultRetryPeriod = 100;
// Number of retry attempts we are willing to perform.
- const int maxRetryAttempts = 1;
+ const int maxAttempts = 1;
// Username to use in error messages.
string? username = null;
@@ -2558,7 +2558,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
// We will perform retries if the provider indicates an error that
// is retryable.
- for (int retryAttempt = 0; retryAttempt < maxRetryAttempts; ++retryAttempt)
+ for (int attempt = 0; attempt < maxAttempts; ++attempt)
{
try
{
@@ -2686,7 +2686,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
if (_timeout.IsExpired || _timeout.MillisecondsRemaining <= 0)
{
// No, so we throw.
- SqlClientEventSource.Log.TryTraceEvent(" Retry Attempt: {0}, Timeout: {1}", retryAttempt, ex.FailureCode);
+ SqlClientEventSource.Log.TryTraceEvent(" Attempt: {0}, Timeout: {1}", attempt, ex.FailureCode);
throw SQL.ActiveDirectoryTokenRetrievingTimeout(Enum.GetName(typeof(SqlAuthenticationMethod), ConnectionOptions.Authentication), ex.FailureCode, ex);
}
@@ -2695,10 +2695,10 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
int retryPeriod =
ex.RetryPeriod > 0
? ex.RetryPeriod
- : defaultRetryPeriod * (2 ^ retryAttempt);
+ : defaultRetryPeriod * (2 ^ attempt);
- SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, Retry Attempt: {1}, sleeping {2}[Milliseconds]", ObjectID, retryAttempt, retryPeriod);
- SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, Retry Attempt: {1}, remaining {2}[Milliseconds]", ObjectID, retryAttempt, _timeout.MillisecondsRemaining);
+ SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, Attempt: {1}, sleeping {2}[Milliseconds]", ObjectID, attempt, retryPeriod);
+ SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, Attempt: {1}, remaining {2}[Milliseconds]", ObjectID, attempt, _timeout.MillisecondsRemaining);
// Sleep for the desired period.
Thread.Sleep(retryPeriod);
From 65091f46051f0237c9ea52e8c6b69835f4f60116 Mon Sep 17 00:00:00 2001
From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com>
Date: Thu, 23 Oct 2025 12:54:59 -0300
Subject: [PATCH 11/16] - Fixed build error related to
SqlAuthenticationParameters.
---
src/Microsoft.Data.SqlClient.sln | 3 ---
.../Data/SqlClient/SqlAuthenticationParametersBuilder.cs | 2 +-
.../tests/StressTests/Directory.Build.props | 2 +-
3 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/src/Microsoft.Data.SqlClient.sln b/src/Microsoft.Data.SqlClient.sln
index 5a64096ba6..d5efe9e4b9 100644
--- a/src/Microsoft.Data.SqlClient.sln
+++ b/src/Microsoft.Data.SqlClient.sln
@@ -774,14 +774,11 @@ Global
{B21E7C94-D805-427E-928A-8DE8EA2F08CC} = {210228A5-979A-DE06-EE1F-B35C65E1583C}
{59667E4C-0BD2-9F48-FB50-9E55DD8B1011} = {556B486E-F9B0-7EA9-6A25-DA560C312761}
{04ACBF75-CFF2-41AB-B652-776BC0533490} = {59667E4C-0BD2-9F48-FB50-9E55DD8B1011}
-<<<<<<< HEAD
{A20114E1-82D8-903A-C389-726EB4FD943F} = {19F1F1E5-3013-7660-661A-2A15F7D606C1}
{0D2F834B-6D91-18D0-3F09-672D448751BD} = {A20114E1-82D8-903A-C389-726EB4FD943F}
{20C16035-7293-45AC-8217-9B86A389E571} = {0D2F834B-6D91-18D0-3F09-672D448751BD}
{5AF52CDD-DF78-3712-7516-5B49F94F9491} = {A20114E1-82D8-903A-C389-726EB4FD943F}
{A7C0B6C7-A4B2-43CA-921B-D4FAEE86ACBC} = {5AF52CDD-DF78-3712-7516-5B49F94F9491}
-=======
->>>>>>> feat/azure-split
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {01D48116-37A2-4D33-B9EC-94793C702431}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationParametersBuilder.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationParametersBuilder.cs
index d95427d052..a9863ee2ac 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationParametersBuilder.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAuthenticationParametersBuilder.cs
@@ -35,7 +35,7 @@ public static implicit operator SqlAuthenticationParameters(SqlAuthenticationPar
userId: builder._userId,
password: builder._password,
connectionId: builder._connectionId,
- authenticationTimeout: builder._authenticationTimeout);
+ connectionTimeout: builder._authenticationTimeout);
}
///
diff --git a/src/Microsoft.Data.SqlClient/tests/StressTests/Directory.Build.props b/src/Microsoft.Data.SqlClient/tests/StressTests/Directory.Build.props
index 66fbacae6c..26de699227 100644
--- a/src/Microsoft.Data.SqlClient/tests/StressTests/Directory.Build.props
+++ b/src/Microsoft.Data.SqlClient/tests/StressTests/Directory.Build.props
@@ -6,7 +6,7 @@
- net462;net47;net471;net472;net48;net481;net8.0;net9.0
+ net462;net8.0;net9.0
Microsoft.Data.SqlClient.Extensions.Abstractions
- $(AssemblyName)
+
+
+
Microsoft.Data.SqlClient.Extensions.Azure
- $(AssemblyName)
+
+
+