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


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

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

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

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

Введение

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

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

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

Примечание

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

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

Прежде чем мы будем беспокоиться об обработке исключений, возникающих во время рабочего процесса обновления, сначала создадим редактируемый Список данных. Откройте страницу 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 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();
}

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

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

Перед лицом недопустимых входных данных, которые могут быть в виде неправильно отформатированных цен за единицу, незаконной цены за единицу, такой как -$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 должно исчезнуть. Это можно сделать, очистив свойство Label Text или присвоив его Visible свойству False значение в Page_Load обработчике событий (как это было в руководстве По обработке исключений BLL- и DAL-Level в ASP.NET Page ) или отключив поддержку состояния представления Label. Давайте воспользуемся последним вариантом.

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

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

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

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

При возникновении исключения любого типа кодом в Try блоке Catch начинается выполнение кода блока. Тип создаваемого DbExceptionисключения , NoNullAllowedException, ArgumentExceptionи т. д. зависит от того, что именно ускорит ошибку. Если на уровне базы данных возникла проблема, DbException возникнет исключение . Если для UnitPriceполей , UnitsInStock, UnitsOnOrder, или ReorderLevel введено недопустимое значение, ArgumentException будет выдано исключение , так как мы добавили код для проверки этих значений полей в ProductsDataTable классе (см. учебник Создание уровня бизнес-логики ).

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

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

Чтобы выполнить инструкции из этого руководства, просто вызовите 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.