Condividi tramite


Controlli origine dati

di Microsoft

Il controllo DataGrid in ASP.NET 1.x ha segnato un notevole miglioramento dell'accesso ai dati nelle applicazioni Web. Tuttavia, non era così facile da usare come poteva essere. È comunque necessaria una notevole quantità di codice per ottenere funzionalità molto utili. Questo è il modello in tutti gli sforzi di accesso ai dati in 1.x.

Il controllo DataGrid in ASP.NET 1.x ha segnato un notevole miglioramento dell'accesso ai dati nelle applicazioni Web. Tuttavia, non era così facile da usare come poteva essere. È comunque necessaria una notevole quantità di codice per ottenere funzionalità molto utili. Questo è il modello in tutti gli sforzi di accesso ai dati in 1.x.

ASP.NET 2.0 risolve questo problema con in parte con i controlli origine dati. I controlli origine dati in ASP.NET 2.0 forniscono agli sviluppatori un modello dichiarativo per il recupero dei dati, la visualizzazione dei dati e la modifica dei dati. Lo scopo dei controlli origine dati è fornire una rappresentazione coerente dei dati ai controlli associati a dati indipendentemente dall'origine di tali dati. Al centro dei controlli origine dati in ASP.NET 2.0 è la classe astratta DataSourceControl. La classe DataSourceControl fornisce un'implementazione di base dell'interfaccia IDataSource e dell'interfaccia IListSource, quest'ultima delle quali consente di assegnare il controllo origine dati come Origine dati di un controllo associato a dati (tramite la nuova proprietà DataSourceId illustrata più avanti) ed esporre i dati in esso contenuti come elenco. Ogni elenco di dati di un controllo origine dati viene esposto come oggetto DataSourceView. L'accesso alle istanze di DataSourceView viene fornito dall'interfaccia IDataSource. Ad esempio, il metodo GetViewNames restituisce un oggetto ICollection che consente di enumerare i DataSourceView associati a un particolare controllo origine dati e il metodo GetView consente di accedere a una particolare istanza di DataSourceView in base al nome.

I controlli origine dati non dispongono di interfaccia utente. Vengono implementati come controlli server in modo che possano supportare la sintassi dichiarativa e in modo che abbiano accesso allo stato della pagina, se necessario. I controlli origine dati non eseguono il rendering di markup HTML nel client.

Nota

Come si vedrà più avanti, esistono anche vantaggi della memorizzazione nella cache ottenuti usando i controlli origine dati.

Archiviazione di stringhe di connessione

Prima di esaminare come configurare i controlli origine dati, è necessario esaminare una nuova funzionalità in ASP.NET 2.0 relative alle stringhe di connessione. ASP.NET 2.0 introduce una nuova sezione nel file di configurazione che consente di archiviare facilmente le stringhe di connessione che possono essere lette dinamicamente in fase di esecuzione. La <sezione connectionStrings> semplifica l'archiviazione delle stringhe di connessione.

Il frammento di codice seguente aggiunge una nuova stringa di connessione.

<connectionStrings> <add name="Northwind" connectionString="Data Source=localhost; Integrated Security=SSPI;Initial Catalog=Northwind;" providerName="System.Data.SqlClient" /> </connectionStrings>

Nota

Analogamente alla <sezione appSettings> , la <sezione connectionStrings> viene visualizzata all'esterno della <sezione system.web> nel file di configurazione.

Per utilizzare questa stringa di connessione, è possibile utilizzare la sintassi seguente quando si imposta l'attributo ConnectionString di un controllo server.

ConnectionString="<%$ ConnectionStrings:Northwind%>"

La <sezione connectionStrings> può essere crittografata anche in modo che le informazioni riservate non vengano esposte. Tale capacità verrà illustrata in un modulo successivo.

Memorizzazione nella cache delle origini dati

Ogni DataSourceControl fornisce quattro proprietà per la configurazione della memorizzazione nella cache; EnableCaching, CacheDuration, CacheExpirationPolicy e CacheKeyDependency.

EnableCaching

EnableCaching è una proprietà booleana che determina se la memorizzazione nella cache è abilitata o meno per il controllo origine dati.

CacheDuration, proprietà

La proprietà CacheDuration imposta il numero di secondi per cui la cache rimane valida. Se si imposta questa proprietà su 0 , la cache rimane valida fino a quando non viene invalidata in modo esplicito.

CacheExpirationPolicy, proprietà

La proprietà CacheExpirationPolicy può essere impostata su Absolute o Sliding. Impostandolo su Assoluto significa che la quantità massima di tempo in cui i dati verranno memorizzati nella cache corrisponde al numero di secondi specificato dalla proprietà CacheDuration. Impostandolo su Scorrevole, la scadenza viene reimpostata quando viene eseguita ogni operazione.

CacheKeyDependency, proprietà

Se per la proprietà CacheKeyDependency viene specificato un valore stringa, ASP.NET imposterà una nuova dipendenza della cache in base a tale stringa. In questo modo è possibile invalidare in modo esplicito la cache semplicemente modificando o rimuovendo CacheKeyDependency.

Importante: se la rappresentazione è abilitata e l'accesso all'origine dati e/o al contenuto dei dati si basano sull'identità client, è consigliabile disabilitare la memorizzazione nella cache impostando EnableCaching su False. Se la memorizzazione nella cache è abilitata in questo scenario e un utente diverso dall'utente che ha originariamente richiesto i dati invia una richiesta, l'autorizzazione all'origine dati non viene applicata. I dati verranno semplicemente serviti dalla cache.

Controllo SqlDataSource

Il controllo SqlDataSource consente a uno sviluppatore di accedere ai dati archiviati in qualsiasi database relazionale che supporta ADO.NET. Può usare il provider System.Data.SqlClient per accedere a un database SQL Server, al provider System.Data.OleDb, al provider System.Data.Odbc o al provider System.Data.OracleClient per accedere a Oracle. Pertanto, SqlDataSource non viene usato solo per accedere ai dati in un database di SQL Server.

Per usare SqlDataSource, è sufficiente specificare un valore per la proprietà ConnectionString e specificare un comando o una stored procedure SQL. Il controllo SqlDataSource gestisce l'uso dell'architettura di ADO.NET sottostante. Apre la connessione, esegue una query sull'origine dati o esegue la stored procedure, restituisce i dati e quindi chiude automaticamente la connessione.

Nota

Poiché la classe DataSourceControl chiude automaticamente la connessione, dovrebbe ridurre il numero di chiamate dei clienti generate dalla perdita di connessioni alle banche dati.

Il frammento di codice seguente associa un controllo DropDownList a un controllo SqlDataSource usando la stringa di connessione archiviata nel file di configurazione, come illustrato in precedenza.

<asp:SqlDataSource id="SqlDataSource1" runat="server" DataSourceMode="DataReader" ConnectionString="<%$ ConnectionStrings:Northwind%>" SelectCommand="SELECT EmployeeID, LastName FROM Employees"> </asp:SqlDataSource><asp:DropDownList id="ListBox1" runat="server" DataTextField="LastName" DataValueField="EmployeeID" DataSourceID="SqlDataSource1"> </asp:DropDownList>

Come illustrato in precedenza, la proprietà DataSourceMode di SqlDataSource specifica la modalità per l'origine dati. Nell'esempio precedente, DataSourceMode è impostato su DataReader. In tal caso, SqlDataSource restituirà un oggetto IDataReader usando un cursore forward-only e di sola lettura. Il tipo specificato di oggetto restituito è controllato dal provider utilizzato. In questo caso si usa il provider System.Data.SqlClient come specificato nella <sezione connectionStrings> del file web.config. Di conseguenza, l'oggetto restituito sarà di tipo SqlDataReader. Specificando un valore DataSourceMode di DataSet, i dati possono essere archiviati in un dataset nel server. Questa modalità consente di aggiungere funzionalità come l'ordinamento, il paging e così via. Se avessi eseguito il data binding di SqlDataSource a un controllo GridView, avrei scelto la modalità DataSet. Tuttavia, nel caso di un oggetto DropDownList, la modalità DataReader è la scelta corretta.

Nota

Quando si memorizza nella cache un oggetto SqlDataSource o AccessDataSource, la proprietà DataSourceMode deve essere impostata su DataSet. Se si abilita la memorizzazione nella cache con DataSourceMode di DataReader, si verificherà un'eccezione.

Proprietà SqlDataSource

Di seguito sono riportate alcune delle proprietà del controllo SqlDataSource.

CancelSelectOnNullParameter

Valore booleano che specifica se un comando select viene annullato se uno dei parametri è Null. True per impostazione predefinita.

Conflictdetection

In una situazione in cui più utenti possono aggiornare contemporaneamente un'origine dati, la proprietà ConflictDetection determina il comportamento del controllo SqlDataSource. Questa proprietà restituisce uno dei valori dell'enumerazione ConflictOptions. Questi valori sono CompareAllValues e OverwriteChanges. Se è impostato su OverwriteChanges, l'ultima persona per scrivere dati nell'origine dati sovrascrive eventuali modifiche precedenti. Tuttavia, se la proprietà ConflictDetection è impostata su CompareAllValues, i parametri vengono creati per le colonne restituite dai parametri SelectCommand e vengono creati anche per contenere i valori originali in ognuna di queste colonne, consentendo a SqlDataSource di determinare se i valori sono stati modificati dopo l'esecuzione di SelectCommand.

Deletecommand

Imposta o ottiene la stringa SQL utilizzata durante l'eliminazione di righe dal database. Può trattarsi di una query SQL o di un nome di stored procedure.

DeleteCommandType

Imposta o ottiene il tipo di comando delete, una query SQL (testo) o una stored procedure (StoredProcedure).

Deleteparameters

Restituisce i parametri utilizzati dall'oggetto DeleteCommand dell'oggetto SqlDataSourceView associato al controllo SqlDataSource.

OldValuesParameterFormatString

Questa proprietà viene utilizzata per specificare il formato dei parametri del valore originale nei casi in cui la proprietà ConflictDetection è impostata su CompareAllValues. Il valore predefinito è {0} il che significa che i parametri del valore originale accettano lo stesso nome del parametro originale. In altre parole, se il nome del campo è EmployeeID, il parametro del valore originale sarà @EmployeeID.

SelectCommand

Imposta o ottiene la stringa SQL utilizzata per recuperare i dati dal database. Può trattarsi di una query SQL o di un nome di stored procedure.

SelectCommandType

Imposta o ottiene il tipo di comando select, una query SQL (testo) o una stored procedure (StoredProcedure).

Selectparameters

Restituisce i parametri utilizzati dal selectCommand dell'oggetto SqlDataSourceView associato al controllo SqlDataSourceSource.

SortParameterName

Ottiene o imposta il nome di un parametro di stored procedure utilizzato per l'ordinamento dei dati recuperati dal controllo origine dati. Valido solo quando SelectCommandType è impostato su StoredProcedure.

Sqlcachedependency

Stringa delimitata da punti e virgola che specifica i database e le tabelle usati in una dipendenza della cache SQL Server. Le dipendenze della cache SQL verranno illustrate in un modulo successivo.

Updatecommand

Imposta o ottiene la stringa SQL utilizzata per l'aggiornamento dei dati nel database. Può trattarsi di una query SQL o di un nome di stored procedure.

UpdateCommandType

Imposta o ottiene il tipo di comando di aggiornamento, una query SQL (testo) o una stored procedure (StoredProcedure).

Updateparameters

Restituisce i parametri utilizzati dall'oggetto UpdateCommand dell'oggetto SqlDataSourceView associato al controllo SqlDataSource.

Controllo AccessDataSource

Il controllo AccessDataSource deriva dalla classe SqlDataSource e viene usato per l'associazione dati a un database di Microsoft Access. La proprietà ConnectionString per il controllo AccessDataSource è una proprietà di sola lettura. Anziché utilizzare la proprietà ConnectionString, la proprietà DataFile viene utilizzata per puntare al database di Access, come illustrato di seguito.

<asp:AccessDataSource id="AccessDataSource1" runat="server" DataFile="~/App_Data/Northwind.mdb"> </asp:AccessDataSource>

AccessDataSource imposterà sempre providerName della base SqlDataSource su System.Data.OleDb e si connetterà al database utilizzando il provider Microsoft.Jet.OLEDB.4.0 OLE DB. Non è possibile utilizzare il controllo AccessDataSource per connettersi a un database di Access protetto da password. Se è necessario connettersi a un database protetto da password, è necessario usare il controllo SqlDataSource.

Nota

I database di accesso archiviati all'interno del sito Web devono essere inseriti nella directory App_Data. ASP.NET non consente l'esplorazione dei file in questa directory. È necessario concedere all'account di processo autorizzazioni lettura e scrittura per la directory App_Data quando si usano i database di Access.

Controllo XmlDataSource

XmlDataSource viene utilizzato per associare dati XML ai controlli associati a dati. È possibile eseguire il binding a un file XML utilizzando la proprietà DataFile oppure è possibile eseguire il binding a una stringa XML utilizzando la proprietà Data. XmlDataSource espone gli attributi XML come campi associabili. Nei casi in cui è necessario eseguire l'associazione a valori non rappresentati come attributi, è necessario usare una trasformazione XSL. È anche possibile usare espressioni XPath per filtrare i dati XML.

Si consideri il file XML seguente:

<?xml version="1.0" encoding="utf-8" ?> <People> <Person FirstName="Jake" LastName="Stone"> <Address> <Street>345 Maple St.</Street> <City>Redmond</City> <Region>WA</Region> <ZipCode>01434</ZipCode> </Address> <Job> <Title>CEO</Title> <Description>Develops company strategies.</Description> </Job> </Person> <Person FirstName="Jacob" LastName="Ladder"> <Address> <Street>123 Elm St.</Street> <City>Seattle</City> <Region>WA</Region> <ZipCode>11223</ZipCode> </Address> <Job> <Title>Attorney</Title> <Description>Reviews legal issues.</Description> </Job> </Person> <Person FirstName="Angela" LastName="Hound"> <Address> <Street>34 Palm Avenue</Street> <City>Renton</City> <Region>WA</Region> <ZipCode>63910</ZipCode> </Address> <Job> <Title>IT Director</Title> <Description>In charge of corporate network.</Description> </Job> </Person> </People>

Si noti che XmlDataSource usa una proprietà XPath di Persone/Person per filtrare solo i <nodi Person>. DropDownList esegue quindi il binding dei dati all'attributo LastName usando la proprietà DataTextField.

Anche se il controllo XmlDataSource viene utilizzato principalmente per l'associazione di dati ai dati XML di sola lettura, è possibile modificare il file di dati XML. Si noti che in questi casi, l'inserimento automatico, l'aggiornamento e l'eliminazione di informazioni nel file XML non avviene automaticamente come avviene con altri controlli origine dati. Sarà invece necessario scrivere codice per modificare manualmente i dati usando i metodi seguenti del controllo XmlDataSource.

GetXmlDocument

Recupera un oggetto XmlDocument contenente il codice XML recuperato da XmlDataSource.

Salva

Salva xmlDocument in memoria nell'origine dati.

È importante tenere presente che il metodo Save funzionerà solo quando vengono soddisfatte le due condizioni seguenti:

  1. XmlDataSource utilizza la proprietà DataFile per eseguire il binding a un file XML anziché alla proprietà Data da associare ai dati XML in memoria.
  2. Non viene specificata alcuna trasformazione tramite la proprietà Transform o TransformFile.

Si noti anche che il metodo Save può produrre risultati imprevisti quando vengono chiamati contemporaneamente da più utenti.

Controllo ObjectDataSource

I controlli dell'origine dati trattati fino a questo punto sono opzioni eccellenti per le applicazioni a due livelli in cui il controllo origine dati comunica direttamente all'archivio dati. Tuttavia, molte applicazioni reali sono applicazioni multilivello in cui un controllo origine dati potrebbe dover comunicare con un oggetto business che, a sua volta, comunica con il livello dati. In queste situazioni, ObjectDataSource riempie bene la fattura. ObjectDataSource funziona insieme a un oggetto di origine. Il controllo ObjectDataSource creerà un'istanza dell'oggetto di origine, chiamerà il metodo specificato ed eliminerà l'istanza dell'oggetto all'interno dell'ambito di una singola richiesta, se l'oggetto dispone di metodi di istanza anziché metodi statici (Shared in Visual Basic). Pertanto, l'oggetto deve essere senza stato. Ovvero, l'oggetto deve acquisire e rilasciare tutte le risorse necessarie all'interno dell'intervallo di una singola richiesta. È possibile controllare la modalità di creazione dell'oggetto di origine gestendo l'evento ObjectCreating del controllo ObjectDataSource. È possibile creare un'istanza dell'oggetto di origine e quindi impostare la proprietà ObjectInstance della classe ObjectDataSourceEventArgs su tale istanza. Il controllo ObjectDataSource userà l'istanza creata nell'evento ObjectCreating anziché creare un'istanza autonomamente.

Se l'oggetto di origine per un controllo ObjectDataSource espone metodi statici pubblici (Condivisi in Visual Basic) che possono essere chiamati per recuperare e modificare i dati, un controllo ObjectDataSource chiamerà direttamente tali metodi. Se un controllo ObjectDataSource deve creare un'istanza dell'oggetto di origine per effettuare chiamate al metodo, l'oggetto deve includere un costruttore pubblico che non accetta parametri. Il controllo ObjectDataSource chiamerà questo costruttore quando crea una nuova istanza dell'oggetto di origine.

Se l'oggetto di origine non contiene un costruttore pubblico senza parametri, è possibile creare un'istanza dell'oggetto di origine che verrà utilizzata dal controllo ObjectDataSource nell'evento ObjectCreating.

Specifica dei metodi dell'oggetto

L'oggetto di origine per un controllo ObjectDataSource può contenere qualsiasi numero di metodi utilizzati per selezionare, inserire, aggiornare o eliminare dati. Questi metodi vengono chiamati dal controllo ObjectDataSource in base al nome del metodo, come identificato tramite la proprietà SelectMethod, InsertMethod, UpdateMethod o DeleteMethod del controllo ObjectDataSource. L'oggetto di origine può includere anche un metodo SelectCount facoltativo, identificato dal controllo ObjectDataSource tramite la proprietà SelectCountMethod, che restituisce il conteggio del numero totale di oggetti nell'origine dati. Il controllo ObjectDataSource chiamerà il metodo SelectCount dopo che è stato chiamato un metodo Select per recuperare il numero totale di record nell'origine dati da utilizzare durante il paging.

Lab con controlli origine dati

Esercizio 1 - Visualizzazione dei dati con il controllo SqlDataSource

Nell'esercizio seguente viene usato il controllo SqlDataSource per connettersi al database Northwind. Si presuppone che l'utente abbia accesso al database Northwind in un'istanza di SQL Server 2000.

  1. Creare un nuovo sito Web ASP.NET.

  2. Aggiungere un nuovo file web.config.

    1. Fare clic con il pulsante destro del mouse sul progetto in Esplora soluzioni e scegliere Aggiungi nuovo elemento.
    2. Scegliere File di configurazione Web dall'elenco dei modelli e fare clic su Aggiungi.
  3. Modificare la <sezione connectionStrings> come indicato di seguito:

    <asp:SqlDataSource ID="SqlDataSource1" runat="server"
        ConnectionString="<%$ConnectionStrings:Northwind%>"
        SelectCommand="SELECT * FROM Products">
    </asp:SqlDataSource>
    
  4. Passare alla visualizzazione Codice e aggiungere un attributo ConnectionString e un attributo SelectCommand al <controllo asp:SqlDataSource> come indicato di seguito:

    <asp:SqlDataSource ID="SqlDataSource1" runat="server"
        ConnectionString="<%$ConnectionStrings:Northwind%>"
        SelectCommand="SELECT * FROM Products">
    </asp:SqlDataSource>
    
  5. Dalla visualizzazione Struttura aggiungere un nuovo controllo GridView.

  6. Dall'elenco a discesa Scegli origine dati nel menu Attività di GridView scegliere SqlDataSource1.

  7. Fare clic con il pulsante destro del mouse su Default.aspx e scegliere Visualizza nel browser dal menu. Fare clic su Sì quando viene richiesto di salvare.

  8. GridView visualizza i dati della tabella Products.

Esercizio 2 - Modifica dei dati con il controllo SqlDataSource

L'esercizio seguente illustra come associare un controllo DropDownList usando la sintassi dichiarativa e consente di modificare i dati presentati nel controllo DropDownList.

  1. Nella visualizzazione Struttura eliminare il controllo GridView da Default.aspx.

    Importante: lasciare il controllo SqlDataSource nella pagina.

  2. Aggiungere un controllo DropDownList a Default.aspx.

  3. Passare alla visualizzazione Origine.

  4. Aggiungere un attributo DataSourceId, DataTextField e DataValueField al <controllo asp:DropDownList> come indicato di seguito:

    <asp:DropDownList ID="ddlProducts" runat="server"
         DataSourceId="SqlDataSource1" DataTextField="ProductName"
         DataValueField="ProductID">
    </asp:DropDownList>
    
  5. Salvare Default.aspx e visualizzarlo nel browser. Si noti che DropDownList contiene tutti i prodotti del database Northwind.

  6. Chiudere il browser.

  7. Nella visualizzazione Origine di Default.aspx aggiungere un nuovo controllo TextBox sotto il controllo DropDownList. Modificare la proprietà ID di TextBox in txtProductName.

  8. Nel controllo TextBox aggiungere un nuovo controllo Button. Modificare la proprietà ID di Button in btnUpdate e la proprietà Text in Update Product Name.Change the ID property of the Button to btnUpdate and the Text property to Update Product Name.

  9. Nella visualizzazione Origine di Default.aspx aggiungere una proprietà UpdateCommand e due nuovi UpdateParameters al tag SqlDataSource come indicato di seguito:

    <asp:SqlDataSource ID="SqlDataSource1" runat="server"
        ConnectionString="<%$ConnectionStrings:Northwind%>"
        SelectCommand="SELECT * FROM Products"
        UpdateCommand="UPDATE Products SET ProductName=@ProductName WHERE ProductID=@ProductID">
          <UpdateParameters>
          <asp:ControlParameter Name="ProductName" 
            ControlID="txtProductName" PropertyName="Text" />
          <asp:ControlParameter Name="ProductID" 
            ControlID="ddlProducts" PropertyName="SelectedValue" />
    </asp:SqlDataSource>
    

    Nota

    Si noti che sono presenti due parametri di aggiornamento (ProductName e ProductID) aggiunti in questo codice. Questi parametri vengono mappati alla proprietà Text della proprietà txtProductName TextBox e alla proprietà SelectedValue dell'elenco a discesa ddlProducts.

  10. Passare alla visualizzazione Progettazione e fare doppio clic sul controllo Pulsante per aggiungere un gestore eventi.

  11. Aggiungere il codice seguente al codice btnUpdate_Click:

    SqlDataSource1.Update();
    
  12. Fare clic con il pulsante destro del mouse su Default.aspx e scegliere di visualizzarlo nel browser. Fare clic su Sì quando viene richiesto di salvare tutte le modifiche.

  13. ASP.NET classi parziali 2.0 consentono la compilazione in fase di esecuzione. Non è necessario compilare un'applicazione per visualizzare le modifiche al codice.

  14. Selezionare un prodotto dall'elenco a discesa.

  15. Immettere un nuovo nome per il prodotto selezionato in TextBox e quindi fare clic sul pulsante Aggiorna.

  16. Il nome del prodotto viene aggiornato nel database.

Esercizio 3 usando il controllo ObjectDataSource

Questo esercizio illustra come usare il controllo ObjectDataSource e un oggetto di origine per interagire con il database Northwind.

  1. Fare clic con il pulsante destro del mouse sul progetto in Esplora soluzioni e fare clic su Aggiungi nuovo elemento.

  2. Selezionare Web Form nell'elenco modelli. Modificare il nome in object.aspx e fare clic su Aggiungi.

  3. Fare clic con il pulsante destro del mouse sul progetto in Esplora soluzioni e fare clic su Aggiungi nuovo elemento.

  4. Selezionare Classe nell'elenco modelli. Modificare il nome della classe in NorthwindData.cs e fare clic su Aggiungi.

  5. Fare clic su Sì quando viene richiesto di aggiungere la classe alla cartella App_Code.

  6. Aggiungere il codice seguente al file NorthwindData.cs:

    using System;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    using System.Data.SqlClient;
    public class NorthwindData {
        private string _connectionString;
        public NorthwindData() {
            Initialize();
        }
    
        private void Initialize() {
            if (ConfigurationManager.ConnectionStrings["Northwind"] == null ||
                ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString.Trim() == "") {
                    throw new Exception("A connection string named 'Northwind' with " +
                    "a valid connection string must exist in the <connectionStrings> " +
                    "configuration section for the application.");
            }
            _connectionString = ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;
        }
    
        public DataTable GetAllEmployees(string sortColumns, int startRecord, int maxRecords) {
            VerifySortColumns(sortColumns);
            string sqlCmd = "SELECT EmployeeID, LastName, FirstName, Address, " +
                "City, Region, PostalCode FROM Employees ";
            if (sortColumns.Trim() == "")
                sqlCmd += "ORDER BY EmployeeID";
            else
                sqlCmd += "ORDER BY " + sortColumns;
    
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlDataAdapter da = new SqlDataAdapter(sqlCmd, conn);
            DataSet ds = new DataSet();
            try {
                conn.Open();
                da.Fill(ds, startRecord, maxRecords, "Employees");
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
            return ds.Tables["Employees"];
        }
    
        public int SelectCount() {
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlCommand cmd = new SqlCommand("SELECT COUNT(*) FROM Employees", conn);
            int result = 0;
    
            try {
                conn.Open();
                result = (int)cmd.ExecuteScalar();
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
            return result;
        }
    
        //////////
        // Verify that only valid columns are specified in the sort expression to
        // avoid a SQL Injection attack.
        private void VerifySortColumns(string sortColumns) {
            if (sortColumns.ToLowerInvariant().EndsWith(" desc"))
                sortColumns = sortColumns.Substring(0, sortColumns.Length - 5);
            string[] columnNames = sortColumns.Split(',');
            foreach (string columnName in columnNames) {
                switch (columnName.Trim().ToLowerInvariant()) {
                    case "employeeid":
                        break;
                    case "lastname":
                        break;
                    case "firstname":
                        break;
                    case "":
                        break;
                    default:
                        throw new ArgumentException("SortColumns contains an " +
                            "invalid column name.");
                        break;
                }
            }
        }
    
        // Select an employee.
        public DataTable GetEmployee(int EmployeeID) {
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlDataAdapter da =
                new SqlDataAdapter("SELECT EmployeeID, LastName, FirstName, " +
                "Address, City, Region, PostalCode " +
                " FROM Employees WHERE EmployeeID = @EmployeeID", conn);
            da.SelectCommand.Parameters.Add("@EmployeeID", SqlDbType.Int).Value = EmployeeID;
            DataSet ds = new DataSet();
            try {
                conn.Open();
                da.Fill(ds, "Employees");
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
    
            return ds.Tables["Employees"];
        }
    
        // Delete the Employee by ID.
        public int DeleteEmployee(int EmployeeID) {
             SqlConnection conn = new SqlConnection(_connectionString);
             SqlCommand cmd = new SqlCommand("DELETE FROM Employees WHERE " +
                 "EmployeeID = @EmployeeID", conn);
             cmd.Parameters.Add("@EmployeeID", SqlDbType.Int).Value = EmployeeID;
             int result = 0;
             try {
                 conn.Open();
                 result = cmd.ExecuteNonQuery();
             } catch (SqlException e) {
                 // Handle exception.
             } finally {
                 conn.Close();
             }
    
             return result;
         }
    
         // Update the Employee by original ID.
         public int UpdateEmployee(int EmployeeID, string LastName, string FirstName,
             string Address, string City, string Region,
             string PostalCode) {
             if (String.IsNullOrEmpty(FirstName))
                 throw new ArgumentException("FirstName cannot be null or an empty string.");
             if (String.IsNullOrEmpty(LastName))
                 throw new ArgumentException("LastName cannot be null or an empty string.");
             if (Address == null) { Address = String.Empty; }
             if (City == null) { City = String.Empty; }
             if (Region == null) { Region = String.Empty; }
             if (PostalCode == null) { PostalCode = String.Empty; }
    
             SqlConnection conn = new SqlConnection(_connectionString);
             SqlCommand cmd = new SqlCommand("UPDATE Employees " +
                 " SET FirstName=@FirstName, " +
                 "LastName=@LastName, " +
                 "Address=@Address, City=@City, " +
                 "Region=@Region, " +
                 "PostalCode=@PostalCode " +
                 "WHERE EmployeeID=@EmployeeID", conn);
             cmd.Parameters.Add("@FirstName", SqlDbType.VarChar, 10).Value = FirstName;
             cmd.Parameters.Add("@LastName", SqlDbType.VarChar, 20).Value = LastName;
             cmd.Parameters.Add("@Address", SqlDbType.VarChar, 60).Value = Address;
             cmd.Parameters.Add("@City", SqlDbType.VarChar, 15).Value = City;
             cmd.Parameters.Add("@Region", SqlDbType.VarChar, 15).Value = Region;
             cmd.Parameters.Add("@PostalCode", SqlDbType.VarChar, 10).Value = PostalCode;
             cmd.Parameters.Add("@EmployeeID", SqlDbType.Int).Value = EmployeeID;
    
             int result = 0;
             try {
                 conn.Open();
                 result = cmd.ExecuteNonQuery();
             } catch (SqlException e) {
                 // Handle exception.
             } finally {
                 conn.Close();
             }
    
             return result;
        }
    
        // Insert an Employee.
        public int InsertEmployee(string LastName, string FirstName,
            string Address, string City, string Region,
            string PostalCode) {
            if (String.IsNullOrEmpty(FirstName))
                throw new ArgumentException("FirstName cannot be null or an empty string.");
            if (String.IsNullOrEmpty(LastName))
                throw new ArgumentException("LastName cannot be null or an empty string.");
            if (Address == null) { Address = String.Empty; }
            if (City == null) { City = String.Empty; }
            if (Region == null) { Region = String.Empty; }
            if (PostalCode == null) { PostalCode = String.Empty; }
    
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlCommand cmd = new SqlCommand("INSERT INTO Employees " +
                " (FirstName, LastName, Address, " +
                " City, Region, PostalCode) " +
                " Values(@FirstName, @LastName, " +
                "@Address, @City, @Region, @PostalCode); " +
                "SELECT @EmployeeID = SCOPE_IDENTITY()", conn);
    
            cmd.Parameters.Add("@FirstName", SqlDbType.VarChar, 10).Value = FirstName;
            cmd.Parameters.Add("@LastName", SqlDbType.VarChar, 20).Value = LastName;
            cmd.Parameters.Add("@Address", SqlDbType.VarChar, 60).Value = Address;
            cmd.Parameters.Add("@City", SqlDbType.VarChar, 15).Value = City;
            cmd.Parameters.Add("@Region", SqlDbType.VarChar, 15).Value = Region;
            cmd.Parameters.Add("@PostalCode", SqlDbType.VarChar, 10).Value = PostalCode;
            SqlParameter p = cmd.Parameters.Add("@EmployeeID", SqlDbType.Int);
                p.Direction = ParameterDirection.Output;
            int newEmployeeID = 0;
            try {
                conn.Open();
                cmd.ExecuteNonQuery();
                newEmployeeID = (int)p.Value;
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
    
            return newEmployeeID;
        }
    
        //
        // Methods that support Optimistic Concurrency checks.
        //
        // Delete the Employee by ID.
        public int DeleteEmployee(int original_EmployeeID, string original_LastName,
            string original_FirstName, string original_Address,
            string original_City, string original_Region,
            string original_PostalCode) {
    
            if (String.IsNullOrEmpty(original_FirstName))
                throw new ArgumentException("FirstName cannot be null or an empty string.");
            if (String.IsNullOrEmpty(original_LastName))
                throw new ArgumentException("LastName cannot be null or an empty string.");
            if (original_Address == null) { original_Address = String.Empty; }
            if (original_City == null) { original_City = String.Empty; }
            if (original_Region == null) { original_Region = String.Empty; }
            if (original_PostalCode == null) { original_PostalCode = String.Empty; }
            string sqlCmd = "DELETE FROM Employees WHERE EmployeeID = " + @original_EmployeeID
    
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlCommand cmd = new SqlCommand(sqlCmd, conn);
            cmd.Parameters.Add("@original_EmployeeID",
                SqlDbType.Int).Value = original_EmployeeID;
            cmd.Parameters.Add("@original_FirstName",
                SqlDbType.VarChar, 10).Value = original_FirstName;
            cmd.Parameters.Add("@original_LastName",
                SqlDbType.VarChar, 20).Value = original_LastName;
            cmd.Parameters.Add("@original_Address",
                SqlDbType.VarChar, 60).Value = original_Address;
            cmd.Parameters.Add("@original_City",
                SqlDbType.VarChar, 15).Value = original_City;
            cmd.Parameters.Add("@original_Region",
                SqlDbType.VarChar, 15).Value = original_Region;
            cmd.Parameters.Add("@original_PostalCode",
                SqlDbType.VarChar, 10).Value = original_PostalCode;
    
            int result = 0;
            try {
                conn.Open();
                result = cmd.ExecuteNonQuery();
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
    
            return result;
        }
    
        // Update the Employee by original ID.
        public int UpdateEmployee(string LastName, string FirstName,
            string Address, string City, string Region,
            string PostalCode, int original_EmployeeID,
            string original_LastName, string original_FirstName,
            string original_Address, string original_City,
            string original_Region, string original_PostalCode) {
    
            if (String.IsNullOrEmpty(FirstName))
                throw new ArgumentException("FirstName cannot be null or an empty string.");
            if (String.IsNullOrEmpty(LastName))
                throw new ArgumentException("LastName cannot be null or an empty string.");
            if (Address == null) { Address = String.Empty; }
            if (City == null) { City = String.Empty; }
            if (Region == null) { Region = String.Empty; }
            if (PostalCode == null) { PostalCode = String.Empty; }
            if (original_Address == null) { original_Address = String.Empty; }
            if (original_City == null) { original_City = String.Empty; }
            if (original_Region == null) { original_Region = String.Empty; }
            if (original_PostalCode == null) { original_PostalCode = String.Empty; }
    
            string sqlCmd = "UPDATE Employees " +
                " SET FirstName = @FirstName, LastName = @LastName, " +
                " Address = @Address, City = @City, Region = @Region, " +
                " PostalCode = @PostalCode " +
                " WHERE EmployeeID = @original_EmployeeID";
    
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlCommand cmd = new SqlCommand(sqlCmd, conn);
            cmd.Parameters.Add("@FirstName", SqlDbType.VarChar, 10).Value = FirstName;
            cmd.Parameters.Add("@LastName", SqlDbType.VarChar, 20).Value = LastName;
            cmd.Parameters.Add("@Address", SqlDbType.VarChar, 60).Value = Address;
            cmd.Parameters.Add("@City", SqlDbType.VarChar, 15).Value = City;
            cmd.Parameters.Add("@Region", SqlDbType.VarChar, 15).Value = Region;
            cmd.Parameters.Add("@PostalCode", SqlDbType.VarChar, 10).Value = PostalCode;
            cmd.Parameters.Add("@original_EmployeeID",
                SqlDbType.Int).Value = original_EmployeeID;
            cmd.Parameters.Add("@original_FirstName",
                SqlDbType.VarChar, 10).Value = original_FirstName;
            cmd.Parameters.Add("@original_LastName",
                SqlDbType.VarChar, 20).Value = original_LastName;
            cmd.Parameters.Add("@original_Address",
                SqlDbType.VarChar, 60).Value = original_Address;
            cmd.Parameters.Add("@original_City",
                SqlDbType.VarChar, 15).Value = original_City;
            cmd.Parameters.Add("@original_Region",
                SqlDbType.VarChar, 15).Value = original_Region;
            cmd.Parameters.Add("@original_PostalCode",
                SqlDbType.VarChar, 10).Value = original_PostalCode;
    
            int result = 0;
    
            try {
                conn.Open();
                result = cmd.ExecuteNonQuery();
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
            return result;
        }
    }
    
  7. Aggiungere il codice seguente alla visualizzazione Origine di object.aspx:

    <%@ Page language="C#" %>
    <script RunAt="server">
    void EmployeesDetailsView_ItemInserted(Object sender, DetailsViewInsertedEventArgs e) {
        EmployeesGridView.DataBind();
    }
    
    void EmployeesDetailsView_ItemUpdated(Object sender, DetailsViewUpdatedEventArgs e) {
        EmployeesGridView.DataBind();
    }
    
    void EmployeesDetailsView_ItemDeleted(Object sender, DetailsViewDeletedEventArgs e) {
        EmployeesGridView.DataBind();
    }
    void EmployeesGridView_OnSelectedIndexChanged(object sender, EventArgs e) {
        EmployeeDetailsObjectDataSource.SelectParameters["EmployeeID"].DefaultValue =
            EmployeesGridView.SelectedDataKey.Value.ToString();
        EmployeesDetailsView.DataBind();
    }
    void EmployeeDetailsObjectDataSource_OnInserted(object sender,
        ObjectDataSourceStatusEventArgs e) {
    
        EmployeeDetailsObjectDataSource.SelectParameters["EmployeeID"].DefaultValue =
            e.ReturnValue.ToString();
        EmployeesDetailsView.DataBind();
    }
    void EmployeeDetailsObjectDataSource_OnUpdated(object sender,
        ObjectDataSourceStatusEventArgs e) {
    
        if ((int)e.ReturnValue == 0)
            Msg.Text = "Employee was not updated. Please try again.";
    }
    void EmployeeDetailsObjectDataSource_OnDeleted(object sender,
        ObjectDataSourceStatusEventArgs e) {
    
        if ((int)e.ReturnValue == 0)
            Msg.Text = "Employee was not deleted. Please try again.";
    }
    void Page_Load() {
        Msg.Text = "";
    }
    </script>
    <html>
      <body>
        <form id="Form1" runat="server">
          <h3>ObjectDataSource Example</h3>
          <asp:Label id="Msg" runat="server" ForeColor="Red" />
          <asp:ObjectDataSource
              ID="EmployeesObjectDataSource"
              runat="server"
              TypeName="NorthwindData"
              SortParameterName="SortColumns"
              EnablePaging="true"
              SelectCountMethod="SelectCount"
              StartRowIndexParameterName="StartRecord"
              MaximumRowsParameterName="MaxRecords"
              SelectMethod="GetAllEmployees" >
          </asp:ObjectDataSource>
          <asp:ObjectDataSource
              ID="EmployeeDetailsObjectDataSource"
              runat="server"
              TypeName="NorthwindData"
              ConflictDetection="CompareAllValues"
              OldValuesParameterFormatString="{0}"
              SelectMethod="GetEmployee"
              InsertMethod="InsertEmployee"
              UpdateMethod="UpdateEmployee"
              DeleteMethod="DeleteEmployee"
              OnInserted="EmployeeDetailsObjectDataSource_OnInserted"
              OnUpdated="EmployeeDetailsObjectDataSource_OnUpdated"
              OnDeleted="EmployeeDetailsObjectDataSource_OnDeleted">
              <SelectParameters>
                  <asp:Parameter Name="EmployeeID" Type="Int32" />
              </SelectParameters>
          </asp:ObjectDataSource>
          <table cellspacing="10">
            <tr>
              <td valign="top">
                <asp:GridView ID="EmployeesGridView"
                    DataSourceID="EmployeesObjectDataSource"
                    AutoGenerateColumns="false"
                    AllowSorting="true"
                    AllowPaging="true"
                    PageSize="5"
                    DataKeyNames="EmployeeID"
                    OnSelectedIndexChanged="EmployeesGridView_OnSelectedIndexChanged"
                    RunAt="server">
                    <HeaderStyle backcolor="lightblue" forecolor="black"/>
                    <Columns>
                    <asp:ButtonField Text="Details..."
                    HeaderText="Show Details"
                    CommandName="Select"/>
    
                    <asp:BoundField DataField="EmployeeID" HeaderText="Employee ID"
                    SortExpression="EmployeeID" />
                    <asp:BoundField DataField="FirstName" HeaderText="First Name"
                    SortExpression="FirstName" />
                    <asp:BoundField DataField="LastName" HeaderText="Last Name"
                    SortExpression="LastName, FirstName" />
                    </Columns>
                </asp:GridView>
              </td>
              <td valign="top">
                <asp:DetailsView ID="EmployeesDetailsView"
                    DataSourceID="EmployeeDetailsObjectDataSource"
                    AutoGenerateRows="false"
                    EmptyDataText="No records."
                    DataKeyNames="EmployeeID"
                    Gridlines="Both"
                    AutoGenerateInsertButton="true"
                    AutoGenerateEditButton="true"
                    AutoGenerateDeleteButton="true"
                    OnItemInserted="EmployeesDetailsView_ItemInserted"
                    OnItemUpdated="EmployeesDetailsView_ItemUpdated"
                    OnItemDeleted="EmployeesDetailsView_ItemDeleted"
                    RunAt="server">
                    <HeaderStyle backcolor="Navy" forecolor="White"/>
                    <RowStyle backcolor="White"/>
                    <AlternatingRowStyle backcolor="LightGray"/>
                    <EditRowStyle backcolor="LightCyan"/>
                    <Fields>
                        <asp:BoundField DataField="EmployeeID" HeaderText="Employee ID"
                            InsertVisible="False" ReadOnly="true"/>
                        <asp:BoundField DataField="FirstName" HeaderText="First Name"/>
                        <asp:BoundField DataField="LastName" HeaderText="Last Name"/>
                        <asp:BoundField DataField="Address" HeaderText="Address"/>
                        <asp:BoundField DataField="City" HeaderText="City"/>
                        <asp:BoundField DataField="Region" HeaderText="Region"/>
                        <asp:BoundField DataField="PostalCode" HeaderText="Postal Code"/>
                    </Fields>
                  </asp:DetailsView>
                </td>
              </tr>
            </table>
          </form>
        </body>
      </html>
    
  8. Salvare tutti i file e sfogliare object.aspx.

  9. Interagire con l'interfaccia visualizzando i dettagli, modificando i dipendenti, aggiungendo dipendenti ed eliminando i dipendenti.