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

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

Загрузить PDF-файл

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

Введение

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

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

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

Примечание

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

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

Прежде чем беспокоиться об обработке исключений, возникающих во время рабочего процесса обновления, сначала создадим редактируемый DataList. Откройте страницу ErrorHandling.aspx в папкеEditDeleteDataList, добавьте DataList в Designer, задайте для его ID свойства Productsзначение и добавьте новый объект 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 EditCommand, CancelCommandи UpdateCommand . События EditCommand и CancelCommand просто обновляют свойство DataList EditItemIndex и повторно привязывать данные к 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

Обработчик UpdateCommand событий немного более задействован. Он должен считывать измененные продукты ProductID из DataKeys коллекции, а также название продукта и цену из TextBoxes в EditItemTemplate, а затем вызвать ProductsBLL метод класса s 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 вызовет исключение.

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

При возникновении ошибки требуется, чтобы метка отображалась только один раз. Это значит, что при последующих обратных операциях предупреждение label должно исчезнуть. Это можно сделать, очистив свойство Labels Text или задав его Visible свойству False значение в Page_Load обработчике событий (как это было в руководстве по обработке исключений BLL- и DAL-Level в 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, NoNullAllowedException, ArgumentExceptionи т. д., зависит от того, что именно ускорит ошибку в первую очередь. При возникновении проблемы на уровне базы данных будет выдано DbException исключение . Если введено недопустимое значение для UnitPriceполей , UnitsInStock, UnitsOnOrderили ReorderLevel , ArgumentException будет выдано исключение , так как мы добавили код для проверки этих значений полей в ProductsDataTable классе (см. учебник Создание уровня бизнес-логики ).

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

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, добавив элементы управления проверки в .

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

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

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

Об авторе

Скотт Митчелл( Scott Mitchell), автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с веб-технологиями Майкрософт с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Sams Teach Yourself ASP.NET 2.0 в 24 часах. Он может быть доступен в mitchell@4GuysFromRolla.com. или через его блог, который можно найти по адресу http://ScottOnWriting.NET.

Особая благодарность

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