Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
In questa esercitazione verrà illustrato come visualizzare un messaggio di errore descrittivo e informativo in caso di eccezione durante un'operazione di inserimento, aggiornamento o eliminazione di un controllo Web dati ASP.NET.
Introduzione
L'uso dei dati da un'applicazione Web ASP.NET tramite un'architettura di applicazioni a livelli prevede i tre passaggi generali seguenti:
- Determinare quale metodo del livello di logica di business deve essere richiamato e quali valori dei parametri da passare. I valori dei parametri possono essere integrati, assegnati tramite programmazione o valori immessi dall'utente.
- Richiama il metodo.
- Elaborare i risultati. Quando si chiama un metodo BLL che restituisce dati, ciò può comportare l'associazione dei dati a un controllo Web dati. Per i metodi BLL che modificano i dati, questa operazione può includere l'esecuzione di alcune azioni in base a un valore restituito o la gestione normale di qualsiasi eccezione generata nel passaggio 2.
Come illustrato nell'esercitazione precedente, sia ObjectDataSource che i controlli Web dati forniscono punti di estendibilità per i passaggi 1 e 3. GridView, ad esempio, genera l'evento RowUpdating
prima di assegnare i relativi valori di campo alla raccolta ObjectDataSource. L'evento UpdateParameters
viene generato dopo che ObjectDataSource ha completato l'operazione.
Sono già stati esaminati gli eventi generati durante il passaggio 1 e si è visto come possono essere usati per personalizzare i parametri di input o annullare l'operazione. In questo tutorial rivolgeremo la nostra attenzione agli eventi che si verificano alla conclusione dell'operazione. Con questi gestori eventi di post-livello è possibile, tra le altre cose, determinare se si è verificata un'eccezione durante l'operazione e gestirlo normalmente, visualizzando un messaggio di errore descrittivo e informativo sullo schermo invece di impostare come predefinito la pagina standard ASP.NET eccezione.
Per illustrare l'uso di questi eventi a livello di post, creare una pagina che visualizza l'elenco dei prodotti in un GridView modificabile. Quando si aggiorna un prodotto, se viene generata un'eccezione, la pagina ASP.NET visualizzerà un breve messaggio sopra GridView che spiega che si è verificato un problema. È ora di iniziare.
Passaggio 1: Creare una vista di griglia modificabile per i prodotti
Nell'esercitazione precedente, abbiamo creato un controllo GridView modificabile con solo due campi: ProductName
e UnitPrice
. Ciò richiedeva la creazione di un overload aggiuntivo per il ProductsBLL
metodo della UpdateProduct
classe, uno che accettava solo tre parametri di input (nome del prodotto, prezzo unitario e ID) anziché un parametro per ogni campo prodotto. Per questa esercitazione, si proverà di nuovo a eseguire questa tecnica, creando un controllo GridView modificabile che visualizza il nome del prodotto, la quantità per unità, il prezzo unitario e le unità in magazzino, ma consente solo la modifica del nome, del prezzo unitario e delle unità in magazzino.
Per soddisfare questo scenario, è necessario un ulteriore overload del metodo UpdateProduct
, che accetta quattro parametri: il nome del prodotto, il prezzo unitario, le unità in magazzino e l'ID. Aggiungere il metodo seguente alla classe ProductsBLL
:
[System.ComponentModel.DataObjectMethodAttribute(
System.ComponentModel.DataObjectMethodType.Update, false)]
public bool UpdateProduct(string productName, decimal? unitPrice, short? unitsInStock,
int productID)
{
Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID);
if (products.Count == 0)
// no matching record found, return false
return false;
Northwind.ProductsRow product = products[0];
product.ProductName = productName;
if (unitPrice == null) product.SetUnitPriceNull();
else product.UnitPrice = unitPrice.Value;
if (unitsInStock == null) product.SetUnitsInStockNull();
else product.UnitsInStock = unitsInStock.Value;
// Update the product record
int rowsAffected = Adapter.Update(product);
// Return true if precisely one row was updated, otherwise false
return rowsAffected == 1;
}
Al termine di questo metodo, è possibile creare la pagina ASP.NET che consente di modificare questi quattro campi di prodotto specifici. Aprire la pagina ErrorHandling.aspx
nella cartella EditInsertDelete
e aggiungere un controllo GridView alla pagina tramite il Designer. Associare GridView a un nuovo ObjectDataSource, associando il metodo Select()
al metodo ProductsBLL
della classe GetProducts()
e il metodo Update()
all'overload UpdateProduct
appena creato.
Figura 1: Usare l'overload del UpdateProduct
metodo che accetta quattro parametri di input (fare clic per visualizzare l'immagine a dimensione intera)
Verrà creato un ObjectDataSource con una collezione UpdateParameters
con quattro parametri e un GridView con un campo per ognuno dei campi di prodotto. Il markup dichiarativo di ObjectDataSource assegna il valore OldValuesParameterFormatString
alla proprietà original_{0}
, il che causerà un'eccezione perché la classe BLL non si aspetta che venga passato un parametro di input denominato original_productID
. Non dimenticare di rimuovere completamente questa impostazione dalla sintassi dichiarativa (o impostarla sul valore predefinito, {0}
).
Passare quindi a ridurre il GridView per includere solo i campi ProductName
, QuantityPerUnit
, UnitPrice
e UnitsInStock
BoundFields. Inoltre, è possibile applicare qualsiasi formattazione a livello di campo che si ritiene necessario (ad esempio modificando le HeaderText
proprietà).
Nell'esercitazione precedente è stato illustrato come formattare BoundField UnitPrice
come valuta sia in modalità di sola lettura che in modalità di modifica. Facciamo lo stesso qui. Ricorda che ciò richiedeva di impostare la proprietà DataFormatString
del BoundField su {0:c}
, la sua proprietà HtmlEncode
su false
, e la proprietà ApplyFormatInEditMode
su true
, come mostrato nella figura 2.
Figura 2: Configurare BoundField UnitPrice
per la visualizzazione come valuta (fare clic per visualizzare l'immagine a dimensione intera)
La formattazione di UnitPrice
come valuta nell'interfaccia di modifica richiede la creazione di un gestore per l'evento GridView RowUpdating
che converte una stringa formattata come valuta in un valore decimal
. Tenere presente che il RowUpdating
gestore eventi dell'ultima esercitazione ha controllato anche per assicurarsi che l'utente abbia fornito un UnitPrice
valore. Per questa esercitazione, lasciamo tuttavia che l'utente ometta il prezzo.
protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
if (e.NewValues["UnitPrice"] != null)
e.NewValues["UnitPrice"] =decimal.Parse(e.NewValues["UnitPrice"].ToString(),
System.Globalization.NumberStyles.Currency);
}
GridView includono un QuantityPerUnit
BoundField, ma questo BoundField deve essere utilizzato esclusivamente per la visualizzazione e non deve essere editabile dall'utente. Per disporre questa operazione, impostare semplicemente la proprietà BoundFields ReadOnly
su true
.
Figura 3: Impostare QuantityPerUnit
l'Read-Only BoundField (fare clic per visualizzare l'immagine a dimensione intera)
Selezionare infine la casella di controllo Abilita modifica tramite lo smart tag di GridView. Dopo aver completato questi passaggi, la ErrorHandling.aspx
finestra di progettazione della pagina dovrebbe essere simile alla figura 4.
Figura 4: Rimuovere tutti i BoundFields tranne quelli necessari e selezionare la casella di controllo Attiva modifica (fare clic per visualizzare l'immagine a dimensione intera)
A questo punto è disponibile un elenco di tutti i campi dei prodotti ProductName
, QuantityPerUnit
, UnitPrice
e UnitsInStock
; tuttavia, è possibile modificare solo i campi ProductName
, UnitPrice
e UnitsInStock
.
Figura 5: Gli utenti possono ora modificare facilmente i nomi, i prezzi e le unità dei prodotti nei campi azionari (fare clic per visualizzare l'immagine a dimensione intera)
Passaggio 2: Gestire correttamente le eccezioni DAL-Level
Anche se il GridView modificabile funziona meravigliosamente quando gli utenti inseriscono valori validi per il nome, il prezzo e le unità in magazzino del prodotto modificato, inserire valori non validi comporta un'eccezione. Se ad esempio il valore viene ProductName
omesso, viene generata un'eccezione NoNullAllowedException poiché la ProductName
proprietà nella ProductsRow
classe ha la proprietà AllowDBNull
impostata su false
. Se il database è inattivo, viene generata un'eccezione SqlException
da TableAdapter quando si tenta di connettersi al database. Senza eseguire alcuna azione, queste eccezioni passano dal livello di accesso ai dati al livello della logica di business, quindi alla pagina ASP.NET e infine al runtime di ASP.NET.
A seconda del modo in cui l'applicazione Web è configurata e se si visita o meno l'applicazione da localhost
, un'eccezione non gestita può comportare una pagina generica di errore del server, un report di errore dettagliato o una pagina Web intuitiva. Per altre informazioni su come il runtime di ASP.NET risponde a un'eccezione non rilevata, vedere Gestione degli errori dell'applicazione Web in ASP.NET e l'elemento customErrors .
La figura 6 mostra la schermata rilevata quando si tenta di aggiornare un prodotto senza specificare il ProductName
valore. Questo è il report di errore dettagliato predefinito visualizzato quando si passa attraverso localhost
.
Figura 6: Omettendo il nome del prodotto verranno visualizzati i dettagli dell'eccezione (fare clic per visualizzare l'immagine a dimensione intera)
Anche se tali dettagli di eccezione sono utili durante il test di un'applicazione, la presentazione di un utente finale con tale schermata in presenza di un'eccezione è minore dell'ideale. Un utente finale probabilmente non sa che cos'è NoNullAllowedException
o perché è stato causato. Un approccio migliore consiste nel presentare all'utente un messaggio più descrittivo che spiega che si sono verificati problemi durante il tentativo di aggiornare il prodotto.
Se si verifica un'eccezione durante l'esecuzione dell'operazione, gli eventi di post-livello sia dell'ObjectDataSource sia del controllo dati Web forniscono un mezzo per rilevarla e impedire che l'eccezione si propaghi fino al runtime di ASP.NET. Per questo esempio, creiamo un gestore eventi per l'evento gridView RowUpdated
che determina se un'eccezione è stata attivata e, in tal caso, visualizza i dettagli dell'eccezione in un controllo Web Label.
Per iniziare, aggiungere un'etichetta alla pagina ASP.NET, impostando la proprietà ID
su ExceptionDetails
e cancellando la proprietà Text
. Per attirare l'attenzione dell'utente su questo messaggio, imposta la sua proprietà CssClass
su Warning
, ovvero una classe CSS che abbiamo aggiunto al file Styles.css
nell'esercitazione precedente. Tenere presente che questa classe CSS fa sì che il testo dell'etichetta venga visualizzato in un tipo di carattere rosso, corsivo, grassetto, extra grande.
Aggiungere un controllo Web di etichetta alla pagina
Figura 7: Aggiungere un controllo Web etichetta alla pagina (fare clic per visualizzare l'immagine a dimensione intera)
Poiché vogliamo che questo controllo Web di etichetta sia visibile solo immediatamente dopo il verificarsi di un'eccezione, impostare la sua proprietà Visible
su false nel gestore eventi Page_Load
.
protected void Page_Load(object sender, EventArgs e)
{
ExceptionDetails.Visible = false;
}
Con questo codice, alla prima visita della pagina e ai successivi postback, il controllo ExceptionDetails
avrà la proprietà Visible
impostata su false
. In presenza di un'eccezione a livello DAL o BLL, che è possibile rilevare nel gestore eventi di RowUpdated
GridView, la ExceptionDetails
proprietà del Visible
controllo verrà impostata su true. Poiché i gestori di eventi del controllo Web si verificano dopo il Page_Load
gestore di eventi nel ciclo di vita della pagina, verrà visualizzata l'Etichetta. Tuttavia, nel postback successivo, il gestore eventi Page_Load
ripristinerà la proprietà Visible
a false
, nascondendola nuovamente alla vista.
Annotazioni
In alternativa, è possibile rimuovere la necessità di impostare la ExceptionDetails
proprietà del Visible
controllo in Page_Load
assegnandone Visible
la proprietà false
nella sintassi dichiarativa e disabilitandone lo stato di visualizzazione (impostandone la EnableViewState
proprietà su false
). Questo approccio alternativo verrà usato in un'esercitazione futura.
Con il controllo Label aggiunto, il passaggio successivo consiste nel creare il gestore eventi per l'evento gridView RowUpdated
. Selezionare GridView in Progettazione, passare alla finestra Proprietà e fare clic sull'icona a forma di fulmine, elencando gli eventi di GridView. Dovrebbe già esserci una voce per l'evento del GridView RowUpdating
, poiché abbiamo precedentemente creato un gestore per questo evento in questo tutorial. Creare anche un gestore eventi per l'evento RowUpdated
.
Figura 8: Creare un gestore eventi per l'evento di RowUpdated
GridView
Annotazioni
È anche possibile creare il gestore eventi tramite gli elenchi a discesa nella parte superiore del file di classe code-behind. Seleziona "GridView" dall'elenco a discesa a sinistra e l'evento RowUpdated
da quello a destra.
La creazione di questo gestore eventi aggiungerà il codice seguente alla classe code-behind della pagina ASP.NET:
protected void GridView1_RowUpdated(object sender, GridViewUpdatedEventArgs e)
{
}
Il secondo parametro di input del gestore eventi è un oggetto di tipo GridViewUpdatedEventArgs, che ha tre proprietà di interesse per la gestione delle eccezioni:
-
Exception
riferimento all'eccezione generata; se non è stata generata alcuna eccezione, questa proprietà avrà un valore pari anull
-
ExceptionHandled
Valore booleano che indica se l'eccezione è stata gestita nelRowUpdated
gestore eventi; sefalse
(impostazione predefinita), l'eccezione viene generata nuovamente, percolando fino al runtime ASP.NET -
KeepInEditMode
se impostato sullatrue
riga gridView modificata rimane in modalità di modifica; sefalse
(impostazione predefinita), la riga GridView torna alla modalità di sola lettura
Il nostro codice, quindi, dovrebbe verificare se Exception
non è null
, il che significa che è stata sollevata un'eccezione durante l'esecuzione dell'operazione. In questo caso, si vuole:
- Visualizzare un messaggio descrittivo nell'etichetta
ExceptionDetails
- Indicare che l'eccezione è stata gestita
- Mantenere la riga GridView in modalità di modifica
Questo codice seguente consente di raggiungere questi obiettivi:
protected void GridView1_RowUpdated(object sender, GridViewUpdatedEventArgs e)
{
if (e.Exception != null)
{
// Display a user-friendly message
ExceptionDetails.Visible = true;
ExceptionDetails.Text = "There was a problem updating the product. ";
if (e.Exception.InnerException != null)
{
Exception inner = e.Exception.InnerException;
if (inner is System.Data.Common.DbException)
ExceptionDetails.Text +=
"Our database is currently experiencing problems." +
"Please try again later.";
else if (inner is NoNullAllowedException)
ExceptionDetails.Text +=
"There are one or more required fields that are missing.";
else if (inner is ArgumentException)
{
string paramName = ((ArgumentException)inner).ParamName;
ExceptionDetails.Text +=
string.Concat("The ", paramName, " value is illegal.");
}
else if (inner is ApplicationException)
ExceptionDetails.Text += inner.Message;
}
// Indicate that the exception has been handled
e.ExceptionHandled = true;
// Keep the row in edit mode
e.KeepInEditMode = true;
}
}
Questo gestore eventi inizia controllando se e.Exception
è null
. Se non è così, la proprietà ExceptionDetails
dell'etichetta Visible
viene impostata su true
e la sua proprietà Text
su "Si è verificato un problema durante l'aggiornamento del prodotto". I dettagli dell'eccezione effettiva generata risiedono nella proprietà e.Exception
dell'oggetto InnerException
. Questa eccezione interna viene esaminata e, se è di un tipo particolare, viene aggiunto un messaggio utile e aggiuntivo ExceptionDetails
alla proprietà Text
dell'etichetta. Infine, le ExceptionHandled
proprietà e KeepInEditMode
sono entrambe impostate su true
.
La figura 9 mostra una schermata di questa pagina quando si omette il nome del prodotto; La figura 10 mostra i risultati quando si immette un valore non valido UnitPrice
(-50).
Figura 9: BoundField ProductName
deve contenere un valore (fare clic per visualizzare l'immagine a dimensione intera)
Figura 10: I valori negativi UnitPrice
non sono consentiti (fare clic per visualizzare l'immagine a dimensione intera)
Impostando la e.ExceptionHandled
proprietà su true
, il RowUpdated
gestore eventi ha indicato che ha gestito l'eccezione. Pertanto, l'eccezione non verrà propagata fino al runtime di ASP.NET.
Annotazioni
Le figure 9 e 10 mostrano un modo normale per gestire le eccezioni generate a causa dell'input utente non valido. Idealmente, tuttavia, tale input non valido non raggiungerà mai il livello della logica di business, perché la pagina ASP.NET dovrebbe assicurarsi che gli input dell'utente siano validi prima di richiamare il ProductsBLL
metodo della UpdateProduct
classe. Nell'esercitazione successiva verrà illustrato come aggiungere controlli di convalida alle interfacce di modifica e inserimento per assicurarsi che i dati inviati al livello della logica di business siano conformi alle regole business. I controlli di convalida non solo impediscono la chiamata del UpdateProduct
metodo fino a quando i dati forniti dall'utente non sono validi, ma forniscono anche un'esperienza utente più informativa per identificare i problemi di immissione dei dati.
Passaggio 3: Gestire correttamente le eccezioni BLL-Level
Durante l'inserimento, l'aggiornamento o l'eliminazione di dati, il livello di accesso ai dati può generare un'eccezione in caso di errore correlato ai dati. Il database potrebbe essere offline, una colonna della tabella di database necessaria potrebbe non avere un valore specificato oppure è possibile che sia stato violato un vincolo a livello di tabella. Oltre alle eccezioni strettamente correlate ai dati, il livello della logica di business può usare le eccezioni per indicare quando le regole business sono state violate.
Nell'esercitazione Creazione di un livello di logica aziendale, ad esempio, è stata aggiunta una verifica della regola aziendale al sovraccarico originale.UpdateProduct
In particolare, se l'utente contrassegnava un prodotto come sospeso, abbiamo richiesto che il prodotto non sia l'unico fornito dal suo fornitore. Se questa condizione è stata violata, è stata generata un'eccezione ApplicationException
.
Per l'overload UpdateProduct
creato in questa esercitazione, aggiungere una regola aziendale che vieta l'assegnazione al campo UnitPrice
di un nuovo valore che sia maggiore del doppio del valore originale UnitPrice
. A tale scopo, regolare l'overload UpdateProduct
in modo che esegua questo controllo e generi un'eccezione ApplicationException
se la regola viene violata. Il metodo aggiornato segue:
public bool UpdateProduct(string productName, decimal? unitPrice, short? unitsInStock,
int productID)
{
Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID);
if (products.Count == 0)
// no matching record found, return false
return false;
Northwind.ProductsRow product = products[0];
// Make sure the price has not more than doubled
if (unitPrice != null && !product.IsUnitPriceNull())
if (unitPrice > product.UnitPrice * 2)
throw new ApplicationException(
"When updating a product price," +
" the new price cannot exceed twice the original price.");
product.ProductName = productName;
if (unitPrice == null) product.SetUnitPriceNull();
else product.UnitPrice = unitPrice.Value;
if (unitsInStock == null) product.SetUnitsInStockNull();
else product.UnitsInStock = unitsInStock.Value;
// Update the product record
int rowsAffected = Adapter.Update(product);
// Return true if precisely one row was updated, otherwise false
return rowsAffected == 1;
}
Con questa modifica, qualsiasi aggiornamento del prezzo che sia più del doppio del prezzo esistente verrà generata un'eccezione ApplicationException
. Proprio come l'eccezione generata dal DAL, questa BLL-generata ApplicationException
può essere rilevata e gestita nel gestore eventi di GridView RowUpdated
. Infatti, il codice del gestore eventi RowUpdated
, come scritto, rileverà correttamente questa eccezione e visualizzerà il valore della proprietà ApplicationException
di Message
. La figura 11 mostra uno screenshot quando un utente tenta di aggiornare il prezzo di Chai a $ 50,00, che è più del doppio del prezzo corrente di $ 19,95.
Le regole aziendali vietano aumenti di prezzo che superano più del doppio il prezzo di un prodotto.
Figura 11: Le regole di business non consentono aumenti di prezzo che più del doppio prezzo di un prodotto (fare clic per visualizzare l'immagine a dimensione intera)
Annotazioni
Idealmente, le regole della logica di business dovrebbero essere refattorizzate dagli overload del metodo UpdateProduct
e in un metodo comune. Questa operazione viene lasciata come esercizio per il lettore.
Riassunto
Durante l'inserimento, l'aggiornamento e l'eliminazione delle operazioni, sia il controllo Web dei dati che l'ObjectDataSource attivano eventi pre-operativi e post-operativi che delimitano l'operazione effettiva. Come abbiamo visto in questo tutorial e in quello precedente, quando si lavora con un GridView modificabile, viene attivato l'evento RowUpdating
del GridView, seguito dall'evento Updating
dell'ObjectDataSource, momento in cui il comando di aggiornamento viene eseguito sull'oggetto sottostante di ObjectDataSource. Al termine dell'operazione, viene generato l'evento ObjectDataSourceUpdated
, seguito dall'evento GridView.RowUpdated
È possibile creare gestori eventi per gli eventi di prelivello per personalizzare i parametri di input o per gli eventi post-livello per controllare e rispondere ai risultati dell'operazione. I gestori eventi post-livello vengono usati più comunemente per rilevare se si è verificata un'eccezione durante l'operazione. In caso di eccezione, questi gestori di eventi a livello post possono scegliere di gestire l'eccezione autonomamente. In questa esercitazione è stato illustrato come gestire tale eccezione visualizzando un messaggio di errore descrittivo.
Nell'esercitazione successiva verrà illustrato come ridurre la probabilità di eccezioni derivanti da problemi di formattazione dei dati, ad esempio l'immissione di un valore negativo UnitPrice
. In particolare, verrà illustrato come aggiungere controlli di convalida alle interfacce di modifica e inserimento.
Buon programmatori!
Informazioni sull'autore
Scott Mitchell, autore di sette libri ASP/ASP.NET e fondatore di 4GuysFromRolla.com, ha lavorato 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 a mitchell@4GuysFromRolla.com.
Grazie speciale a
Questa serie di esercitazioni è stata esaminata da molti revisori competenti. Il revisore principale per questo tutorial è Liz Shulok. Si è interessati a esaminare i prossimi articoli MSDN? In tal caso, mandami un messaggio a mitchell@4GuysFromRolla.com.