Udostępnij za pomocą


Obsługa wyjątków na poziomie warstwy logiki biznesowej i warstwy dostępu do danych (C#)

Autor : Scott Mitchell

Pobierz plik PDF

W tym samouczku zobaczymy, jak tactfully obsługiwać wyjątki zgłaszane podczas edytowalnego przepływu pracy aktualizacji elementu DataList.

Wprowadzenie

W samouczku Omówienie edytowania i usuwania danych w usłudze DataList utworzyliśmy element DataList, który oferował proste funkcje edytowania i usuwania. Chociaż w pełni funkcjonalny, nie był przyjazny dla użytkownika, ponieważ wszelkie błędy, które wystąpiły podczas procesu edytowania lub usuwania, spowodowały nieobsługiwany wyjątek. Na przykład pominięcie nazwy produktu lub, podczas edytowania produktu, wprowadzenie wartości ceny bardzo przystępnej!, zgłasza wyjątek. Ponieważ ten wyjątek nie jest przechwytywane w kodzie, bąbelki do środowiska uruchomieniowego ASP.NET, które następnie wyświetla szczegóły wyjątku na stronie internetowej.

Jak pokazano w artykule Obsługa wyjątków BLL i DAL-Level w samouczku dotyczącym strony ASP.NET , jeśli zostanie zgłoszony wyjątek z głębi warstwy logiki biznesowej lub dostępu do danych, szczegóły wyjątku zostaną zwrócone do obiektu ObjectDataSource, a następnie do kontrolki GridView. Zobaczyliśmy, jak bezpiecznie obsługiwać te wyjątki, tworząc Updated programy obsługi zdarzeń dla RowUpdated obiektu ObjectDataSource lub GridView, sprawdzając wyjątek, a następnie wskazując, że wyjątek został obsłużony.

Nasze samouczki DataList nie używają jednak obiektu ObjectDataSource do aktualizowania i usuwania danych. Zamiast tego pracujemy bezpośrednio przeciwko BLL. Aby wykryć wyjątki pochodzące z biblioteki BLL lub DAL, musimy zaimplementować kod obsługi wyjątków w kodzie naszej strony ASP.NET. W tym samouczku zobaczymy, jak bardziej taktownie obsługiwać wyjątki zgłaszane podczas edytowalnego przepływu pracy aktualizacji listy DataList.

Uwaga / Notatka

W samouczku Omówienie edytowania i usuwania danych w usłudze DataList omówiliśmy różne techniki edytowania i usuwania danych z listy DataList, niektóre techniki związane z używaniem obiektu ObjectDataSource do aktualizowania i usuwania. Jeśli zastosujesz te techniki, możesz obsługiwać wyjątki z biblioteki BLL lub DAL za pośrednictwem obiektów ObjectDataSource Updated lub Deleted programów obsługi zdarzeń.

Krok 1. Tworzenie edytowalnej listy danych

Zanim martwimy się o obsługę wyjątków występujących podczas aktualizowania przepływu pracy, najpierw utwórzmy edytowalną listę danych. Otwórz stronę ErrorHandling.aspx w folderze EditDeleteDataList, dodaj element DataList do projektanta, ustaw jego właściwość ID na Products, a dodaj nowy obiekt ObjectDataSource o nazwie ProductsDataSource. Skonfiguruj obiekt ObjectDataSource do używania ProductsBLL metody klasy s GetProducts() do wybierania rekordów; ustaw listy rozwijane na kartach INSERT, UPDATE i DELETE na wartość (Brak).

Zwracanie informacji o produkcie przy użyciu metody GetProducts()

Rysunek 1. Zwracanie informacji o produkcie GetProducts() przy użyciu metody (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Po ukończeniu pracy kreatora ObjectDataSource program Visual Studio automatycznie utworzy obiekt ItemTemplate dla elementu DataList. Zastąp element wartością ItemTemplate , która wyświetla nazwę i cenę każdego produktu oraz zawiera przycisk Edytuj. Następnie utwórz element EditItemTemplate z kontrolką internetową TextBox dla nazw i cen oraz przycisków Aktualizuj i Anuluj. Na koniec ustaw właściwość DataList RepeatColumns na 2.

Po tych zmianach deklaratywny znacznik strony powinien wyglądać podobnie do poniższego. Sprawdź dwukrotnie, aby upewnić się, że przyciski Edytuj, Anuluj i Aktualizuj mają właściwości CommandName ustawione odpowiednio na Edytuj, Anuluj i Aktualizuj.

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

Uwaga / Notatka

Na potrzeby tego samouczka należy włączyć stan widoku DataList.

Poświęć chwilę, aby wyświetlić nasz postęp w przeglądarce (zobacz Rysunek 2).

Każdy produkt zawiera przycisk Edycji

Rysunek 2. Każdy produkt zawiera przycisk edycji (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Obecnie przycisk Edytuj powoduje tylko odświeżenie strony, ale nie pozwala jeszcze na edycję produktu. Aby włączyć edycję, musimy utworzyć programy obsługi zdarzeń dla zdarzeń DataList s EditCommand, CancelCommandi UpdateCommand . Zdarzenia EditCommand i CancelCommand po prostu aktualizują właściwość EditItemIndex elementu DataList i ponownie wiążą dane z 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();
}

Procedura UpdateCommand obsługi zdarzeń jest nieco bardziej złożona. Należy odczytać zmienione produkty ProductID z kolekcji DataKeys wraz z nazwą i ceną produktu z pól TextBoxes w EditItemTemplate, a następnie wywołać metodę klasy ProductsBLLUpdateProduct przed zwróceniem elementu DataList do stanu przed edycją.

Na razie użyjemy dokładnie tego samego kodu z UpdateCommand procedury obsługi zdarzeń w samouczku Omówienie edytowania i usuwania danych w DataList. Dodamy kod, aby bezpiecznie obsługiwać wyjątki w kroku 2.

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();
}

W przypadku nieprawidłowych danych wejściowych, które mogą mieć formę poprawnie niesformatowanej ceny jednostkowej, nielegalnej wartości ceny jednostkowej, na przykład -5,00 PLN, lub pominięcia nazwy produktu, zostanie zgłoszony wyjątek. Ponieważ obsługa zdarzeń UpdateCommand nie zawiera w tym momencie żadnego kodu obsługi wystąpienia, wyjątek będzie przekazywany do środowiska uruchomieniowego ASP.NET, gdzie zostanie wyświetlony użytkownikowi końcowemu (zobacz Rysunek 3).

Gdy wystąpi nieobsługiwany wyjątek, użytkownik końcowy zobaczy stronę błędu

Rysunek 3. Gdy wystąpi nieobsługiwany wyjątek, użytkownik końcowy zobaczy stronę błędu

Krok 2. Bezproblemowa obsługa wyjątków w procedurze obsługi zdarzeń UpdateCommand

Podczas aktualizacji przepływu pracy wyjątki mogą wystąpić w UpdateCommand obsłudze zdarzeń, BLL lub DAL. Jeśli na przykład użytkownik wprowadzi zbyt kosztowną cenę, instrukcja Decimal.Parse w procedurze obsługi zdarzeń UpdateCommand zgłosi wyjątek FormatException. Jeśli użytkownik pominie nazwę produktu lub jeśli cena ma wartość ujemną, DAL zgłosi wyjątek.

Gdy wystąpi wyjątek, chcemy wyświetlić komunikat informacyjny w obrębie samej strony. Dodaj kontrolkę Etykieta sieci Web do strony, której ID ustawiono wartość ExceptionDetails. Skonfiguruj tekst Etykiety tak, aby był wyświetlany w kolorze czerwonym, bardzo dużą, pogrubioną i kursywą czcionką, przypisując jego właściwość CssClass klasie CSS Warning, która jest zdefiniowana w pliku Styles.css.

Gdy wystąpi błąd, chcemy, aby etykieta będzie wyświetlana tylko raz. Oznacza to, że po kolejnych powrotach komunikat ostrzegawczy Etykieta powinien zniknąć. Można to osiągnąć, wyczyszczając właściwość Text etykiety lub ustawiając jej właściwość Visible na False w obsłudze zdarzeń Page_Load (tak jak zrobiliśmy to w samouczku Obsługa wyjątków BLL i DAL-Level na stronie ASP.NET), lub wyłączając obsługę stanu widoku etykiety. Użyjmy tej drugiej opcji.

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

Po wystąpieniu wyjątku przypiszemy szczegóły wyjątku do właściwości kontrolki ExceptionDetails Label Text. Ponieważ jego stan widoku jest wyłączony, podczas kolejnych zwrotnych przetworzeń Text, programowe zmiany właściwości zostaną utracone, przywracając domyślny tekst (pusty ciąg znaków), co skutkuje ukryciem komunikatu ostrzegawczego.

Aby ustalić moment wystąpienia błędu i wyświetlić pomocny komunikat na stronie, musimy dodać blok Try ... Catch do programu obsługi zdarzeń UpdateCommand. Część Try zawiera kod, który może prowadzić do wyjątku, podczas gdy Catch blok zawiera kod wykonywany w obliczu wyjątku. Zapoznaj się z sekcją Podstawy obsługi wyjątków w dokumentacji programu .NET Framework, aby uzyskać więcej informacji na temat bloku Try ... Catch.

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

Gdy kod w bloku Try zgłasza wyjątek dowolnego typu, kod w bloku Catch zostanie rozpoczęty. Typ wyjątku, który jest rzucany DbException, NoNullAllowedException, ArgumentException, i tak dalej, zależy od tego, co dokładnie spowodowało błąd w pierwszej kolejności. Jeśli wystąpi problem na poziomie bazy danych, zostanie zgłoszony błąd DbException . Jeśli dla pól UnitPrice, UnitsInStock, UnitsOnOrder lub ReorderLevel zostanie wprowadzona niedozwolona wartość, zostanie zgłoszony ArgumentException, ponieważ dodaliśmy kod, aby sprawdzić te wartości pól w klasie ProductsDataTable (zobacz samouczek Tworzenie warstwy logiki biznesowej).

Możemy podać bardziej przydatne wyjaśnienie dla użytkownika końcowego, opierając tekst komunikatu na typie przechwyconego wyjątku. Poniższy kod, który został użyty w niemal identycznej formie w samouczku Obsługa wyjątków BLL i DAL-Level na stronie ASP.NET, zawiera ten poziom szczegółów.

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

Aby ukończyć ten samouczek, po prostu wywołaj metodę DisplayExceptionDetails z Catch bloku przekazującego wystąpienie przechwycone Exception (ex).

Po utworzeniu Try ... Catch bloku użytkownicy otrzymują bardziej informacyjny komunikat o błędzie, jak pokazano na rysunkach 4 i 5. Należy pamiętać, że w obliczu wyjątku lista Danych Pozostaje w trybie edycji. Jest to spowodowane tym, że po wystąpieniu wyjątku przepływ sterowania jest natychmiast przekierowywany do bloku Catch, pomijając kod, który zwraca DataList do stanu sprzed edycji.

Komunikat o błędzie jest wyświetlany, jeśli użytkownik pomija wymagane pole

Rysunek 4. Komunikat o błędzie jest wyświetlany, jeśli użytkownik pomija wymagane pole (kliknij, aby wyświetlić obraz pełnowymiarowy)

Komunikat o błędzie jest wyświetlany podczas wprowadzania ceny ujemnej

Rysunek 5. Podczas wprowadzania ceny ujemnej jest wyświetlany komunikat o błędzie (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Podsumowanie

Kontrolki GridView i ObjectDataSource udostępniają programy obsługi zdarzeń po poziomie, które zawierają informacje o wszelkich wyjątkach zgłoszonych podczas aktualizowania i usuwania przepływu pracy, a także właściwości, które można ustawić, aby wskazać, czy wyjątek został obsłużony. Te funkcje są jednak niedostępne podczas pracy z DataList i bezpośrednio korzystając z BLL. Zamiast tego jesteśmy odpowiedzialni za implementację obsługi wyjątków.

W tym samouczku pokazano, jak dodać obsługę wyjątków do przepływu pracy aktualizacji edytowalnego elementu DataList przez dodanie bloku Try ... Catch do obsługi zdarzeń UpdateCommand. Jeśli podczas aktualizowania przepływu pracy zostanie zgłoszony wyjątek, kod bloku Catch wykonuje się, wyświetlając przydatne informacje na etykiecie ExceptionDetails.

Na tym etapie DataList nie podejmuje żadnych działań, aby zapobiec występowaniu wyjątków od początku. Mimo że wiemy, że ujemna cena spowoduje wyjątek, nie dodaliśmy jeszcze żadnych funkcji, aby aktywnie uniemożliwić użytkownikowi wprowadzanie takich nieprawidłowych danych wejściowych. W następnym samouczku zobaczymy, jak zmniejszyć liczbę wyjątków spowodowanych nieprawidłowymi danymi wejściowymi użytkownika przez dodanie kontrolek weryfikacji w pliku EditItemTemplate.

Szczęśliwe programowanie!

Dalsza lektura

Aby uzyskać więcej informacji na temat tematów omówionych w tym samouczku, zapoznaj się z następującymi zasobami:

Informacje o autorze

Scott Mitchell, autor siedmiu książek ASP/ASP.NET i założyciel 4GuysFromRolla.com, współpracuje z technologiami internetowymi firmy Microsoft od 1998 roku. Scott pracuje jako niezależny konsultant, trener i pisarz. Jego najnowsza książka to Sams Teach Yourself ASP.NET 2.0 w ciągu 24 godzin. Można go uzyskać pod adresem mitchell@4GuysFromRolla.com.

Specjalne podziękowania

Ta seria samouczków została omówiona przez wielu przydatnych recenzentów. Głównym recenzentem tego samouczka był Ken Pespisa. Chcesz przejrzeć nadchodzące artykuły MSDN? Jeśli tak, napisz do mnie na adres mitchell@4GuysFromRolla.com.