Implement async APIs in Always Encrypted Azure Key Vault provider - #4540
Conversation
Overrides the four async SqlColumnEncryptionKeyStoreProvider APIs in SqlColumnEncryptionAzureKeyVaultProvider with truly asynchronous Azure Key Vault SDK calls, so Always Encrypted async paths no longer block on HTTP I/O (issue #3672, spec phase 2A). - AzureSqlKeyCryptographer: async counterparts for AddKey, SignData, VerifyData, WrapKey and UnwrapKey, all propagating a CancellationToken. AddKeyAsync fetches before locking so no lock is held during network I/O. - LocalCache: GetOrCreateAsync with an async factory, mirroring sync semantics (TTL bypass, compaction, expiration) without holding a lock during I/O. - SqlColumnEncryptionAzureKeyVaultProvider: async overrides for encrypt, decrypt, sign and verify. Blob parse/build logic extracted into shared helpers so sync and async paths stay identical. Sync behavior is unchanged. - AsyncEventScope: reference-type event scope, since SqlClientEventScope is a ref struct and cannot cross an await boundary. - Tests: async round-trip, sync/async interoperability, cache behavior, cancellation and argument validation coverage in the AKV manual tests. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The reference-type scope wrapper only existed because SqlClientEventScope is a ref struct. Tracking the scope id in a try/finally achieves the same tracing without a new type or an allocation per async call. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Addresses review feedback on sync/async behavioral parity: - LocalCache.GetOrCreateAsync now gates concurrent misses per key, so a burst of concurrent decryptions of the same key issues a single Azure Key Vault request instead of one per caller. Misses for different keys still proceed in parallel, cancellation stays per caller, and a failed or cancelled owner lets the next waiter retry with its own token. - AzureSqlKeyCryptographer.AddKeyAsync double-checks under the semaphore and fetches while holding it, mirroring the deduplication of AddKey. Previously the semaphore only guarded a ConcurrentDictionary write, and a token cancelled mid-flight discarded an already fetched key. - LocalCache.GetOrCreate compacts on Count >= maxSize rather than ==, so a count that overshoots the limit cannot disable compaction permanently. - The async overrides observe the cancellation token before validating arguments, matching SqlColumnEncryptionKeyStoreProvider. - Documented that async argument validation failures surface through the returned task rather than being thrown synchronously. - Tests for concurrent decryption deduplication and for cancellation taking precedence over argument validation. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Follow-up to the async provider work, addressing defects found while auditing it for performance and compatibility problems. AddKeyAsync held _keyDictionarySemaphore across the awaited Azure Key Vault fetch. That semaphore is shared with the synchronous AddKey, so a synchronous caller blocked a thread pool thread for the duration of an asynchronous network round trip, which risks thread pool starvation. The semaphore is also global, so fetching one key serialized fetching every other key. The asynchronous path now uses its own per key gate and leaves the synchronous path on its original semaphore. A synchronous and an asynchronous caller may both fetch the same key, which yields an identical result, and this matches the deliberate absence of cross path deduplication in LocalCache. LocalCache.GetOrCreateAsync published its gate before awaiting it, and the try/finally that removed the gate began after the await. A cancelled wait therefore left the gate behind permanently, and the gate dictionary is not bounded by the cache size limit. A loop of a thousand pre-cancelled calls on distinct keys retained a thousand gates. The gate lifetime is now managed by KeyedAsyncLock, which removes the gate when a wait is abandoned and cleans up through a disposable releaser. The per key gating logic now lives in KeyedAsyncLock rather than being repeated, so the release and cleanup ordering is defined in one place. GetCryptographyClient used TryGetValue followed by TryAdd, so concurrent callers could each use a different CryptographyClient instance for the same key. It now uses GetOrAdd, and all callers observe the instance that wins the race. Also documents that gating is bypassed when caching is disabled, and adds a regression test asserting that cancelled asynchronous decryptions do not accumulate creation gates. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
EncryptColumnEncryptionKeyAsync repeated the body of ValidateSignature inline, including both of its trace messages, so a change to one would have silently diverged from the other. The logic now lives in ValidateSignatureAsync next to its synchronous counterpart. ParseEncryptedColumnEncryptionKey carried a null check on a buffer that had just been allocated with new byte[], which no execution can reach. The check moved into the helper when the parsing logic was extracted, and is now dropped. ADP.NullHashFound is left in place because removing it would also strip the associated resource string for no functional gain. Neither change alters behavior. Comparing every statement of the original synchronous encrypt and decrypt paths against the current file confirms all of them are preserved except the unreachable null check and a dead store to a position variable that was never read after its final update. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR adds truly asynchronous Always Encrypted key store operations to the Azure Key Vault provider, wiring the provider’s async overrides to Azure SDK async calls and extending local caching with async entry creation + per-key deduplication gates to avoid bursty duplicate Key Vault requests.
Changes:
- Implemented async overrides in
SqlColumnEncryptionAzureKeyVaultProviderfor encrypt/decrypt and CMK metadata sign/verify, flowingCancellationTokento Azure SDK async APIs. - Added async-capable
LocalCache.GetOrCreateAsyncplus a per-keyKeyedAsyncLock<TKey>to deduplicate concurrent cache misses without blocking threads. - Expanded AKV manual tests to cover async round-trips, cache sharing between sync/async, cancellation, and concurrency semantics.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider/src/SqlColumnEncryptionAzureKeyVaultProvider.cs | Adds async overrides for AE AKV provider and extracts shared parsing/message helpers for CEK/signature handling. |
| src/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider/src/LocalCache.cs | Introduces async cache entry creation with per-key gating and fixes compaction threshold under concurrency. |
| src/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider/src/KeyedAsyncLock.cs | New helper providing per-key async mutual exclusion with gate cleanup. |
| src/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider/src/AzureSqlKeyCryptographer.cs | Adds async key fetch/sign/verify/wrap/unwrap APIs and deduplicates concurrent key fetches per key. |
| src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/AKVUnitTests.cs | Adds manual tests for async API behavior, caching/deduplication, and cancellation semantics. |
| src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ExceptionTestAKVStore.cs | Adds manual tests for async encrypt/decrypt argument validation and decrypt failure modes. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
CancelledAsyncDecryptionsDoNotAccumulateCreationGates cancelled its token before calling DecryptColumnEncryptionKeyAsync. Cancellation is observed before the cache is reached, so no gate was ever created and the assertion held trivially. The test now has one caller take the gate and hold it across the key vault round trip while other callers queue behind it and are cancelled while waiting, which is the path where an abandoned wait could strand a gate. ExceptionTestAKVStore covered argument validation for the asynchronous encrypt and decrypt members only. Adds the same coverage for the asynchronous sign and verify members, mirroring the existing SignInvalidAKVPath cases. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Suppressed comments (1)
src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ExceptionTestAKVStore.cs:84
- These assertions use Assert.Matches with a plain message string that includes regex metacharacters (e.g., the trailing '.' in the null-path case). That makes the check less precise than intended and can produce false positives. Since the goal is substring matching (prefix may vary), Assert.Contains is a better fit here.
string expectedMessage = masterKeyPath == null
? "Azure Key Vault key path cannot be null."
: "Invalid Azure Key Vault key path specified";
Assert.Matches(expectedMessage, signException.Message);
Assert.Matches(expectedMessage, verifyException.Message);
VerifyColumnMasterKeyMetadata and VerifyColumnMasterKeyMetadataAsync now reject a null or empty signature with ArgumentNullException/ArgumentException instead of deferring the failure to the Azure Key Vault SDK. Both overloads validate identically so the sync and async surfaces stay in parity. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: ff71f86b-9c50-45f7-b79f-5aaaf7f98289
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4540 +/- ##
==========================================
- Coverage 64.78% 63.08% -1.70%
==========================================
Files 288 283 -5
Lines 44418 67609 +23191
==========================================
+ Hits 28774 42654 +13880
- Misses 15644 24955 +9311
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
priyankatiwari08
left a comment
There was a problem hiding this comment.
Overall looks good, just few small comments need to be addressed.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Updated [Microsoft.Data.SqlClient](https://github.com/dotnet/sqlclient)
from 6.1.6 to 7.1.0.
<details>
<summary>Release notes</summary>
_Sourced from [Microsoft.Data.SqlClient's
releases](https://github.com/dotnet/sqlclient/releases)._
## 7.1.0
This is the general availability release of **Microsoft.Data.SqlClient
7.1**. It closes out the `7.1` preview cycle with application identity
reporting for telemetry, the deprecation of
`TransparentNetworkIPResolution`, and a set of connection, transaction,
and Named Pipes fixes.
> **Important — package version alignment:** Starting with the
[7.0.2](https://github.com/dotnet/SqlClient/blob/main/release-notes/7.0/7.0.2.md)
release, the `Microsoft.Data.SqlClient` driver and its companion
packages share a single aligned version. The `7.1.0` GA release
continues this alignment; the following packages ship together as
`7.1.0`:
>
> - `Microsoft.Data.SqlClient`
> - `Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider`
> - `Microsoft.Data.SqlClient.Extensions.Azure`
> - `Microsoft.Data.SqlClient.Extensions.Abstractions`
> - `Microsoft.Data.SqlClient.Internal.Logging`
>
> (`Microsoft.SqlServer.Server` continues to version independently and
remains at `1.0.0`.)
>
> Applications must reference the same versions of
`Microsoft.Data.SqlClient` and its extensions for best compatibility. In
particular, applications that reference
`Microsoft.Data.SqlClient.Extensions.Azure` must upgrade it to `7.1.0`
when upgrading `Microsoft.Data.SqlClient` to `7.1.0`.
>
> **Compatibility guarantee:** All aligned assemblies ship with
`FileVersion 7.1.0.x` and `AssemblyVersion 7.0.0.0`. The
`AssemblyVersion` is unchanged from
[7.0.2](https://github.com/dotnet/SqlClient/blob/main/release-notes/7.0/7.0.2.md),
so upgrading from `7.0.2`, `7.0.3`, or any `7.1` preview to `7.1.0` does
**not** require any new .NET Framework strong-name binding redirects.
Applications upgrading from `7.0.0` or `7.0.1` should note that
`Extensions.Azure`, `Extensions.Abstractions`, and `Internal.Logging`
raised their `AssemblyVersion` from `1.0.0.0` to `7.0.0.0` in
[7.0.2](https://github.com/dotnet/SqlClient/blob/main/release-notes/7.0/7.0.2.md);
see those release notes for the one-time .NET Framework impact.
### Companion package release notes
- [Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider
7.1.0](https://github.com/dotnet/SqlClient/blob/main/release-notes/add-ons/AzureKeyVaultProvider/7.1/7.1.0.md)
- [Microsoft.Data.SqlClient.Extensions.Azure
7.1.0](https://github.com/dotnet/SqlClient/blob/main/release-notes/Extensions/Azure/7.1/7.1.0.md)
- [Microsoft.Data.SqlClient.Extensions.Abstractions
7.1.0](https://github.com/dotnet/SqlClient/blob/main/release-notes/Extensions/Abstractions/7.1/7.1.0.md)
- [Microsoft.Data.SqlClient.Internal.Logging
7.1.0](https://github.com/dotnet/SqlClient/blob/main/release-notes/Internal/Logging/7.1/7.1.0.md)
## Changes Since
[7.1.0-preview3](https://github.com/dotnet/SqlClient/blob/main/release-notes/7.1/7.1.0-preview3.md)
### Added
#### Application Identity in the USERAGENT Payload
*What Changed:*
- Added a `RegisteredApplication` enum and a matching
`SqlConnection.RegisteredApplication` property that let a library or
tool identify itself to SQL Server through version 2 of the TDS
USERAGENT feature extension. The payload also carries a new driver-owned
64-bit *Driver Properties* flag field; bit 0 reports whether connection
pool V2 is enabled for the process. Both fields are emitted as unpadded
uppercase hexadecimal.
([#3201](https://github.com/dotnet/SqlClient/issues/3201),
[#4632](https://github.com/dotnet/SqlClient/pull/4632))
*Who Benefits:*
- Middleware and tooling built on top of the driver — Entity Framework
Core, Semantic Kernel, SQL Server Management Studio, SqlPackage, Data
API Builder, and similar — can be distinguished in server-side telemetry
without the driver accepting arbitrary user-supplied user-agent text.
This originated as a request from the Entity Framework Core team.
- Service operators gain a more accurate picture of which client stacks
are connecting, which helps when diagnosing workload-specific behavior.
*Impact:*
- Purely additive from the application's perspective: a newly created
physical connection whose `RegisteredApplication` is unset reports
`Unknown` (`0`). On the wire the field itself is new — USERAGENT payload
v1 carried no application identifier, while v2 always emits one.
- Set the property before calling `Open` or `OpenAsync`. Assigning it
while the connection is connecting or open throws
`InvalidOperationException`.
```c#
using var connection = new SqlConnection(connectionString);
connection.RegisteredApplication = RegisteredApplication.EntityFrameworkCore;
await connection.OpenAsync();
```
- The enum is `ushort`-backed and marked `[CLSCompliant(false)]`. Values
are partitioned by range: `0x0001`–`0x7FFF` for Microsoft-defined
large-scale applications, `0x8000`–`0xBFFF` for small-scale use, and
`0xC000`–`0xFFFF` for public/developer use. Applications that are not
yet registered can cast an unassigned value from the appropriate range.
... (truncated)
## 7.1.0-preview3
This update brings the following changes since the
[7.1.0-preview2](https://github.com/dotnet/SqlClient/blob/main/release-notes/7.1/7.1.0-preview2.md)
release.
> **Package version alignment:** The `Microsoft.Data.SqlClient` driver
and its companion packages continue the aligned versioning introduced in
[7.0.2](https://github.com/dotnet/SqlClient/blob/main/release-notes/7.0/7.0.2.md).
All five packages listed below ship together as `7.1.0-preview3`.
(`Microsoft.SqlServer.Server` continues to version independently and
remains at `1.0.0`.) Applications that reference
`Microsoft.Data.SqlClient.Extensions.Azure` must upgrade it to
`7.1.0-preview3` when upgrading `Microsoft.Data.SqlClient`.
> **Compatibility guarantee:** All aligned assemblies ship with
`FileVersion 7.1.0.x` and `AssemblyVersion 7.0.0.0` — unchanged from
7.0.2 — so upgrading from `7.0.2` to `7.1.0-preview3` does **not**
require any new .NET Framework strong-name binding redirects.
## Packages in this release
### `Microsoft.Data.SqlClient` 7.1.0-preview3
**Added**
- Asynchronous key store provider APIs for Always Encrypted — four
`virtual` methods on `SqlColumnEncryptionKeyStoreProvider` with
`CancellationToken` support. Purely additive; defaults delegate to the
synchronous methods, so existing providers are unaffected
([#3672](https://github.com/dotnet/SqlClient/issues/3672),
[#3673](https://github.com/dotnet/SqlClient/pull/3673))
- Connection Pool V2 nears parity with the default pool (opt-in via
`Switch.Microsoft.Data.SqlClient.UseConnectionPoolV2`):
- Transaction support
([#4487](https://github.com/dotnet/SqlClient/pull/4487))
- Broken-connection replacement during command execution
([#4429](https://github.com/dotnet/SqlClient/pull/4429))
- Background warmup to `Min Pool Size` and automatic replenishment
([#4452](https://github.com/dotnet/SqlClient/pull/4452))
- Idle pruning driven by `Connection Idle Timeout`
([#4463](https://github.com/dotnet/SqlClient/pull/4463))
- Optional `ConcurrencyLimiter` rate limiting for new physical
connections ([#4395](https://github.com/dotnet/SqlClient/pull/4395),
[#4396](https://github.com/dotnet/SqlClient/pull/4396))
- Leaked connection reclamation, including the previously always-zero
`number-of-reclaimed-connections` counter
([#4529](https://github.com/dotnet/SqlClient/pull/4529))
- Metrics and tracing parity with the default pool
([#4504](https://github.com/dotnet/SqlClient/pull/4504))
**Changed**
- Single cross-platform build — Windows-only native SNI types now trim
cleanly on Linux and macOS. Package structure and contents unchanged
([#4207](https://github.com/dotnet/SqlClient/pull/4207),
[#4239](https://github.com/dotnet/SqlClient/issues/4239),
[#4465](https://github.com/dotnet/SqlClient/pull/4465),
[#4474](https://github.com/dotnet/SqlClient/pull/4474))
- Async read-path allocations restored to baseline via `PacketData` node
reuse — `ExecuteReaderAsync` goes from +120.9% to +0.1% against 6.1.6
([#4536](https://github.com/dotnet/SqlClient/pull/4536))
- `SqlBulkCopy` skips graph alias mapping when no graph pseudo-columns
are present, recovering a regression from
[#3677](https://github.com/dotnet/SqlClient/pull/3677)
([#4535](https://github.com/dotnet/SqlClient/pull/4535))
- No formatted trace string is allocated when `SqlClientEventSource`
tracing is disabled, recovering a memory regression against 6.1.6. Trace
output unchanged
([#4528](https://github.com/dotnet/SqlClient/pull/4528))
- `net9.0` dependencies moved to `9.0.18`;
`System.Threading.RateLimiting` added to packaged metadata. Other
targets keep their `8.0.x` pins
([#4507](https://github.com/dotnet/SqlClient/pull/4507))
- `Microsoft.Data.SqlClient.SNI` and `.SNI.runtime` updated to
`7.1.0-preview3.26226.3`
([#4564](https://github.com/dotnet/SqlClient/pull/4564))
**Fixed**
- Always Encrypted VSM/HGS attestation now verifies the enclave public
key is bound to the signed report, using a fixed-time `SHA-256`
comparison against `EnclaveData`
([#4532](https://github.com/dotnet/SqlClient/pull/4532))
- `SqlConnectionFactory` no longer wakes the process every 30 seconds
when no pools exist — including with `Pooling=False` and after
`ClearAllPools()`
([#1881](https://github.com/dotnet/SqlClient/issues/1881),
[#4479](https://github.com/dotnet/SqlClient/pull/4479))
- Connection pool performance counters affecting the **default** pool as
well as pool V2 — `active-soft-connects` and
`number-of-active-connections` could go negative after a failed
activation, and several gauges drifted upward permanently after a broken
connection was replaced
([#4504](https://github.com/dotnet/SqlClient/pull/4504))
- `OverflowException` when sending large `decimal` values with explicit
`Precision` and `Scale`, which primarily affected Always Encrypted
([#1655](https://github.com/dotnet/SqlClient/issues/1655),
[#4443](https://github.com/dotnet/SqlClient/pull/4443))
- TDS stream error when passing a `DateOnly` value with
`SqlDbType.Variant` (net8.0/net9.0)
([#3953](https://github.com/dotnet/SqlClient/issues/3953),
[#4294](https://github.com/dotnet/SqlClient/pull/4294))
- `DateOnly` in table-valued parameter `sql_variant` columns sent as
`datetime` instead of `date`, which overflowed for values valid as
`date` (net8.0/net9.0)
([#3934](https://github.com/dotnet/SqlClient/issues/3934),
[#4439](https://github.com/dotnet/SqlClient/pull/4439))
- `ServerCertificate` keyword ignored when the platform reported no TLS
policy errors. It is now always compared, and an unloadable certificate
fails closed with `SSLCertificateAuthenticationException` instead of
silently falling back to host-name validation
([#4445](https://github.com/dotnet/SqlClient/pull/4445))
- `SqlConnection.AccessTokenCallback` not disabling TNIR by default,
plus pool-key construction and `SspiContextProvider` exclusivity with
token auth (net462 for the TNIR behavior)
([#4520](https://github.com/dotnet/SqlClient/pull/4520))
- Fatal exceptions such as `OutOfMemoryException` captured into faulted
`Task`s across several `SqlBulkCopy`, `SqlDataReader`, and `SqlCommand`
async entry points
([#4437](https://github.com/dotnet/SqlClient/pull/4437))
- Entra ID authentication failing against multi-segment authorities such
as the Dataverse / Dynamics 365 TDS endpoint. Ships in
`Microsoft.Data.SqlClient.Extensions.Azure`
([#4496](https://github.com/dotnet/SqlClient/issues/4496),
[#4521](https://github.com/dotnet/SqlClient/pull/4521))
Full details:
[release-notes/7.1/7.1.0-preview3.md](https://github.com/dotnet/SqlClient/blob/main/release-notes/7.1/7.1.0-preview3.md)
---
### `Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider`
7.1.0-preview3
**Added**
- `SqlColumnEncryptionAzureKeyVaultProvider` overrides the four
asynchronous key store provider methods introduced in
[#3673](https://github.com/dotnet/SqlClient/pull/3673), calling the
Azure SDK's own async APIs and flowing the supplied `CancellationToken`
([#4540](https://github.com/dotnet/SqlClient/pull/4540))
- Concurrent cache misses for the same key collapse into a single Key
Vault request. The gate is only awaited, so no thread blocks, and misses
for different keys still proceed in parallel
([#4540](https://github.com/dotnet/SqlClient/pull/4540))
... (truncated)
## 7.1.0-preview2
This update brings the following changes since the
[7.1.0-preview1](https://github.com/dotnet/SqlClient/blob/main/release-notes/7.1/7.1.0-preview1.md)
release.
> **Package version alignment:** The `Microsoft.Data.SqlClient` driver
and its companion packages continue the aligned versioning introduced in
[7.0.2](https://github.com/dotnet/SqlClient/blob/main/release-notes/7.0/7.0.2.md).
All five packages listed below ship together as `7.1.0-preview2`.
(`Microsoft.SqlServer.Server` continues to version independently and
remains at `1.0.0`.) Applications that reference
`Microsoft.Data.SqlClient.Extensions.Azure` must upgrade it to
`7.1.0-preview2` when upgrading `Microsoft.Data.SqlClient`.
> **Compatibility guarantee:** All aligned assemblies ship with
`FileVersion 7.1.0.x` and `AssemblyVersion 7.0.0.0` — unchanged from
7.0.2 — so upgrading from `7.0.2` to `7.1.0-preview2` does **not**
require any new .NET Framework strong-name binding redirects.
## Packages in this release
### `Microsoft.Data.SqlClient` 7.1.0-preview2
**Added**
- `SqlConnection.GetSchemaAsync` overloads with `CancellationToken`
support ([#3005](https://github.com/dotnet/SqlClient/pull/3005))
- SQL Graph pseudo-column aliases (`$node_id`, `$edge_id`, `$from_id`,
`$to_id`) accepted in `SqlBulkCopy` mappings
([#3677](https://github.com/dotnet/SqlClient/pull/3677))
- `SqlBatchCommand.CommandBehavior` and
`SqlBatch.ExecuteReader(CommandBehavior)` are now honored
([#4125](https://github.com/dotnet/SqlClient/pull/4125))
- Configurable idle connection timeout via `Connection Idle Timeout` /
`SqlConnectionStringBuilder.IdleTimeout` (opt-in via
`Switch.Microsoft.Data.SqlClient.UseLegacyIdleTimeoutBehavior=false`)
([#4295](https://github.com/dotnet/SqlClient/pull/4295))
**Changed**
- `Connect Timeout` now propagates through the pool when
`Switch.Microsoft.Data.SqlClient.UseOverallConnectTimeoutForPoolWait=true`
is set (default off; introduces a `Microsoft.Bcl.TimeProvider`
dependency) ([#4270](https://github.com/dotnet/SqlClient/pull/4270))
- SQL Server 2025 `json` type added to the `DataTypes` collection
returned by `SqlConnection.GetSchema`
([#3858](https://github.com/dotnet/SqlClient/pull/3858))
- Internal state-machine hardening via `Interlocked.CompareExchange`
guards ([#4267](https://github.com/dotnet/SqlClient/pull/4267))
- Internal cleanup of connection-options inheritance and related pool
interfaces ([#4237](https://github.com/dotnet/SqlClient/pull/4237),
[#4261](https://github.com/dotnet/SqlClient/pull/4261),
[#4235](https://github.com/dotnet/SqlClient/pull/4235),
[#4415](https://github.com/dotnet/SqlClient/pull/4415),
[#4334](https://github.com/dotnet/SqlClient/pull/4334))
- LCID hardcoded mappings to avoid repeated culture lookups
([#4212](https://github.com/dotnet/SqlClient/pull/4212))
- Allocation reductions on `SqlErrorCollection` and null-return paths
([#4157](https://github.com/dotnet/SqlClient/pull/4157),
[#4099](https://github.com/dotnet/SqlClient/pull/4099),
[#4102](https://github.com/dotnet/SqlClient/pull/4102))
- Improved `EnclaveDiffieHellmanInfo.Size` accuracy
([#4346](https://github.com/dotnet/SqlClient/pull/4346))
- `SqlVector<float>` serialization is now explicitly little-endian for
cross-architecture consistency
([#3861](https://github.com/dotnet/SqlClient/pull/3861))
- Bundled .NET 10 SDK updated to `10.0.300`
([#4287](https://github.com/dotnet/SqlClient/pull/4287))
**Fixed**
- `NullReferenceException` in `SqlCommand.Cancel()` when the connection
has already been torn down
([#4372](https://github.com/dotnet/SqlClient/pull/4372))
- Always Encrypted CMK signature verification incorrectly reusing cached
results after a prior failure
([#4339](https://github.com/dotnet/SqlClient/pull/4339))
- Missing TDS token / feature-ack length bounds checks (spoofing server
could trigger unbounded allocations)
([#4340](https://github.com/dotnet/SqlClient/pull/4340))
- `SqlBulkCopy` failing in least-privilege environments
([#4306](https://github.com/dotnet/SqlClient/pull/4306))
- Always Encrypted `CekMdVersion` / `EkValueCount` reads aligned with
the TDS specification
([#4240](https://github.com/dotnet/SqlClient/pull/4240))
- `LoginWithFailover` parser-state validation
([#4140](https://github.com/dotnet/SqlClient/pull/4140))
- SPN during login now uses the resolved port instead of instance name
for `Protocol=None` / `Protocol=Admin`
([#4180](https://github.com/dotnet/SqlClient/pull/4180))
- Race in `SqlConnection.TryOpenInner` that could surface as
`InvalidCastException` now returns a deterministic
`InvalidOperationException`
([#4179](https://github.com/dotnet/SqlClient/pull/4179))
- Multiple `CancellationTokenSource` leaks in `SqlDataReader`,
`SqlConnection`, `SqlCommand` reconnect paths, and sequential-stream
helpers ([#4009](https://github.com/dotnet/SqlClient/pull/4009))
- Docs fix for server certificate configuration
([#4408](https://github.com/dotnet/SqlClient/pull/4408))
**Removed (breaking)**
- SQL Server 7.0 / 2000 code paths removed; `Type System Version=SQL
Server 2000` now throws `ArgumentException` at open. Applications should
switch to `Latest` (or another supported value). No change to
server-version support — 7.0 / 2000 were already rejected during login
version negotiation.
([#4015](https://github.com/dotnet/SqlClient/pull/4015))
Full details:
[release-notes/7.1/7.1.0-preview2.md](https://github.com/dotnet/SqlClient/blob/main/release-notes/7.1/7.1.0-preview2.md)
---
### `Microsoft.Data.SqlClient.Extensions.Azure` 7.1.0-preview2
**Added — WAM (Windows Account Manager) broker support for Entra ID
authentication (Windows only)**
([#4288](https://github.com/dotnet/SqlClient/pull/4288),
[#4388](https://github.com/dotnet/SqlClient/pull/4388))
- Covers `ActiveDirectoryIntegrated`, `ActiveDirectoryInteractive`,
`ActiveDirectoryDeviceCodeFlow`, and the deprecated
`ActiveDirectoryPassword` modes.
... (truncated)
## 7.1.0-preview1
This update brings the following changes since the
[7.0.0](https://github.com/dotnet/SqlClient/blob/main/release-notes/7.0/7.0.0.md)
release:
### Added
#### `SqlBatch` Support on .NET Framework
*What Changed:*
- Added `SqlBatch` and related batch-command support for the .NET
Framework target so the batching API is now available across the full
supported platform matrix, including `net462`.
([#3926](https://github.com/dotnet/SqlClient/pull/3926))
*Who Benefits:*
- Applications that target .NET Framework but also want to use the newer
batching APIs no longer need a separate implementation strategy from
.NET 8/9 applications.
- Libraries that multi-target .NET Framework and modern .NET can use a
more consistent data-access surface area.
*Impact:*
- `SqlBatch`, `SqlBatchCommand`, and the related execution methods are
now usable on .NET Framework builds in addition to .NET.
#### Cross-Driver Connection-String Synonym Alignment
*What Changed:*
- Added additional accepted connection-string synonyms for better
compatibility with other SQL Server drivers and existing
connection-string conventions. Newly accepted synonyms include
`ColumnEncryption`, `ConnectTimeout`, `FailoverPartner`, `PacketSize`,
and `WorkstationId`.
([#4192](https://github.com/dotnet/SqlClient/pull/4192))
*Who Benefits:*
- Applications migrating connection strings from other SQL Server
drivers or shared infrastructure can reuse more existing keywords
without rewriting them first.
*Impact:*
- Existing canonical keywords continue to work unchanged; this preview
simply accepts more equivalent aliases during parsing.
### Changed
#### Type Forwards for Authentication Abstractions
*What Changed:*
- Added type forwards from the core `Microsoft.Data.SqlClient` assembly
to public authentication-related types that were moved into
`Microsoft.Data.SqlClient.Extensions.Abstractions`, including
`SqlAuthenticationMethod`, `SqlAuthenticationParameters`,
`SqlAuthenticationProvider`, `SqlAuthenticationProviderException`, and
`SqlAuthenticationToken`.
([#4067](https://github.com/dotnet/SqlClient/pull/4067),
[#4117](https://github.com/dotnet/SqlClient/pull/4117))
*Who Benefits:*
- Applications and libraries compiled against earlier package layouts
retain binary compatibility when those authentication types are resolved
from the core assembly name.
*Impact:*
- No application code changes are required; the type forwards preserve
existing compiled references.
#### User Agent Feature Extension Enabled by Default
... (truncated)
## 7.0.3
This update brings the following changes since the [7.0.2](7.0.2.md)
release:
The core driver and its companion packages ship together as version
`7.0.3`. Update the companion packages you use alongside the driver to
`7.0.3`. Assembly versions remain `7.0.0.0`, unchanged from `7.0.2`.
### Companion package release notes
- [Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider
7.0.3](../add-ons/AzureKeyVaultProvider/7.0/7.0.3.md)
- [Microsoft.Data.SqlClient.Extensions.Azure
7.0.3](../Extensions/Azure/7.0/7.0.3.md) — includes the Entra ID
authority parsing fix for Dataverse/Dynamics 365 connections.
- [Microsoft.Data.SqlClient.Extensions.Abstractions
7.0.3](../Extensions/Abstractions/7.0/7.0.3.md)
- [Microsoft.Data.SqlClient.Internal.Logging
7.0.3](../Internal/Logging/7.0/7.0.3.md)
### Changed
- Updated the `Microsoft.Data.SqlClient.SNI` and
`Microsoft.Data.SqlClient.SNI.runtime` dependencies to 6.0.3 (was
6.0.2).
([#4599](https://github.com/dotnet/SqlClient/pull/4599))
### Fixed
- Fixed a `SqlBulkCopy` regression in environments where the application
login cannot read `sys.all_columns`. Bulk copy now falls back to the
earlier column-discovery behavior when that permission is unavailable.
Support for hidden columns and SQL Graph column aliases still requires
access to the metadata view.
([#4370](https://github.com/dotnet/SqlClient/issues/4370),
[#4306](https://github.com/dotnet/SqlClient/pull/4306),
[#4402](https://github.com/dotnet/SqlClient/pull/4402))
- Fixed a memory-allocation regression in connection and command
operations caused by formatting diagnostic strings even when tracing was
disabled. Also corrected trace messages that reported an incorrect
object ID or could throw `FormatException` when traced values contained
braces.
([#4528](https://github.com/dotnet/SqlClient/pull/4528),
[#4533](https://github.com/dotnet/SqlClient/pull/4533))
- Fixed `ServerCertificate` validation on the managed SNI path so the
configured certificate is compared against the server certificate even
when the server certificate passes chain and host-name validation. When
certificate validation is enabled, a missing, unreadable, or invalid
certificate file, a certificate mismatch, or a missing server
certificate now causes the TLS handshake to fail instead of bypassing
the configured certificate check. (net8.0/net9.0 only)
([#4445](https://github.com/dotnet/SqlClient/pull/4445),
[#4583](https://github.com/dotnet/SqlClient/pull/4583))
- Fixed Always Encrypted VSM/HGS enclave attestation to verify that the
enclave public key used to establish a session matches the key committed
to by the signed attestation report. Missing, malformed, or mismatched
key-binding data now causes attestation to fail before the session
secret is derived.
([#4532](https://github.com/dotnet/SqlClient/pull/4532),
[#4553](https://github.com/dotnet/SqlClient/pull/4553))
- Fixed `SqlConnection.AccessTokenCallback` not disabling Transparent
Network IP Resolution by default, making it consistent with
`SqlConnection.AccessToken`. An explicitly configured
`TransparentNetworkIPResolution` connection-string value still takes
precedence. (net462 only)
([#4520](https://github.com/dotnet/SqlClient/pull/4520),
[#4561](https://github.com/dotnet/SqlClient/pull/4561))
- Fixed authentication state handling so clearing
`SqlConnection.AccessToken`, `AccessTokenCallback`, or
`SspiContextProvider` preserves the other authentication values in the
connection pool key. Cloning a connection or updating its credential
also preserves its `SspiContextProvider`. Combining a non-null
`SspiContextProvider` with `AccessToken` or `AccessTokenCallback` now
throws `InvalidOperationException` instead of silently discarding
authentication state; applications must use one authentication mechanism
at a time.
([#4520](https://github.com/dotnet/SqlClient/pull/4520),
[#4561](https://github.com/dotnet/SqlClient/pull/4561),
[#4644](https://github.com/dotnet/SqlClient/pull/4644))
- Fixed configurable retry logic installing a permanent, process-wide
assembly-resolution handler that could interfere with unrelated assembly
loading. The handler is now active only while an explicitly configured
custom retry provider is resolved and constructed, and probes
`AppContext.BaseDirectory` instead of the current working directory.
Place custom retry assemblies in the application base directory;
dependencies loaded after provider construction must be resolvable
through normal application dependency resolution or an
application-provided handler. (net8.0/net9.0 only)
([#2214](https://github.com/dotnet/SqlClient/issues/2214),
[#4547](https://github.com/dotnet/SqlClient/pull/4547),
[#4663](https://github.com/dotnet/SqlClient/pull/4663))
## Contributors
We thank the following public contributors. Their efforts toward this
project are very much appreciated.
- [edwardneal](https://github.com/edwardneal)
## Target Platform Support
- .NET Framework 4.6.2+ (Windows x86, Windows x64, Windows ARM64)
- .NET 8.0+ (Windows x86, Windows x64, Windows ARM, Windows ARM64,
Linux, macOS)
... (truncated)
## 7.0.2
This update brings the following changes since the
[7.0.1](https://github.com/dotnet/SqlClient/blob/main/release-notes/7.0/7.0.1.md)
release:
> **Important — package version alignment:** Starting with 7.0.2, the
`Microsoft.Data.SqlClient` driver and its companion packages share a
single aligned version. The following packages now ship together as
`7.0.2`:
>
> - `Microsoft.Data.SqlClient`
> - `Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider`
> - `Microsoft.Data.SqlClient.Extensions.Azure`
> - `Microsoft.Data.SqlClient.Extensions.Abstractions`
> - `Microsoft.Data.SqlClient.Internal.Logging`
>
> (`Microsoft.SqlServer.Server` continues to version independently and
remains at `1.0.0`.)
>
> Applications must reference the same versions of
`Microsoft.Data.SqlClient` and its extensions for best compatibility. In
particular, applications that reference
`Microsoft.Data.SqlClient.Extensions.Azure` must upgrade it to `7.0.2`
when upgrading `Microsoft.Data.SqlClient` to `7.0.2`.
> **Breaking change (.NET Framework only):** As part of this alignment,
the `AssemblyVersion` of `Microsoft.Data.SqlClient.Extensions.Azure`,
`Microsoft.Data.SqlClient.Extensions.Abstractions`, and
`Microsoft.Data.SqlClient.Internal.Logging` changed from `1.0.0.0` to
`7.0.0.0` (the `Microsoft.Data.SqlClient` and
`Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider`
assembly versions are unchanged). On .NET Framework, `AssemblyVersion`
is part of the strong-name identity, so applications that drop these
assemblies into an existing deployment without rebuilding must rebuild
against the 7.0.2 packages (or add binding redirects). Applications on
.NET / .NET Core are not affected.
### Companion package release notes
The following companion packages ship aligned as `7.0.2`. See their
individual release notes for package-specific changes (including the
`Microsoft.Data.SqlClient.Extensions.Azure` WAM broker support):
- [Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider
7.0.2](https://github.com/dotnet/SqlClient/blob/main/release-notes/add-ons/AzureKeyVaultProvider/7.0/7.0.2.md)
- [Microsoft.Data.SqlClient.Extensions.Azure
7.0.2](https://github.com/dotnet/SqlClient/blob/main/release-notes/Extensions/Azure/7.0/7.0.2.md)
- [Microsoft.Data.SqlClient.Extensions.Abstractions
7.0.2](https://github.com/dotnet/SqlClient/blob/main/release-notes/Extensions/Abstractions/7.0/7.0.2.md)
- [Microsoft.Data.SqlClient.Internal.Logging
7.0.2](https://github.com/dotnet/SqlClient/blob/main/release-notes/Internal/Logging/7.0/7.0.2.md)
### Fixed
- Fixed a `NullReferenceException` in `SqlCommand.Cancel()`. The
diagnostic message built during cancellation dereferenced the active
connection directly; it now uses a null-conditional access so
cancellation no longer throws when the connection has already been torn
down.
([#4372](https://github.com/dotnet/SqlClient/pull/4372),[#4373](https://github.com/dotnet/SqlClient/pull/4373))
- Fixed a `NullReferenceException` in `SqlDataReader` when calling
`GetBytes`/`GetChars` with a `null` destination buffer. The
argument-validation path that constructs the
`InvalidDestinationBufferIndex` exception now guards against the null
buffer so the correct `ArgumentException` is surfaced instead of an NRE.
([#4159](https://github.com/dotnet/SqlClient/pull/4159),[#4206](https://github.com/dotnet/SqlClient/pull/4206))
- Fixed Always Encrypted column master key signature verification
incorrectly reusing cached results. The `SignatureVerificationCache`
lookup logic was corrected so signature verification outcomes are cached
and retrieved against the correct key, preventing stale or mismatched
verification results.
([#4339](https://github.com/dotnet/SqlClient/pull/4339),[#4343](https://github.com/dotnet/SqlClient/pull/4343))
### Changed
#### Hardened TDS token parsing with data-length bounds checks
*What Changed:*
- Added bounds checking when parsing TDS token and
feature-extension-acknowledgment data lengths. The parser now validates
the declared length of incoming token data against the available buffer
before reading, rejecting malformed or out-of-range length values
instead of reading past the intended boundary.
([#4340](https://github.com/dotnet/SqlClient/pull/4340),[#4358](https://github.com/dotnet/SqlClient/pull/4358))
*Who Benefits:*
- All consumers benefit from improved resilience against malformed or
hostile TDS responses. A server (or man-in-the-middle) sending an
invalid token length can no longer drive the parser to read beyond the
declared payload.
*Impact:*
... (truncated)
## 7.0.1
This update brings the following changes since the
[7.0.0](https://github.com/dotnet/SqlClient/blob/release/7.0/release-notes/7.0/7.0.0.md)
release:
### Fixed
- Fixed `SqlBulkCopy` failing on SQL Server 2016 with `Invalid column
name 'graph_type'` error. The column metadata query now uses dynamic SQL
so that references to the `graph_type` column (introduced in SQL Server
2017) are not compiled on older versions that lack the column.
([#3714](https://github.com/dotnet/SqlClient/issues/3714),
[#4092](https://github.com/dotnet/SqlClient/pull/4092),
[#4147](https://github.com/dotnet/SqlClient/pull/4147))
- Fixed `SqlBulkCopy` failing on Azure Synapse Analytics dedicated SQL
pools. The column-list query previously used a variable-assignment
pattern that Synapse does not support; it now uses `STRING_AGG` when
targeting Synapse (engine edition 6) and falls back to the
variable-assignment approach for SQL Server 2016 compatibility.
([#4149](https://github.com/dotnet/SqlClient/issues/4149),
[#4176](https://github.com/dotnet/SqlClient/pull/4176),
[#4182](https://github.com/dotnet/SqlClient/pull/4182))
- Fixed `SqlDataReader.GetFieldType()` and
`GetProviderSpecificFieldType()` returning `typeof(byte[])` instead of
`typeof(SqlVector<float>)` for vector float32 columns. The methods now
follow the same type-determination logic as `GetValue()`.
([#4104](https://github.com/dotnet/SqlClient/issues/4104),
[#4105](https://github.com/dotnet/SqlClient/pull/4105),
[#4152](https://github.com/dotnet/SqlClient/pull/4152))
- Added missing `System.Data.Common` (v4.3.0) NuGet package dependency
for .NET Framework consumers. The inbox `System.Data.Common` assembly on
.NET Framework predates APIs such as `IDbColumnSchemaGenerator`; without
the explicit NuGet dependency, consumers encountered `CS0012`
compilation errors when using these types through
`Microsoft.Data.SqlClient`.
([#4063](https://github.com/dotnet/SqlClient/pull/4063),
[#4074](https://github.com/dotnet/SqlClient/pull/4074))
### Changed
- Enabled the User Agent TDS feature extension unconditionally. The
`Switch.Microsoft.Data.SqlClient.EnableUserAgent` AppContext switch has
been removed; the driver now always sends User Agent information during
login. ([#4124](https://github.com/dotnet/SqlClient/pull/4124),
[#4154](https://github.com/dotnet/SqlClient/pull/4154))
- Added type forwards from the core `Microsoft.Data.SqlClient` assembly
to public types that were moved to the
`Microsoft.Data.SqlClient.Extensions.Abstractions` package:
`SqlAuthenticationMethod`, `SqlAuthenticationParameters`,
`SqlAuthenticationProvider`, `SqlAuthenticationProviderException`, and
`SqlAuthenticationToken`. This ensures binary compatibility for
assemblies compiled against earlier versions of
`Microsoft.Data.SqlClient` where these types lived in the core assembly.
([#4067](https://github.com/dotnet/SqlClient/pull/4067),
[#4117](https://github.com/dotnet/SqlClient/pull/4117))
- Fixed API documentation include paths and duplicate doc snippets.
([#4084](https://github.com/dotnet/SqlClient/pull/4084),
[#4086](https://github.com/dotnet/SqlClient/pull/4086),
[#4107](https://github.com/dotnet/SqlClient/pull/4107),
[#4161](https://github.com/dotnet/SqlClient/pull/4161))
## Contributors
We thank the following public contributors. Their efforts toward this
project are very much appreciated.
- [edwardneal](https://github.com/edwardneal)
## Target Platform Support
- .NET Framework 4.6.2+ (Windows x86, Windows x64, Windows ARM64)
- .NET 8.0+ (Windows x86, Windows x64, Windows ARM, Windows ARM64,
Linux, macOS)
### Dependencies
#### .NET 9.0
- Microsoft.Bcl.Cryptography 9.0.13
- Microsoft.Data.SqlClient.Extensions.Abstractions 1.0.0
- Microsoft.Data.SqlClient.Internal.Logging 1.0.0
- Microsoft.Data.SqlClient.SNI.runtime 6.0.2
- Microsoft.Extensions.Caching.Memory 9.0.13
- Microsoft.IdentityModel.JsonWebTokens 8.16.0
- Microsoft.IdentityModel.Protocols.OpenIdConnect 8.16.0
- Microsoft.SqlServer.Server 1.0.0
- System.Configuration.ConfigurationManager 9.0.13
- System.Security.Cryptography.Pkcs 9.0.13
#### .NET 8.0
- Microsoft.Bcl.Cryptography 8.0.0
- Microsoft.Data.SqlClient.Extensions.Abstractions 1.0.0
... (truncated)
## 7.0.0
This is the general availability release of **Microsoft.Data.SqlClient
7.0**, a major milestone for the .NET data provider for SQL Server. This
release addresses the most upvoted issue in the repository's history —
extracting Azure dependencies from the core package — introduces
pluggable SSPI authentication, adds enhanced routing for Azure SQL
Hyperscale, and delivers async read performance improvements.
Also released as part of this milestone:
- Released Microsoft.Data.SqlClient.Extensions.Abstractions 1.0.0. See
[release notes](../Extensions/Abstractions/1.0/1.0.0.md).
- Released Microsoft.Data.SqlClient.Extensions.Azure 1.0.0. See [release
notes](../Extensions/Azure/1.0/1.0.0.md).
- Released Microsoft.Data.SqlClient.Internal.Logging 1.0.0. See [release
notes](../Internal/Logging/1.0/1.0.0.md).
- Released
Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider 7.0.0.
See [release notes](../add-ons/AzureKeyVaultProvider/7.0/7.0.0.md).
## Changes Since [7.0.0-preview4](7.0.0-preview4.md)
### Added
- Added actionable error message when Entra ID authentication methods
are used without the `Microsoft.Data.SqlClient.Extensions.Azure` package
installed, guiding users to install the correct package.
([#3962](https://github.com/dotnet/SqlClient/issues/3962),
[#4046](https://github.com/dotnet/SqlClient/pull/4046))
- Added Azure authentication sample application.
([#3988](https://github.com/dotnet/SqlClient/pull/3988))
### Changed
#### Other changes
- Renamed the `Microsoft.Data.SqlClient.Extensions.Logging` package to
`Microsoft.Data.SqlClient.Internal.Logging` to indicate it is for
internal use only and should not be referenced directly by application
code. ([#4038](https://github.com/dotnet/SqlClient/pull/4038))
- Fixed non-localized exception strings.
([#4022](https://github.com/dotnet/SqlClient/pull/4022))
- Codebase merge and cleanup:
([#3997](https://github.com/dotnet/SqlClient/pull/3997),
[#4052](https://github.com/dotnet/SqlClient/pull/4052))
- Various test improvements:
([#3891](https://github.com/dotnet/SqlClient/pull/3891),
[#3996](https://github.com/dotnet/SqlClient/pull/3996),
[#4002](https://github.com/dotnet/SqlClient/pull/4002),
[#4034](https://github.com/dotnet/SqlClient/pull/4034),
[#4041](https://github.com/dotnet/SqlClient/pull/4041),
[#4044](https://github.com/dotnet/SqlClient/pull/4044))
- Documentation improvements (including Entra ID branding updates):
([#4021](https://github.com/dotnet/SqlClient/pull/4021),
[#4047](https://github.com/dotnet/SqlClient/pull/4047),
[#4049](https://github.com/dotnet/SqlClient/pull/4049))
- Updated Dependencies
([#4045](https://github.com/dotnet/SqlClient/pull/4045)):
- Updated `Azure.Core` to v1.51.1
- Updated `Azure.Identity` to v1.18.0
- Updated `Azure.Security.KeyVault.Keys` to v4.9.0
- Updated `Microsoft.Extensions.Caching.Memory` to v9.0.13 (.NET 9.0)
- Updated `Microsoft.IdentityModel.JsonWebTokens` to v8.16.0
- Updated `Microsoft.IdentityModel.Protocols.OpenIdConnect` to v8.16.0
- Updated `Microsoft.Bcl.Cryptography` to v9.0.13 (.NET 9.0)
- Updated `System.Configuration.ConfigurationManager` to v9.0.13 (.NET
9.0)
- Updated `System.Diagnostics.DiagnosticSource` to v10.0.3
- Updated `System.Security.Cryptography.Pkcs` to v9.0.13 (.NET 9.0)
- Updated `System.Text.Json` to v10.0.3
- Updated `System.Threading.Channels` to v10.0.3
- Updated `System.ValueTuple` to v4.6.2
## Cumulative Changes Since [6.1](../6.1/README.md)
This section summarizes all changes across the 7.0 preview cycle for
users upgrading from the latest 6.1 stable release.
### Changed
#### Azure Dependencies Removed from Core Package
*What Changed:*
- The core `Microsoft.Data.SqlClient` package no longer depends on
`Azure.Core`, `Azure.Identity`, or their transitive dependencies (e.g.,
`Microsoft.Identity.Client`, `Microsoft.Web.WebView2`). Azure Active
Directory / Entra ID authentication functionality
(`ActiveDirectoryAuthenticationProvider` and related types) has been
extracted into a new `Microsoft.Data.SqlClient.Extensions.Azure`
package. ([#1108](https://github.com/dotnet/SqlClient/issues/1108),
[#3680](https://github.com/dotnet/SqlClient/pull/3680),
[#3902](https://github.com/dotnet/SqlClient/pull/3902),
[#3904](https://github.com/dotnet/SqlClient/pull/3904),
[#3908](https://github.com/dotnet/SqlClient/pull/3908),
[#3917](https://github.com/dotnet/SqlClient/pull/3917),
[#3982](https://github.com/dotnet/SqlClient/pull/3982),
[#3978](https://github.com/dotnet/SqlClient/pull/3978),
[#3986](https://github.com/dotnet/SqlClient/pull/3986))
... (truncated)
## 7.0.0-preview4
### Changed
#### Azure Dependencies Removed from Core Package
*What Changed:*
- The core `Microsoft.Data.SqlClient` package no longer depends on
`Azure.Core`, `Azure.Identity`, or their transitive dependencies (e.g.,
`Microsoft.Identity.Client`, `Microsoft.Web.WebView2`). Azure Active
Directory / Entra authentication functionality
(`ActiveDirectoryAuthenticationProvider` and related types) has been
extracted into a new `Microsoft.Data.SqlClient.Extensions.Azure` package
that can be installed separately when needed.
([#1108](https://github.com/dotnet/SqlClient/issues/1108),
[#3680](https://github.com/dotnet/SqlClient/pull/3680),
[#3902](https://github.com/dotnet/SqlClient/pull/3902),
[#3904](https://github.com/dotnet/SqlClient/pull/3904),
[#3908](https://github.com/dotnet/SqlClient/pull/3908),
[#3917](https://github.com/dotnet/SqlClient/pull/3917),
[#3982](https://github.com/dotnet/SqlClient/pull/3982),
[#3978](https://github.com/dotnet/SqlClient/pull/3978),
[#3986](https://github.com/dotnet/SqlClient/pull/3986))
- To support this separation, two additional packages were introduced:
`Microsoft.Data.SqlClient.Extensions.Abstractions` (shared types between
the core driver and extensions) and
`Microsoft.Data.SqlClient.Extensions.Logging` (shared ETW tracing
infrastructure).
([#3626](https://github.com/dotnet/SqlClient/pull/3626),
[#3628](https://github.com/dotnet/SqlClient/pull/3628),
[#3967](https://github.com/dotnet/SqlClient/pull/3967))
*Who Benefits:*
- All users benefit from a significantly lighter core package.
Previously, the Azure dependency chain pulled in numerous assemblies
(including `Azure.Core`, `Azure.Identity`, `Microsoft.Identity.Client`,
and `Microsoft.Web.WebView2`) even for applications that only needed
basic SQL Server connectivity. This was the most upvoted open issue in
the repository
([#1108](https://github.com/dotnet/SqlClient/issues/1108)).
- Users who do not use Azure AD authentication no longer carry
Azure-related assemblies in their build output, reducing deployment size
and eliminating confusion about unexpected dependencies.
- Users who do use Azure AD authentication can now manage Azure
dependency versions independently from the core driver.
*Impact:*
- Applications using Azure AD authentication (e.g.,
`ActiveDirectoryPassword`, `ActiveDirectoryInteractive`,
`ActiveDirectoryDefault`, etc.) must now install the
`Microsoft.Data.SqlClient.Extensions.Azure` NuGet package separately. No
code changes are required beyond adding the package reference.
### Added
#### Expose SSPI Context Provider as Public API
*What Changed:*
- Added the `SspiContextProvider` abstract class and a public
`SspiContextProvider` property on `SqlConnection`, allowing applications
to supply a custom SSPI context provider for integrated authentication.
This enables custom Kerberos ticket negotiation and NTLM
username/password authentication scenarios that the driver does not
natively support.
([#2253](https://github.com/dotnet/SqlClient/issues/2253),
[#2494](https://github.com/dotnet/SqlClient/pull/2494))
*Who Benefits:*
- Users authenticating across untrusted domains, non-domain-joined
machines, or cross-platform environments where configuring integrated
authentication on the client is difficult or impossible.
- Users running in containers who need manual Kerberos negotiation
without deploying sidecars or external ticket-refresh mechanisms.
- Users who need NTLM username/password authentication to SQL Server,
which the driver does not provide natively.
*Impact:*
- Applications can set a custom `SspiContextProvider` on `SqlConnection`
before opening the connection. The provider handles the authentication
token exchange during integrated authentication. This is an additive API
— existing authentication behavior is unchanged when no custom provider
is set. See
[SspiContextProvider_CustomProvider.cs](../../doc/samples/SspiContextProvider_CustomProvider.cs)
for a sample implementation.
- **Note:** The `SspiContextProvider` is a part of the connection pool
key. Care should be taken when using this property to ensure the
implementation returns a stable identity per resource.
#### Expose Default Transient Error List
*What Changed:*
- Exposed the default transient error codes list via the new
`SqlConfigurableRetryFactory.BaselineTransientErrors` static property
(returns a `ReadOnlyCollection<int>`), making it easier to extend the
set of transient errors without copy-pasting from the repository source.
([#3903](https://github.com/dotnet/SqlClient/pull/3903))
*Who Benefits:*
- Developers implementing custom retry logic who want to extend the
built-in transient error list rather than replacing it.
*Impact:*
... (truncated)
## 7.0.0-preview3
## Preview Release 7.0.0-preview3.25342.7 - December 8, 2025
### Added
#### Support for .NET 10
*What Changed:*
- Updated pipelines and test suites to compile the driver using the .NET
10 SDK. Cleaned up unnecessary dependency references.
([#3686](https://github.com/dotnet/SqlClient/pull/3686))
*Who Benefits:*
- Developers targeting .NET 10.
*Impact:*
- Addressed .NET 10 warnings regarding unused/unnecessary dependencies.
#### Enable SqlClientDiagnosticListener in SqlCommand on .NET Framework
*What Changed:*
- Enabled SqlClientDiagnosticListener functionality on SqlCommand for
.NET Framework.
([#3658](https://github.com/dotnet/SqlClient/pull/3658))
*Who Benefits:*
- Developers requiring diagnostic information on .NET Framework.
*Impact:*
- Improved observability and diagnostics for SqlCommand on .NET
Framework.
#### Enable User Agent Extension
*What Changed:*
- Enabled User Agent Feature Extension.
([#3606](https://github.com/dotnet/SqlClient/pull/3606))
*Who Benefits:*
- Telemetry and diagnostics consumers.
*Impact:*
- When the `Switch.Microsoft.Data.SqlClient.EnableUserAgent` app context
switch is enabled, the driver sends more detailed user agent strings.
This switch is disabled by default. This change will assist with
troubleshooting and quantifying driver usage by version and operating
system.
### Fixed
... (truncated)
## 7.0.0-preview2
This update brings the following changes since the
[7.0.0-preview1](7.0.0-preview1.md) release:
### Bug Fixes
- Fixed a debug assertion in connection pool (no impact to production
code) ([#3587](https://github.com/dotnet/SqlClient/pull/3587))
- Prevent uninitialized performance counters escaping
`CreatePerformanceCounters`
([#3623](https://github.com/dotnet/SqlClient/pull/3623))
- Fix SetProvider to return immediately if user-defined authentication
provider found ([#3620](https://github.com/dotnet/SqlClient/pull/3620))
- Allow SqlBulkCopy to operate on hidden columns
([#3590](https://github.com/dotnet/SqlClient/pull/3590))
- Fix connection pool concurrency issue
([#3632](https://github.com/dotnet/SqlClient/pull/3632))
### Added
#### App Context Switch for Ignoring Server-Provided Failover Partner
*What Changed:*
- A new app context switch
`Switch.Microsoft.Data.SqlClient.IgnoreServerProvidedFailoverPartner`
was introduced to let the client ignore server-provided failover partner
info in Basic Availability Groups (BAGs). When the switch is enabled,
only the failover partner specified in the connection string is used;
server-supplied partner values are skipped. This context switch was
introduced in PR
[#3625](https://github.com/dotnet/SqlClient/pull/3625).
*Who Benefits:*
- Applications connecting to SQL Server BAGs using TCP and custom ports,
especially where the server's provided partner name lacks the protocol,
host, or port. This avoids connection failures when the server-provided
partner is incompatible or incomplete.
- Teams who manage availability groups and rely on client-side control
of failover behavior in heterogeneous networking environments.
*Impact:*
- If your environment might be affected (i.e., you operate a BAG with
custom ports, or have experienced failures after failover), you can
enable the new switch in your application:
```
AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.IgnoreServerProvidedFailoverPartner", true);
```
- Then, ensure your connection string includes your preferred failover
partner (with correct `tcp:host,port`) so that the client uses that
instead of the server's suggestion.
- Without enabling this, by default, the client continues to prefer the
server-provided partner, maintaining backwards compatibility.
#### Other Additions
- Add app context switch for enabling asynchronous multi-packet
improvements ([#3605](https://github.com/dotnet/SqlClient/pull/3605))
### Changed
#### Deprecation of `SqlAuthenticationMethod.ActiveDirectoryPassword`
*What Changed:*
- Username/Password authentication for Microsoft Entra (formerly Active
Directory) has been deprecated.
`SqlAuthenticationMethod.ActiveDirectoryPassword` is now marked as
`[Obsolete]`. This change occurred in PR
[#3671](https://github.com/dotnet/SqlClient/pull/3671)
*Who benefits:*
- Teams moving toward stronger, passwordless or MFA-compliant auth (in
line with changes across MSAL/Azure.Identity and Entra MFA enforcement).
This aligns Microsoft.Data.SqlClient with Microsoft's direction to avoid
username/password (ROPC) flows. See
https://learn.microsoft.com/en-us/entra/identity/authentication/concept-mandatory-multifactor-authentication
for more explanation of why this change is being made across Microsoft
products/services.
... (truncated)
## 7.0.0-preview1
## Changes Since
[6.1.0](https://github.com/dotnet/SqlClient/blob/main/release-notes/6.1/6.1.0.md)
This update brings the following changes since the
[6.1.0](https://github.com/dotnet/SqlClient/blob/main/release-notes/6.1/6.1.0.md)
release:
### Breaking Changes
- Removed `Constrained Execution Region` error handling blocks and
associated `SqlConnection` cleanup which may affect how
potentially-broken connections are expunged from the pool.
([#3535](https://github.com/dotnet/SqlClient/pull/3535))
### Bug Fixes
- Packet multiplexing disabled by default, and several bug fixes.
([#3534](https://github.com/dotnet/SqlClient/pull/3534),
[#3537](https://github.com/dotnet/SqlClient/pull/3537))
### Added
- `SqlColumnEncryptionCertificateStoreProvider` now works on Windows,
Linux, and macOS.
([#3014](https://github.com/dotnet/SqlClient/pull/3014))
### Changed
- Updated `SqlVector.Null` to return a nullable `SqlVector` instance in
the reference API to match the implementation.
([#3521](https://github.com/dotnet/SqlClient/pull/3521))
- Performance improvements for all built-in
`SqlColumnEncryptionKeyStoreProvider` implementations.
([#3554](https://github.com/dotnet/SqlClient/pull/3554))
- Various test improvements.
([#3456](https://github.com/dotnet/SqlClient/pull/3456),
[#2968](https://github.com/dotnet/SqlClient/pull/2968),
[#3458](https://github.com/dotnet/SqlClient/pull/3458),
[#3494](https://github.com/dotnet/SqlClient/pull/3494),
[#3559](https://github.com/dotnet/SqlClient/pull/3559),
[#3575](https://github.com/dotnet/SqlClient/pull/3575))
- Codebase merge project and related cleanup.
([#3436](https://github.com/dotnet/SqlClient/pull/3436),
[#3434](https://github.com/dotnet/SqlClient/pull/3434),
[#3448](https://github.com/dotnet/SqlClient/pull/3448),
[#3454](https://github.com/dotnet/SqlClient/pull/3454),
[#3462](https://github.com/dotnet/SqlClient/pull/3462),
[#3435](https://github.com/dotnet/SqlClient/pull/3435),
[#3492](https://github.com/dotnet/SqlClient/pull/3492),
[#3473](https://github.com/dotnet/SqlClient/pull/3473),
[#3469](https://github.com/dotnet/SqlClient/pull/3469),
[#3394](https://github.com/dotnet/SqlClient/pull/3394),
[#3493](https://github.com/dotnet/SqlClient/pull/3493),
[#3593](https://github.com/dotnet/SqlClient/pull/3593))
- Documentation improvements.
([#3490](https://github.com/dotnet/SqlClient/pull/3490))
- Updated `Azure.Identity` dependency to v1.14.2.
([#3538](https://github.com/dotnet/SqlClient/pull/3538))
## Changes Since
[6.0.2](https://github.com/dotnet/SqlClient/blob/main/release-notes/6.0/6.0.2.md)
This update brings the following changes since the
[6.0.2](https://github.com/dotnet/SqlClient/blob/main/release-notes/6.0/6.0.2.md)
release. Changes already noted above are omitted:
### Additions
#### Added dedicated SQL Server vector datatype support
*What Changed:*
- Optimized vector communications between MDS and SQL Server 2025,
employing a custom binary format over the TDS protocol.
([#3433](https://github.com/dotnet/SqlClient/pull/3433),
[#3443](https://github.com/dotnet/SqlClient/pull/3443))
- Reduced processing load compared to existing JSON-based vector
support.
- Initial support for 32-bit single-precision floating point vectors.
*Who Benefits:*
- Applications moving large vector data sets will see beneficial
improvements to processing times and memory requirements.
- Vector-specific APIs are ready to support future numeric
representations with a consistent look-and-feel.
*Impact:*
... (truncated)
## 6.1.7
This update brings the following changes since the [6.1.6](6.1.6.md)
release:
### Changed
- Updated the `Microsoft.Data.SqlClient.SNI` and
`Microsoft.Data.SqlClient.SNI.runtime` dependencies to 6.0.3 (was
6.0.2).
([#4598](https://github.com/dotnet/SqlClient/pull/4598))
### Fixed
- Fixed `ServerCertificate` validation on the managed SNI path so the
configured certificate is compared against the server certificate even
when the server certificate passes chain and host-name validation. When
certificate validation is enabled, a missing, unreadable, or invalid
certificate file, a certificate mismatch, or a missing server
certificate now causes the TLS handshake to fail instead of bypassing
the configured certificate check. (net8.0/net9.0 only)
([#4445](https://github.com/dotnet/SqlClient/pull/4445),
[#4584](https://github.com/dotnet/SqlClient/pull/4584))
- Fixed Always Encrypted VSM/HGS enclave attestation to verify that the
enclave public key used to establish a session matches the key committed
to by the signed attestation report. Missing, malformed, or mismatched
key-binding data now causes attestation to fail before the session
secret is derived.
([#4532](https://github.com/dotnet/SqlClient/pull/4532),
[#4552](https://github.com/dotnet/SqlClient/pull/4552))
- Fixed `SqlConnection.AccessTokenCallback` not disabling Transparent
Network IP Resolution by default, making it consistent with
`SqlConnection.AccessToken`. An explicitly configured
`TransparentNetworkIPResolution` connection-string value still takes
precedence. (net462 only)
([#4520](https://github.com/dotnet/SqlClient/pull/4520),
[#4560](https://github.com/dotnet/SqlClient/pull/4560))
- Fixed token authentication state handling so clearing
`SqlConnection.AccessToken` preserves an existing `AccessTokenCallback`
in the connection pool key, and clearing `AccessTokenCallback` preserves
an existing `AccessToken`. Callback-based authentication now also
follows the same prelogin server-certificate validation rules as an
explicitly supplied access token.
([#4520](https://github.com/dotnet/SqlClient/pull/4520),
[#4560](https://github.com/dotnet/SqlClient/pull/4560))
- Fixed configurable retry logic installing a permanent, process-wide
assembly-resolution handler that could interfere with unrelated assembly
loading. The handler is now active only while an explicitly configured
custom retry provider is resolved and constructed, and probes
`AppContext.BaseDirectory` instead of the current working directory.
Place custom retry assemblies in the application base directory;
dependencies loaded after provider construction must be resolvable
through normal application dependency resolution or an
application-provided handler. (net8.0/net9.0 only)
([#2214](https://github.com/dotnet/SqlClient/issues/2214),
[#4547](https://github.com/dotnet/SqlClient/pull/4547),
[#4664](https://github.com/dotnet/SqlClient/pull/4664))
## Target Platform Support
- .NET Framework 4.6.2+ (Windows x86, Windows x64, Windows ARM64)
- .NET 8.0+ (Windows x86, Windows x64, Windows ARM64, Linux, macOS)
- .NET Standard 2.0+ (Windows x86, Windows x64, Windows ARM64, Linux,
macOS)
Full details:
[release-notes/6.1/6.1.7.md](https://github.com/dotnet/SqlClient/blob/main/release-notes/6.1/6.1.7.md)
Commits viewable in [compare
view](https://github.com/dotnet/sqlclient/compare/v6.1.6...v7.1.0).
</details>
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jason Carney <jason.carney1@gmail.com>
Description
Implements the four asynchronous key store provider APIs on
SqlColumnEncryptionAzureKeyVaultProvider, overriding the base class virtualsadded in #3673. Phase 2A of
specs/002-async-always-encrypted/spec.md.New
EncryptColumnEncryptionKeyAsync,DecryptColumnEncryptionKeyAsync,SignColumnMasterKeyMetadataAsync,VerifyColumnMasterKeyMetadataAsync.These call the Azure SDK's own async methods and flow the cancellation token
to them, rather than completing sync work on a returned task.
LocalCache.GetOrCreateAsync, plus aKeyedAsyncLock<TKey>helper that gatesconcurrent misses per key so a burst of callers makes one Key Vault request.
duplicated.
Behavior considerations
by one is visible to the other.
different keys stay parallel. Cancellation applies to the requesting caller
only; if the gate owner is cancelled or fails, the next waiter retries with
its own token and failures are not cached.
AddKeyAsyncdeliberately does not share_keyDictionarySemaphorewith syncAddKey. A sync caller blocking on a gate held across an awaited network callwould tie up a thread pool thread for that call's duration. Consequence: a
sync and an async caller may both fetch the same key, yielding the same result.
SqlColumnEncryptionKeyStoreProvider.synchronously, matching FR-003.
ColumnEncryptionKeyCacheTtlof zero) gating isbypassed, since there is no entry for a waiter to observe. Callers reach Key
Vault in parallel where the sync path serialized them.
VerifyColumnMasterKeyMetadataandVerifyColumnMasterKeyMetadataAsyncnowboth reject a null or empty
signaturewithArgumentNullException/ArgumentException. Previously it reached the Azure SDK and failed there. Thisis a deliberate behavior change to the existing sync API, kept in both
overloads for parity; in-product callers are unaffected because
SqlSecurityUtility.VerifyColumnMasterKeySignaturealready rejects it upstream.Worth a release note callout.
covers restore, but a runtime downgrade below 7.1 produces a
TypeLoadExceptionbecause assembly versions unify atmajor.0.0.0. Worth arelease note callout.
Incidental fixes in code the refactor touched
LocalCache.GetOrCreatecompacts onCount >= maxSizerather than==; theequality test could be stepped past under concurrency, permanently disabling
compaction on the 2000 entry signature cache.
GetCryptographyClientusedTryGetValuethenTryAdd, so concurrentcallers could each use a different
CryptographyClientfor one key. NowGetOrAdd.new byte[]on thepreceding line.
No public API removed or changed.
Issues
Addresses #3672 (Step 2)
Testing
AKVUnitTests: async encrypt/decrypt and sign/verify round trips; sync andasync keys interchangeable; caching during async decryption and sharing with the
sync path; caching disabled at TTL zero; signature verification caching; 32
concurrent decryptions collapsing to one cache entry; cancelled decryptions not
accumulating gates; cancellation honoured and taking precedence over validation;
master key path validation.
ExceptionTestAKVStore: argument validation for all four members, plus invalidalgorithm version, invalid signature and invalid cipher text length.
These need a live vault and are gated on
DataTestUtility.IsAKVSetupAvailable,so they run in the pipeline.
LocalCacheandKeyedAsyncLockconcurrency wasadditionally verified locally against the built assembly with a standalone
harness covering deduplication, parallelism across keys, cancelled waiters,
owner failure and retry, gate cleanup and compaction.
Sync behavior preservation was checked by comparing every statement of the
original sync encrypt and decrypt methods against the current file. All are
preserved except the unreachable null check above and a dead store to a
positionvariable never read after its final update.