Dela via


Hantering av BLL- och DAL-Level-undantag (VB)

av Scott Mitchell

Ladda ned PDF

I den här självstudien får vi se hur du taktfullt hanterar undantag som genererats under en redigerbar datalistas uppdateringsarbetsflöde.

Inledning

I självstudiekursen Översikt över redigering och borttagning av data i DataList skapade vi en datalista som erbjöd enkel redigering och borttagning. Även om det var fullt funktionellt var det knappast användarvänligt, eftersom eventuella fel som uppstod under redigerings- eller borttagningsprocessen resulterade i ett ohanterat undantag. Om du till exempel utelämnar produktens namn eller, när du redigerar en produkt, anger ett prisvärde på Mycket överkomligt!, utlöser ett undantag. Eftersom det här undantaget inte fångas i kod bubblar det upp till ASP.NET-körningen, som sedan visar undantagets information på webbsidan.

Som vi såg i självstudiekursen Hantera BLL- och DAL-Level undantag i en ASP.NET-sida , returneras undantagsinformationen till ObjectDataSource och sedan till GridView om ett undantag hämtas från djupet i affärslogik- eller dataåtkomstskikten. Vi såg hur du korrekt hanterar dessa undantag genom att skapa Updated eller RowUpdated händelsehanterare för ObjectDataSource eller GridView, söka efter ett undantag och sedan ange att undantaget hanterades.

Våra datalist-självstudier använder dock inte ObjectDataSource för att uppdatera och ta bort data. I stället arbetar vi direkt mot BLL:n. För att kunna identifiera undantag från BLL eller DAL måste vi implementera kod för undantagshantering i koden bakom vår ASP.NET-sida. I den här självstudien får vi se hur du mer taktfullt hanterar undantag som genereras under en redigerbar DataList-uppdatering av arbetsflödet.

Anmärkning

I självstudiekursen En översikt över redigering och borttagning av data i DataList diskuterade vi olika tekniker för att redigera och ta bort data från DataList, några tekniker som används med hjälp av en ObjectDataSource för uppdatering och borttagning. Om du använder dessa tekniker kan du hantera undantag från BLL eller DAL via ObjectDataSources Updated eller Deleted händelsehanterare.

Steg 1: Skapa en redigerbar datalista

Innan vi oroar oss för att hantera undantag som inträffar under uppdateringsarbetsflödet ska vi först skapa en redigerbar datalista. Öppna sidan ErrorHandling.aspx i EditDeleteDataList mappen, lägg till en DataList i designern, ange dess ID egenskap till Productsoch lägg till en ny ObjectDataSource med namnet ProductsDataSource. Konfigurera ObjectDataSource att använda ProductsBLL klassens GetProducts() metod för att välja poster. Ange listrutorna på flikarna INSERT, UPDATE och DELETE till (Ingen).

Returnera produktinformationen med metoden GetProducts()

Bild 1: Returnera produktinformationen GetProducts() med hjälp av metoden (Klicka om du vill visa en bild i full storlek)

När du har slutfört guiden ObjectDataSource skapar Visual Studio automatiskt en ItemTemplate för DataList. Ersätt detta med ett ItemTemplate som visar varje produkts namn och pris och innehåller en redigera-knapp. Skapa sedan en EditItemTemplate med en TextBox-webbkontroll för namn och pris samt knapparna Uppdatera och Avbryt. Slutligen anger du egenskapen DataList s RepeatColumns till 2.

Efter dessa ändringar bör sidans deklarativa markering se ut ungefär så här. Dubbelkolla för att se till att knapparna Redigera, Avbryt och Uppdatera har sina CommandName egenskaper inställda på Redigera, Avbryt respektive Uppdatera.

<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>

Anmärkning

För den här handledningen måste DataLists visningstillstånd vara aktiverat.

Ta en stund att visa våra framsteg via en webbläsare (se bild 2).

Varje produkt innehåller en redigeringsknapp

Bild 2: Varje produkt innehåller en redigeringsknapp (klicka om du vill visa en bild i full storlek)

För närvarande orsakar knappen Redigera bara en begäran men gör ännu inte produkten redigeringsbar. För att aktivera redigering måste vi skapa händelsehanterare för datalistans EditCommand, CancelCommandoch UpdateCommand händelser. Händelserna EditCommand och CancelCommand uppdaterar helt enkelt datalistans EditItemIndex egenskap och binder om data till DataList:

Protected Sub Products_EditCommand(source As Object, e As DataListCommandEventArgs) _
    Handles Products.EditCommand
    ' 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()
End Sub
Protected Sub Products_CancelCommand(source As Object, e As DataListCommandEventArgs) _
    Handles Products.CancelCommand
    ' Set the DataList's EditItemIndex property to -1
    Products.EditItemIndex = -1
    ' Rebind the data to the DataList
    Products.DataBind()
End Sub

Händelsehanteraren UpdateCommand är lite mer involverad. Den måste läsa in de redigerade produkterna ProductID från DataKeys-samlingen tillsammans med produktens namn och pris från textrutorna i EditItemTemplate, och sedan anropa klassens metod ProductsBLL i UpdateProduct innan datalistan återgår till dess förredigeringstillstånd.

Låt oss använda exakt samma kod från UpdateCommand händelsehanteraren i handledning Översikt över redigering och borttagning av data i DataList. Vi lägger till koden för att korrekt hantera undantag i steg 2.

Protected Sub Products_UpdateCommand(source As Object, e As DataListCommandEventArgs) _
    Handles Products.UpdateCommand
    ' Read in the ProductID from the DataKeys collection
    Dim productID As Integer = Convert.ToInt32(Products.DataKeys(e.Item.ItemIndex))
    ' Read in the product name and price values
    Dim productName As TextBox = CType(e.Item.FindControl("ProductName"), TextBox)
    Dim unitPrice As TextBox = CType(e.Item.FindControl("UnitPrice"), TextBox)
    Dim productNameValue As String = Nothing
    If productName.Text.Trim().Length > 0 Then
        productNameValue = productName.Text.Trim()
    End If
    Dim unitPriceValue As Nullable(Of Decimal) = Nothing
    If unitPrice.Text.Trim().Length > 0 Then
        unitPriceValue = Decimal.Parse(unitPrice.Text.Trim(), _
                         System.Globalization.NumberStyles.Currency)
    End If
    ' Call the ProductsBLL's UpdateProduct method...
    Dim productsAPI As New ProductsBLL()
    productsAPI.UpdateProduct(productNameValue, unitPriceValue, productID)
    ' Revert the DataList back to its pre-editing state
    Products.EditItemIndex = -1
    Products.DataBind()
End Sub

Mot bakgrund av ogiltiga indata som kan vara i form av ett felaktigt formaterat enhetspris, ett olagligt enhetsprisvärde som -$5.00 eller utelämnandet av produktens namn kommer ett undantag att höjas. UpdateCommand Eftersom händelsehanteraren inte innehåller någon kod för undantagshantering just nu bubblar undantaget upp till ASP.NET körning, där det visas för slutanvändaren (se bild 3).

När ett ohanterat undantag inträffar ser slutanvändaren en felsida

Bild 3: När ett ohanterat undantag inträffar ser slutanvändaren en felsida

Steg 2: Hantera undantag på ett korrekt sätt i UpdateCommand-händelsehanteraren

Under arbetsflödet för uppdatering kan undantag inträffa i UpdateCommand händelsehanteraren, BLL eller DAL. Om en användare till exempel anger priset För dyrt utlöser instruktionen Decimal.ParseUpdateCommand i händelsehanteraren ett FormatException undantag. Om användaren utelämnar produktens namn eller om priset har ett negativt värde, genererar DAL ett undantag.

När ett undantag inträffar vill vi visa ett informativt meddelande på själva sidan. Lägg till en etikettwebbkontroll på sidan vars ID är inställd på ExceptionDetails. Konfigurera etikettens text så att den CssClass visas i ett rött, extra stort, fetstilt och kursivt teckensnitt genom att tilldela dess Warning egenskap till CSS-klassen, som definieras i Styles.css filen.

När ett fel inträffar vill vi bara att etiketten ska visas en gång. Det vill säga, vid efterföljande återanrop, bör varningsmeddelandet från Label försvinna. Detta kan åstadkommas genom att antingen tömma ut egenskapen Text eller ställa in dess egenskap till Visible i händelsehanteraren False (som vi gjorde i Page_Load) eller genom att inaktivera stödet för etikettens vytilstånd. Låt oss använda det senare alternativet.

<asp:Label ID="ExceptionDetails" EnableViewState="False" CssClass="Warning"
    runat="server" />

När ett undantag utlöses kommer vi att tilldela informationen om undantaget till Etikettkontrollens egenskap ExceptionDetailsText. Eftersom dess visningstillstånd är inaktiverat går egenskapens programmässiga ändringar förlorade vid efterföljande postbacks Text och återgår till standardtexten (en tom sträng) och döljer därmed varningsmeddelandet.

För att avgöra när ett fel har uppstått för att visa ett användbart meddelande på sidan måste vi lägga till ett Try ... Catch block i UpdateCommand händelsehanteraren. Delen Try innehåller kod som kan leda till ett undantag, medan Catch blocket innehåller kod som körs inför ett undantag. Mer information om blocket finns i avsnittet Grunderna för undantagshantering i .NET Framework-dokumentationen Try ... Catch .

Protected Sub Products_UpdateCommand(source As Object, e As DataListCommandEventArgs) _
    Handles Products.UpdateCommand
    ' Handle any exceptions raised during the editing process
    Try
        ' Read in the ProductID from the DataKeys collection
        Dim productID As Integer = _
            Convert.ToInt32(Products.DataKeys(e.Item.ItemIndex))
        ... Some code omitted for brevity ...
    Catch ex As Exception
        ' TODO: Display information about the exception in ExceptionDetails
    End Try
End Sub

När ett undantag av någon typ genereras av kod i Try-blocket, börjar koden i Catch-blocket att köras. Vilken typ av undantag som genereras DbException, NoNullAllowedException, ArgumentExceptionoch så vidare beror på exakt vad som utlöste felet från början. Om det uppstår ett problem på databasnivå genereras ett DbException . Om ett ogiltigt värde anges för fälten UnitPrice, UnitsInStock, UnitsOnOrder, eller ReorderLevel genereras ett ArgumentException, eftersom vi lade till kod för att validera dessa fältvärden i ProductsDataTable-klassen (se handledningen Skapa ett affärslogiklager).

Vi kan ge slutanvändaren en mer användbar förklaring genom att basera meddelandetexten på vilken typ av undantag som fångas. Följande kod som användes i nästan identisk form i självstudien Hantera BLL- och DAL-Level-undantag i en ASP.NET-sida innehåller den här detaljnivån:

Private Sub DisplayExceptionDetails(ByVal ex As Exception)
    ' Display a user-friendly message
    ExceptionDetails.Text = "There was a problem updating the product. "
    If TypeOf ex Is System.Data.Common.DbException Then
        ExceptionDetails.Text += "Our database is currently experiencing problems." + _
                                 "Please try again later."
    ElseIf TypeOf ex Is System.Data.NoNullAllowedException Then
        ExceptionDetails.Text+="There are one or more required fields that are missing."
    ElseIf TypeOf ex Is ArgumentException Then
        Dim paramName As String = CType(ex, ArgumentException).ParamName
        ExceptionDetails.Text+=String.Concat("The ", paramName, " value is illegal.")
    ElseIf TypeOf ex Is ApplicationException Then
        ExceptionDetails.Text += ex.Message
    End If
End Sub

För att slutföra den här självstudien behöver du helt enkelt anropa DisplayExceptionDetails-metoden från Catch-blocket och skicka in den fångade Exception-instansen (ex).

Try ... Catch När blocket är på plats får användarna ett mer informativt felmeddelande, som figur 4 och 5 visar. Observera att datalistan förblir i redigeringsläge även vid ett undantag. Detta beror på att när undantaget inträffar omdirigeras kontrollflödet omedelbart till Catch blocket och kringgår koden som returnerar DataList till dess förredigeringstillstånd.

Ett felmeddelande visas om en användare utelämnar ett obligatoriskt fält

Bild 4: Ett felmeddelande visas om en användare utelämnar ett obligatoriskt fält (Klicka om du vill visa en bild i full storlek)

Ett felmeddelande visas när du anger ett negativt pris

Bild 5: Ett felmeddelande visas när du anger ett negativt pris (klicka om du vill visa en bild i full storlek)

Sammanfattning

GridView och ObjectDataSource tillhandahåller händelsehanterare på efternivå som innehåller information om eventuella undantag som uppstod under uppdaterings- och borttagningsarbetsflödet, samt egenskaper som kan anges för att ange om undantaget har hanterats eller inte. Dessa funktioner är dock inte tillgängliga när du arbetar med DataList och använder BLL direkt. I stället ansvarar vi för att implementera undantagshantering.

I den här självstudien såg vi hur du lägger till undantagshantering i ett redigerbart DataList-uppdateringsarbetsflöde genom att lägga till ett Try ... Catch block i UpdateCommand händelsehanteraren. Om ett undantag utlöses under uppdateringsarbetsflödet Catch körs blockkoden och visar användbar information i etiketten ExceptionDetails .

I det här läget gör DataList inget för att förhindra att undantag sker från första början. Även om vi vet att ett negativt pris kommer att resultera i ett undantag har vi ännu inte lagt till några funktioner för att proaktivt förhindra att en användare anger sådana ogiltiga indata. I nästa självstudie får vi se hur du kan minska de undantag som orsakas av ogiltiga användarindata genom att lägga till verifieringskontroller i EditItemTemplate.

Lycka till med programmerandet!

Ytterligare läsning

Mer information om de ämnen som beskrivs i den här självstudien finns i följande resurser:

Om författaren

Scott Mitchell, författare till sju ASP/ASP.NET-böcker och grundare av 4GuysFromRolla.com, har arbetat med Microsofts webbtekniker sedan 1998. Scott arbetar som oberoende konsult, tränare och författare. Hans senaste bok är Sams Teach Yourself ASP.NET 2.0 på 24 timmar. Han kan nås på mitchell@4GuysFromRolla.com.

Särskilt tack till

Den här självstudieserien granskades av många användbara granskare. Ansvarig granskare för den här handledningen var Ken Pespisa. Vill du granska mina kommande MSDN-artiklar? Om så är fallet, hör av dig på mitchell@4GuysFromRolla.com.