Поделиться через


Обработка исключений уровней BLL и DAL (VB)

Скотт Митчелл

Скачать в формате PDF

В этом руководстве мы посмотрим, как тактично обрабатывать исключения, возникающие во время редактируемого рабочего процесса обновления DataList.

Введение

В руководстве по редактированию и удалению данных в учебнике DataList мы создали список данных, который предложил простые возможности редактирования и удаления. Хотя он полностью функциональный, он вряд ли был понятным для пользователя, так как любая ошибка, которая произошла во время редактирования или удаления процесса, привела к необработанным исключениям. Например, опущение имени продукта или при редактировании продукта, ввод ценовой стоимости очень доступно!, вызывает исключение. Так как это исключение не появляется в коде, он пузырится до среды выполнения ASP.NET, которая затем отображает сведения об исключении на веб-странице.

Как мы видели в руководстве по обработке исключений уровня BLL и DAL на странице ASP.NET , если исключение возникает из глубин бизнес-логики или уровней доступа к данным, сведения об исключении возвращаются в ObjectDataSource, а затем в GridView. Мы узнали, как корректно обрабатывать эти исключения, создавая Updated или RowUpdated обработчики событий для ObjectDataSource или GridView, проверяя исключение, а затем указывая, что исключение было обработано.

Однако наши учебники DataList не используют ObjectDataSource для обновления и удаления данных. Вместо этого мы работаем непосредственно против BLL. Чтобы обнаружить исключения, исходящие из BLL или DAL, необходимо реализовать код обработки исключений в коде ASP.NET страницы. В этом руководстве мы посмотрим, как более тактично обрабатывать исключения, возникающие во время редактируемого рабочего процесса обновления DataList.

Примечание.

В обзоре редактирования и удаления данных в учебнике DataList мы обсудили различные методы редактирования и удаления данных из DataList , некоторые методы, связанные с использованием ObjectDataSource для обновления и удаления. При использовании этих методов можно обрабатывать исключения из BLL или DAL с помощью обработчиков событий ObjectDataSource или Deleted ObjectDataSourceUpdated.

Шаг 1. Создание редактируемого списка данных

Прежде чем беспокоиться об обработке исключений, возникающих во время обновления рабочего процесса, сначала создадим редактируемый список данных. ErrorHandling.aspx Откройте страницу в папке, добавьте DataList в EditDeleteDataList конструктор, задайте для его свойства Productsзначение ID и добавьте новый объект ObjectDataSource с именем ProductsDataSource. Настройте ObjectDataSource для выбора ProductsBLL записей метод класса GetProducts() ; задайте раскрывающиеся списки на вкладках INSERT, UPDATE и DELETE (Нет).

Возврат сведений о продукте с помощью метода GetProducts()

Рис. 1. Возврат сведений о продукте GetProducts() с помощью метода (щелкните, чтобы просмотреть изображение полного размера)

После завершения работы мастера ObjectDataSource Visual Studio автоматически создаст ItemTemplate объект для DataList. Замените это ItemTemplate именем и ценой каждого продукта и включает кнопку "Изменить". Затем создайте EditItemTemplate веб-элемент управления TextBox для кнопок "Имя" и "Обновить" и "Отмена". Наконец, задайте для свойства DataList RepeatColumns значение 2.

После этих изменений декларативная разметка страницы должна выглядеть следующим образом. Чтобы убедиться, что кнопки "Изменить", "Отмена" и "Обновить" имеют их CommandName свойства, равные "Изменить", "Отмена" и "Обновить" соответственно.

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

Примечание.

Для этого руководства необходимо включить состояние представления DataList.

Ознакомьтесь с нашим прогрессом в браузере (см. рис. 2).

Каждый продукт включает кнопку

Рис. 2. Каждый продукт включает кнопку "Изменить" (нажмите, чтобы просмотреть изображение полного размера)

В настоящее время кнопка "Изменить" вызывает только обратную передачу, которая пока не делает продукт редактируемым. Чтобы включить редактирование, необходимо создать обработчики событий для dataList s EditCommandCancelCommandи UpdateCommand событий. И EditCommand CancelCommand события просто обновляют свойство DataList и повторно привязывать данные к DataList EditItemIndex :

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

Обработчик UpdateCommand событий немного более вовлечен. Он должен прочитать в редактируемых продуктах ProductID из DataKeys коллекции вместе с именем продукта и ценой из TextBoxes в поле EditItemTemplate, а затем вызвать ProductsBLL метод класса UpdateProduct перед возвратом DataList в его состояние предварительного редактирования.

Теперь давайте просто используйте тот же код из UpdateCommand обработчика событий в руководстве по редактированию и удалению данных в руководстве по DataList . Мы добавим код для корректной обработки исключений на шаге 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

В случае недопустимых входных данных, которые могут быть в виде неправильно отформатированных цен на единицу, незаконное значение цены единицы, например $5,00, или упущение имени продукта будет поднято. UpdateCommand Так как обработчик событий не включает в себя код обработки исключений на данный момент, исключение будет пузыриться до среды выполнения ASP.NET, где она будет отображаться для конечного пользователя (см. рис. 3).

При возникновении необработанного исключения конечный пользователь видит страницу ошибки

Рис. 3. При возникновении необработанного исключения конечный пользователь видит страницу ошибки

Шаг 2. Обработка исключений в обработчике событий UpdateCommand

Во время обновления рабочих процессов исключения могут возникать в UpdateCommand обработчике событий, BLL или DAL. Например, если пользователь вводит цену слишком дорогой, Decimal.Parse инструкция в обработчике UpdateCommand событий вызовет FormatException исключение. Если пользователь пропускает имя продукта или если цена имеет отрицательное значение, DAL вызовет исключение.

При возникновении исключения мы хотим отобразить информативное сообщение на самой странице. Добавьте веб-элемент управления label на страницу, для которой ID задано ExceptionDetailsзначение . Настройте текст Label для отображения в красном, большом, полужирном и курсивном шрифте, назначив его CssClass свойству Warning класс CSS, который определен в Styles.css файле.

При возникновении ошибки мы хотим, чтобы метка отображалась только один раз. То есть при последующих обратных операциях предупреждение метки должно исчезнуть. Это можно сделать путем очистки свойства Label или Text настройки его Visible свойства False в Page_Load обработчике событий (так как мы сделали еще в руководстве по обработке исключений BLL и DAL уровня в руководстве по ASP.NET page) или отключении поддержки состояния представления метки . Давайте будем использовать последний вариант.

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

При возникновении исключения мы назначим сведения об исключении свойству ExceptionDetails элемента управления Text Label. Так как состояние представления отключено, при последующих обратном обратном выполнении программных изменений свойства будут потеряны Text , возвращая текст по умолчанию (пустую строку), тем самым скрывая предупреждающее сообщение.

Чтобы определить, когда возникла ошибка, чтобы отобразить полезное сообщение на странице, необходимо добавить Try ... Catch блок в UpdateCommand обработчик событий. Часть Try содержит код, который может привести к исключению, а Catch блок содержит код, выполняемый перед лицом исключения. Дополнительные сведения о блоке см. в разделе "Основы обработки исключенийTry ... Catch" в документации по платформа .NET Framework.

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

Если исключение любого типа создается кодом внутри Try блока, Catch код блока начнет выполняться. Тип исключения, вызываемого DbException, NoNullAllowedExceptionArgumentExceptionи т. д. зависит от того, что именно, спровоцировало ошибку в первую очередь. Если на уровне базы данных возникла проблема, DbException возникнет ошибка. Если для полей или ReorderLevel полей введено UnitPriceUnitsOnOrderUnitsInStockнедопустимое значение, ArgumentException создается исключение, так как мы добавили код для проверки этих значений полей в ProductsDataTable классе (см. руководство по созданию уровня бизнес-логики).

Мы можем предоставить более полезное объяснение для конечного пользователя, основывая текст сообщения на типе исключения, пойманным. Следующий код, который использовался в почти идентичной форме, в руководстве по обработке исключений уровня BLL и DAL в руководстве по странице ASP.NET представлен этот уровень детализации:

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

Чтобы завершить работу с этим руководством, просто вызовите DisplayExceptionDetails метод из Catch блока, передаваемого в пойманный Exception экземпляр (ex).

Try ... Catch При наличии блока пользователи получают более информативное сообщение об ошибке, как показано на рисунках 4 и 5. Обратите внимание, что перед лицом исключения DataList остается в режиме редактирования. Это связано с тем, что после возникновения исключения поток управления немедленно перенаправляется в Catch блок, обход кода, возвращающего DataList в состояние предварительного редактирования.

Сообщение об ошибке отображается, если пользователю не удается указать обязательное поле

Рис. 4. Сообщение об ошибке отображается, если пользователь опечатляет обязательное поле (щелкните, чтобы просмотреть изображение полного размера)

При вводе отрицательной цены отображается сообщение об ошибке

Рис. 5. При вводе отрицательной цены отображается сообщение об ошибке (щелкните, чтобы просмотреть изображение полного размера)

Итоги

GridView и ObjectDataSource предоставляют обработчики событий после уровня, содержащие сведения о любых исключениях, возникающих во время обновления и удаления рабочего процесса, а также свойства, которые можно задать, чтобы указать, обрабатывается ли исключение. Однако эти функции недоступны при работе с DataList и использовании BLL напрямую. Вместо этого мы отвечаем за реализацию обработки исключений.

В этом руководстве мы узнали, как добавить обработку исключений в редактируемый рабочий процесс обновления DataList, добавив Try ... Catch блок в UpdateCommand обработчик событий. Если во время обновления возникает исключение, Catch код блока выполняется, отображая полезные сведения в ExceptionDetails метке.

На этом этапе DataList не предпринимает никаких усилий, чтобы предотвратить возникновение исключений в первую очередь. Несмотря на то что мы знаем, что отрицательная цена приведет к исключению, мы еще не добавили какие-либо функции, чтобы заранее запретить пользователю вводить такие недопустимые входные данные. В следующем руководстве мы посмотрим, как уменьшить исключения, вызванные недопустимым вводом пользователем, добавив элементы управления проверкой в элемент EditItemTemplateуправления.

Счастливое программирование!

Дополнительные материалы

Дополнительные сведения о разделах, описанных в этом руководстве, см. в следующих ресурсах:

Об авторе

Скотт Митчелл, автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с технологиями Microsoft Web с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Сэмс Учит себя ASP.NET 2.0 в 24 часах. Он может быть достигнут в mitchell@4GuysFromRolla.com. или через его блог, который можно найти на http://ScottOnWriting.NET.

Особое спасибо

Эта серия учебников была проверена многими полезными рецензентами. Ведущий рецензент этого руководства был Кен Песписа. Хотите просмотреть мои предстоящие статьи MSDN? Если да, упадите меня линию в mitchell@4GuysFromRolla.com.