Zpracování výjimek na úrovni knihoven BLL a DAL na stránce ASP.NET (C#)
V tomto kurzu se dozvíte, jak zobrazit popisnou a informativní chybovou zprávu, pokud během operace vložení, aktualizace nebo odstranění webového ovládacího prvku ASP.NET dat dojde k výjimce.
Úvod
Práce s daty z ASP.NET webové aplikace pomocí architektury vrstvených aplikací zahrnuje následující tři obecné kroky:
- Určete, jakou metodu vrstvy obchodní logiky je potřeba vyvolat a jaké hodnoty parametrů se mají předat. Hodnoty parametrů můžou být pevně kódované, programově přiřazené nebo vstupy zadané uživatelem.
- Vyvolejte metodu .
- Zpracujte výsledky. Při volání metody BLL, která vrací data, to může zahrnovat vazbu dat na datový webový ovládací prvek. U metod BLL, které upravují data, to může zahrnovat provedení určité akce na základě návratové hodnoty nebo řádné zpracování výjimky, která vznikla v kroku 2.
Jak jsme viděli v předchozím kurzu, ovládací prvky ObjectDataSource a data Web poskytují body rozšiřitelnosti pro kroky 1 a 3. Objekt GridView například aktivuje událost RowUpdating
před přiřazením hodnot svých polí kolekci ObjectDataSource UpdateParameters
; jeho RowUpdated
událost je vyvolána po dokončení operace ObjectDataSource.
Už jsme prozkoumali události, které se aktivují během kroku 1, a zjistili jsme, jak je možné je použít k přizpůsobení vstupních parametrů nebo zrušení operace. V tomto kurzu obrátíme pozornost na události, které se aktivují po dokončení operace. Pomocí těchto obslužných rutin událostí po úrovni můžeme mimo jiné určit, jestli během operace došlo k výjimce, a elegantně ji zpracovat a zobrazit na obrazovce popisnou a informativní chybovou zprávu místo výchozího nastavení standardní stránky ASP.NET výjimky.
Pro ilustraci práce s těmito událostmi po úrovni vytvoříme stránku se seznamem produktů v upravitelném zobrazení GridView. Pokud při aktualizaci produktu dojde k výjimce, zobrazí se na stránce ASP.NET nad objektem GridView krátká zpráva s vysvětlením, že došlo k problému. Pusťme se do toho.
Krok 1: Vytvoření upravitelného zobrazení GridView produktů
V předchozím kurzu jsme vytvořili upravitelný objekt GridView se dvěma poli ProductName
a UnitPrice
. To vyžadovalo vytvoření dalšího přetížení pro metodu ProductsBLL
třídy UpdateProduct
, která přijímala pouze tři vstupní parametry (název produktu, jednotkovou cenu a ID) na rozdíl od parametru pro každé pole produktu. Pro účely tohoto kurzu si tuto techniku znovu procvičme a vytvoříme upravitelný objekt GridView, který zobrazuje název produktu, množství na jednotku, jednotkovou cenu a jednotky na skladě, ale umožňuje úpravy pouze názvu, jednotkové ceny a jednotek na skladě.
Pro tento scénář budeme potřebovat další přetížení UpdateProduct
metody, které přijímá čtyři parametry: název produktu, jednotkovou cenu, jednotky na skladě a ID. Do třídy ProductsBLL
přidejte následující metodu:
[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;
}
Po dokončení této metody jsme připraveni vytvořit stránku ASP.NET, která umožňuje upravit tato čtyři konkrétní pole produktů. ErrorHandling.aspx
Otevřete stránku ve EditInsertDelete
složce a přidejte gridview na stránku prostřednictvím Designer. Vytvořte vazbu GridView na nový ObjectDataSource a namapujte metodu Select()
na metodu ProductsBLL
třídy GetProducts()
a metodu Update()
na UpdateProduct
právě vytvořené přetížení.
Obrázek 1: Použití UpdateProduct
přetížení metody, která přijímá čtyři vstupní parametry (kliknutím zobrazíte obrázek v plné velikosti)
Tím se vytvoří ObjectDataSource s kolekcí UpdateParameters
se čtyřmi parametry a Objekt GridView s polem pro každé pole produktu. Deklarativní kód ObjectDataSource přiřadí OldValuesParameterFormatString
vlastnosti hodnotu original_{0}
, která způsobí výjimku, protože naše třída BLL neočekává předání vstupního parametru s názvem original_productID
. Nezapomeňte toto nastavení úplně odebrat z deklarativní syntaxe (nebo ho nastavit na výchozí hodnotu {0}
).
Dále parepište Objekt GridView tak, aby zahrnoval pouze ProductName
objekty , QuantityPerUnit
UnitPrice
, a UnitsInStock
BoundFields. Nebojte se také použít jakékoli formátování na úrovni pole, které považujete za nezbytné (například změnu HeaderText
vlastností).
V předchozím kurzu jsme se podívali na to, jak formátovat UnitPrice
BoundField jako měnu v režimu jen pro čtení i v režimu úprav. Uděláme to samé tady. Vzpomeňte si, že toto nastavení vyžaduje nastavení vlastnosti BoundField DataFormatString
na {0:c}
, jeho HtmlEncode
vlastnost na false
a jeho ApplyFormatInEditMode
na true
, jak je znázorněno na obrázku 2.
Obrázek 2: Konfigurace UnitPrice
pole BoundField tak, aby se zobrazilo jako měna (kliknutím zobrazíte obrázek v plné velikosti)
Formátování UnitPrice
jako měny v rozhraní pro úpravy vyžaduje vytvoření obslužné rutiny události gridview události RowUpdating
, která parsuje řetězec ve formátu měny na decimal
hodnotu. Vzpomeňte RowUpdating
si, že obslužná rutina události z posledního kurzu také zkontrolovala, aby se zajistilo, že uživatel zadal UnitPrice
hodnotu. V tomto kurzu ale umožníme uživateli vynechat cenu.
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);
}
Naše zobrazení GridView obsahuje QuantityPerUnit
BoundField, ale toto BoundField by mělo být pouze pro účely zobrazení a uživatel by ho neměl upravovat. Pokud to chcete uspořádat, jednoduše nastavte vlastnost BoundFields ReadOnly
na true
.
Obrázek 3: Nastavení QuantityPerUnit
Read-Only BoundField (kliknutím zobrazíte obrázek v plné velikosti)
Nakonec zaškrtněte políčko Povolit úpravy u inteligentní značky GridView. Po dokončení těchto kroků ErrorHandling.aspx
by Designer stránky měly vypadat podobně jako na obrázku 4.
Obrázek 4: Odeberte všechna kromě potřebných boundfields a zaškrtněte políčko Povolit úpravy (kliknutím zobrazíte obrázek v plné velikosti).
V tomto okamžiku máme seznam všech polí produktů , , , a UnitsInStock
. Upravit se ale dají jenom ProductName
pole , UnitPrice
a UnitsInStock
. UnitPrice
QuantityPerUnit
ProductName
Obrázek 5: Uživatelé teď můžou snadno upravovat názvy produktů, ceny a jednotky v polích zásob (kliknutím zobrazíte obrázek v plné velikosti)
Krok 2: Řádné zpracování DAL-Level výjimek
Zatímco naše upravitelné GridView funguje skvěle, když uživatelé zadají právní hodnoty pro název, cenu a jednotky upraveného produktu na skladě, zadání neplatných hodnot vede k výjimce. Například vynechání ProductName
hodnoty způsobí, že NoNullAllowedException bude vyvolána, protože ProductName
vlastnost ve ProductsRow
třídě má svou AllowDBNull
vlastnost nastavenou na false
hodnotu . Pokud je databáze mimo provoz, SqlException
bude vyvolána objektEm TableAdapter při pokusu o připojení k databázi. Bez provedení jakékoli akce se tyto výjimky zobrazí z vrstvy přístupu k datům do vrstvy obchodní logiky, pak na stránku ASP.NET a nakonec do ASP.NET modulu runtime.
V závislosti na tom, jak je vaše webová aplikace nakonfigurovaná a jestli aplikaci navštěvujete z localhost
aplikace , může neošetřená výjimka vést buď k obecné chybové stránce serveru, podrobné zprávě o chybách, nebo k uživatelsky přívětivé webové stránce. Další informace o tom, jak modul runtime ASP.NET reaguje na nezachycenou výjimku, najdete v tématech Zpracování chyb webové aplikace v ASP.NET a elementu customErrors .
Obrázek 6 znázorňuje obrazovku zobrazenou při pokusu o aktualizaci produktu bez zadání ProductName
hodnoty. Toto je výchozí podrobná zpráva o chybách, která se zobrazí při procházení .localhost
Obrázek 6: Vynechání názvu produktu zobrazí podrobnosti o výjimce (kliknutím zobrazíte obrázek v plné velikosti)
I když jsou takové podrobnosti o výjimce užitečné při testování aplikace, prezentace takové obrazovky koncovému uživateli před výjimkou není ideální. Koncový uživatel pravděpodobně neví, co NoNullAllowedException
je nebo proč k němu došlo. Lepším přístupem je zobrazit uživateli uživatelsky přívětivější zprávu vysvětlující, že při pokusu o aktualizaci produktu došlo k problémům.
Pokud při provádění operace dojde k výjimce, události po úrovni v ovládacím prvku ObjectDataSource a data Web poskytují prostředky k jeho zjištění a zrušení výjimky z probublávání až do ASP.NET modulu runtime. V našem příkladu vytvoříme obslužnou rutinu události objektu GridView RowUpdated
, která určí, jestli se aktivovala výjimka, a pokud ano, zobrazí podrobnosti o výjimce v ovládacím prvku Label Web.
Začněte tím, že na stránku ASP.NET přidáte popisek, nastavíte jeho ID
vlastnost na ExceptionDetails
a vymažete jeho Text
vlastnost. Pokud chcete upoutat pozornost uživatele na tuto zprávu, nastavte jeho CssClass
vlastnost na Warning
, což je třída CSS, kterou jsme přidali do Styles.css
souboru v předchozím kurzu. Vzpomeňte si, že tato třída CSS způsobí, že se text popisku zobrazí červeným, kurzívou, tučným a extra velkým písmem.
Obrázek 7: Přidání webového ovládacího prvku Popisek na stránku (kliknutím zobrazíte obrázek v plné velikosti)
Vzhledem k tomu, že chceme, aby byl tento ovládací prvek Label Web viditelný hned po výjimce, nastavte jeho Visible
vlastnost v obslužné rutině události na Page_Load
hodnotu false:
protected void Page_Load(object sender, EventArgs e)
{
ExceptionDetails.Visible = false;
}
S tímto kódem bude mít ovládací prvek při první návštěvě stránky a následných zpětných ExceptionDetails
odesláních nastavenou vlastnost Visible
na false
. V případě výjimky na úrovni DAL nebo BLL, kterou můžeme zjistit v obslužné rutině události GridView RowUpdated
, nastavíme ExceptionDetails
vlastnost ovládacího prvku Visible
na true. Vzhledem k tomu, že se obslužné rutiny událostí webového Page_Load
ovládacího prvku vyskytují po obslužné rutině události v životním cyklu stránky, zobrazí se popisek. Při dalším zpětném odeslání Page_Load
však obslužná rutina události vrátí Visible
vlastnost zpět na false
a znovu ji skryje ze zobrazení.
Poznámka
Alternativně bychom mohli odebrat nutnost nastavení ExceptionDetails
vlastnosti ovládacího prvku Visible
v Page_Load
souboru tím, že přiřadíme jeho Visible
vlastnost false
v deklarativní syntaxi a zakážeme jeho stav zobrazení (nastavíme jeho EnableViewState
vlastnost na false
). Tento alternativní přístup použijeme v budoucím kurzu.
Po přidání ovládacího prvku Label je naším dalším krokem vytvoření obslužné rutiny události pro událost GridView RowUpdated
. V Designer vyberte Objekt GridView, přejděte na okno Vlastnosti a klikněte na ikonu blesku se seznamem událostí objektu GridView. Už by tam měla být položka pro událost GridView RowUpdating
, protože jsme pro tuto událost dříve v tomto kurzu vytvořili obslužnou rutinu události. Vytvořte také obslužnou rutinu RowUpdated
události pro událost.
Obrázek 8: Vytvoření obslužné rutiny události pro událost GridView RowUpdated
Poznámka
Obslužnou rutinu události můžete také vytvořit prostřednictvím rozevíracích seznamů v horní části souboru třídy kódu na pozadí. V rozevíracím seznamu vlevo vyberte GridView a RowUpdated
událost z pravého seznamu.
Při vytváření této obslužné rutiny události se do třídy kódu na pozadí stránky ASP.NET přidá následující kód:
protected void GridView1_RowUpdated(object sender, GridViewUpdatedEventArgs e)
{
}
Druhý vstupní parametr této obslužné rutiny události je objekt typu GridViewUpdatedEventArgs, který má tři vlastnosti, které jsou zajímavé pro zpracování výjimek:
Exception
odkaz na vyvolanou výjimku; Pokud nebyla vyvolána žádná výjimka, bude mít tato vlastnost hodnotunull
ExceptionHandled
Logická hodnota, která označuje, jestli byla výjimka zpracována vRowUpdated
obslužné rutině události. Pokudfalse
(výchozí), výjimka se znovu vyvolá a přejde až do ASP.NET modulu runtime.KeepInEditMode
pokud je nastaveno natrue
upravený řádek GridView zůstane v režimu úprav. Pokudfalse
(výchozí), řádek GridView se vrátí do režimu jen pro čtení.
Náš kód by pak měl zkontrolovat, jestli Exception
není null
, což znamená, že při provádění operace byla vyvolána výjimka. V takovém případě chceme:
- Zobrazení uživatelsky přívětivé zprávy v popisku
ExceptionDetails
- Označení, že výjimka byla zpracována
- Zachování řádku GridView v režimu úprav
Následující kód dosahuje těchto cílů:
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;
}
}
Tato obslužná rutina události začíná kontrolou, jestli e.Exception
je null
. Pokud tomu tak není, ExceptionDetails
vlastnost Label je Visible
nastavená na true
a vlastnost Text
"Při aktualizaci produktu došlo k potížím". Podrobnosti o skutečné výjimce, která byla vyvolán, se nacházejí ve vlastnosti objektu e.Exception
InnerException
. Tato vnitřní výjimka se prověří a pokud je konkrétního typu, připojí se k ExceptionDetails
vlastnosti Label Text
další užitečná zpráva. ExceptionHandled
Nakonec jsou vlastnosti a KeepInEditMode
nastaveny na true
hodnotu .
Obrázek 9 ukazuje snímek obrazovky této stránky při vynechání názvu produktu; Obrázek 10 ukazuje výsledky při zadávání neplatné UnitPrice
hodnoty (-50).
Obrázek 9: BoundField ProductName
musí obsahovat hodnotu (kliknutím zobrazíte obrázek v plné velikosti)
Obrázek 10: Záporné UnitPrice
hodnoty nejsou povolené (kliknutím zobrazíte obrázek v plné velikosti)
Nastavením e.ExceptionHandled
vlastnosti na true
hodnotu byla obslužná RowUpdated
rutina události označena, že zpracovala výjimku. Proto se výjimka nebude šířit až do modulu runtime ASP.NET.
Poznámka
Obrázky 9 a 10 ukazují elegantní způsob zpracování výjimek vyvolaných kvůli neplatnému vstupu uživatele. V ideálním případě se ale takový neplatný vstup nikdy nedostane do vrstvy obchodní logiky, protože stránka ASP.NET by měla před vyvoláním ProductsBLL
metody třídy UpdateProduct
zajistit, aby vstupy uživatele byly platné. V dalším kurzu se dozvíte, jak přidat ověřovací ovládací prvky do rozhraní pro úpravy a vkládání, abychom zajistili, že data odeslaná do vrstvy obchodní logiky odpovídají obchodním pravidlům. Ověřovací ovládací prvky nejen brání vyvolání UpdateProduct
metody, dokud nebudou data zadaná uživatelem platná, ale také poskytují informativnější uživatelské prostředí pro identifikaci problémů se zadáváním dat.
Krok 3: Řádné zpracování výjimek BLL-Level
Při vkládání, aktualizaci nebo odstraňování dat může vrstva přístupu k datům vyvolat výjimku tváří v tvář chybě související s daty. Databáze může být offline, požadovaný sloupec tabulky databáze nemusí mít zadanou hodnotu nebo došlo k porušení omezení na úrovni tabulky. Kromě výjimek výhradně souvisejících s daty může vrstva obchodní logiky používat výjimky k označení, kdy došlo k porušení obchodních pravidel. Například v kurzu Vytvoření vrstvy obchodní logiky jsme do původního UpdateProduct
přetížení přidali kontrolu obchodních pravidel. Konkrétně pokud uživatel označoval produkt jako ukončený, požadovali jsme, aby produkt nebyl jediný, který mu poskytl jeho dodavatel. Pokud byla tato podmínka porušena, došlo k ApplicationException
vyvolání.
UpdateProduct
Pro přetížení vytvořené v tomto kurzu přidáme obchodní pravidlo, které zakážeUnitPrice
, aby pole bylo nastaveno na novou hodnotu, která je více než dvakrát vyšší než původní UnitPrice
hodnota. Chcete-li toho dosáhnout, upravte UpdateProduct
přetížení tak, aby provedlo tuto kontrolu a vyvolá chybu ApplicationException
, pokud je pravidlo porušeno. Aktualizovaná metoda následuje:
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;
}
Při této změně způsobí ApplicationException
jakákoli aktualizace cen, která je více než dvojnásobek stávající ceny, vyvolá vyvolání. Stejně jako výjimka vyvolaná z DAL, může být tato zvýšená ApplicationException
BLL rozpoznána a zpracována v obslužné rutině události GridView RowUpdated
. Ve skutečnosti RowUpdated
kód obslužné rutiny události, jak je napsaný, tuto výjimku správně rozpozná a zobrazí ApplicationException
hodnotu vlastnosti .Message
Obrázek 11 ukazuje snímek obrazovky, když se uživatel pokusí aktualizovat cenu Chai na 50,00 USD, což je více než dvojnásobek aktuální ceny 19,95 USD.
Obrázek 11: Obchodní pravidla neumožňují zvýšení ceny, které je vyšší než dvojnásobek ceny produktu (kliknutím zobrazíte obrázek v plné velikosti)
Poznámka
V ideálním případě by se pravidla obchodní logiky refaktorovala z UpdateProduct
přetížení metod do běžné metody. Toto je ponecháno jako cvičení pro čtenáře.
Souhrn
Při vkládání, aktualizaci a odstraňování operací zahrnoval ovládací prvek web dat i ObjectDataSource události před a po úrovni, které zarezervují skutečnou operaci. Jak jsme viděli v tomto kurzu a předchozím, při práci s upravitelným objektem GridView se aktivuje událost GridView RowUpdating
následovaná událostí ObjectDataSource Updating
, v tomto okamžiku se provede příkaz update na podkladový objekt ObjectDataSource. Po dokončení operace se aktivuje událost ObjectDataSource Updated
následovaná událostí GridView RowUpdated
.
Můžeme vytvořit obslužné rutiny událostí pro události před úrovní, abychom mohli přizpůsobit vstupní parametry nebo pro události po úrovni, abychom mohli zkontrolovat výsledky operace a reagovat na ně. Obslužné rutiny událostí po úrovni se nejčastěji používají ke zjištění, jestli během operace došlo k výjimce. V případě výjimky můžou tyto obslužné rutiny událostí po úrovni volitelně zpracovávat výjimku samostatně. V tomto kurzu jsme viděli, jak takovou výjimku zpracovat zobrazením popisné chybové zprávy.
V dalším kurzu se dozvíte, jak zmenšit pravděpodobnost výjimek vyplývajících z problémů s formátováním dat (například zadání záporné UnitPrice
hodnoty ). Konkrétně se podíváme na to, jak přidat ověřovací ovládací prvky do rozhraní pro úpravy a vkládání.
Šťastné programování!
O autorovi
Scott Mitchell, autor sedmi knih o ASP/ASP.NET a zakladatel 4GuysFromRolla.com, pracuje s webovými technologiemi Microsoftu od roku 1998. Scott pracuje jako nezávislý konzultant, školitel a spisovatel. Jeho nejnovější kniha je Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Můžete ho najít na mitchell@4GuysFromRolla.comadrese . nebo prostřednictvím jeho blogu, který najdete na http://ScottOnWriting.NETadrese .
Zvláštní poděkování
Tato série kurzů byla zkontrolována mnoha užitečnými recenzenty. Hlavní kontrolorka tohoto kurzu byla Liz Shulok. Chcete si projít moje nadcházející články na WEBU MSDN? Pokud ano, dejte mi čáru na mitchell@4GuysFromRolla.comadresu .