Gestione delle eccezioni a livello BLL e DAL (C#)
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 Updated
Deleted
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 Products
e 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).
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).
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 , CancelCommand
e UpdateCommand
di EditCommand
DataList. 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 ProductID
DataKeys
raccolta insieme al nome e al prezzo del prodotto da TextBoxes in EditItemTemplate
e 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).
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.Parse
FormatException
.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
, , NoNullAllowedException
ArgumentException
e 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 UnitPrice
campi , UnitsInStock
, UnitsOnOrder
o 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.
Figura 4: Viene visualizzato un messaggio di errore se un utente omette un campo obbligatorio (fare clic per visualizzare l'immagine a dimensione intera)
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:
- Linee guida di progettazione delle eccezioni
- Moduli e gestori di registrazione degli errori (ELMAH) ( una libreria open source per la registrazione degli errori)
- Libreria enterprise per .NET Framework 2.0 (include il blocco di applicazioni di gestione delle eccezioni)
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.