Обработка исключений уровней BLL и DAL (VB)
В этом руководстве мы посмотрим, как тактично обрабатывать исключения, возникающие во время редактируемого рабочего процесса обновления 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 (Нет).
Рис. 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 EditCommand
CancelCommand
и 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
, NoNullAllowedException
ArgumentException
и т. д. зависит от того, что именно, спровоцировало ошибку в первую очередь. Если на уровне базы данных возникла проблема, DbException
возникнет ошибка. Если для полей или ReorderLevel
полей введено UnitPrice
UnitsOnOrder
UnitsInStock
недопустимое значение, 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
управления.
Счастливое программирование!
Дополнительные материалы
Дополнительные сведения о разделах, описанных в этом руководстве, см. в следующих ресурсах:
- Правила разработки исключений
- Модули ведения журнала ошибок и обработчики (ELMAH) (библиотека с открытым кодом для ведения журнала ошибок)
- Корпоративная библиотека для платформа .NET Framework 2.0 (включает блок приложения управления исключениями)
Об авторе
Скотт Митчелл, автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с технологиями Microsoft Web с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Сэмс Учит себя ASP.NET 2.0 в 24 часах. Он может быть достигнут в mitchell@4GuysFromRolla.com. или через его блог, который можно найти на http://ScottOnWriting.NET.
Особое спасибо
Эта серия учебников была проверена многими полезными рецензентами. Ведущий рецензент этого руководства был Кен Песписа. Хотите просмотреть мои предстоящие статьи MSDN? Если да, упадите меня линию в mitchell@4GuysFromRolla.com.