Controlar las excepciones de nivel BLL y DAL (C#)
por Scott Mitchell
En este tutorial, veremos cómo controlar correctamente las excepciones generadas durante un flujo de trabajo de actualización de DataList editable.
Introducción
En la tutorial Introducción a la edición y eliminación de datos en el DataList, creamos una lista de datos que ofrecía funcionalidades de edición y eliminación sencillas. Aunque era totalmente funcional, apenas era fácil de usar, ya que cualquier error que se produjo durante el proceso de edición o eliminación dio lugar a una excepción no controlada. Por ejemplo, omitir el nombre del producto o, al editar un producto, escribir un valor de precio de ¡Muy asequible!, produce una excepción. Dado que esta excepción no se detecta en el código, se propaga hasta el entorno de ejecución de ASP.NET, que a continuación muestra los detalles de la excepción en la página web.
Como vimos en el tutorial Control de excepciones de nivel BLL y DAL en una página de ASP.NET, si se genera una excepción a partir de las profundidades de las capas de lógica de negocios o acceso a datos, los detalles de la excepción se devuelven a ObjectDataSource y a continuación, a GridView. Hemos visto cómo controlar correctamente estas excepciones creando controlador de eventos Updated
o RowUpdated
para ObjectDataSource o GridView, comprobando una excepción y a continuación, indicando que se controló la excepción.
Sin embargo, nuestros tutoriales de DataList no usan ObjectDataSource para actualizar y eliminar datos. En su lugar, estamos trabajando directamente contra el BLL. Para detectar excepciones que se originan en BLL o DAL, es necesario implementar código de control de excepciones en el código subyacente de nuestra página de ASP.NET. En este tutorial, veremos cómo controlar de forma más táctil las excepciones generadas durante un flujo de trabajo de actualización de DataList editable.
Nota:
En el Introducción a la edición y eliminación de datos en el tutorial de DataList analizamos diferentes técnicas para editar y eliminar datos de DataList, algunas técnicas implicadas en el uso de ObjectDataSource para actualizar y eliminar. Si emplea estas técnicas, puede controlar las excepciones de BLL o DAL mediante los controladores de eventos Updated
o Deleted
de ObjectDataSource.
Paso 1: Crear una DataList editable
Antes de preocuparnos por controlar las excepciones que se producen durante el flujo de trabajo de actualización, primero vamos a crear una lista de DataList. Abra la ErrorHandling.aspx
página en la EditDeleteDataList
carpeta, agregue un objeto DataList al Diseñador, establezca su ID
propiedad en Products
, y agregue un nuevo ObjectDataSource denominado ProductsDataSource
. Configure ObjectDataSource para usar el ProductsBLL
método de la clase s GetProducts()
para seleccionar registros; establezca las listas desplegables en las pestañas INSERT, UPDATE y DELETE en (Ninguno).
Figura 1: Devolver la información del producto mediante el método GetProducts()
(Haga clic para ver la imagen de tamaño completo)
Después de completar el asistente ObjectDataSource, Visual Studio creará automáticamente un ItemTemplate
para DataList. Reemplácelo por un ItemTemplate
que muestra el nombre y el precio de cada producto e incluye un botón Editar. A continuación, cree un EditItemTemplate
con un control Web TextBox para los botones Nombre y Precio y Actualizar y Cancelar. Por último, establezca la propiedad RepeatColumns
DataList en 2.
Después de estos cambios, el marcado declarativo de la página debe tener un aspecto similar al siguiente. Compruebe que los botones Editar, Cancelar y Actualizar tienen sus CommandName
propiedades establecidas en Editar, Cancelar y Actualizar, respectivamente.
<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>
Nota:
Para este tutorial, el estado de vista de DataList debe estar habilitado.
Dedique un momento a ver el progreso a través de un explorador (vea la figura 2).
Figura 2: cada producto incluye un botón de edición (hacer clic para ver la imagen de tamaño completo)
Actualmente, el botón Editar solo hace que se pueda editar un postback. Para habilitar la edición, es necesario crear controladores de eventos para los eventos DataList EditCommand
, CancelCommand
y UpdateCommand
. ElEditCommand
evento y CancelCommand
simplemente actualizan la propiedad DataList y EditItemIndex
vuelven a enlazar los datos a 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();
}
El UpdateCommand
controlador de eventos está un poco más implicado. Debe leer en los productos editados ProductID
de la DataKeys
colección junto con el nombre y el precio del producto de los Cuadros de texto de la EditItemTemplate
y, a continuación, llamar al método ProductsBLL
clase s UpdateProduct
antes de devolver DataList a su estado de edición previa.
Por ahora, vamos a usar exactamente el mismo código del UpdateCommand
controlador de eventos en la introducción a la edición y eliminación de datos en el tutorial DataList. Agregaremos el código para controlar correctamente las excepciones en el paso 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();
}
En el caso de una entrada no válida que puede estar en forma de un precio unitario con formato incorrecto, se generará una excepción un valor de precio unitario ilegal como -$5.00 o la omisión del nombre del producto. Dado que el controlador de eventos UpdateCommand
no incluye ningún código de control de excepciones en este momento, la excepción se propagará hasta el entorno de ejecución de ASP.NET, donde se mostrará al usuario final (consulte la figura 3).
Figura 3: Cuando se produce una excepción no controlada, el usuario final ve una página de error
Paso 2: Control correcto de excepciones en el controlador de eventos UpdateCommand
Durante el flujo de trabajo de actualización, se pueden producir excepciones en el UpdateCommand
controlador de eventos, BLL o DAL. Por ejemplo, si un usuario escribe un precio demasiado caro, la Decimal.Parse
instrucción del UpdateCommand
controlador de eventos producirá una FormatException
excepción. Si el usuario omite el nombre del producto o si el precio tiene un valor negativo, DAL generará una excepción.
Cuando se produce una excepción, queremos mostrar un mensaje informativo dentro de la propia página. Agregue un control Web Label a la página cuyaID
valor está establecido en ExceptionDetails
. Configure el texto de la etiqueta para que se muestre en una fuente roja, extra grande, en negrita y cursiva asignando su propiedad CssClass
a la clase CSS de Warning
, que se define en el Styles.css
archivo.
Cuando se produce un error, solo queremos que la etiqueta se muestre una vez. Es decir, en posteriores postbacks, el mensaje de advertencia Etiqueta debe desaparecer. Esto se puede lograr borrando la propiedad etiquetaText
o la configuración de suVisible
propiedadFalse
en el Page_Load
controlador de eventos de (como hicimos en el Control de excepciones de nivel BLL y DAL en un tutorial de ASP.NET Página) o deshabilitando el soporte con el estado de vista de etiqueta. Vamos a usar la última opción.
<asp:Label ID="ExceptionDetails" EnableViewState="False" CssClass="Warning"
runat="server" />
Cuando se produzca una excepción, asignaremos los detalles de la excepción a la ExceptionDetails
propiedad del Text
control de etiqueta. Dado que su estado de vista está deshabilitado, en posteriores postbacks se perderán los cambios mediante programación de la propiedad Text
, volviendo al texto predeterminado (una cadena vacía), ocultando así el mensaje de advertencia.
Para determinar cuándo se ha generado un error para mostrar un mensaje útil en la página, es necesario agregar un Try ... Catch
bloque al controlador de UpdateCommand
eventos. La Try
parte contiene código que puede provocar una excepción, mientras que el Catch
bloque contiene código que se ejecuta ante una excepción. Consulte la sección Aspectos básicos del control de excepciones en la documentación de .NET Framework para obtener más información sobre el Try ... Catch
bloque.
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
}
}
Cuando se produce una excepción de cualquier tipo por código dentro del Try
bloque, el Catch
código del bloque comenzará a ejecutarse. El tipo de excepción que se produce DbException
, NoNullAllowedException
, ArgumentException
, etc. depende de lo que, exactamente, precipita el error en primer lugar. Si hay un problema en el nivel de base de datos, se producirá una DbException
excepción. Si se especifica un valor no válido para los UnitPrice
campos, UnitsInStock
, UnitsOnOrder
o ReorderLevel
, se producirá una ArgumentException
excepción, ya que se ha agregado código para validar estos valores de campo en la ProductsDataTable
clase (consulte el tutorial Creación de una capa lógica de negocios).
Podemos proporcionar una explicación más útil al usuario final si basamos el texto del mensaje en el tipo de excepción detectado. El código siguiente que se usó en un formulario casi idéntico en el Control de excepciones de nivel BLL y DAL en un tutorial de ASP.NET Page proporciona este nivel de detalle:
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;
}
Para completar este tutorial, simplemente llame al DisplayExceptionDetails
método desde el Catch
bloque pasando la instancia detectada Exception
(ex
).
Con el Try ... Catch
bloque en su lugar, los usuarios presentan un mensaje de error más informativo, como se muestra en las figuras 4 y 5. Tenga en cuenta que, en la cara de una excepción, DataList permanece en modo de edición. Esto se debe a que una vez que se produce la excepción, el flujo de control se redirige inmediatamente al Catch
bloque, pasando el código que devuelve DataList a su estado de edición previa.
Figura 4: Se muestra un mensaje de error si un usuario omite un campo obligatorio (haga clic para ver la imagende tamaño completo)
Figura 5: se muestra un mensaje de error al especificar un precio negativo (Haga clic para ver la imagen de tamaño completo)
Resumen
GridView y ObjectDataSource proporcionan controladores de eventos posteriores que incluyen información sobre las excepciones que se generaron durante el flujo de trabajo de actualización y eliminación, así como las propiedades que se pueden establecer para indicar si se ha controlado o no la excepción. Sin embargo, estas características no están disponibles cuando se trabaja con DataList y se usa el BLL directamente. En su lugar, somos responsables de implementar el control de excepciones.
En este tutorial hemos visto cómo agregar el control de excepciones a un flujo de trabajo de actualización de DataList editable agregando un bloque de Try ... Catch
al controlador de eventos UpdateCommand
. Si se produce una excepción durante el flujo de trabajo de actualización, se ejecuta el código del bloque Catch
, mostrando información útil en la etiqueta de ExceptionDetails
.
En este momento, DataList no hace ningún esfuerzo para evitar que se produzcan excepciones en primer lugar. Aunque sabemos que un precio negativo dará lugar a una excepción, aún no hemos agregado ninguna funcionalidad para evitar que un usuario entre en dicha entrada no válida. En nuestro siguiente tutorial veremos cómo ayudar a reducir las excepciones causadas por una entrada de usuario no válida agregando controles de validación en el EditItemTemplate
.
¡Feliz programación!
Lecturas adicionales
Para obtener más información sobre los temas tratados en este tutorial, consulte los siguientes recursos:
- Instrucciones de diseño de excepciones
- Módulos y controladores de registro de errores (ELMAH) (una biblioteca de código abierto para registrar errores)
- Biblioteca empresarial para .NET Framework 2.0 (incluye el bloque de aplicaciones de administración de excepciones)
Acerca del autor
Scott Mitchell, autor de siete libros de ASP/ASP.NET y fundador de 4GuysFromRolla.com, ha estado trabajando con tecnologías web de Microsoft desde 1998. Scott trabaja como consultor independiente, entrenador y escritor. Su último libro es Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Puede llegar a mitchell@4GuysFromRolla.com. o a través de su blog, que se puede encontrar en http://ScottOnWriting.NET.
Agradecimientos especiales a
Esta serie de tutoriales fue revisada por muchos revisores que fueron de gran ayuda. El revisor principal de este tutorial era Ken Pespisa. ¿Le interesaría revisar mis próximos artículos de MSDN? Si es así, escríbame a mitchell@4GuysFromRolla.com.