# Fix Connessione SQL Server con Localhost **Data**: 15 Febbraio 2026 **Versione**: 2.1+ ## 📋 Problema Risolto Il sistema non riusciva a connettersi correttamente a SQL Server quando si utilizzava "localhost" come host, specialmente per: - Named Instances (es. `localhost\SQLEXPRESS`) - LocalDB (es. `(localdb)\MSSQLLocalDB`) - Windows Authentication ## 🔧 Modifiche Implementate ### 1. ConnectionStringBuilder - Gestione Intelligente del Server **File**: `CredentialManager/Models/CredentialModels.cs` #### Miglioramenti: **a) Named Instances** - Se l'host contiene `\` (backslash), la porta viene omessa automaticamente - Esempi supportati: - `localhost\SQLEXPRESS` - `.\SQLEXPRESS` - `SERVERNAME\INSTANCE` **b) LocalDB** - Se l'host inizia con `(localdb)`, la porta viene omessa - Esempi supportati: - `(localdb)\MSSQLLocalDB` - `(localdb)\v11.0` - `(localdb)\ProjectsV13` **c) Localhost con Named Pipes** - Per `localhost`, `.` o `127.0.0.1` con porta 1433 (default), la porta viene omessa - Questo permette a SQL Server di usare Named Pipes invece di TCP/IP per connessioni locali più veloci **d) Windows Authentication** - Se username è vuoto, `Integrated` o `Windows`, usa Windows Authentication - Non richiede password quando si usa Windows Authentication - Connection string include `Integrated Security=True` #### Codice Modificato: ```csharp private static string BuildSqlServerConnectionString(DatabaseCredential credential) { var builder = new List(); // Gestione speciale per SQL Server locale e named instances bool hasInstanceName = credential.Host.Contains('\\') || credential.Host.StartsWith("(localdb)", StringComparison.OrdinalIgnoreCase); if (hasInstanceName) { // Per named instances e LocalDB, non includere la porta builder.Add($"Server={credential.Host}"); } else { // Per localhost con porta default, ometti la porta per usare Named Pipes if ((credential.Host.Equals("localhost", StringComparison.OrdinalIgnoreCase) || credential.Host == "." || credential.Host == "127.0.0.1") && credential.Port == 1433) { builder.Add($"Server={credential.Host}"); } else { // Per altri casi, usa host,porta builder.Add($"Server={credential.Host},{credential.Port}"); } } // Windows Authentication vs SQL Authentication if (string.IsNullOrWhiteSpace(credential.Username) || credential.Username.Equals("Integrated", StringComparison.OrdinalIgnoreCase) || credential.Username.Equals("Windows", StringComparison.OrdinalIgnoreCase)) { builder.Add("Integrated Security=True"); } else { builder.Add($"User Id={credential.Username}"); builder.Add($"Password={credential.Password}"); } builder.Add($"Connection Timeout={credential.CommandTimeout}"); if (!string.IsNullOrEmpty(credential.DatabaseName)) builder.Add($"Database={credential.DatabaseName}"); if (credential.IgnoreSslErrors) builder.Add("TrustServerCertificate=True"); return string.Join(";", builder); } ``` ### 2. UI - Guida Contestuale per SQL Server **File**: `Data_Coupler/Pages/CredentialManagement.razor` #### Aggiunte: **a) Help Text per Host/Server** - Mostra esempi specifici per SQL Server locale: - Named Instance: `localhost\SQLEXPRESS` o `.\SQLEXPRESS` - LocalDB: `(localdb)\MSSQLLocalDB` - Default: `localhost` o `.` (usa porta 1433) **b) Nota sulla Porta** - Indica che la porta viene ignorata per named instances e LocalDB **c) Guida Windows Authentication** - Nel campo Username: placeholder "o scrivi 'Integrated' per Windows Auth" - Help text: "Per Windows Authentication, scrivi **Integrated** o lascia vuoto" - Nel campo Password: "Non richiesta per Windows Authentication" #### Codice Aggiunto: ```razor @if (currentDatabaseCredential.DatabaseType == DatabaseType.SqlServer) {
SQL Server locale:
• Named Instance: localhost\SQLEXPRESS o .\SQLEXPRESS
• LocalDB: (localdb)\MSSQLLocalDB
• Default: localhost o . (usa porta 1433)
} ``` ### 3. Validazione Aggiornata **File**: `Data_Coupler/Pages/CredentialManagement.razor` #### Miglioramenti: **a) Validazione Credenziali** - Permette username/password vuoti per SQL Server con Windows Authentication - Riconosce "Integrated" e "Windows" come segnali per Windows Authentication - Validazione più specifica con messaggi di errore appropriati #### Codice Modificato: ```csharp // Per SQL Server, permetti Windows Authentication bool isSqlServerWithWindowsAuth = currentDatabaseCredential.DatabaseType == DatabaseType.SqlServer && (string.IsNullOrWhiteSpace(currentDatabaseCredential.Username) || currentDatabaseCredential.Username.Equals("Integrated", StringComparison.OrdinalIgnoreCase) || currentDatabaseCredential.Username.Equals("Windows", StringComparison.OrdinalIgnoreCase)); if (!isSqlServerWithWindowsAuth) { // Per database che non usano Windows Authentication, richiedi username e password if (string.IsNullOrEmpty(currentDatabaseCredential.Username) || string.IsNullOrEmpty(currentDatabaseCredential.Password)) { await JSRuntime.InvokeVoidAsync("alert", "Username e Password sono obbligatori. Per SQL Server con Windows Authentication, inserisci 'Integrated' come username."); return; } } ``` ## 📚 Guida Utilizzo ### Scenario 1: SQL Server Express Locale **Configurazione Credenziale:** - **Host**: `localhost\SQLEXPRESS` o `.\SQLEXPRESS` - **Porta**: 1433 (ignorata) - **Database**: Nome del database (es. `MyDatabase`) - **Username**: `Integrated` o lascia vuoto - **Password**: Lascia vuoto **Connection String Generata:** ``` Server=localhost\SQLEXPRESS;Integrated Security=True;Connection Timeout=30;Database=MyDatabase;TrustServerCertificate=True ``` ### Scenario 2: SQL Server LocalDB **Configurazione Credenziale:** - **Host**: `(localdb)\MSSQLLocalDB` - **Porta**: 1433 (ignorata) - **Database**: Nome del database (es. `TestDB`) - **Username**: `Integrated` o lascia vuoto - **Password**: Lascia vuoto **Connection String Generata:** ``` Server=(localdb)\MSSQLLocalDB;Integrated Security=True;Connection Timeout=30;Database=TestDB ``` ### Scenario 3: SQL Server Locale con SQL Authentication **Configurazione Credenziale:** - **Host**: `localhost` - **Porta**: 1433 - **Database**: Nome del database (es. `Production`) - **Username**: `sa` (o un altro utente SQL) - **Password**: Password dell'utente **Connection String Generata:** ``` Server=localhost;User Id=sa;Password=***;Connection Timeout=30;Database=Production;TrustServerCertificate=True ``` ### Scenario 4: SQL Server Remoto **Configurazione Credenziale:** - **Host**: `sql.example.com` - **Porta**: 1433 (o porta custom, es. 14330) - **Database**: Nome del database - **Username**: Utente SQL - **Password**: Password **Connection String Generata:** ``` Server=sql.example.com,1433;User Id=username;Password=***;Connection Timeout=30;Database=DBName;TrustServerCertificate=True ``` ### Scenario 5: SQL Server con Instance Name Remoto **Configurazione Credenziale:** - **Host**: `server.domain.com\PRODUCTION` - **Porta**: 1433 (ignorata) - **Database**: Nome del database - **Username**: Utente SQL - **Password**: Password **Connection String Generata:** ``` Server=server.domain.com\PRODUCTION;User Id=username;Password=***;Connection Timeout=30;Database=DBName;TrustServerCertificate=True ``` ## 🔍 Troubleshooting ### Problema: "A network-related or instance-specific error" **Possibili Cause:** 1. **SQL Server Browser non in esecuzione** (per named instances) - Soluzione: Avvia il servizio "SQL Server Browser" da services.msc 2. **TCP/IP non abilitato** - Soluzione: SQL Server Configuration Manager → Protocols → Enable TCP/IP 3. **Named Instance non specificata** - Soluzione: Usa `localhost\SQLEXPRESS` invece di solo `localhost` 4. **Firewall blocca la porta** - Soluzione: Aggiungi eccezione firewall per SQL Server ### Problema: "Login failed for user" **Possibili Cause:** 1. **Windows Authentication richiesta ma SQL Auth specificata** - Soluzione: Usa username `Integrated` o lascialo vuoto 2. **SQL Authentication non abilitata** - Soluzione: SQL Server Management Studio → Proprietà Server → Security → SQL Server and Windows Authentication mode 3. **Password errata** - Soluzione: Verifica la password ### Problema: "Cannot open database" **Possibili Cause:** 1. **Database non esiste** - Soluzione: Verifica il nome del database o lascia il campo vuoto per connetterti solo al server 2. **Permessi insufficienti** - Soluzione: Verifica che l'utente abbia accesso al database ## ✅ Test di Connessione Dopo aver configurato la credenziale, usa il pulsante **"Testa Connessione"** per verificare: - ✅ Connection string corretta - ✅ SQL Server raggiungibile - ✅ Autenticazione riuscita - ✅ Database accessibile (se specificato) Il test mostra: - Versione SQL Server - Host e porta usati - Database connesso - Timeout configurato ## 📝 Note Tecniche ### Differenze TCP/IP vs Named Pipes **Named Pipes** (preferito per localhost): - Più veloce per connessioni locali - Non richiede SQL Server Browser - Usa IPC invece di network stack - Sintassi: `Server=localhost` o `Server=.` **TCP/IP** (richiesto per remote): - Richiesto per connessioni remote - Richiede porta specifica - Richiede SQL Server Browser per named instances - Sintassi: `Server=hostname,port` ### Windows Authentication vs SQL Authentication **Windows Authentication**: - ✅ Più sicuro (usa credenziali Windows) - ✅ No password nel codice - ✅ Single Sign-On - ❌ Richiede domain trust per remote **SQL Authentication**: - ✅ Funziona sempre (anche cross-domain) - ✅ Credenziali specifiche per SQL Server - ❌ Password nel connection string - ❌ Deve essere abilitato in SQL Server ## 🔄 Retrocompatibilità Le modifiche sono completamente retrocompatibili: - ✅ Connection string esistenti continuano a funzionare - ✅ Credenziali già salvate non richiedono modifiche - ✅ Comportamento default invariato per server remoti - ✅ Nessuna migrazione database richiesta ## 📊 Impatto Performance **Miglioramenti**: - 🚀 Named Pipes più veloce di TCP/IP per localhost - 🚀 Riduzione overhead network stack - 🚀 Connection pooling più efficiente **Nessun Impatto Negativo**: - ✅ Server remoti usano sempre TCP/IP (comportamento corretto) - ✅ Connection string ottimizzate per scenario specifico --- **Sviluppatore**: Alessio Dalsanto **Issue**: Connessione localhost SQL Server **Status**: ✅ Risolto