Files
Data-Coupler/SQL_SERVER_LOCALHOST_FIX.md
T
Alessio 483eb7b407 Fix: Risolto double-mapping negli External ID Relationships per Salesforce
- Implementata funzionalità completa External ID Relationships nell'interfaccia di mapping
- Corretto bug double-mapping: i campi sorgente usati per External ID non vengono più inclusi nei mapping normali
- Risolto errore MALFORMED_ID causato dall'invio duplicato di campi come proprietà dirette e nested objects
- Implementata logica corretta per relationship names: oggetti standard usano il nome diretto, custom objects usano suffisso __r
- Aggiunta UI a 3 colonne (Object, External ID Field, Source Field) per configurazione External ID Relationships
- Migrazione database per supporto External ID Relationships nei profili
- Aggiornato ProfileSaver.razor.cs per salvare/caricare External ID Relationships
- Aggiornato ScheduledProfileExecutionService.cs per gestire External ID nelle esecuzioni schedulate
- Formato JSON output corretto: { 'Account': { 'CardCode__c': 'V50000' } }

Documentazione: EXTERNAL_ID_RELATIONSHIPS_IMPLEMENTATION.md
2026-02-15 18:44:15 +01:00

11 KiB

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:

private static string BuildSqlServerConnectionString(DatabaseCredential credential)
{
    var builder = new List<string>();
    
    // 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:

@if (currentDatabaseCredential.DatabaseType == DatabaseType.SqlServer)
{
    <div class="form-text">
        <strong>SQL Server locale:</strong><br/>
        • Named Instance: <code>localhost\SQLEXPRESS</code> o <code>.\SQLEXPRESS</code><br/>
        • LocalDB: <code>(localdb)\MSSQLLocalDB</code><br/>
        • Default: <code>localhost</code> o <code>.</code> (usa porta 1433)
    </div>
}

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:

// 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

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