Connettere un'applicazione ASP.NET al database SQL di Azure

Completato

Sono disponibili diversi modi per connettersi ai database all'interno del servizio Database SQL di Azure da un'applicazione. Per le app .NET è possibile usare la libreria System.Data.SqlClient.

L'app Web per l'università deve recuperare e visualizzare i dati caricati nel database SQL. In questa unità si apprende come connettersi a un database da un'app Web e come usare la libreria System.Data.SqlClient per elaborare i dati.

Panoramica della libreria System.Data.SqlClient

La libreria System.Data.SqlClient è una raccolta di tipi e metodi che è possibile usare per connettersi a un database di SQL Server in esecuzione in locale o nel cloud nel database SQL. La libreria offre un'interfaccia generalizzata per il recupero e la gestione dei dati. È possibile usare la libreria System.Data.SqlClient per eseguire comandi Transact-SQL (T-SQL) e operazioni transazionali e per recuperare i dati. È possibile impostare i parametri di queste operazioni per evitare problemi correlati agli attacchi SQL injection. Se un'operazione non riesce, la libreria System.Data.SqlClient fornisce le informazioni sugli errori tramite classi di eccezioni ed errori specializzate. Queste eccezioni vengono gestite come qualsiasi altro tipo di eccezione in un'applicazione .NET.

La libreria System.Data.SqlClient è disponibile nel pacchetto NuGet System.Data.SqlClient.

Connettersi a un singolo database

Per creare una connessione al database si usa un oggetto SqlConnection. Specificare una stringa di connessione che indica il nome e il percorso del database, le credenziali da usare e altri parametri correlati alla connessione. Una stringa di connessione tipica per un singolo database è simile alla seguente:

Server=tcp:myserver.database.windows.net,1433;Initial Catalog=mydatabase;Persist Security Info=False;User ID=myusername;Password=mypassword;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;

È possibile trovare la stringa di connessione per il database singolo nella pagina Stringhe di connessione per il database nel portale di Azure.

L'esempio di codice seguente illustra come creare un oggetto SqlConnection:

using System.Data.SqlClient;

...

string connectionString = "Server=tcp:myserver.database.windows.net,...";
SqlConnection con = new SqlConnection(connectionString);

La connessione al database non viene stabilita finché non si apre la connessione. In genere la connessione si apre immediatamente prima dell'esecuzione di un comando o di una query T-SQL.

con.Open();

Alcuni database supportano solo un numero finito di connessioni simultanee. Dopo aver completato l'esecuzione di un comando e il recupero di eventuali risultati, è quindi consigliabile chiudere la connessione e rilasciare tutte le risorse usate.

con.Close();

Un altro approccio comune consiste nel creare la connessione in un'istruzione using. Questa strategia chiude automaticamente la connessione al termine dell'istruzione using. È anche possibile, tuttavia, chiamare il metodo Close in modo esplicito.

using (SqlConnection con = new SqlConnection(connectionString))
{
    // Open and Use the connection here
    con.Open();
    ...
}
// Connection is now closed

Definire un comando o una query T-SQL

Creare un oggetto SqlCommand per specificare un comando o una query T-SQL da eseguire. L'esempio seguente illustra un'istruzione T-SQL DELETE che rimuove le righe per un determinato cliente dalla tabella dbo.Orders. È possibile impostare parametri per i comandi. In questo esempio viene usato un parametro denominato CustID per il CustomerID valore . La riga che imposta la proprietà CommandType dell'oggetto SqlCommand su Text indica che il comando è un'istruzione T-SQL. È anche possibile eseguire una stored procedure anziché un'istruzione T-SQL. In questo caso, impostare CommandType su StoredProcedure.

SqlCommand deleteOrdersForCustomer = new SqlCommand("DELETE FROM Orders WHERE CustomerID = @custID", con);
deleteOrdersForCustomer.CommandType = CommandType.Text;
string customerID = <prompt the user for a customer to delete>;
deleteOrdersForCustomer.Parameters.Add(new SqlParameter("custID", customerID));

Il parametro finale per il costruttore SqlCommand in questo esempio è la connessione usata per eseguire il comando.

Nell'esempio seguente viene illustrata una query che unisce le dbo.Customers tabelle e dbo.Orders per produrre un elenco di nomi dei clienti e i relativi ordini.

SqlCommand queryCmd = new SqlCommand(
                    @"SELECT c.FirstName, c.LastName, o.OrderID
                      FROM Customers c JOIN Orders o
                      ON c.CustomerID = o.CustomerID", con);
queryCmd.CommandType = CommandType.Text;

Eseguire un comando

Se l'oggetto SqlCommand fa riferimento a un'istruzione T-SQL che non restituisce un set di risultati, eseguire il comando usando il metodo ExecuteNonQuery. Se il comando ha esito positivo, restituisce il numero di righe interessate dall'operazione. Nell'esempio seguente viene illustrato come eseguire il deleteOrdersForCustomer comando illustrato in precedenza.

int numDeleted = deleteOrdersForCustomer.ExecuteNonQuery();

Se si prevede che l'esecuzione del comando richieda tempo, è possibile usare il metodo ExecuteNonQueryAsync per eseguire l'operazione in modo asincrono.

Eseguire una query e recuperare i dati

Se SqlCommand contiene un'istruzione T-SQL SELECT, eseguirla usando il metodo ExecuteReader. Questo metodo restituisce un oggetto SqlDataReader che è possibile usare per eseguire l'iterazione nei risultati ed elaborare ogni singola riga. I dati si recuperano da un oggetto SqlReader usando il metodo Read. Questo metodo restituisce true se viene trovata una riga e false se non rimangono altre righe da leggere. Dopo la lettura di una riga, i dati di questa sono disponibili nei campi dell'oggetto SqlReader. Ogni campo ha lo stesso nome della colonna corrispondente nell'istruzione SELECT originale. I dati presenti in ogni campo, tuttavia, vengono recuperati come elemento object non tipizzato, quindi è necessario convertirli nel tipo appropriato prima di usarli. Il codice seguente illustra come eseguire il queryCmd comando illustrato in precedenza per recuperare i dati una riga alla volta.

SqlDataReader rdr = queryCmd.ExecuteReader();

// Read the data a row at a time
while (rdr.Read())
{
    string firstName = rdr["FirstName"].ToString();
    string lastName = rdr["LastName"].ToString();
    int orderID = Convert.ToInt32(rdr["OrderID"]);

    // Process the data
    ...
}

Gestire errori ed eccezioni

Quando si usa un database, possono verificarsi eccezioni ed errori per diversi motivi, ad esempio perché si tenta di accedere a una tabella che non esiste più. È possibile individuare gli errori T-SQL usando il tipo SqlException.

Vari eventi o problemi nel database potrebbero generare un'eccezione. Un oggetto SqlException ha una proprietà Errors che contiene una raccolta di oggetti SqlError. Questi oggetti specificano i dettagli per ogni errore. L'esempio seguente illustra come individuare un oggetto SqlException e come elaborare gli errori che contiene.

...
using (SqlConnection con = new SqlConnection(connectionString))
{
    SqlCommand command = new SqlCommand("DELETE FROM ...", con);
    try
    {
        con.Open();
        command.ExecuteNonQuery();
    }
    catch (SqlException ex)
    {
        for (int i = 0; i < ex.Errors.Count; i++)
        {
            Console.WriteLine($"Index # {i} Error: {ex.Errors[i].ToString()}");
        }
    }
}