La migrazione a SQL Server 2022 e all’ODBC Driver 18 può far “rompere” un’app .NET che funzionava con SQL Server 2019. Qui trovi cause, diagnostica e soluzioni per evitare di installare Visual Studio sui server di produzione.
Relazione fra SQL Server 2022, ODBC Driver 18 e Visual Studio 2022
L’aggiornamento di una soluzione C#/.NET a SQL Server 2022 introduce tre cambiamenti chiave:
- Driver: ODBC Driver 18 sostituisce i provider legacy, abilita la crittografia per impostazione predefinita e richiede TLS 1.2.
- Provider .NET: molte app usano ancora
System.Data.SqlCliento ODBC viaSystem.Data.Odbc; per funzionalità moderne e compatibilità sicurezza, è consigliatoMicrosoft.Data.SqlClient. - Runtime: Visual Studio installa una costellazione di prerequisiti (VC++ Redist, .NET Desktop Runtime, librerie COM, DACFx) che su una VM “pulita” non ci sono.
Risultato tipico: l’app che in laboratorio funziona (perché è presente VS) crasha su una VM minimalista. Installando Visual Studio il problema scompare, ma non è una soluzione accettabile in produzione.
Sintomi tipici
- Crash all’avvio senza messaggi, oppure
System.DllNotFoundException/BadImageFormatExceptionnel registro eventi. - Connessione che fallisce dopo il passaggio a ODBC 18 con errori su certificato, crittografia o protocolli TLS.
- Richiami a DLL non più presenti (
sqlncli*.dlldi Native Client).
Analisi delle cause (in sintesi)
| Possibile causa | Spiegazione |
|---|---|
| Componenti di runtime mancanti | L’installazione di Visual Studio porta con sé runtime MSVC, .NET Desktop Runtime, librerie COM, MSBuild‑Tools, DACFx, ecc. L’app può dipendere da uno o più di questi file che, in una VM dove è presente solo l’ODBC Driver 18, non vengono installati. |
| Uso involontario di provider deprecati | SQL Server Native Client (SQLNCLI/SQLNCLI11) è stato rimosso da SQL Server 2022; se il programma tenta di caricarlo, all’assenza della DLL segue un crash. |
| Impostazioni di connessione non aggiornate | ODBC Driver 18 abilita TLS 1.2 e la crittografia per default; se il server non è configurato in modo coerente oppure Encrypt non è gestito correttamente, l’inizializzazione della connessione può fallire. |
Perché installare Visual Studio “risolve” (ma non è la cura)
VS 2022 include i redistributable VC++ (2015‑2022), i runtime .NET Desktop nelle versioni correnti, componenti COM condivisi da tool Microsoft e spesso anche DACFx/SqlPackage. Se l’app fa P/Invoke verso librerie native o si appoggia a componenti COM registrati, l’assenza di questi prerequisiti su una macchina pulita porta a crash. La soluzione corretta è distribuire solo i runtime necessari nel tuo setup.
ODBC Driver 18: cosa cambia davvero
- Crittografia by default:
Encryptè attivo di default. Se il server non ha un certificato valido o il nome non corrisponde al CN/SAN, la connessione fallisce. - TrustServerCertificate: per impostazione predefinita è disattivato; bypassare la validazione del certificato richiede esplicitare
TrustServerCertificate=Yes(sconsigliato in produzione). - TLS: richiede TLS 1.2 (o superiore) sia lato client che server; suite obsolete non sono accettate.
- Compatibilità: ODBC 18 è retro‑compatibile con SQL Server 2008+; non servono più driver multipli per versioni diverse.
Native Client è storia
SQL Server Native Client (SQLNCLI/SQLNCLI11) è deprecato e non è distribuito con SQL Server 2022. Se la tua app usa stringhe del tipo Provider=SQLNCLI11.1; o fa riferimento a sqlncli11.dll, devi migrare a:
- ODBC Driver 18 con
System.Data.Odbc; - oppure Microsoft.Data.SqlClient (ADO.NET moderno);
- oppure Microsoft OLE DB Driver 19 for SQL Server se l’applicazione è OLE DB e non può essere modificata.
Soluzioni pratiche (passo‑passo)
Elimina dipendenze da Native Client
- Aggiorna la stringa di connessione a
Driver={ODBC Driver 18 for SQL Server};oppure passa al provider ADO.NETMicrosoft.Data.SqlClient(≥ v5.x consigliata). - Rimuovi dal setup qualsiasi MSI/merge‑module che installi
sqlncli*.dll.
Distribuisci i runtime senza installare Visual Studio
Includi nel tuo installer:
- Microsoft Visual C++ Redistributable 14.3x (x86 e/o x64, coerenti con l’architettura dell’app).
- .NET Desktop Runtime corrispondente al target (es. 6.0 LTS o 8.0).
- ODBC Driver 18 (x86 e/o x64, in base alla bitness dell’app).
- DACFx/SqlPackage solo se effettivamente utilizzati a runtime (migrazioni schema, deploy dacpac).
Strumenti utili per creare un unico bootstrapper: WiX Burn, Inno Setup o MSIX Packaging.
Diagnosi rapida su VM pulita
- Verifica i runtime .NET presenti:
dotnet --list-runtimes - Controlla le DLL mancanti a ridosso del crash con strumenti come Dependency Walker o ProcMon (filtro su Result=NAME NOT FOUND).
- Registro eventi → Applicazione: cerca eccezioni
System.DllNotFoundException,BadImageFormatException(tipico mismatch x86/x64), errori di crittografia o TLS.
Convalida e modernizza la stringa di connessione
Allinea la configurazione del server e della stringa di connessione agli obblighi di ODBC 18:
- Ambiente di produzione (consigliato): installa un certificato TLS valido su SQL Server, usa
Encrypt=TrueeTrustServerCertificate=False. - Ambiente di test/lab: se il certificato non è disponibile, imposta
Encrypt=OptionaloppureTrustServerCertificate=Yestemporaneamente.
Esempi concreti
ADO.NET moderno (Microsoft.Data.SqlClient)
using Microsoft.Data.SqlClient;
var cs = new SqlConnectionStringBuilder
{
DataSource = "tcp:sqlserver.miodominio.local,1433",
InitialCatalog = "AppDb",
UserID = "app_user",
Password = "",
Encrypt = true, // esplicito per evitare ambiguità di default
TrustServerCertificate = false // in produzione: valida il certificato
// IntegratedSecurity = true // alternativa a UserID/Password
};
using var con = new SqlConnection(cs.ConnectionString);
await con.OpenAsync();
Console.WriteLine($"Connesso a {con.DataSource}, versione {con.ServerVersion}");
ODBC .NET con ODBC Driver 18
using System.Data.Odbc;
var cnString = "Driver={ODBC Driver 18 for SQL Server};" +
"Server=tcp:sqlserver.miodominio.local,1433;" +
"Database=AppDb;" +
"Uid=app_user;Pwd=;" +
"Encrypt=Optional;"; // per test; in prod preferire Encrypt=Yes/TrustServerCertificate=No
using var cn = new OdbcConnection(cnString);
cn.Open();
Console.WriteLine("OK via ODBC: " + cn.ServerVersion);
Stringhe “pronte all’uso”
| Scenario | Stringa di connessione |
|---|---|
| ODBC 18 con SQL Auth (produzione) | Driver={ODBC Driver 18 for SQL Server};Server=tcp:sqlserver.miodominio.local,1433;Database=AppDb;Uid=app_user;Pwd=*;Encrypt=Yes;TrustServerCertificate=No; |
| ODBC 18 con Integrated Security | Driver={ODBC Driver 18 for SQL Server};Server=sqlserver.miodominio.local;Database=AppDb;Trusted_Connection=Yes;Encrypt=Yes;TrustServerCertificate=No; |
| ADO.NET (Microsoft.Data.SqlClient) con SQL Auth | Server=tcp:sqlserver.miodominio.local,1433;Database=AppDb;User ID=app_user;Password=*;Encrypt=True;TrustServerCertificate=False;MultipleActiveResultSets=True; |
| Lab senza certificato | ...;Encrypt=Optional;TrustServerCertificate=Yes; (solo temporaneo) |
Bitness, DSN e strumenti di amministrazione ODBC
- Un’app x64 deve usare driver x64 e, se si appoggia a DSN, un DSN creato con
C:\Windows\System32\odbcad32.exe. - Un’app x86 deve usare driver x86 e DSN creati con
C:\Windows\SysWOW64\odbcad32.exe. - BadImageFormatException all’apertura della connessione è spesso un mismatch 32/64 bit tra app e driver.
- Il tracing ODBC (tab “Tracing” dell’amministratore ODBC) può aiutare a individuare errori di handshake TLS/parametri.
Distribuzione automatizzata dei prerequisiti
Sequenza consigliata
- Visual C++ Redistributable (x64 → x86, se servono entrambi).
- .NET Desktop Runtime (versione target LTS o corrente).
- ODBC Driver 18 (x64/x86 in base alla tua app).
- Eventuali componenti facoltativi (DACFx/SqlPackage).
- La tua applicazione.
Comandi silent install (template)
:: VC++ Redist (x64)
vc_redist.x64.exe /install /quiet /norestart
:: VC++ Redist (x86)
vc_redist.x86.exe /install /quiet /norestart
:: .NET Desktop Runtime (8.0 x64)
windowsdesktop-runtime-8.0.x-win-x64.exe /quiet /norestart
:: ODBC Driver 18 (x64)
msiexec /i msodbcsql18.msi IACCEPTMSODBCSQLLICENSETERMS=YES /qn
:: ODBC Driver 18 (x86)
msiexec /i msodbcsql18_x86.msi IACCEPTMSODBCSQLLICENSETERMS=YES /qn
Esempio WiX Burn: bundle minimale
<Bundle Name="App Setup" Version="1.0.0.0" Manufacturer="Contoso" UpgradeCode="{GUID}">
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense" />
<Chain>
<PackageGroupRef Id="VcRedistX64" />
<ExePackage Id="DotNetDesktopRuntime"
SourceFile="windowsdesktop-runtime-8.0.x-win-x64.exe"
InstallCommand="/quiet /norestart"
Permanent="yes" Vital="yes" />
<MsiPackage Id="Odbc18x64"
SourceFile="msodbcsql18.msi"
DisplayInternalUI="no"
Permanent="yes" Vital="yes">
<MsiProperty Name="IACCEPTMSODBCSQLLICENSETERMS" Value="YES"/>
</MsiPackage>
<MsiPackage Id="MyApp" SourceFile="MyApp.msi" />
</Chain>
</Bundle>
Esempio Inno Setup: prerequisiti + app
[Run]
Filename: "{tmp}\vc_redist.x64.exe"; Parameters: "/install /quiet /norestart"; Check: IsWin64
Filename: "{tmp}\windowsdesktop-runtime-8.0.x-win-x64.exe"; Parameters: "/quiet /norestart"; Check: IsWin64
Filename: "msiexec.exe"; Parameters: "/i ""{tmp}\msodbcsql18.msi"" IACCEPTMSODBCSQLLICENSETERMS=YES /qn"; StatusMsg: "Installazione ODBC Driver 18..."
Filename: "{app}\MyApp.exe"; Description: "Avvia l'applicazione"; Flags: postinstall nowait
Checklist di preflight
| Voce | Come verificare |
|---|---|
| VC++ Redist (x86/x64) | Appwiz.cpl → “Microsoft Visual C++ 2015‑2022 Redistributable”; oppure controllo registro. |
| .NET Desktop Runtime | dotnet --list-runtimes → presenza di Microsoft.WindowsDesktop.App nella versione attesa. |
| ODBC Driver 18 | Amministratore ODBC → “ODBC Driver 18 for SQL Server” nella scheda Driver. |
| Certificato server | CN/SAN corrisponde al nome usato nel parametro Server; catena di fiducia valida; non scaduto. |
| Bitness coerente | Processo x86 usa driver x86; processo x64 usa driver x64; DSN creato nel giusto amministratore ODBC. |
Diagnostica avanzata
Abilitare minidump con Windows Error Reporting
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /f
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyApp.exe" /v DumpType /t REG_DWORD /d 2 /f
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyApp.exe" /v DumpCount /t REG_DWORD /d 10 /f
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyApp.exe" /v DumpFolder /t REGEXPANDSZ /d "C:\Dumps" /f
Riproduci il crash e analizza lo stack per identificare la libreria mancante o l’errore di handshake TLS.
Log utili nel Registro Eventi
- Applicazione: eccezioni .NET (Source: .NET Runtime, Application Error).
- System: errori di driver/certificati.
- Microsoft‑Windows‑ODBC Driver Logs (se attivati): dettaglio sulle negoziazioni.
Migrazione verso Microsoft.Data.SqlClient
Se puoi toccare il codice, preferisci il provider ADO.NET Microsoft.Data.SqlClient rispetto a System.Data.SqlClient. Vantaggi:
- Allineamento alle policy di sicurezza recenti (Encrypt di default nelle versioni moderne del provider).
- Supporto migliorato a funzionalità come Always Encrypted, Azure Active Directory, MARS.
- Rilascio indipendente dal framework, quindi aggiornabile senza cambiare il target .NET.
Consiglio operativo: imposta sempre esplicitamente Encrypt e TrustServerCertificate nella connection string per evitare sorprese con cambi di default tra versioni.
FAQ per decisioni rapide
| Domanda | Risposta |
|---|---|
| Serve Visual Studio 2022 per usare SQL Server 2022 + ODBC 18? | No. VS non è richiesto; servono solo i runtime che VS installa automaticamente. |
| Devo usare SQL Server Native Client? | No. Native Client è deprecato e non distribuito con SQL Server 2022; sostituiscilo con ODBC Driver 18 o, per OLE DB, con Microsoft OLE DB Driver 19. |
| È opzionale o obbligatorio installare Native Client insieme a SQL Server 2019/2022? | Oggi è opzionale e sconsigliato; usa i driver moderni (ODBC 18 o Microsoft.Data.SqlClient). |
Suggerimenti extra e buone pratiche
- Compila l’app nella stessa architettura dei driver ODBC installati (x86/x64) ed evita AnyCPU se fai P/Invoke verso DLL native.
- Se il crash persiste, strumenta l’avvio: logga le variabili d’ambiente, il PATH, le versioni di runtime e le eccezioni non gestite.
- Abilita un test di integrazione che avvia l’eseguibile in una VM “pulita” con soli prerequisiti: intercetta regressioni prima del rilascio.
- Documenta i prerequisiti in un file README‑Ops interno con i pacchetti da installare e le opzioni silent.
- Se usi DSN, versione e denominazione dei driver devono essere coerenti con la VM target; valuta DSN‑less per evitare sorprese.
Script rapidi per verifiche di ambiente
PowerShell: verifica ODBC 18 e VC++
# ODBC Driver 18 installato?
Get-ItemProperty 'HKLM:\SOFTWARE\ODBC\ODBCINST.INI\ODBC Drivers' |
Select-Object -ExpandProperty 'ODBC Driver 18 for SQL Server' -ErrorAction SilentlyContinue
VC++ Redist 2015-2022
Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes','HKLM:\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\14.0\VC\Runtimes' -ErrorAction SilentlyContinue |
ForEach-Object {
$v = (Get-ItemProperty $*.PsPath -ErrorAction SilentlyContinue)
[PSCustomObject]@{Arch=$*.PSChildName; Version="$($v.Major).$($v.Minor).$($v.Bld).$($v.Qfe)"; Installed=$v.Installed}
}
.NET Desktop Runtime
dotnet --list-runtimes | Select-String "Microsoft.WindowsDesktop.App"
PowerShell: health‑check di connessione
$cs = "Driver={ODBC Driver 18 for SQL Server};Server=tcp:sqlserver.miodominio.local,1433;Database=AppDb;Uid=app_user;Pwd=*;Encrypt=Yes;TrustServerCertificate=No;"
Add-Type -AssemblyName System.Data
$con = New-Object System.Data.Odbc.OdbcConnection($cs)
try { $con.Open(); "Connesso: $($con.ServerVersion)" } catch { $_.Exception | Format-List -Force } finally { $con.Dispose() }
Piano di deploy consigliato
- Prepara un bundle che installa VC++ Redist, .NET Desktop Runtime, ODBC 18 e l’app.
- Configura SQL Server con certificato TLS valido (CN/SAN corrispondente al nome usato dai client).
- Imposta connection string esplicite con
Encrypt/TrustServerCertificatecoerenti con l’ambiente. - Automaticamente testa su VM “pulita” in pipeline CI: esegui l’app, apri una connessione, verifica query triviale (
SELECT 1). - Monitora all’avvio i log applicativi ed eventi di sistema per individuare tempestivamente errori TLS o DLL.
Conclusione
Non serve Visual Studio per far girare un’app .NET con SQL Server 2022: servono i suoi runtime. Aggiornando i provider (ODBC 18 o Microsoft.Data.SqlClient), distribuendo i redistributable corretti e adeguando le impostazioni di sicurezza (Encrypt/TLS), puoi eliminare i crash all’avvio e standardizzare il deployment su VM pulite—senza installare strumenti di sviluppo sui server.
Riepilogo operativo
- Driver: usa ODBC Driver 18 o Microsoft.Data.SqlClient; non usare Native Client.
- Runtime: includi VC++ Redist e .NET Desktop Runtime nel tuo installer.
- Sicurezza: configura certificato TLS su SQL Server oppure esplicita
Encrypt=Optionalsolo in test. - Bitness: allinea x86/x64 tra app, driver e DSN.
- Automazione: crea un bootstrapper e un test di integrazione su VM “pulita”.
Con queste azioni, la relazione fra SQL Server 2022, ODBC Driver 18 e Visual Studio 2022 torna a essere un vantaggio (sicurezza e stabilità) anziché una fonte di regressioni.
—
Appendice: mapping veloce problemi → rimedi
| Problema | Possibile causa | Rimedio immediato |
|---|---|---|
| Crash all’avvio senza log | DLL native mancanti (VC++), COM non registrato | Installa VC++ Redist x64/x86; abilita WER dumps; verifica con ProcMon |
| Errore certificato/handshake | Encrypt attivo, certificato non valido o nome server non corrispondente | Installa certificato valido; usa Encrypt=Yes, TrustServerCertificate=No |
BadImageFormatException | Mismatch x86/x64 tra app e driver | Allinea bitness; reinstalla driver corretti; ricrea DSN nel giusto odbcad32.exe |
DllNotFoundException: sqlncli11.dll | Uso di provider deprecato | Migra a ODBC 18 o Microsoft.Data.SqlClient; rimuovi riferimenti a Native Client |
| Funziona solo con VS installato | Dipendenze implicite da runtime VS | Bundla i redistributable; verifica su VM pulita prima del rilascio |
