Skip to content

Migration Runtime and Compatibility

Cheena Malhotra edited this page Sep 11, 2026 · 1 revision

Migration: runtime behavior and compatibility

Home / Migrate / Runtime

Compare results, not just successful connections. Data-shape and precision changes can be more consequential than an obvious exception.

Focus the regression suite

Area What to exercise
Nullable rowversion / timestamp results MDS uses DBNull rather than the legacy empty-byte-array shape. Check nulls before casting. Include outer-join results.
Decimal precision and scale MDS's scale adjustment rounds by default. Verify stored values at scale boundaries, especially financial calculations.
Date and time parameters Use TimeSpan, not DateTime, for DbType.Time. Sending a DateTime as DbType.Date truncates its time component. Verify round trips.
Exceptions Retype SDS-specific handlers; check authentication and Always Encrypted error paths against the selected release.
Asynchronous operations Exercise synchronous and asynchronous open/read/execute, cancellation, disposal, and large payloads. Remove assumptions about synchronous completion.
Observability Set a stable application name if dashboards or server-side classification depend on it. Recheck diagnostic subscriptions and identifiers.
Connection-string sharing MDS builders can emit keyword spellings an SDS parser does not accept. Use provider-appropriate configuration at each boundary.
Always Encrypted Exercise custom key-provider registration, precedence, permissions, and enclave paths your application uses.

Connection strings across provider boundaries

MDS accepts both the original keywords and newer aliases with spaces. Its connection-string builder can emit the spaced aliases, which SDS does not accept:

MDS builder output Spelling accepted by SDS and MDS
Application Intent=ReadOnly ApplicationIntent=ReadOnly
Multi Subnet Failover=True MultiSubnetFailover=True

Prefer building each connection string with the provider that will consume it. If a shared configuration must support both providers, map these keyword names explicitly and check every other setting for compatibility. Do not remove spaces from the entire string: that can corrupt server names, database names, credentials, and other values. An MDS-only setting does not become SDS-compatible just by changing whitespace.

Globalization when moving to modern .NET

.NET Framework uses Windows National Language Support (NLS). Modern .NET uses International Components for Unicode (ICU) by default on supported Windows versions, as it does on Linux/macOS. This runtime change can affect culture-sensitive System.Data.SqlTypes.SqlString comparisons independently of the provider migration.

Test client-side equality and ordering against the database's actual collation, including application-relevant casing, accents, and punctuation. Do not assume client comparisons will match SQL Server after the runtime move.

For a Windows application that requires the previous NLS behavior, merge this setting into the application's runtimeconfig.json before starting the process:

{
  "runtimeOptions": {
    "configProperties": {
      "System.Globalization.UseNls": true
    }
  }
}

Preserve existing runtime settings. NLS is Windows-only, and this is an application-wide .NET setting, not a SqlClient-only switch or a guarantee of equivalence to every SQL collation. Retest other culture-sensitive operations. See NLS configuration guidance for project/environment alternatives and precedence rules.

Compatibility switches are temporary controls

Prefer correcting application assumptions. Where a selected release supports a compatibility switch, record the exact name, purpose, owner, and removal condition.

Two established migration controls are Switch.Microsoft.Data.SqlClient.LegacyRowVersionNullBehavior and Switch.Microsoft.Data.SqlClient.TruncateScaledDecimal. Enabling them restores the corresponding legacy null/decimal behavior; it also changes semantics process-wide. Validate that this is what all affected callers require.

Configure switches before the driver first uses them, normally at startup before SqlClient initialization. Many values are cached. Do not copy a development-branch switch list into a released application: availability, defaults, and interactions depend on version.

Leave optional pool and networking performance experiments unchanged during the initial migration. Benchmark those independently afterward.

A historical change not to carry forward

The statement "GetSchemaTable() never returns null in modern MDS" is not a valid migration rule. The 2.0.0 empty-table change was reverted in 2.0.1. Retain appropriate null handling; do not replace it with an unconditional schema.Rows dereference.

Next: Deployment and rollout.

Sources: porting guide, decimal behavior, schema-table reversion, 3.0 behavior changes, globalization guidance.

Clone this wiki locally