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

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

Скачивание примера приложения или Загрузка PDF-файла

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

Введение

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

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

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

Note

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

Шаг 1. Создание изменяемого элемента управления DataList

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

получить сведения о продукте с помощью метода WebMethod ()

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

После завершения работы мастера ObjectDataSource Visual Studio автоматически создаст ItemTemplate для DataList. Введите здесь ItemTemplate, где отображаются названия и цены каждого продукта и включается кнопка "Изменить". Затем создайте EditItemTemplate с помощью веб-элемента управления TextBox для Name and Price, а также кнопок Update и Cancel. Наконец, задайте свойству RepeatColumns DataList s значение 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>

Note

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

Потратьте время на просмотр нашего хода работы в браузере (см. рис. 2).

каждый продукт включает кнопку "Изменить"

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

В настоящее время кнопка Edit (изменить) только вызывает обратную передачу, но не делает продукт редактируемым. Чтобы включить редактирование, необходимо создать обработчики событий для EditCommand, CancelCommandи UpdateCommand событий DataList. События 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 является немного более сложным. Он должен прочесть измененный продукт s ProductID из коллекции DataKeys вместе с именем и ценой продукта из текстовых полей в EditItemTemplate, а затем вызвать метод ProductsBLL Class 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. Настройте текст метки, чтобы он отображался красным, очень крупным полужирным шрифтом и курсивом, назначив его свойство CssClass для класса Warning CSS, который определен в файле Styles.css.

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

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

При возникновении исключения сведения об исключении будут назначаться свойству ExceptionDetails меток Text. Так как состояние представления отключено, при последующих обратных передачах программные изменения свойств 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 блока s начнет выполняться. Тип исключения, вызываемого DbException, NoNullAllowedException, ArgumentExceptionи т. д., зависит от того, что точно, причиной ошибку в первую очередь. Если на уровне базы данных возникла проблема, будет выдана DbException. Если для полей UnitPrice, UnitsInStock, UnitsOnOrderили ReorderLevel введено недопустимое значение, будет выдано исключение 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 s, добавив блок Try ... Catch в обработчик событий UpdateCommand. Если во время прогона обновления возникает исключение, код блока Catch блокируется, отображая полезную информацию в ExceptionDetails метке.

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

Поздравляем с программированием!

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

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

Об авторе

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

Специальная благодарность

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