Обработка исключений уровней BLL и DAL (C#)
В этом руководстве мы посмотрим, как тактично обрабатывать исключения, возникающие во время редактируемого рабочего процесса обновления 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 значение (Нет).
Рис. 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
.
Счастливое программирование!
Дополнительные материалы
Дополнительные сведения по темам, рассматриваемым в этом руководстве, см. в следующих ресурсах:
- Правила разработки исключений
- Модули и обработчики ведения журнала ошибок (ELMAH) (библиотека с открытым исходным кодом для ведения журнала ошибок)
- Корпоративная библиотека для платформа .NET Framework 2.0 (включает блок приложения управления исключениями)
Об авторе
Скотт Митчелл (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.