Zpracování výjimek na úrovni knihoven BLL a DAL na stránce ASP.NET (VB)
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 webové aplikace ASP.NET pomocí vrstvené aplikační architektury 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.
- Vyvolá 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í jakékoli 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. GridView například aktivuje svou RowUpdating
událost před přiřazením hodnot polí do kolekce 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 se dají 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 tak, že na obrazovce zobrazíme 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, která obsahuje seznam 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 s pouhými 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. V tomto kurzu si tuto techniku znovu procvičme a vytvoříme upravitelné zobrazení GridView, které zobrazuje název produktu, množství na jednotku, jednotkovou cenu a jednotky na skladě, ale umožňuje úpravu pouze názvu, jednotkové ceny a jednotek na skladě.
K tomuto scénáři budeme potřebovat další přetížení UpdateProduct
metody, které přijímá čtyři parametry: název produktu, jednotkovou cenu, skladové jednotky a ID. Do třídy ProductsBLL
přidejte následující metodu:
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Update, True)> _
Public Function UpdateProduct _
(ByVal productName As String, ByVal unitPrice As Nullable(Of Decimal), _
ByVal unitsInStock As Nullable(Of Short), ByVal productID As Integer) As Boolean
Dim products As Northwind.ProductsDataTable = _
Adapter.GetProductByProductID(productID)
If products.Count = 0 Then
Return False
End If
Dim product As Northwind.ProductsRow = products(0)
product.ProductName = productName
If Not unitPrice.HasValue Then
product.SetUnitPriceNull()
Else
product.UnitPrice = unitPrice.Value
End If
If Not unitsInStock.HasValue Then
product.SetUnitsInStockNull()
Else
product.UnitsInStock = unitsInStock.Value
End If
Dim rowsAffected As Integer = Adapter.Update(product)
Return rowsAffected = 1
End Function
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 na stránku objekt GridView prostřednictvím Designer. Vytvořte vazbu objektu GridView na nový ObjectDataSource, mapování Select()
metody 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í značka ObjectDataSource přiřadí OldValuesParameterFormatString
vlastnost hodnotu original_{0}
, což způsobí výjimku, protože naše třídy BLL neočekávají 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. Pojďme to samé udělat tady. Vzpomeňte si, že to 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 zobrazovala jako měna (kliknutím zobrazíte obrázek v plné velikosti)
Formátování objektu UnitPrice
jako měny v rozhraní pro úpravy vyžaduje vytvoření obslužné rutiny události pro událost GridView 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 však uživateli umožníme vynechat cenu.
Protected Sub GridView1_RowUpdating(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.GridViewUpdateEventArgs) _
Handles GridView1.RowUpdating
If e.NewValues("UnitPrice") IsNot Nothing Then
e.NewValues("UnitPrice") = _
Decimal.Parse(e.NewValues("UnitPrice").ToString(), _
System.Globalization.NumberStyles.Currency)
End If
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: Vytvoření 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, ale potřebná 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 polí , , a všech produktůProductName
. Upravit je ale možné pouze ProductName
pole , UnitPrice
a UnitsInStock
.UnitsInStock
UnitPrice
QuantityPerUnit
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í výjimek DAL-Level
Zatímco náš upravitelný GridView funguje skvěle, když uživatelé zadávají právní hodnoty pro název, cenu a jednotky upraveného produktu na skladě, zadáním neplatných hodnot dojde k výjimce. Například vynechání ProductName
hodnoty způsobí vyvolání NoNullAllowedException , protože ProductName
vlastnost ve ProductsRow
třídě má svou AllowDBNull
vlastnost nastavenou na false
; pokud je databáze mimo provoz, SqlException
bude objekt TableAdapter vyvolán 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 modulu runtime ASP.NET.
V závislosti na tom, jak je vaše webová aplikace nakonfigurovaná a jestli ji navštěvujete z localhost
aplikace , může neošetřená výjimka vést buď k obecné chybové stránce serveru, k 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ématu Zpracování chyb webové aplikace v ASP.NET a elementu customErrors .
Obrázek 6 znázorňuje obrazovku 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, prezentování takové obrazovky koncovému uživateli tváří v tvář výjimce není ideální. Koncový uživatel pravděpodobně neví, co NoNullAllowedException
je nebo proč k němu došlo. Lepším přístupem je prezentovat 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 modulu runtime ASP.NET. V našem příkladu vytvoříme obslužnou rutinu události pro událost 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 na tuto zprávu nakreslit oko uživatele, 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ý pouze okamžitě po vytvoření výjimky, nastavte jeho Visible
vlastnost v obslužné rutině Page_Load
události na hodnotu false:
Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
ExceptionDetails.Visible = False
End Sub
S tímto kódem bude mít ovládací prvek na první stránce ExceptionDetails
nastavenou false
vlastnost Visible
na . Tváří v tvář výjimce 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 obslužné rutiny událostí webového Page_Load
ovládacího prvku se vyskytují po obslužné rutině události v životním cyklu stránky, zobrazí se popisek. Při dalším postbacku však obslužná rutina Page_Load
události vrátí Visible
vlastnost zpět na false
a znovu ji skryje ze zobrazení.
Poznámka
Případně 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 GridView, přejděte na okno Vlastnosti a klikněte na ikonu blesku se seznamem událostí GridView. Již by tam měla být položka pro událost GridView RowUpdating
, protože jsme vytvořili obslužnou rutinu události pro tuto událost dříve v tomto kurzu. Vytvořte obslužnou rutinu události také pro událost RowUpdated
.
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
v pravé části vyberte událost GridView.
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 Sub GridView1_RowUpdated(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.GridViewUpdatedEventArgs) _
Handles GridView1.RowUpdated
End Sub
Druhý vstupní parametr 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řekryje až do modulu runtime ASP.NETKeepInEditMode
pokud je nastavený natrue
upravený řádek GridView, zůstane v režimu úprav. Pokudfalse
(výchozí), vrátí se řádek GridView zpě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 Sub GridView1_RowUpdated(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.GridViewUpdatedEventArgs) _
Handles GridView1.RowUpdated
If e.Exception IsNot Nothing Then
ExceptionDetails.Visible = True
ExceptionDetails.Text = "There was a problem updating the product. "
If e.Exception.InnerException IsNot Nothing Then
Dim inner As Exception = e.Exception.InnerException
If TypeOf inner Is System.Data.Common.DbException Then
ExceptionDetails.Text &= _
"Our database is currently experiencing problems." & _
"Please try again later."
ElseIf TypeOf inner _
Is System.Data.NoNullAllowedException Then
ExceptionDetails.Text += _
"There are one or more required fields that are missing."
ElseIf TypeOf inner Is ArgumentException Then
Dim paramName As String = CType(inner, ArgumentException).ParamName
ExceptionDetails.Text &= _
String.Concat("The ", paramName, " value is illegal.")
ElseIf TypeOf inner Is ApplicationException Then
ExceptionDetails.Text += inner.Message
End If
End If
e.ExceptionHandled = True
e.KeepInEditMode = True
End If
End Sub
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:
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Update, True)> _
Public Function UpdateProduct(ByVal productName As String, _
ByVal unitPrice As Nullable(Of Decimal), ByVal unitsInStock As Nullable(Of Short), _
ByVal productID As Integer) As Boolean
Dim products As Northwind.ProductsDataTable = Adapter.GetProductByProductID(productID)
If products.Count = 0 Then
Return False
End If
Dim product As Northwind.ProductsRow = products(0)
If unitPrice.HasValue AndAlso Not product.IsUnitPriceNull() Then
If unitPrice > product.UnitPrice * 2 Then
Throw New ApplicationException( _
"When updating a product price," & _
" the new price cannot exceed twice the original price.")
End If
End If
product.ProductName = productName
If Not unitPrice.HasValue Then
product.SetUnitPriceNull()
Else
product.UnitPrice = unitPrice.Value
End If
If Not unitsInStock.HasValue Then
product.SetUnitsInStockNull()
Else
product.UnitsInStock = unitsInStock.Value
End If
Dim rowsAffected As Integer = Adapter.Update(product)
Return rowsAffected = 1
End Function
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 .