<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Naveen Kanagala</title>
    <description>The latest articles on DEV Community by Naveen Kanagala (@naveen_kanagala).</description>
    <link>https://dev.to/naveen_kanagala</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1946030%2F3be78889-704c-4693-a227-528d13d7da64.jpg</url>
      <title>DEV Community: Naveen Kanagala</title>
      <link>https://dev.to/naveen_kanagala</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/naveen_kanagala"/>
    <language>en</language>
    <item>
      <title>Fixing AAD Authentication and SSL Issues in IIS — Why We Migrated from System.Data.SqlClient to Microsoft.Data.SqlClient</title>
      <dc:creator>Naveen Kanagala</dc:creator>
      <pubDate>Tue, 24 Mar 2026 16:37:05 +0000</pubDate>
      <link>https://dev.to/naveen_kanagala/fixing-aad-authentication-and-ssl-issues-in-iis-why-we-migrated-from-systemdatasqlclient-to-21l0</link>
      <guid>https://dev.to/naveen_kanagala/fixing-aad-authentication-and-ssl-issues-in-iis-why-we-migrated-from-systemdatasqlclient-to-21l0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;"Everything was working fine. Then someone added an Azure database connection string. And suddenly, nothing was fine."&lt;br&gt;
— Every senior developer on a legacy project, at least once&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4qecnws5t3egyvvn5jl5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4qecnws5t3egyvvn5jl5.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;🧭 Overview&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I have been working on enterprise .NET applications for over 11+ years now. Most of them are what people politely call "legacy systems" — Web Forms,API's, IIS deployments, App.config files, the works. These applications run without issues for years. On-prem SQL Server connections are rock solid. Everyone is happy.&lt;/p&gt;

&lt;p&gt;Then one day, your team decides to add a cloud database — Azure SQL — because the client wants to "move to the cloud" or some new feature needs it. You add a new connection string, you test locally, it kind of works, and then you deploy to IIS.&lt;/p&gt;

&lt;p&gt;That is when the fun begins.&lt;/p&gt;

&lt;p&gt;This article is about exactly that situation — what went wrong in one of our production systems, why it went wrong, and how we fixed it properly. If you are working on a legacy .NET app and adding Azure SQL connections, please read this fully before you touch anything.&lt;/p&gt;




&lt;h2&gt;
  
  
  😤 The Real Problem
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Let me describe what happened on our project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We had a large ASP.NET Web API is running on IIS. It was talking to an on-prem SQL Server using System.Data.SqlClient. No issues. Hundreds of stored procedures, millions of rows, everything running smoothly for years.&lt;br&gt;
    Then we added a new module that needed to connect to an Azure SQL Database using Azure Active Directory (AAD) authentication. The connection string looked something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"AzureDB"&lt;/span&gt;
     &lt;span class="na"&gt;connectionString=&lt;/span&gt;&lt;span class="s"&gt;"Server=tcp:myserver.database.windows.net,1433;
                       Initial Catalog=MyDatabase;
                       Authentication=Active Directory Default;
                       Encrypt=True;
                       TrustServerCertificate=False;"&lt;/span&gt;
     &lt;span class="na"&gt;providerName=&lt;/span&gt;&lt;span class="s"&gt;"System.Data.SqlClient"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Locally on dev machines — it worked. Sometimes. On IIS in staging — error. In production — different error. The errors we saw were:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SSQL: A connection was successfully established with the server, 
but then an error occurred during the login process.
(provider: SSL Provider, error: 0 - The certificate chain was issued 
by an authority that is not trusted.) 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;System.Data.SqlClient.SqlException: 
Failed to authenticate the user in Active Directory (Authentication=ActiveDirectoryDefault).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our on-prem connections were still working perfectly. Only the Azure connection was failing. And every time we tried to fix one error, another one showed up.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🔍 Root Cause — The Actual Diagnosis&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;After a lot of head-scratching and reading through event logs, we figured out the real problem.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;System.Data.SqlClient&lt;/code&gt; &lt;strong&gt;is the old provider.&lt;/strong&gt;  It is the one that ships with the .NET Framework itself. Microsoft stopped actively developing it for new features years ago.&lt;br&gt;
 Specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It does &lt;strong&gt;not support AAD authentication&lt;/strong&gt; properly in older versions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It has &lt;strong&gt;SSL/TLS handling issues&lt;/strong&gt; with Azure SQL, especially around certificate validation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It does &lt;strong&gt;not support&lt;/strong&gt; the newer &lt;code&gt;Authentication=Active Directory Default&lt;/code&gt; or &lt;code&gt;Active Directory Interactive modes&lt;/code&gt; reliably.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Microsoft.Data.SqlClient&lt;/code&gt; is the new, actively maintained NuGet package from Microsoft. It:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Supports all AAD authentication modes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Has proper TLS 1.2/1.3 support for Azure connections.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Works correctly in both .NET Framework and .NET Core/.NET 5+.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Is the &lt;strong&gt;officially recommended&lt;/strong&gt; replacement.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The root cause was simple: we were trying to use a 2005-era database driver to connect to a 2023-era cloud authentication system. It was never going to work reliably.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚠️ The Partial Migration Trap&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;WARNING: This is the most dangerous part. Please read carefully&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After reading about &lt;code&gt;Microsoft.Data.SqlClient&lt;/code&gt;, many developers do what seems logical — they install the NuGet package and start updating files one by one. Some files get the new &lt;code&gt;using Microsoft.Data.SqlClient;&lt;/code&gt;and some still have &lt;code&gt;using System.Data.SqlClient;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This causes a whole new category of problems:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;System.InvalidCastException: 
Unable to cast object of type 'Microsoft.Data.SqlClient.SqlConnection' 
to type 'System.Data.SqlClient.SqlConnection'.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;System.ArgumentException: 
DbCommand is of an invalid type for this DbConnection.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These happen because objects from the two namespaces &lt;strong&gt;look identical but are completely different types.&lt;/strong&gt; Passing a &lt;code&gt;Microsoft.Data.SqlClient.SqlConnection&lt;/code&gt; to a method that expects &lt;code&gt;System.Data.SqlClient.SqlConnection&lt;/code&gt; will throw a cast exception at runtime — not at compile time. It will pass your unit tests and explode in production.&lt;br&gt;
 &lt;strong&gt;You cannot mix these two providers in the same application unless you are extremely careful about isolation.&lt;/strong&gt; The safest approach — and what we did — was to migrate fully.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;✅ The Solution — Step by Step&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here is exactly what we did, in order.&lt;br&gt;
&lt;strong&gt;Step 1 — Install the NuGet Package&lt;/strong&gt;&lt;br&gt;
Open your Package Manager Console or right-click the project in Visual Studio:&lt;br&gt;
&lt;code&gt;Install-Package Microsoft.Data.SqlClient&lt;/code&gt;&lt;br&gt;
Or via CLI:&lt;br&gt;
&lt;code&gt;dotnet add package Microsoft.Data.SqlClient&lt;/code&gt;&lt;br&gt;
At the time of our migration, we used version 5.x. Use the latest stable version. This package works fine with .NET Framework 4.6.1 and above, as well as .NET 6/7/8.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Step 2 — Update All C# Files (The &lt;code&gt;using&lt;/code&gt;Statement)&lt;/strong&gt;&lt;br&gt;
This is the tedious part but you cannot skip it. Go through every single C# file that uses SQL:&lt;br&gt;
&lt;strong&gt;Before:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Data.SqlClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DataTable&lt;/span&gt; &lt;span class="nf"&gt;GetUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;connString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SqlConnection&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SqlConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connString&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;SqlCommand&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SqlCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT * FROM Users"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;SqlDataAdapter&lt;/span&gt; &lt;span class="n"&gt;da&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SqlDataAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;DataTable&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DataTable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;da&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Data.SqlClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// ← Only this line changes&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DataTable&lt;/span&gt; &lt;span class="nf"&gt;GetUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;connString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SqlConnection&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SqlConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connString&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;SqlCommand&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SqlCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT * FROM Users"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;SqlDataAdapter&lt;/span&gt; &lt;span class="n"&gt;da&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SqlDataAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;DataTable&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DataTable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;da&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The class names — &lt;code&gt;SqlConnection&lt;/code&gt;, &lt;code&gt;SqlCommand&lt;/code&gt;, &lt;code&gt;SqlDataAdapter&lt;/code&gt;, &lt;code&gt;SqlDataReader&lt;/code&gt;, &lt;code&gt;SqlParameter&lt;/code&gt;, &lt;code&gt;SqlException&lt;/code&gt;— all remain exactly the same. Only the namespace changes. This makes the migration much smoother.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pro Tip&lt;/strong&gt;: Use Visual Studio's Find &amp;amp; Replace across the entire solution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Find: &lt;code&gt;using System.Data.SqlClient;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Replace: &lt;code&gt;using Microsoft.Data.SqlClient;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scope: Entire Solution&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then do a full build and fix any remaining compilation errors one by one.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Step 3 — Update Web.config — DbProviderFactories&lt;/strong&gt;&lt;br&gt;
This step is &lt;strong&gt;critical for IIS deployments&lt;/strong&gt; and the one most people miss.&lt;br&gt;
If your application uses DbProviderFactory (which many enterprise apps do for abstraction), you need to register the new provider in &lt;code&gt;Web.config&lt;/code&gt; under &lt;code&gt;system.data&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;system.data&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;DbProviderFactories&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Remove or comment out the old one --&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!--
    &amp;lt;remove invariant="System.Data.SqlClient" /&amp;gt;
    &amp;lt;add name="SqlClient Data Provider"
         invariant="System.Data.SqlClient"
         description=".Net Framework Data Provider for SqlServer"
         type="System.Data.SqlClient.SqlClientFactory, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /&amp;gt;
    --&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Add the new Microsoft.Data.SqlClient provider --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;remove&lt;/span&gt; &lt;span class="na"&gt;invariant=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.Data.SqlClient"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"SqlClient Data Provider"&lt;/span&gt;
         &lt;span class="na"&gt;invariant=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.Data.SqlClient"&lt;/span&gt;
         &lt;span class="na"&gt;description=&lt;/span&gt;&lt;span class="s"&gt;".NET Framework Data Provider for SQL Server"&lt;/span&gt;
         &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.Data.SqlClient.SqlClientFactory, Microsoft.Data.SqlClient"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/DbProviderFactories&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/system.data&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you skip this step, IIS will throw:&lt;br&gt;
&lt;code&gt;Unable to find the requested .Net Framework Data Provider. &lt;br&gt;
It may not be installed.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Even if your code compiles perfectly and runs on localhost, IIS uses these registered factories to resolve providers at runtime.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Step 4 — Update Connection Strings in Web.config&lt;/strong&gt;&lt;br&gt;
Update the providerName in your connection strings from the old value to the new one:&lt;br&gt;
&lt;strong&gt;Before:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;connectionStrings&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"OnPremDB"&lt;/span&gt;
       &lt;span class="na"&gt;connectionString=&lt;/span&gt;&lt;span class="s"&gt;"Server=MYSERVER;Database=MyDB;Integrated Security=True;"&lt;/span&gt;
       &lt;span class="na"&gt;providerName=&lt;/span&gt;&lt;span class="s"&gt;"System.Data.SqlClient"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"AzureDB"&lt;/span&gt;
       &lt;span class="na"&gt;connectionString=&lt;/span&gt;&lt;span class="s"&gt;"Server=tcp:myserver.database.windows.net,1433;
                         Initial Catalog=MyDatabase;
                         Authentication=Active Directory Default;
                         Encrypt=True;
                         TrustServerCertificate=False;"&lt;/span&gt;
       &lt;span class="na"&gt;providerName=&lt;/span&gt;&lt;span class="s"&gt;"System.Data.SqlClient"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/connectionStrings&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;connectionStrings&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"OnPremDB"&lt;/span&gt;
       &lt;span class="na"&gt;connectionString=&lt;/span&gt;&lt;span class="s"&gt;"Server=MYSERVER;Database=MyDB;Integrated Security=True;"&lt;/span&gt;
       &lt;span class="na"&gt;providerName=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.Data.SqlClient"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"AzureDB"&lt;/span&gt;
       &lt;span class="na"&gt;connectionString=&lt;/span&gt;&lt;span class="s"&gt;"Server=tcp:myserver.database.windows.net,1433;
                         Initial Catalog=MyDatabase;
                         Authentication=Active Directory Default;
                         Encrypt=True;
                         TrustServerCertificate=False;"&lt;/span&gt;
       &lt;span class="na"&gt;providerName=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.Data.SqlClient"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/connectionStrings&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;connectionStrings&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"OnPremDB"&lt;/span&gt;
       &lt;span class="na"&gt;connectionString=&lt;/span&gt;&lt;span class="s"&gt;"Server=MYSERVER;Database=MyDB;Integrated Security=True;"&lt;/span&gt;
       &lt;span class="na"&gt;providerName=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.Data.SqlClient"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"AzureDB"&lt;/span&gt;
       &lt;span class="na"&gt;connectionString=&lt;/span&gt;&lt;span class="s"&gt;"Server=tcp:myserver.database.windows.net,1433;
                         Initial Catalog=MyDatabase;
                         Authentication=Active Directory Default;
                         Encrypt=True;
                         TrustServerCertificate=False;"&lt;/span&gt;
       &lt;span class="na"&gt;providerName=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.Data.SqlClient"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/connectionStrings&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Step 5 — Handle the Encrypt=True Change (Breaking Change Alert!)&lt;/strong&gt;&lt;br&gt;
Starting from &lt;code&gt;Microsoft.Data.SqlClient&lt;/code&gt; version &lt;strong&gt;4.0&lt;/strong&gt;, &lt;code&gt;Encrypt=True&lt;/code&gt; is the &lt;strong&gt;default&lt;/strong&gt;. This is a breaking change from the old driver where &lt;code&gt;Encrypt=False&lt;/code&gt; was the default.&lt;/p&gt;

&lt;p&gt;If your on-prem SQL Server does not have a properly configured SSL certificate, you will suddenly get SSL errors on previously working connections after migration.&lt;/p&gt;

&lt;p&gt;Fix this by being explicit in your on-prem connection strings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- For On-Prem SQL Server without SSL certificate --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"OnPremDB"&lt;/span&gt;
     &lt;span class="na"&gt;connectionString=&lt;/span&gt;&lt;span class="s"&gt;"Server=MYSERVER;
                       Database=MyDB;
                       Integrated Security=True;
                       Encrypt=False;"&lt;/span&gt;
     &lt;span class="na"&gt;providerName=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.Data.SqlClient"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- For Azure SQL — always use Encrypt=True --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"AzureDB"&lt;/span&gt;
     &lt;span class="na"&gt;connectionString=&lt;/span&gt;&lt;span class="s"&gt;"Server=tcp:myserver.database.windows.net,1433;
                       Initial Catalog=MyDatabase;
                       Authentication=Active Directory Default;
                       Encrypt=True;
                       TrustServerCertificate=False;"&lt;/span&gt;
     &lt;span class="na"&gt;providerName=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.Data.SqlClient"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🏢 &lt;strong&gt;Special Case — On-Prem + Cloud Running Together&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is our exact scenario, and I want to give it its own section because it has some nuances.&lt;/p&gt;

&lt;p&gt;When you have &lt;strong&gt;both on-prem SQL Server and Azure SQL&lt;/strong&gt; in the same application, you need to be careful about:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Authentication Mode Differences&lt;/strong&gt;&lt;br&gt;
On-prem typically uses Windows Authentication (Integrated Security) or SQL Authentication. Azure SQL uses AAD-based authentication or SQL Authentication. These are completely different mechanisms, and &lt;code&gt;Microsoft.Data.SqlClient&lt;/code&gt; handles both cleanly — you just need the right connection string.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- On-Prem: Windows Auth --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"OnPremDB"&lt;/span&gt;
     &lt;span class="na"&gt;connectionString=&lt;/span&gt;&lt;span class="s"&gt;"Server=SQLPROD01;
                       Database=CoreDB;
                       Integrated Security=True;
                       Encrypt=False;"&lt;/span&gt;
     &lt;span class="na"&gt;providerName=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.Data.SqlClient"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Azure: AAD Managed Identity --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"AzureDB"&lt;/span&gt;
     &lt;span class="na"&gt;connectionString=&lt;/span&gt;&lt;span class="s"&gt;"Server=tcp:prodserver.database.windows.net,1433;
                       Initial Catalog=CloudDB;
                       Authentication=Active Directory Managed Identity;
                       Encrypt=True;"&lt;/span&gt;
     &lt;span class="na"&gt;providerName=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.Data.SqlClient"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Azure: AAD Username/Password (for dev/testing) --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"AzureDevDB"&lt;/span&gt;
     &lt;span class="na"&gt;connectionString=&lt;/span&gt;&lt;span class="s"&gt;"Server=tcp:devserver.database.windows.net,1433;
                       Initial Catalog=DevDB;
                       Authentication=Active Directory Password;
                       User ID=myuser@mycompany.com;
                       Password=MyPassword;
                       Encrypt=True;"&lt;/span&gt;
     &lt;span class="na"&gt;providerName=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.Data.SqlClient"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. IIS Application Pool Identity Matters for AAD&lt;/strong&gt;&lt;br&gt;
When you use &lt;code&gt;Authentication=Active Directory Default&lt;/code&gt;  or &lt;code&gt;Authentication=Active Directory Managed Identity&lt;/code&gt; on IIS, the &lt;strong&gt;Application Pool Identity&lt;/strong&gt; must have the right permissions assigned in Azure.&lt;br&gt;
If you are using a &lt;strong&gt;Managed Identity&lt;/strong&gt;, make sure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your App Service or VM has a System Assigned Managed Identity enabled.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;2.That identity is added to the Azure SQL database as a user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Run this in your Azure SQL database&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;USER&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;your&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="k"&gt;EXTERNAL&lt;/span&gt; &lt;span class="n"&gt;PROVIDER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;ROLE&lt;/span&gt; &lt;span class="n"&gt;db_datareader&lt;/span&gt; &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="n"&gt;MEMBER&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;your&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;ROLE&lt;/span&gt; &lt;span class="n"&gt;db_datawriter&lt;/span&gt; &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="n"&gt;MEMBER&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;your&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the app pool is running under a service account and you are using Active Directory Integrated, that service account must be synced to Azure AD.&lt;br&gt;
&lt;strong&gt;3. Firewall and Network Rules&lt;/strong&gt;&lt;br&gt;
On-prem SQL Server connections go through your internal network. Azure SQL connections go out through the internet (or Express Route / VPN). Make sure your IIS server's outbound IP is whitelisted in the Azure SQL firewall rules.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;❌ Common Mistakes We Made (So You Don't Have To)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mistake 1 — Partial Migration&lt;/strong&gt;&lt;br&gt;
Already covered above, but worth repeating: if you update half the files and leave the rest, you will get casting exceptions at runtime. Do the complete migration in one go.&lt;br&gt;
&lt;strong&gt;Mistake 2 — Forgetting the DbProviderFactories Section&lt;/strong&gt;&lt;br&gt;
Every time we forgot to update Web.config DbProviderFactories, we got:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Unable to find the requested .Net Framework Data Provider.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This happens only on IIS, not on local dev. Very frustrating.&lt;br&gt;
&lt;strong&gt;Mistake 3 — Not Setting Encrypt Explicitly&lt;/strong&gt;&lt;br&gt;
After upgrading to v4+, our on-prem connections started failing with SSL certificate errors because Encrypt=True became the default. We had to explicitly add Encrypt=False for on-prem connections where SSL was not configured.&lt;br&gt;
&lt;strong&gt;Mistake 4 — Using TrustServerCertificate=True as a Shortcut&lt;/strong&gt;&lt;br&gt;
Yes, this silences the SSL error. But don't do it for Azure connections in production. It makes your connection vulnerable to man-in-the-middle attacks. Fix the actual certificate issue properly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- ❌ Don't do this for Azure production connections --&amp;gt;&lt;/span&gt;
TrustServerCertificate=True

&lt;span class="c"&gt;&amp;lt;!-- ✅ Do this instead — use proper certificate validation --&amp;gt;&lt;/span&gt;
Encrypt=True;TrustServerCertificate=False
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Mistake 5 — Not Restarting the IIS Application Pool&lt;/strong&gt;&lt;br&gt;
After deploying the updated DLLs and Web.config, always recycle the Application Pool in IIS. The old provider might be cached in the worker process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;iisreset /noforce
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or from IIS Manager → Application Pools → Recycle.&lt;br&gt;
&lt;strong&gt;Mistake 6 — Ignoring the Event Viewer&lt;/strong&gt;&lt;br&gt;
Most AAD and SSL errors on IIS show up in Windows Event Viewer under Application Logs — not just in your &lt;strong&gt;application logs&lt;/strong&gt;. Always check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Event Viewer → Windows Logs → Application
Event Viewer → Windows Logs → System
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;🎉 Final Result&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;After the complete migration:&lt;br&gt;
✅ On-prem SQL Server connections — still working, no change in behavior.&lt;br&gt;
✅ Azure SQL connection — connected successfully using AAD authentication.&lt;br&gt;
✅ SSL/TLS errors — gone completely. Microsoft.Data.SqlClient handles TLS 1.2 properly.&lt;br&gt;
✅ IIS deployment — stable. No more "Data Provider not found" errors.&lt;br&gt;
✅ No more mixed namespace issues — clean codebase with a single provider.&lt;br&gt;
Here is a quick sanity check you can run after migration to make sure both connections are working:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Data.SqlClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConnectionTester&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;TestConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SqlConnection&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SqlConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Connected to: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; | Database: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SqlException&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Connection failed: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;🏁 Conclusion&lt;/strong&gt;&lt;br&gt;
If your legacy .NET application is running on IIS and you are adding Azure SQL connections, do not try to use &lt;code&gt;System.Data.SqlClient&lt;/code&gt; for it. That provider was not built for AAD authentication or modern Azure SSL requirements.&lt;br&gt;
The migration from &lt;code&gt;System.Data.SqlClient&lt;/code&gt; to &lt;code&gt;Microsoft.Data.SqlClient&lt;/code&gt; is actually not that complicated — the class names are the same, the APIs are the same, only the namespace changes. The tricky parts are:&lt;/p&gt;

&lt;p&gt;Doing it &lt;strong&gt;completely&lt;/strong&gt;, not partially.&lt;br&gt;
Updating the &lt;strong&gt;Web.config DbProviderFactories&lt;/strong&gt; section (this one bites everyone on IIS).&lt;br&gt;
Being &lt;strong&gt;explicit about Encrypt=&lt;/strong&gt; in all your connection strings.&lt;br&gt;
Understanding that on-prem and Azure connections need &lt;strong&gt;different settings&lt;/strong&gt; even when using the same provider.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;📝 Short Summary&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Problem:&lt;/strong&gt; Legacy IIS app using &lt;code&gt;System.Data.SqlClient&lt;/code&gt; started failing with AAD and SSL errors after adding Azure SQL connections.&lt;br&gt;
Reason: &lt;code&gt;System.Data.SqlClient&lt;/code&gt; doesn't properly support AAD authentication modes or modern TLS requirements for Azure SQL.&lt;br&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; Full migration to &lt;strong&gt;Microsoft.Data.SqlClient&lt;/strong&gt; NuGet package — update &lt;code&gt;using&lt;/code&gt;statements across all C# files, register the new provider in &lt;code&gt;Web.config&lt;/code&gt;DbProviderFactories, update connection string &lt;code&gt;providerName&lt;/code&gt;, and be explicit about &lt;code&gt;Encrypt&lt;/code&gt;settings per connection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💡 Practical Advice from Experience&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Plan the migration as a single Sprint task&lt;/strong&gt;, not a side change. Partial migration causes more problems than the original bug.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Test on IIS staging first&lt;/strong&gt; — many of these errors don't show up on your local IIS Express setup.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Keep one environment running the old code&lt;/strong&gt; until you verify the new deployment is stable. Don't cut over both environments at the same time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;For AAD connections, always test with the exact IIS App Pool identity&lt;/strong&gt; — not your personal Windows account. What works for you locally might not work for the service account.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Read the Microsoft.Data.SqlClient release notes&lt;/strong&gt; before upgrading major versions. The team has been making breaking changes between version 3, 4, and 5. Encrypt default change in v4 is the most common surprise.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If this article helped you, please share it with your team. Legacy app migrations don't have to be painful if you know exactly what to change and in what order.&lt;/p&gt;

&lt;p&gt;Happy shipping! 🚀&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>azure</category>
      <category>sqlserver</category>
      <category>csharp</category>
    </item>
  </channel>
</rss>
