Обработка исключений уровней BLL и DAL на странице ASP.NET(C#)Handling BLL- and DAL-Level Exceptions in an ASP.NET Page (C#)

по Скотт Митчеллby Scott Mitchell

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

В этом учебнике будет показано, как отобразить понятное информативное сообщение об ошибке, которое должно быть вызвано исключением во время операции вставки, обновления или удаления веб-элемента управления данными ASP.NET.In this tutorial we will see how to display a friendly, informative error message should an exception occur during an insert, update, or delete operation of an ASP.NET data Web control.

ВведениеIntroduction

Работа с данными из веб-приложения ASP.NET с использованием многоуровневой архитектуры приложения включает следующие три основных действия.Working with data from an ASP.NET web application using a tiered application architecture involves the following three general steps:

  1. Определите, какой метод уровня бизнес-логики необходимо вызвать и какие значения параметров передать.Determine what method of the Business Logic Layer needs to be invoked and what parameter values to pass it. Значения параметров могут быть жестко запрограммированными, назначенными программно или вводимыми пользователем.The parameter values can be hard coded, programmatically-assigned, or inputs entered by the user.
  2. Вызовите метод.Invoke the method.
  3. Обработка результатов.Process the results. При вызове метода BLL, возвращающего данные, это может привести к привязке данных к веб-элементу управления данными.When calling a BLL method that returns data, this may involve binding the data to a data Web control. Для методов BLL, изменяющих данные, это может включать выполнение некоторых действий на основе возвращаемого значения или аккуратной обработки любого исключения, возник на шаге 2.For BLL methods that modify data, this may include performing some action based on a return value or gracefully handling any exception that arose in Step 2.

Как было показано в предыдущем руководстве, элементы управления ObjectDataSource и Data Web предоставляют точки расширения для шагов 1 и 3.As we saw in the previous tutorial, both the ObjectDataSource and the data Web controls provide extensibility points for Steps 1 and 3. Например, GridView вызывает событие RowUpdating, прежде чем присвоить его значения полей коллекции UpdateParameters элемента ObjectDataSource. его RowUpdated событие возникает после завершения операции ObjectDataSource.The GridView, for example, fires its RowUpdating event prior to assigning its field values to its ObjectDataSource's UpdateParameters collection; its RowUpdated event is raised after the ObjectDataSource has completed the operation.

Мы уже рассматривали события, которые возникают на шаге 1, и увидели, как их можно использовать для настройки входных параметров или отмены операции.We've already examined the events that fire during Step 1 and have seen how they can be used to customize the input parameters or cancel the operation. В этом учебнике мы вернем внимание к событиям, которые срабатывают после завершения операции.In this tutorial we'll turn our attention to the events that fire after the operation has completed. С этими обработчиками событий последующей проверки мы можем, помимо прочего, определить, произошло ли исключение во время операции, и правильно обработать его, отображая понятное информативное сообщение об ошибке на экране, а не стандартный ASP.NET страница исключения.With these post-level event handlers we can, among other things, determine if an exception occurred during the operation and handle it gracefully, displaying a friendly, informative error message on the screen rather than defaulting to the standard ASP.NET exception page.

Чтобы продемонстрировать работу с этими событиями уровня поста, давайте создадим страницу, в которой перечислены продукты в редактируемом элементе управления GridView.To illustrate working with these post-level events, let's create a page that lists the products in an editable GridView. При обновлении продукта при возникновении исключения на странице ASP.NET будет отображаться короткое сообщение над GridView, объясняющее, что возникла проблема.When updating a product, if an exception is raised our ASP.NET page will display a short message above the GridView explaining that a problem has occurred. Приступим.Let's get started!

Шаг 1. Создание редактируемого элемента управления GridView для продуктовStep 1: Creating an Editable GridView of Products

В предыдущем учебном курсе мы создали редактируемый элемент управления GridView с двумя полями, ProductName и UnitPrice.In the previous tutorial we created an editable GridView with just two fields, ProductName and UnitPrice. Это требовало создания дополнительной перегрузки для метода UpdateProduct класса ProductsBLL, который принимает только три входных параметра (название продукта, Цена за единицу и идентификатор), а не параметр для каждого поля продукта.This required creating an additional overload for the ProductsBLL class's UpdateProduct method, one that only accepted three input parameters (the product's name, unit price, and ID) as opposed a parameter for each product field. В рамках этого руководства мы еще рекомендуем использовать этот метод, создав редактируемый элемент управления GridView, в котором отображается название продукта, количество на единицу, Цена за единицу и единицы склада, но только имя, Цена за единицу и единицы склада, которые должны быть изменены.For this tutorial, let's practice this technique again, creating an editable GridView that displays the product's name, quantity per unit, unit price, and units in stock, but only allows the name, unit price, and units in stock to be edited.

Для реализации этого сценария требуется еще одна перегрузка метода UpdateProduct, принимающая четыре параметра: название продукта, Цена за единицу, единицы в запасах и идентификатор.To accommodate this scenario we'll need another overload of the UpdateProduct method, one that accepts four parameters: the product's name, unit price, units in stock, and ID. Добавьте в класс ProductsBLL следующий метод:Add the following method to the ProductsBLL class:

[System.ComponentModel.DataObjectMethodAttribute(
    System.ComponentModel.DataObjectMethodType.Update, false)]
public bool UpdateProduct(string productName, decimal? unitPrice, short? unitsInStock,
    int productID)
{
    Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID);
    if (products.Count == 0)
        // no matching record found, return false
        return false;
    Northwind.ProductsRow product = products[0];
    product.ProductName = productName;
    if (unitPrice == null) product.SetUnitPriceNull();
      else product.UnitPrice = unitPrice.Value;
    if (unitsInStock == null) product.SetUnitsInStockNull();
      else product.UnitsInStock = unitsInStock.Value;
    // Update the product record
    int rowsAffected = Adapter.Update(product);
    // Return true if precisely one row was updated, otherwise false
    return rowsAffected == 1;
}

После завершения этого метода мы готовы к созданию страницы ASP.NET, позволяющей редактировать эти четыре поля продукта.With this method complete, we're ready to create the ASP.NET page that allows for editing these four particular product fields. Откройте страницу ErrorHandling.aspx в папке EditInsertDelete и добавьте GridView на страницу через конструктор.Open the ErrorHandling.aspx page in the EditInsertDelete folder and add a GridView to the page through the Designer. Привяжите GridView к новому элементу ObjectDataSource, сопоставлению метода Select() с методом GetProducts() класса ProductsBLL и методом Update() в только что созданную перегрузку UpdateProduct.Bind the GridView to a new ObjectDataSource, mapping the Select() method to the ProductsBLL class's GetProducts() method and the Update() method to the UpdateProduct overload just created.

использовать перегрузку метода UpdateProduct, которая принимает четыре входных параметраUse the UpdateProduct Method Overload That Accepts Four Input Parameters

Рис. 1. использование перегрузки метода UpdateProduct, принимающей четыре входных параметра (щелкните, чтобы просмотреть изображение с полным размером)Figure 1: Use the UpdateProduct Method Overload That Accepts Four Input Parameters (Click to view full-size image)

Это приведет к созданию элемента управления ObjectDataSource с коллекцией UpdateParameters с четырьмя параметрами и элементом управления GridView с полем для каждого поля продукта.This will create an ObjectDataSource with an UpdateParameters collection with four parameters and a GridView with a field for each of the product fields. Декларативная разметка ObjectDataSource присваивает свойству OldValuesParameterFormatString значение original_{0}, что вызовет исключение, так как наш класс BLL не ждет передачи входного параметра с именем original_productID.The ObjectDataSource's declarative markup assigns the OldValuesParameterFormatString property the value original_{0}, which will cause an exception since our BLL class's don't expect an input parameter named original_productID to be passed in. Не забудьте полностью удалить этот параметр из декларативного синтаксиса (или задайте для него значение по умолчанию {0}).Don't forget to remove this setting altogether from the declarative syntax (or set it to the default value, {0}).

Затем немного очистить GridView, чтобы включить только ProductName, QuantityPerUnit, UnitPriceи UnitsInStock BoundFields.Next, pare down the GridView to include only the ProductName, QuantityPerUnit, UnitPrice, and UnitsInStock BoundFields. Кроме того, вы можете применить любое необходимое форматирование на уровне полей (например, изменить свойства HeaderText).Also feel free to apply any field-level formatting you deem necessary (such as changing the HeaderText properties).

В предыдущем учебном курсе мы рассматривали форматирование UnitPrice BoundField как денежную единицу как в режиме только для чтения, так и в режиме редактирования.In the previous tutorial we looked at how to format the UnitPrice BoundField as a currency both in read-only mode and edit mode. Давайте сделаем то же самое.Let's do the same here. Помните, что при этом необходимо задать для свойства DataFormatString BoundField значение {0:c}, его свойство HtmlEncode false, а ApplyFormatInEditModetrue, как показано на рис. 2.Recall that this required setting the BoundField's DataFormatString property to {0:c}, its HtmlEncode property to false, and its ApplyFormatInEditMode to true, as shown in Figure 2.

настроить BoundField UnitPrice для вывода в виде валютыConfigure the UnitPrice BoundField to Display as a Currency

Рис. 2. Настройка UnitPrice BoundField для отображения в виде валюты (щелкните, чтобы просмотреть изображение с полным размером)Figure 2: Configure the UnitPrice BoundField to Display as a Currency (Click to view full-size image)

Для форматирования UnitPrice в качестве валюты в интерфейсе редактирования требуется создать обработчик событий для события RowUpdating GridView, которое анализирует строку в формате валюты в decimal значение.Formatting the UnitPrice as a currency in the editing interface requires creating an event handler for the GridView's RowUpdating event that parses the currency-formatted string into a decimal value. Вспомним, что обработчик событий RowUpdating из последнего учебника также проверил, чтобы убедиться, что пользователь предоставил значение UnitPrice.Recall that the RowUpdating event handler from the last tutorial also checked to ensure that the user provided a UnitPrice value. Однако для этого учебника можно разрешить пользователю опустить цену.However, for this tutorial let's allow the user to omit the price.

protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
    if (e.NewValues["UnitPrice"] != null)
        e.NewValues["UnitPrice"] =decimal.Parse(e.NewValues["UnitPrice"].ToString(),
            System.Globalization.NumberStyles.Currency);
}

Наш GridView включает QuantityPerUnit BoundField, но этот BoundField должен быть только для отображаемых целей и не должен быть доступен для редактирования пользователем.Our GridView includes a QuantityPerUnit BoundField, but this BoundField should be only for display purposes and should not be editable by the user. Для этого просто задайте для свойства BoundFields "ReadOnly значение true.To arrange this, simply set the BoundFields' ReadOnly property to true.

сделать QuantityPerUnit BoundField только для чтенияMake the QuantityPerUnit BoundField Read-Only

Рис. 3. Сделайте QuantityPerUnit BoundField только для чтения (щелкните, чтобы просмотреть изображение с полным размером)Figure 3: Make the QuantityPerUnit BoundField Read-Only (Click to view full-size image)

Наконец, установите флажок Включить изменение в смарт-теге GridView.Finally, check the Enable Editing checkbox from the GridView's smart tag. После выполнения этих действий конструктор ErrorHandling.aspx страницы должен выглядеть примерно так, как показано на рис. 4.After completing these steps the ErrorHandling.aspx page's Designer should look similar to Figure 4.

удалить все необходимые BoundFields и установите флажок Enable Edit (включить редактирование).Remove All But the Needed BoundFields and Check the Enable Editing Checkbox

Рис. 4. Удаление всех необходимых BoundFields и установка флажка Enable Edit (щелкните, чтобы просмотреть изображение с полным размером)Figure 4: Remove All But the Needed BoundFields and Check the Enable Editing Checkbox (Click to view full-size image)

На этом этапе у нас есть список всех полей продуктов ProductName, QuantityPerUnit, UnitPriceи UnitsInStock. Однако можно изменять только поля ProductName, UnitPriceи UnitsInStock.At this point we have a list of all of the products' ProductName, QuantityPerUnit, UnitPrice, and UnitsInStock fields; however, only the ProductName, UnitPrice, and UnitsInStock fields can be edited.

пользователи теперь могут легко изменять названия, цены и единицы товара в полях акций.Users Can Now Easily Edit Products' Names, Prices, and Units In Stock Fields

Рис. 5. Теперь пользователи могут легко изменять названия, цены и единицы товара в полях акций (щелкните, чтобы просмотреть изображение с полным размером).Figure 5: Users Can Now Easily Edit Products' Names, Prices, and Units In Stock Fields (Click to view full-size image)

Шаг 2. корректное обработка исключений уровня DALStep 2: Gracefully Handling DAL-Level Exceptions

Хотя наш редактируемый элемент управления GridView прекрасно работает, когда пользователь вводит юридические значения для измененного названия продукта, цены и количества единиц в запасе, при вводе недопустимых значений возникает исключение.While our editable GridView works wonderfully when users enter legal values for the edited product's name, price, and units in stock, entering illegal values results in an exception. Например, пропуск значения ProductName вызывает исключение нонуллалловедексцептион , так как свойство ProductName в классе ProductsRow имеет свойство AllowDBNull со значением false. Если база данных не работает, TableAdapter порождает SqlException при попытке подключиться к базе данных.For example, omitting the ProductName value causes a NoNullAllowedException to be thrown since the ProductName property in the ProductsRow class has its AllowDBNull property set to false; if the database is down, a SqlException will be thrown by the TableAdapter when attempting to connect to the database. Без каких-либо действий эти исключения поднимаются от уровня доступа к данным на уровень бизнес-логики, затем на страницу ASP.NET и, наконец, в среду выполнения ASP.NET.Without taking any action, these exceptions bubble up from the Data Access Layer to the Business Logic Layer, then to the ASP.NET page, and finally to the ASP.NET runtime.

В зависимости от того, как настроено веб-приложение и не посещает ли приложение localhost, необработанное исключение может привести к появлению общей страницы ошибок сервера, подробного отчета об ошибке или удобной веб-страницы.Depending on how your web application is configured and whether or not you're visiting the application from localhost, an unhandled exception can result in either a generic server-error page, a detailed error report, or a user-friendly web page. Дополнительные сведения о том, как среда выполнения ASP.NET реагирует на неперехваченное исключение, см. в разделе Обработка ошибок веб-приложения в ASP.NET и элемент customErrors .See Web Application Error Handling in ASP.NET and the customErrors Element for more information on how the ASP.NET runtime responds to an uncaught exception.

На рис. 6 показан экран, возникающий при попытке обновить продукт без указания значения ProductName.Figure 6 shows the screen encountered when attempting to update a product without specifying the ProductName value. Это подробный отчет об ошибках по умолчанию, отображаемый при переходе на localhost.This is the default detailed error report displayed when coming through localhost.

пропуск названия продукта будет отображать сведения об исключенииOmitting the Product's Name Will Display Exception Details

Рис. 6. при пропуске названия продукта отображаются сведения об исключении (щелкните, чтобы просмотреть изображение с полным размером).Figure 6: Omitting the Product's Name Will Display Exception Details (Click to view full-size image)

Хотя такие сведения об исключении полезны при тестировании приложения, представление конечного пользователя с таким экраном в случае исключения является менее идеальным.While such exception details are helpful when testing an application, presenting an end user with such a screen in the face of an exception is less than ideal. Конечный пользователь, вероятно, не знает, что такое NoNullAllowedException или почему оно вызвано.An end user likely doesn't know what a NoNullAllowedException is or why it was caused. Лучший подход — предоставить пользователю более удобное сообщение, объясняющее, что возникли проблемы при попытке обновления продукта.A better approach is to present the user with a more user-friendly message explaining that there were problems attempting to update the product.

Если при выполнении операции возникает исключение, то события последующей проверки как в элементе управления ObjectDataSource, так и в веб-элементах данных предоставляют средства для обнаружения и отмены исключения из восходящей среды в среду выполнения ASP.NET.If an exception occurs when performing the operation, the post-level events in both the ObjectDataSource and the data Web control provide a means to detect it and cancel the exception from bubbling up to the ASP.NET runtime. В нашем примере создадим обработчик событий для события RowUpdated GridView, которое определяет, было ли вызвано исключение, и, если да, отображает сведения об исключении в веб-элементе управления Label.For our example, let's create an event handler for the GridView's RowUpdated event that determines if an exception has fired and, if so, displays the exception details in a Label Web control.

Начните с добавления метки на страницу ASP.NET, задав для свойства ID значение ExceptionDetails и сняв свойство Text.Start by adding a Label to the ASP.NET page, setting its ID property to ExceptionDetails and clearing out its Text property. Чтобы привлечь внимание пользователя к этому сообщению, присвойте свойству CssClass значение Warning, которое является классом CSS, добавленным в файл Styles.css в предыдущем руководстве.In order to draw the user's eye to this message, set its CssClass property to Warning, which is a CSS class we added to the Styles.css file in the previous tutorial. Вспомним, что этот класс CSS приводит к тому, что текст метки отображается красным, курсивным шрифтом, очень большим шрифтом.Recall that this CSS class causes the Label's text to be displayed in a red, italic, bold, extra large font.

добавить на страницу веб-элемент управления LabelAdd a Label Web Control to the Page

Рис. 7. Добавление на страницу веб-элемента управления Label (щелкните, чтобы просмотреть изображение с полным размером)Figure 7: Add a Label Web Control to the Page (Click to view full-size image)

Поскольку веб-элемент управления "метка" должен быть видимым только сразу после возникновения исключения, присвойте свойству Visible значение false в обработчике событий Page_Load:Since we want this Label Web control to be visible only immediately after an exception has occurred, set its Visible property to false in the Page_Load event handler:

protected void Page_Load(object sender, EventArgs e)
{
    ExceptionDetails.Visible = false;
}

В этом коде при первом посещении страницы и последующих обратных передачах элементу управления ExceptionDetails будет присвоено Visible свойство false.With this code, on the first page visit and subsequent postbacks the ExceptionDetails control will have its Visible property set to false. В случае исключения уровня DAL или BLL, которое мы можем обнаружить в обработчике событий RowUpdated GridView, мы устанавливаем свойству Visible элемента управления ExceptionDetails значение true.In the face of a DAL- or BLL-level exception, which we can detect in the GridView's RowUpdated event handler, we will set the ExceptionDetails control's Visible property to true. Так как обработчики событий веб-элемента управления происходят после обработчика событий Page_Load в жизненном цикле страницы, метка будет отображаться.Since Web control event handlers occur after the Page_Load event handler in the page lifecycle, the Label will be shown. Однако при следующей обратной передаче обработчик событий Page_Load вернет свойство Visible обратно в false, скрывая его из представления.However, on the next postback, the Page_Load event handler will revert the Visible property back to false, hiding it from view again.

Note

Кроме того, можно удалить необходимость установки свойства Visible элемента управления ExceptionDetails в Page_Load, назначив false свойства Visible в декларативном синтаксисе и отключив его состояние просмотра (установив для свойства EnableViewState значение false).Alternatively, we could remove the necessity for setting the ExceptionDetails control's Visible property in Page_Load by assigning its Visible property false in the declarative syntax and disabling its view state (setting its EnableViewState property to false). В следующем учебном курсе мы будем использовать этот альтернативный подход.We'll use this alternative approach in a future tutorial.

После добавления элемента управления Label следующим шагом является создание обработчика событий для RowUpdated события GridView.With the Label control added, our next step is to create the event handler for the GridView's RowUpdated event. Выберите элемент GridView в конструкторе, перейдите к окно свойств и щелкните значок с молнией, в котором перечислены события GridView.Select the GridView in the Designer, go to the Properties window, and click the lightning bolt icon, listing the GridView's events. Уже должна быть запись для события RowUpdating GridView, так как мы создали обработчик событий для этого события ранее в этом руководстве.There should already be an entry there for the GridView's RowUpdating event, as we created an event handler for this event earlier in this tutorial. Создайте обработчик событий для RowUpdated события.Create an event handler for the RowUpdated event as well.

Создание обработчика событий для события RowUpdated элемента управления GridView

Рис. 8. Создание обработчика событий для RowUpdated события GridViewFigure 8: Create an Event Handler for the GridView's RowUpdated Event

Note

Обработчик событий также можно создать с помощью раскрывающихся списков в верхней части файла класса кода программной части.You can also create the event handler through the drop-down lists at the top of the code-behind class file. Выберите элемент GridView из раскрывающегося списка слева и событие RowUpdated из справа.Select the GridView from the drop-down list on the left and the RowUpdated event from the one on the right.

При создании этого обработчика событий в класс кода программной части страницы ASP.NET будет добавлен следующий код:Creating this event handler will add the following code to the ASP.NET page's code-behind class:

protected void GridView1_RowUpdated(object sender, GridViewUpdatedEventArgs e)
{
}

Второй входной параметр этого обработчика событий является объектом типа гридвиевупдатедевентаргс, который имеет три свойства, представляющие интерес для обработки исключений:This event handler's second input parameter is an object of type GridViewUpdatedEventArgs, which has three properties of interest for handling exceptions:

  • Exception ссылку на созданное исключение; Если исключение не было создано, это свойство будет иметь значение nullException a reference to the thrown exception; if no exception has been thrown, this property will have a value of null
  • ExceptionHandled логическое значение, указывающее, было ли исключение обработано в обработчике событий RowUpdated. Если false (значение по умолчанию), исключение создается повторно, распространялась до среды выполнения ASP.NET.ExceptionHandled a Boolean value that indicates whether or not the exception was handled in the RowUpdated event handler; if false (the default), the exception is re-thrown, percolating up to the ASP.NET runtime
  • KeepInEditMode Если задано значение true измененная строка GridView остается в режиме редактирования; Если false (значение по умолчанию), строка GridView возвращается к режиму только для чтения.KeepInEditMode if set to true the edited GridView row remains in edit mode; if false (the default), the GridView row reverts back to its read-only mode

Затем наш код должен проверить, не nullли Exception, что означает, что при выполнении операции было вызвано исключение.Our code, then, should check to see if Exception is not null, meaning that an exception was raised while performing the operation. Если это так, мы хотим:If this is the case, we want to:

  • Отображение сообщения, понятного пользователю, в метке ExceptionDetailsDisplay a user-friendly message in the ExceptionDetails Label
  • Укажите, что исключение обработаноIndicate that the exception was handled
  • Не отключайте строку GridView в режиме редактированияKeep the GridView row in edit mode

В следующем коде выполняются следующие задачи:This following code accomplishes these objectives:

protected void GridView1_RowUpdated(object sender, GridViewUpdatedEventArgs e)
{
    if (e.Exception != null)
    {
        // Display a user-friendly message
        ExceptionDetails.Visible = true;
        ExceptionDetails.Text = "There was a problem updating the product. ";
        if (e.Exception.InnerException != null)
        {
            Exception inner = e.Exception.InnerException;
            if (inner is System.Data.Common.DbException)
                ExceptionDetails.Text +=
                    "Our database is currently experiencing problems." +
                    "Please try again later.";
            else if (inner is NoNullAllowedException)
                ExceptionDetails.Text +=
                    "There are one or more required fields that are missing.";
            else if (inner is ArgumentException)
            {
                string paramName = ((ArgumentException)inner).ParamName;
                ExceptionDetails.Text +=
                    string.Concat("The ", paramName, " value is illegal.");
            }
            else if (inner is ApplicationException)
                ExceptionDetails.Text += inner.Message;
        }
        // Indicate that the exception has been handled
        e.ExceptionHandled = true;
        // Keep the row in edit mode
        e.KeepInEditMode = true;
    }
}

Этот обработчик событий начинает с проверки того, nullли e.Exception.This event handler begins by checking to see if e.Exception is null. Если это не так, свойство Visible ExceptionDetails метки имеет значение true, а свойству Text — "при обновлении продукта возникла проблема".If it's not, the ExceptionDetails Label's Visible property is set to true and its Text property to "There was a problem updating the product." Сведения о фактическом вызываемом исключении находятся в свойстве InnerException объекта e.Exception.The details of the actual exception that was thrown reside in the e.Exception object's InnerException property. Это внутреннее исключение проверяется и, если оно относится к конкретному типу, к свойству Text метки ExceptionDetails добавляется дополнительное, полезное сообщение.This inner exception is examined and, if it is of a particular type, an additional, helpful message is appended to the ExceptionDetails Label's Text property. Наконец, свойствам ExceptionHandled и KeepInEditMode присваивается значение true.Lastly, the ExceptionHandled and KeepInEditMode properties are both set to true.

На рис. 9 показан снимок экрана этой страницы при пропуске имени продукта; На рис. 10 показаны результаты при вводе недопустимого UnitPrice значения (-50).Figure 9 shows a screen shot of this page when omitting the name of the product; Figure 10 shows the results when entering an illegal UnitPrice value (-50).

поле ProductName BoundField должно содержать значениеThe ProductName BoundField Must Contain a Value

Рис. 9. ProductName BoundField должен содержать значение (щелкните, чтобы просмотреть изображение с полным размером)Figure 9: The ProductName BoundField Must Contain a Value (Click to view full-size image)

отрицательные значения UnitPrice не допускаютсяNegative UnitPrice Values are Not Allowed

Рис. 10. отрицательные значения UnitPrice недопустимы (щелкните, чтобы просмотреть изображение с полным размером)Figure 10: Negative UnitPrice Values are Not Allowed (Click to view full-size image)

Установив для свойства e.ExceptionHandled значение true, обработчик событий RowUpdated указал, что он обработал исключение.By setting the e.ExceptionHandled property to true, the RowUpdated event handler has indicated that it has handled the exception. Таким образом, исключение не распространяется на среду выполнения ASP.NET.Therefore, the exception won't propagate up to the ASP.NET runtime.

Note

На рисунках 9 и 10 показан корректный способ обработать исключения, вызванные недопустимым вводом данных пользователем.Figures 9 and 10 show a graceful way to handle exceptions raised due to invalid user input. Однако в идеале такие недопустимые входные данные никогда не будут обращаться к уровню бизнес-логики в первую очередь, так как страница ASP.NET должна обеспечить допустимость входных данных пользователя перед вызовом метода UpdateProduct класса ProductsBLL.Ideally, though, such invalid input will never reach the Business Logic Layer in the first place, as the ASP.NET page should ensure that the user's inputs are valid before invoking the ProductsBLL class's UpdateProduct method. В следующем учебном курсе мы покажем, как добавить элементы управления проверки в интерфейсы правки и вставки, чтобы гарантировать, что данные, передаваемые на слой бизнес-логики, соответствует бизнес-правилам.In our next tutorial we'll see how to add validation controls to the editing and inserting interfaces to ensure that the data submitted to the Business Logic Layer conforms to the business rules. Проверяющие элементы управления не только предотвращают вызов метода UpdateProduct до тех пор, пока предоставленные пользователем данные являются допустимыми, но также предоставляют более информативный пользовательский интерфейс для выявления проблем ввода данных.The validation controls not only prevent the invocation of the UpdateProduct method until the user-supplied data is valid, but also provide a more informative user experience for identifying data entry problems.

Шаг 3. корректное управление исключениями уровня BLLStep 3: Gracefully Handling BLL-Level Exceptions

При вставке, обновлении или удалении данных уровень доступа к данным может вызвать исключение на стороне ошибки, связанной с данными.When inserting, updating, or deleting data, the Data Access Layer may throw an exception in the face of a data-related error. Возможно, база данных находится в режиме «вне сети», в обязательном столбце таблицы базы данных может не быть указано значение или было нарушено ограничение на уровне таблицы.The database may be offline, a required database table column might not have had a value specified, or a table-level constraint may have been violated. В дополнение к строгим исключениям, связанным с данными, уровень бизнес-логики может использовать исключения, чтобы указать, когда нарушены бизнес-правила.In addition to strictly data-related exceptions, the Business Logic Layer can use exceptions to indicate when business rules have been violated. Например, в учебнике Создание уровня бизнес-логики мы добавили проверку бизнес-правила в исходную перегрузку UpdateProduct.In the Creating a Business Logic Layer tutorial, for example, we added a business rule check to the original UpdateProduct overload. В частности, если пользователь пометил продукт как снятый с производства, нам требовалось, чтобы продукт был не единственным, предоставленным поставщиком.Specifically, if the user was marking a product as discontinued, we required that the product not be the only one provided by its supplier. Если это условие нарушено, выдается ApplicationException.If this condition was violated, an ApplicationException was thrown.

Для перегрузки UpdateProduct, созданной в этом руководстве, мы добавим бизнес-правило, запрещающее присвоить UnitPriceному полю новое значение, которое больше, чем в два раза больше исходного значения UnitPrice.For the UpdateProduct overload created in this tutorial, let's add a business rule that prohibits the UnitPrice field from being set to a new value that's more than twice the original UnitPrice value. Для этого измените перегрузку UpdateProduct, чтобы она выполняла эту проверку и выдает исключение ApplicationException при нарушении правила.To accomplish this, adjust the UpdateProduct overload so that it performs this check and throws an ApplicationException if the rule is violated. Обновленный метод выглядит следующим образом:The updated method follows:

public bool UpdateProduct(string productName, decimal? unitPrice, short? unitsInStock,
    int productID)
{
    Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID);
    if (products.Count == 0)
        // no matching record found, return false
        return false;
    Northwind.ProductsRow product = products[0];
    // Make sure the price has not more than doubled
    if (unitPrice != null && !product.IsUnitPriceNull())
        if (unitPrice > product.UnitPrice * 2)
          throw new ApplicationException(
            "When updating a product price," +
            " the new price cannot exceed twice the original price.");
    product.ProductName = productName;
    if (unitPrice == null) product.SetUnitPriceNull();
      else product.UnitPrice = unitPrice.Value;
    if (unitsInStock == null) product.SetUnitsInStockNull();
      else product.UnitsInStock = unitsInStock.Value;
    // Update the product record
    int rowsAffected = Adapter.Update(product);
    // Return true if precisely one row was updated, otherwise false
    return rowsAffected == 1;
}

При таком изменении любое обновление цен, которое больше чем в два раза превышает существующую цену, приведет к появлению ApplicationException.With this change, any price update that is more than twice the existing price will cause an ApplicationException to be thrown. Как и в случае с исключением, вызванным DAL, этот ApplicationException, создаваемый BLL, может быть обнаружен и обработан в обработчике событий RowUpdated GridView.Just like the exception raised from the DAL, this BLL-raised ApplicationException can be detected and handled in the GridView's RowUpdated event handler. На самом деле, код обработчика событий RowUpdated, как написано, будет правильно обнаруживать это исключение и отображать значение свойства Message ApplicationException.In fact, the RowUpdated event handler's code, as written, will correctly detect this exception and display the ApplicationException's Message property value. На рис. 11 показан снимок экрана, когда пользователь пытается обновить цену Chai до $50,00, что превышает его текущую цену $19,95.Figure 11 shows a screen shot when a user attempts to update the price of Chai to $50.00, which is more than double its current price of $19.95.

бизнес-правила не допускать увеличения цены, чем удвоение цены продуктаThe Business Rules Disallow Price Increases That More Than Double a Product's Price

Рис. 11. бизнес-правила не позволяют увеличить цену, превышающую цену продукта в два раза (щелкните, чтобы просмотреть изображение с полным размером).Figure 11: The Business Rules Disallow Price Increases That More Than Double a Product's Price (Click to view full-size image)

Note

В идеале наши правила бизнес-логики будут выделяться из UpdateProduct перегрузок методов и в общий метод.Ideally our business logic rules would be refactored out of the UpdateProduct method overloads and into a common method. Это осталось в качестве упражнения для читателя.This is left as an exercise for the reader.

СводкаSummary

Во время операций вставки, обновления и удаления веб-элемент управления данными и ObjectDataSource вызывают события до и после уровня, Букенд фактическую операцию.During inserting, updating, and deleting operations, both the data Web control and the ObjectDataSource involved fire pre- and post-level events that bookend the actual operation. Как было показано в этом руководстве и предыдущем, при работе с редактируемым элементом управления GridView срабатывает событие RowUpdating GridView, за которым следует событие Updating ObjectDataSource, после чего выполняется команда обновления для базового объекта ObjectDataSource.As we saw in this tutorial and the preceding one, when working with an editable GridView the GridView's RowUpdating event fires, followed by the ObjectDataSource's Updating event, at which point the update command is made to the ObjectDataSource's underlying object. После завершения операции срабатывает событие Updated ObjectDataSource, за которым следует событие RowUpdated GridView.After the operation has completed, the ObjectDataSource's Updated event fires, followed by the GridView's RowUpdated event.

Мы можем создавать обработчики событий для событий предварительного уровня, чтобы настроить входные параметры или события последующей проверки, чтобы проверять результаты операции и реагировать на них.We can create event handlers for the pre-level events in order to customize the input parameters or for the post-level events in order to inspect and respond to the operation's results. Обработчики событий последующей проверки чаще всего используются для определения того, произошло ли исключение во время операции.Post-level event handlers are most commonly used to detect whether an exception occurred during the operation. В случае исключения эти обработчики событий последующей операции могут дополнительно обрабатывали исключение.In the face of an exception, these post-level event handlers can optionally handle the exception on their own. В этом учебнике мы увидели, как справиться с таким исключением, отображая понятное сообщение об ошибке.In this tutorial we saw how to handle such an exception by displaying a friendly error message.

В следующем учебном курсе мы рассмотрим, как уменьшить вероятность исключений, возникающих из-за проблем форматирования данных (например, при вводе отрицательного UnitPrice).In the next tutorial we'll see how to lessen the likelihood of exceptions arising from data formatting issues (such as entering a negative UnitPrice). В частности, мы рассмотрим добавление элементов управления проверки в интерфейсы правки и вставки.Specifically, we'll look at how to add validation controls to the editing and inserting interfaces.

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

Об автореAbout the Author

Скотт Митчелл, автор семи книг по ASP/ASP. NET и основатель 4GuysFromRolla.com, работал с веб-технологиями Майкрософт с 1998.Scott Mitchell, author of seven ASP/ASP.NET books and founder of 4GuysFromRolla.com, has been working with Microsoft Web technologies since 1998. Скотт работает как независимый консультант, преподаватель и модуль записи.Scott works as an independent consultant, trainer, and writer. Его последняя книга — Sams обучать себя ASP.NET 2,0 за 24 часа.His latest book is Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Он доступен по адресу mitchell@4GuysFromRolla.com.He can be reached at mitchell@4GuysFromRolla.com. или через его блог, который можно найти по адресу http://ScottOnWriting.NET.or via his blog, which can be found at http://ScottOnWriting.NET.

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

Эта серия руководств была рассмотрена многими полезными рецензентами.This tutorial series was reviewed by many helpful reviewers. Специалист по интересу для этого руководства был основными рецензентами.Lead reviewer for this tutorial was Liz Shulok. Хотите ознакомиться с моими будущими статьями MSDN?Interested in reviewing my upcoming MSDN articles? Если это так, расположите строку в mitchell@4GuysFromRolla.com.If so, drop me a line at mitchell@4GuysFromRolla.com.