Zpracování výjimek na úrovni knihoven BLL a DAL (C#)
V tomto kurzu se dozvíte, jak taktně zpracovat výjimky vyvolané během pracovního postupu aktualizace upravitelného seznamu dat.
Úvod
V kurzu Přehled úprav a odstranění dat v části DataList jsme vytvořili soubor DataList, který nabízí jednoduché možnosti úprav a odstranění. I když byl plně funkční, nebyl téměř uživatelsky přívětivý, protože jakákoli chyba, ke které došlo během procesu úprav nebo odstraňování, způsobila neošetřenou výjimku. Pokud například vynecháte název produktu nebo při úpravě produktu zadáte hodnotu ceny Velmi dostupné!, vyvolá se výjimka. Vzhledem k tomu, že tato výjimka není zachycena v kódu, přejde do ASP.NET modulu runtime, který pak na webové stránce zobrazí podrobnosti o výjimce.
Jak jsme viděli v kurzu Zpracování výjimek BLL a DAL-Level v kurzu ASP.NET Page , pokud je výjimka vyvolána z hloubky vrstvy obchodní logiky nebo přístupu k datům, podrobnosti o výjimce se vrátí do ObjectDataSource a pak do objektu GridView. Viděli jsme, jak tyto výjimky řádně zpracovat vytvořením Updated
RowUpdated
obslužných rutin nebo událostí pro objekt ObjectDataSource nebo GridView, kontrolou výjimky a následným označením, že byla výjimka zpracována.
Naše kurzy DataList ale nepoužívají ObjectDataSource k aktualizaci a odstraňování dat. Místo toho pracujeme přímo proti BLL. Abychom mohli detekovat výjimky pocházející z BLL nebo DAL, musíme implementovat kód zpracování výjimek v kódu na pozadí naší ASP.NET stránky. V tomto kurzu se dozvíte, jak taktněji zpracovávat výjimky vyvolané během upravitelného pracovního postupu aktualizace seznamu dat.
Poznámka
V kurzu Přehled úprav a odstranění dat v části DataList jsme probrali různé techniky pro úpravu a odstranění dat z objektu DataList. Některé techniky zahrnovaly použití objectDataSource pro aktualizaci a odstranění. Pokud použijete tyto techniky, můžete zpracovávat výjimky z BLL nebo DAL prostřednictvím ObjectDataSource s Updated
nebo Deleted
obslužných rutin událostí.
Krok 1: Vytvoření upravitelného seznamu dat
Než se začneme zabývat zpracováním výjimek, ke kterým dochází během aktualizace pracovního postupu, pojďme nejprve vytvořit upravitelný seznam DataList. ErrorHandling.aspx
Otevřete stránku ve EditDeleteDataList
složce , přidejte do Designer DataList, nastavte jeho ID
vlastnost na Products
a přidejte nový ObjectDataSource s názvem ProductsDataSource
. Nakonfigurujte ObjectDataSource tak, aby používal metodu ProductsBLL
třídy s GetProducts()
pro výběr záznamů; nastavte rozevírací seznamy na kartách INSERT, UPDATE a DELETE na (None).
Obrázek 1: Vrácení informací o produktu pomocí GetProducts()
metody (kliknutím zobrazíte obrázek v plné velikosti)
Po dokončení průvodce ObjectDataSource visual Studio automaticky vytvoří objekt ItemTemplate
pro dataList. Nahraďte ho kódem ItemTemplate
, který zobrazuje název a cenu každého produktu a obsahuje tlačítko Upravit. Dále vytvořte s webovým ovládacím EditItemTemplate
prvku TextBox pro název a cenu a tlačítka Update a Cancel. Nakonec nastavte vlastnost DataList na RepeatColumns
hodnotu 2.
Po těchto změnách by deklarativní kód stránky měl vypadat nějak takto. Pečlivě zkontrolujte, jestli mají CommandName
tlačítka Upravit, Zrušit a Aktualizovat nastavené vlastnosti na Upravit, Zrušit a Aktualizovat.
<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>
Poznámka
Pro účely tohoto kurzu musí být povolený stav zobrazení DataList.
Podívejte se na průběh v prohlížeči (viz Obrázek 2).
Obrázek 2: Každý produkt obsahuje tlačítko Upravit (kliknutím zobrazíte obrázek v plné velikosti)
Tlačítko Upravit v současné době způsobuje pouze zpětné odeslání, které ještě neumožňuje upravovat produkt. Pokud chcete povolit úpravy, musíme vytvořit obslužné rutiny událostí pro události DataList s EditCommand
, CancelCommand
a UpdateCommand
. Události EditCommand
a CancelCommand
jednoduše aktualizují vlastnost DataList s EditItemIndex
a předají data na 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();
}
Obslužná rutina UpdateCommand
události je trochu více zapojená. Musí přečíst upravené produkty ProductID
z DataKeys
kolekce spolu s názvem produktu a cenou z textových polí v EditItemTemplate
a potom zavolat metodu ProductsBLL
třídy s UpdateProduct
před vrácením DataList do stavu předběžné úpravy.
Prozatím použijeme přesně stejný kód z UpdateCommand
obslužné rutiny události v kurzu Přehled úprav a odstranění dat v části DataList . V kroku 2 přidáme kód pro řádné zpracování výjimek.
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();
}
V případě neplatného vstupu, který může mít podobu nesprávně naformátované jednotkové ceny, neplatné hodnoty jednotkové ceny jako -5,00 Usd nebo vynechání názvu produktu, bude vyvolána výjimka. UpdateCommand
Vzhledem k tomu, že obslužná rutina události v tomto okamžiku neobsahuje žádný kód zpracování výjimek, výjimka se zobrazí až do ASP.NET modulu runtime, kde se zobrazí koncovému uživateli (viz obrázek 3).
Obrázek 3: Když dojde k neošetřené výjimce, koncovému uživateli se zobrazí chybová stránka
Krok 2: Řádné zpracování výjimek v obslužné rutině události UpdateCommand
Během aktualizace pracovního postupu může dojít k výjimkám v obslužné rutině UpdateCommand
události, BLL nebo DAL. Například pokud uživatel zadá cenu Příliš drahé, Decimal.Parse
příkaz v obslužné rutině UpdateCommand
události vyvolá FormatException
výjimku. Pokud uživatel vynechá název produktu nebo pokud cena má zápornou hodnotu, dal vyvolá výjimku.
Když dojde k výjimce, chceme na samotné stránce zobrazit informativní zprávu. Přidejte na stránku ovládací prvek Label Web, který ID
je nastavený na ExceptionDetails
. Nakonfigurujte text Label s tak, aby se zobrazoval červeně, velmi velkým tučným písmem a kurzívou tím, že přiřadíte jeho CssClass
vlastnost třídě Warning
CSS, která je definovaná v Styles.css
souboru.
Když dojde k chybě, chceme, aby se popisek zobrazil jenom jednou. To znamená, že při následných zpětných odesláních by zpráva Upozornění na popisek měla zmizet. Toho lze dosáhnout buď vymazáním vlastnosti Label s Text
, nebo nastavením její Visible
vlastnosti na False
hodnotu v Page_Load
obslužné rutině události (jak jsme to udělali v kurzu Zpracování výjimek BLL a DAL-Level na ASP.NET stránce ) nebo zakázáním podpory stavu zobrazení popisků. Použijeme druhou možnost.
<asp:Label ID="ExceptionDetails" EnableViewState="False" CssClass="Warning"
runat="server" />
Při vyvolání výjimky přiřadíme podrobnosti o výjimce vlastnosti ExceptionDetails
ovládacího prvku Text
Popisek. Vzhledem k tomu, že je jeho stav zobrazení zakázán, při následných postbackech Text
dojde ke ztrátě programových změn vlastností a vrátí se zpět na výchozí text (prázdný řetězec), čímž se zpráva upozornění skryje.
Abychom zjistili, kdy byla vyvolána chyba, aby se na stránce zobrazila užitečná zpráva, musíme do UpdateCommand
obslužné Try ... Catch
rutiny události přidat blok. Část Try
obsahuje kód, který může vést k výjimce, zatímco Catch
blok obsahuje kód, který se provádí tváří v tvář výjimce. Další informace Try ... Catch
o tomto bloku najdete v části Základy zpracování výjimek v dokumentaci k rozhraní .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
}
}
Pokud kód v rámci Try
bloku vyvolá výjimku libovolného typu, Catch
kód bloku se začne spouštět. Typ výjimky, která je vyvolán DbException
, NoNullAllowedException
, ArgumentException
atd., závisí na tom, co přesně na prvním místě vyvolalo chybu. Pokud dojde k problému na úrovni databáze, DbException
vyvolá se . Pokud je pro UnitPrice
pole , , UnitsInStock
UnitsOnOrder
nebo ReorderLevel
zadána neplatná hodnota, ArgumentException
vyvolá se chyba , protože jsme přidali kód pro ověření těchto hodnot polí ve ProductsDataTable
třídě (viz kurz Vytvoření vrstvy obchodní logiky).
Můžeme koncovému uživateli poskytnout užitečnější vysvětlení tím, že text zprávy zadáme na typu zachycené výjimky. Následující kód, který byl použit v téměř identické podobě v kurzu Zpracování výjimek BLL a DAL-Level v ASP.NET Page , poskytuje tuto úroveň podrobností:
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;
}
K dokončení tohoto kurzu jednoduše zavolejte metodu DisplayExceptionDetails
z bloku, který Catch
předává zachycenou Exception
instanci (ex
).
Se zavedeným Try ... Catch
blokem se uživatelům zobrazí informativnější chybová zpráva, jak ukazují obrázky 4 a 5. Všimněte si, že tváří v tvář výjimce zůstává Seznam dat v režimu úprav. Je to proto, že jakmile dojde k výjimce, tok řízení je okamžitě přesměrován na Catch
blok a obejde kód, který vrací dataList do stavu předběžné úpravy.
Obrázek 4: Pokud uživatel vynechá povinné pole, zobrazí se chybová zpráva (kliknutím zobrazíte obrázek v plné velikosti).
Obrázek 5: Při zadání záporné ceny se zobrazí chybová zpráva (kliknutím zobrazíte obrázek v plné velikosti)
Souhrn
GridView a ObjectDataSource poskytují obslužné rutiny událostí po úrovni, které obsahují informace o všech výjimkách, které byly vyvolány během aktualizace a odstraňování pracovního postupu, stejně jako vlastnosti, které lze nastavit tak, aby indikovaly, zda byla výjimka zpracována. Tyto funkce však nejsou k dispozici při práci se seznamem DataList a při přímém použití BLL. Místo toho zodpovídáme za implementaci zpracování výjimek.
V tomto kurzu jsme viděli, jak přidat zpracování výjimek do upravitelného pracovního postupu aktualizace DataList přidáním Try ... Catch
bloku do obslužné UpdateCommand
rutiny události. Pokud je během aktualizace pracovního postupu vyvolána výjimka, Catch
spustí se kód bloku s a zobrazí se užitečné informace v popisku ExceptionDetails
.
V tomto okamžiku datový seznam nevydělá žádné úsilí, aby zabránil výjimkám na prvním místě. I když víme, že záporná cena bude mít za následek výjimku, zatím jsme nepřidali žádnou funkci, která by proaktivně zabránila uživateli v zadání takového neplatného vstupu. V dalším kurzu se dozvíte, jak omezit výjimky způsobené neplatným uživatelským vstupem přidáním ověřovacích ovládacích prvků do EditItemTemplate
.
Všechno nejlepší na programování!
Další čtení
Další informace o tématech probíraných v tomto kurzu najdete v následujících zdrojích informací:
- Pokyny k návrhu pro výjimky
- Moduly a obslužné rutiny protokolování chyb (ELMAH) (opensourcová knihovna pro protokolování chyb)
- Enterprise Library for .NET Framework 2.0 (zahrnuje blok aplikací správy výjimek)
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 zastihnout na mitchell@4GuysFromRolla.comadrese . nebo prostřednictvím jeho blogu, který najdete na adrese http://ScottOnWriting.NET.
Zvláštní poděkování
Tato série kurzů byla zkontrolována mnoha užitečnými recenzenty. Hlavním revidujícím pro tento kurz byl Ken Pespisa. Chtěli byste si projít své nadcházející články na webu MSDN? Pokud ano, dejte mi řádek na mitchell@4GuysFromRolla.com.