Gestione delle eccezioni a livello BLL e DAL (C#)

di Scott Mitchell

Scarica il PDF

In questa esercitazione verrà illustrato come gestire le eccezioni generate durante un flusso di lavoro di aggiornamento di DataList modificabile.

Introduzione

Nell'esercitazione Panoramica della modifica e dell'eliminazione di dati nell'esercitazione DataList è stato creato un oggetto DataList che offre funzionalità di modifica ed eliminazione semplici. Anche se completamente funzionante, non era facile da usare, poiché qualsiasi errore che si è verificato durante il processo di modifica o eliminazione ha generato un'eccezione non gestita. Ad esempio, omettendo il nome del prodotto o, quando si modifica un prodotto, immettendo un valore di prezzo molto conveniente!, viene generata un'eccezione. Poiché questa eccezione non viene intercettata nel codice, viene visualizzata fino al runtime di ASP.NET, che visualizza quindi i dettagli dell'eccezione nella pagina Web.

Come illustrato nell'esercitazione Sulla gestione delle eccezioni BLL e DAL-Level in una pagina di ASP.NET , se viene generata un'eccezione dalle profondità della logica di business o dei livelli di accesso ai dati, i dettagli dell'eccezione vengono restituiti a ObjectDataSource e quindi a GridView. È stato illustrato come gestire correttamente queste eccezioni creando Updated gestori eventi o RowUpdated per ObjectDataSource o GridView, verificando un'eccezione e quindi indicando che l'eccezione è stata gestita.

Le esercitazioni di DataList, tuttavia, non usano ObjectDataSource per l'aggiornamento e l'eliminazione dei dati. Al contrario, stiamo lavorando direttamente contro il BLL. Per rilevare le eccezioni provenienti da BLL o DAL, è necessario implementare il codice di gestione delle eccezioni all'interno del code-behind della pagina ASP.NET. In questa esercitazione verrà illustrato come gestire in modo più tattile le eccezioni generate durante un flusso di lavoro di aggiornamento di DataList modificabile.

Nota

In Panoramica della modifica e dell'eliminazione di dati nell'esercitazione DataList sono state illustrate diverse tecniche per la modifica e l'eliminazione di dati da DataList, alcune tecniche relative all'uso di ObjectDataSource per l'aggiornamento e l'eliminazione. Se si usano queste tecniche, è possibile gestire le eccezioni da BLL o DAL tramite i gestori eventi o UpdatedDeleted ObjectDataSource.

Passaggio 1: Creazione di un oggetto DataList modificabile

Prima di preoccuparsi della gestione delle eccezioni che si verificano durante il flusso di lavoro di aggiornamento, è prima necessario creare un oggetto DataList modificabile. Aprire la ErrorHandling.aspx pagina nella EditDeleteDataList cartella, aggiungere un oggetto DataList al Designer, impostarne la ID proprietà su Productse aggiungere un nuovo ObjectDataSource denominato ProductsDataSource. Configurare ObjectDataSource per l'utilizzo del ProductsBLL metodo della GetProducts() classe per la selezione dei record. Impostare gli elenchi a discesa nelle schede INSERT, UPDATE e DELETE su (Nessuno).

Restituire le informazioni sul prodotto utilizzando il metodo GetProducts()

Figura 1: Restituire le informazioni sul prodotto usando il GetProducts() metodo (fare clic per visualizzare l'immagine a dimensione intera)

Al termine della procedura guidata ObjectDataSource, Visual Studio creerà automaticamente un oggetto ItemTemplate per DataList. Sostituirlo con un oggetto ItemTemplate che visualizza il nome e il prezzo di ogni prodotto e include un pulsante Modifica. Creare quindi un EditItemTemplate oggetto con un controllo Web TextBox per i pulsanti nome e prezzo e Aggiorna e Annulla. Impostare infine la proprietà DataList s su RepeatColumns 2.

Dopo queste modifiche, il markup dichiarativo della pagina dovrebbe essere simile al seguente. Verificare che i pulsanti Modifica, Annulla e Aggiorna abbiano le relative CommandName proprietà impostate rispettivamente su Modifica, Annulla e Aggiorna.

<asp:DataList ID="Products" runat="server" DataKeyField="ProductID"
    DataSourceID="ProductsDataSource" RepeatColumns="2">
    <ItemTemplate>
        <h5>
            <asp:Label runat="server" ID="ProductNameLabel"
                Text='<%# Eval("ProductName") %>' />
        </h5>
        Price:
            <asp:Label runat="server" ID="Label1"
                Text='<%# Eval("UnitPrice", "{0:C}") %>' />
        <br />
            <asp:Button runat="server" id="EditProduct" CommandName="Edit"
                Text="Edit" />
        <br />
        <br />
    </ItemTemplate>
    <EditItemTemplate>
        Product name:
            <asp:TextBox ID="ProductName" runat="server"
                Text='<%# Eval("ProductName") %>' />
        <br />
        Price:
            <asp:TextBox ID="UnitPrice" runat="server"
                Text='<%# Eval("UnitPrice", "{0:C}") %>' />
        <br />
        <br />
            <asp:Button ID="UpdateProduct" runat="server" CommandName="Update"
                Text="Update" /> 
            <asp:Button ID="CancelUpdate" runat="server" CommandName="Cancel"
                Text="Cancel" />
    </EditItemTemplate>
</asp:DataList>
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
    SelectMethod="GetProducts" TypeName="ProductsBLL"
    OldValuesParameterFormatString="original_{0}">
</asp:ObjectDataSource>

Nota

Per questa esercitazione è necessario abilitare lo stato di visualizzazione di DataList.

Esaminare lo stato di avanzamento tramite un browser (vedere la figura 2).

Ogni prodotto include un pulsante Modifica

Figura 2: Ogni prodotto include un pulsante modifica (fare clic per visualizzare l'immagine a dimensione intera)

Attualmente, il pulsante Modifica causa solo un postback che non rende ancora modificabile il prodotto. Per abilitare la modifica, è necessario creare gestori eventi per gli eventi , CancelCommande UpdateCommand di EditCommandDataList. Gli EditCommand eventi e CancelCommand aggiornano semplicemente la proprietà DataList s EditItemIndex e riassociano i dati a DataList:

protected void Products_EditCommand(object source, DataListCommandEventArgs e)
{
    // Set the DataList's EditItemIndex property to the
    // index of the DataListItem that was clicked
    Products.EditItemIndex = e.Item.ItemIndex;
    // Rebind the data to the DataList
    Products.DataBind();
}
protected void Products_CancelCommand(object source, DataListCommandEventArgs e)
{
    // Set the DataList's EditItemIndex property to -1
    Products.EditItemIndex = -1;
    // Rebind the data to the DataList
    Products.DataBind();
}

Il UpdateCommand gestore eventi è un po' più coinvolto. Deve leggere nel prodotto modificato dalla ProductIDDataKeys raccolta insieme al nome e al prezzo del prodotto da TextBoxes in EditItemTemplatee quindi chiamare il ProductsBLL metodo della UpdateProduct classe prima di restituire DataList allo stato di pre-modifica.

Per il momento, è sufficiente usare lo stesso codice UpdateCommand del gestore eventi nell'esercitazione Panoramica della modifica e dell'eliminazione di dati nell'esercitazione DataList . Il codice verrà aggiunto per gestire normalmente le eccezioni nel passaggio 2.

protected void Products_UpdateCommand(object source, DataListCommandEventArgs e)
{
    // Read in the ProductID from the DataKeys collection
    int productID = Convert.ToInt32(Products.DataKeys[e.Item.ItemIndex]);
    // Read in the product name and price values
    TextBox productName = (TextBox)e.Item.FindControl("ProductName");
    TextBox unitPrice = (TextBox)e.Item.FindControl("UnitPrice");
    string productNameValue = null;
    if (productName.Text.Trim().Length > 0)
        productNameValue = productName.Text.Trim();
    decimal? unitPriceValue = null;
    if (unitPrice.Text.Trim().Length > 0)
        unitPriceValue = Decimal.Parse(unitPrice.Text.Trim(),
            System.Globalization.NumberStyles.Currency);
    // Call the ProductsBLL's UpdateProduct method...
    ProductsBLL productsAPI = new ProductsBLL();
    productsAPI.UpdateProduct(productNameValue, unitPriceValue, productID);
    // Revert the DataList back to its pre-editing state
    Products.EditItemIndex = -1;
    Products.DataBind();
}

In caso di input non valido che può essere sotto forma di prezzo unitario formattato in modo non corretto, verrà generato un valore unitario non valido come -$5,00 o l'omissione del nome del prodotto. Poiché il UpdateCommand gestore eventi non include codice di gestione delle eccezioni a questo punto, l'eccezione verrà visualizzata fino al runtime di ASP.NET, in cui verrà visualizzata all'utente finale (vedere la figura 3).

Quando si verifica un'eccezione non gestita, l'utente finale visualizza una pagina di errore

Figura 3: Quando si verifica un'eccezione non gestita, l'utente finale visualizza una pagina di errore

Passaggio 2: Gestione normale delle eccezioni nel gestore eventi UpdateCommand

Durante il flusso di lavoro di aggiornamento, le eccezioni possono verificarsi nel UpdateCommand gestore eventi, nel BLL o nel dal. Ad esempio, se un utente immette un prezzo troppo costoso, l'istruzione nel gestore eventi genererà un'eccezione Decimal.ParseFormatException.UpdateCommand Se l'utente omette il nome del prodotto o se il prezzo ha un valore negativo, il dal genererà un'eccezione.

Quando si verifica un'eccezione, si vuole visualizzare un messaggio informativo all'interno della pagina stessa. Aggiungere un controllo Web Etichetta alla pagina la cui ID proprietà è impostata su ExceptionDetails. Configurare il testo di Label per la visualizzazione in un tipo di carattere rosso, extra-large, grassetto e corsivo assegnandone CssClass la Warning proprietà alla classe CSS, definita nel Styles.css file.

Quando si verifica un errore, si vuole che l'etichetta venga visualizzata una sola volta. Ovvero, nei postback successivi, il messaggio di avviso Etichetta deve scomparire. A tale scopo, è possibile cancellare la proprietà Label s o impostarne Visible la proprietà False su nel Page_Load gestore eventi (come è stato fatto di nuovo in Gestione BLL- e DAL-Level Eccezioni in un'esercitazione sulla pagina di ASP.NET) o disabilitando il supporto dello stato di visualizzazione etichetta.Text Usare quest'ultima opzione.

<asp:Label ID="ExceptionDetails" EnableViewState="False" CssClass="Warning"
    runat="server" />

Quando viene generata un'eccezione, verranno assegnati i dettagli dell'eccezione alla ExceptionDetails proprietà del Text controllo Label. Poiché lo stato di visualizzazione è disabilitato, nei postback successivi le modifiche a livello di codice della Text proprietà andranno perse, ripristinando il testo predefinito (una stringa vuota), nascondendo così il messaggio di avviso.

Per determinare quando è stato generato un errore per visualizzare un messaggio utile nella pagina, è necessario aggiungere un Try ... Catch blocco al UpdateCommand gestore eventi. La Try parte contiene codice che può causare un'eccezione, mentre il Catch blocco contiene codice eseguito in caso di eccezione. Per altre informazioni sul Try ... Catch blocco, vedere la sezione Nozioni fondamentali sulla gestione delle eccezioni nella documentazione di .NET Framework.

protected void Products_UpdateCommand(object source, DataListCommandEventArgs e)
{
    // Handle any exceptions raised during the editing process
    try
    {
        // Read in the ProductID from the DataKeys collection
        int productID = Convert.ToInt32(Products.DataKeys[e.Item.ItemIndex]);
        ... Some code omitted for brevity ...
    }
    catch (Exception ex)
    {
        // TODO: Display information about the exception in ExceptionDetails
    }
}

Quando viene generata un'eccezione di qualsiasi tipo dal codice all'interno del Try blocco, il Catch codice del blocco inizierà l'esecuzione. Il tipo di eccezione generata DbException, , NoNullAllowedExceptionArgumentExceptione così via dipende da ciò che, esattamente, ha precipitato l'errore al primo posto. Se si verifica un problema a livello di database, verrà generata un'eccezione DbException . Se viene immesso un valore non valido per i UnitPricecampi , UnitsInStock, UnitsOnOrdero ReorderLevel , verrà generata un'eccezione ArgumentException , come è stato aggiunto il codice per convalidare questi valori di campo nella ProductsDataTable classe (vedere l'esercitazione Creazione di un livello logica di business).

È possibile fornire una spiegazione più utile all'utente finale basando il testo del messaggio sul tipo di eccezione intercettata. Il codice seguente usato in un modulo quasi identico nell'esercitazione Sulla gestione delle eccezioni BLL e DAL-Level in una pagina di ASP.NET fornisce questo livello di dettaglio:

private void DisplayExceptionDetails(Exception ex)
{
    // Display a user-friendly message
    ExceptionDetails.Text = "There was a problem updating the product. ";
    if (ex is System.Data.Common.DbException)
        ExceptionDetails.Text += "Our database is currently experiencing problems.
            Please try again later.";
    else if (ex is NoNullAllowedException)
        ExceptionDetails.Text += "There are one or more required fields that are
            missing.";
    else if (ex is ArgumentException)
    {
        string paramName = ((ArgumentException)ex).ParamName;
        ExceptionDetails.Text +=
            string.Concat("The ", paramName, " value is illegal.");
    }
    else if (ex is ApplicationException)
        ExceptionDetails.Text += ex.Message;
}

Per completare questa esercitazione, chiamare semplicemente il DisplayExceptionDetails metodo dal Catch blocco passando l'istanza rilevata Exception (ex).

Con il Try ... Catch blocco sul posto, gli utenti vengono visualizzati un messaggio di errore più informativo, come illustrato nelle figure 4 e 5. Si noti che, in caso di eccezione, DataList rimane in modalità di modifica. Ciò è dovuto al fatto che una volta che si verifica l'eccezione, il flusso di controllo viene reindirizzato immediatamente al Catch blocco, ignorando il codice che restituisce DataList allo stato di pre-modifica.

Viene visualizzato un messaggio di errore se un utente omette un campo obbligatorio

Figura 4: Viene visualizzato un messaggio di errore se un utente omette un campo obbligatorio (fare clic per visualizzare l'immagine a dimensione intera)

Viene visualizzato un messaggio di errore quando si immette un prezzo negativo

Figura 5: Viene visualizzato un messaggio di errore quando si immette un prezzo negativo (fare clic per visualizzare l'immagine a dimensione intera)

Riepilogo

GridView e ObjectDataSource forniscono gestori eventi post-livello che includono informazioni su eventuali eccezioni generate durante l'aggiornamento e l'eliminazione del flusso di lavoro, nonché proprietà che possono essere impostate per indicare se l'eccezione è stata gestita o meno. Queste funzionalità, tuttavia, non sono disponibili quando si usa DataList e si usa direttamente il BLL. Al contrario, siamo responsabili dell'implementazione della gestione delle eccezioni.

In questa esercitazione è stato illustrato come aggiungere la gestione delle eccezioni a un flusso di lavoro di aggiornamento di DataList modificabile aggiungendo un Try ... Catch blocco al UpdateCommand gestore eventi. Se durante il flusso di lavoro di aggiornamento viene generata un'eccezione, viene eseguito il Catch codice del blocco, visualizzando informazioni utili nell'etichetta ExceptionDetails .

A questo punto, DataList non fa alcuno sforzo per impedire che le eccezioni si verifichino al primo posto. Anche se sappiamo che un prezzo negativo genererà un'eccezione, non abbiamo ancora aggiunto alcuna funzionalità per impedire in modo proattivo a un utente di immettere tale input non valido. Nell'esercitazione successiva verrà illustrato come ridurre le eccezioni causate dall'input dell'utente non valido aggiungendo controlli di convalida in EditItemTemplate.

Buon programmatori!

Altre informazioni

Per altre informazioni sugli argomenti descritti in questa esercitazione, vedere le risorse seguenti:

Informazioni sull'autore

Scott Mitchell, autore di sette libri ASP/ASP.NET e fondatore di 4GuysFromRolla.com, lavora con le tecnologie Web Microsoft dal 1998. Scott lavora come consulente indipendente, formatore e scrittore. Il suo ultimo libro è Sams Teach Yourself ASP.NET 2.0 in 24 ore. Può essere raggiunto all'indirizzo mitchell@4GuysFromRolla.com. o tramite il suo blog, disponibile all'indirizzo http://ScottOnWriting.NET.

Grazie speciali

Questa serie di esercitazioni è stata esaminata da molti revisori utili. Il revisore principale per questa esercitazione è stato Ken Pespisa. Interessati a esaminare i prossimi articoli MSDN? In tal caso, lasciami una riga in mitchell@4GuysFromRolla.com.