Partilhar via


Manipulando exceções de BLL e DAL-Level (C#)

por Scott Mitchell

Descarregar PDF

Neste tutorial, veremos como lidar com tato com as exceções geradas durante o fluxo de trabalho de atualização de uma DataList editável.

Introdução

No tutorial Visão geral da edição e exclusão de dados no DataList , criamos uma DataList que oferecia recursos simples de edição e exclusão. Embora totalmente funcional, era pouco fácil de usar, pois qualquer erro que ocorresse durante o processo de edição ou exclusão resultava em uma exceção não tratada. Por exemplo, omitir o nome do produto ou, ao editar um produto, inserir um valor de preço de Muito acessível!, gera uma exceção. Como essa exceção não é capturada no código, ela propaga até o runtime do ASP.NET, que exibe os detalhes da exceção na página web.

Como vimos no tutorial Manipulando exceções de BLL e DAL-Level em uma página de ASP.NET , se uma exceção for gerada a partir das profundezas da lógica de negócios ou das camadas de acesso a dados, os detalhes da exceção serão retornados para o ObjectDataSource e, em seguida, para o GridView. Vimos como lidar de forma elegante com essas exceções, criando os manipuladores de eventos Updated ou RowUpdated para o ObjectDataSource ou GridView, verificando se há uma exceção e, em seguida, indicando que a exceção foi tratada.

Nossos tutoriais DataList, no entanto, não estão usando o ObjectDataSource para atualizar e excluir dados. Em vez disso, estamos a trabalhar diretamente contra a BLL. Para detetar exceções originadas da BLL ou DAL, precisamos implementar o código de tratamento de exceções dentro do code-behind de nossa página ASP.NET. Neste tutorial, veremos como lidar com mais tato com as exceções geradas durante um fluxo de trabalho de atualização editável da DataList.

Observação

No tutorial Uma visão geral da edição e exclusão de dados no DataList , discutimos diferentes técnicas para editar e excluir dados da DataList, Algumas técnicas envolvidas no uso de um ObjectDataSource para atualizar e excluir. Se utilizar estas técnicas, poderá lidar com exceções da BLL ou DAL por meio do ObjectDataSource Updated ou Deleted dos manipuladores de eventos.

Etapa 1: Criando uma DataList editável

Antes de nos preocuparmos em lidar com exceções que ocorrem durante o fluxo de trabalho de atualização, vamos primeiro criar uma DataList editável. Abra a ErrorHandling.aspx página na EditDeleteDataList pasta, adicione uma DataList ao Designer, defina sua ID propriedade como Products, e adicione um novo ObjectDataSource chamado ProductsDataSource. Configure o ObjectDataSource para usar o método da classe ProductsBLL para selecionar registos; defina as listas suspensas nas guias INSERT, UPDATE e DELETE como (Nenhum).

Retornar as informações do produto usando o método GetProducts()

Figura 1: Retornar as informações do produto usando o método (GetProducts() imagem em tamanho real)

Depois de concluir o assistente ObjectDataSource, o Visual Studio criará automaticamente um ItemTemplate para a DataList. Substitua por um ItemTemplate que exiba o nome e o preço de cada produto e inclua um botão Editar. Em seguida, crie um EditItemTemplate usando um controlo Web de caixa de texto para nome e preço, bem como botões de Atualizar e Cancelar. Finalmente, defina a propriedade DataList s RepeatColumns como 2.

Após essas alterações, a marcação declarativa da página deve ser semelhante à seguinte. Verifique novamente se os botões Editar, Cancelar e Atualizar têm suas CommandName propriedades definidas como Editar, Cancelar e Atualizar, 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>

Observação

Para este tutorial, o estado de exibição de DataList deve ser habilitado.

Reserve um momento para ver nosso progresso através de um navegador (veja a Figura 2).

Cada produto inclui um botão de edição

Figura 2: Cada produto inclui um botão de edição (Clique para visualizar a imagem em tamanho real)

Atualmente, o botão Editar apenas provoca um postback e ainda não permite editar o produto. Para habilitar a edição, precisamos criar manipuladores de eventos para os eventos DataList s EditCommand, CancelCommand, e UpdateCommand . Os eventos EditCommand e CancelCommand apenas atualizam a propriedade EditItemIndex de DataList e vinculam novamente os dados à 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();
}

O UpdateCommand manipulador de eventos está um pouco mais envolvido. Ele precisa ler o produto editado em ProductID da coleção DataKeys, juntamente com o nome e o preço do produto das TextBoxes em EditItemTemplate, e depois chamar o método em ProductsBLL da classe UpdateProduct antes de retornar o DataList ao seu estado de pré-edição.

Por enquanto, vamos usar exatamente o mesmo código do manipulador de UpdateCommand eventos na Visão geral da edição e exclusão de dados no tutorial DataList . Adicionaremos o código para lidar graciosamente com exceções na etapa 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();
}

Em face de entradas inválidas que podem ser na forma de um preço unitário formatado incorretamente, um valor de preço unitário ilegal como -$ 5,00, ou a omissão do nome do produto, uma exceção será levantada. Como o manipulador de UpdateCommand eventos não inclui nenhum código de tratamento de exceção neste momento, a exceção subirá para o tempo de execução do ASP.NET, onde será exibida ao utilizador final (consulte a Figura 3).

Quando ocorre uma exceção sem tratamento, o usuário final vê uma página de erro

Figura 3: Quando ocorre uma exceção sem tratamento, o usuário final vê uma página de erro

Etapa 2: Tratamento elegante de exceções no manipulador de eventos UpdateCommand

Durante o fluxo de trabalho de atualização, exceções podem ocorrer no manipulador de UpdateCommand eventos, na BLL ou na DAL. Por exemplo, se um usuário inserir um preço de Muito caro, a Decimal.Parse instrução no UpdateCommand manipulador de eventos lançará uma FormatException exceção. Se o usuário omitir o nome do produto ou se o preço tiver um valor negativo, a DAL levantará uma exceção.

Quando ocorre uma exceção, queremos exibir uma mensagem informativa dentro da própria página. Adicione um controlo Web Label à página que tenha ID definido como ExceptionDetails. Configure o texto do Label para ser exibido numa fonte extra grande, vermelha, negrito e itálico, atribuindo a sua própria propriedade à classe CSS CssClass, que está definida no arquivo Warning.

Quando ocorre um erro, queremos que o Rótulo seja exibido apenas uma vez. Ou seja, nos postbacks subsequentes, a mensagem de aviso do Label deve desaparecer. Isso pode ser feito limpando a propriedade Text do Label ou definindo a propriedade Visible para False no manipulador de eventos Page_Load (como fizemos no tutorial Handling BLL- and DAL-Level Exceptions in an ASP.NET Page) ou desativando o suporte ao estado de visualização do Label. Vamos usar a última opção.

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

Quando uma exceção for gerada, atribuiremos os detalhes da exceção à ExceptionDetails propriedade do controle Label Text . Como o seu estado de visualização está desativado, em postbacks subsequentes as alterações programáticas na propriedade Text serão perdidas, revertendo para o texto padrão (uma string vazia), ocultando assim a mensagem de aviso.

Para determinar quando um erro foi gerado para exibir uma mensagem útil na página, precisamos adicionar um Try ... Catch bloco ao UpdateCommand manipulador de eventos. A Try parte contém código que pode levar a uma exceção, enquanto o Catch bloco contém código que é executado em face de uma exceção. Confira a seção Fundamentos de tratamento de exceções na documentação do .NET Framework para obter mais informações sobre o Try ... Catch bloco.

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

Quando uma exceção de qualquer tipo é lançada pelo código dentro do bloco Try, o código no bloco Catch começará a ser executado. O tipo de exceção que é lançada DbException, NoNullAllowedException, ArgumentException, e assim por diante depende do que, exatamente, precipitou o erro em primeiro lugar. Se houver um problema no nível do banco de dados, um DbException será lançado. Se um valor ilegal for inserido para os campos UnitPrice, UnitsInStock, UnitsOnOrder ou ReorderLevel, um ArgumentException será lançado, pois adicionámos código para validar esses valores de campo na classe ProductsDataTable (consulte o tutorial Criando uma camada de lógica de negócios).

Podemos fornecer uma explicação mais útil para o usuário final, baseando o texto da mensagem no tipo de exceção capturada. O código a seguir, que foi usado de forma quase idêntica no tutorial Manipulando exceções de BLL e DAL-Level em uma página ASP.NET , fornece esse nível de detalhes:

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 concluir este tutorial, basta chamar o método DisplayExceptionDetails do bloco Catch passando a instância capturada Exception (ex).

Com o bloqueio em vigor, os usuários recebem uma mensagem de erro mais informativa, como mostram as Try ... Catch Figuras 4 e 5. Observe que, em face de uma exceção, o DataList permanece no modo de edição. Isso ocorre porque, uma vez que a exceção ocorre, o fluxo de controle é imediatamente redirecionado para o Catch bloco, ignorando o código que retorna o DataList ao seu estado de pré-edição.

Uma mensagem de erro é exibida se um usuário omite um campo obrigatório

Figura 4: Uma mensagem de erro é exibida se um usuário omitir um campo obrigatório (Clique para visualizar a imagem em tamanho real)

Uma mensagem de erro é exibida ao inserir um preço negativo

Figura 5: Uma mensagem de erro é exibida ao inserir um preço negativo (Clique para visualizar a imagem em tamanho real)

Resumo

O GridView e o ObjectDataSource fornecem manipuladores de eventos de pós-nível que incluem informações sobre quaisquer exceções que foram geradas durante a atualização e exclusão do fluxo de trabalho, bem como propriedades que podem ser definidas para indicar se a exceção foi ou não manipulada. Esses recursos, no entanto, não estão disponíveis ao trabalhar com a DataList e usar a BLL diretamente. Em vez disso, somos responsáveis pela implementação do tratamento de exceções.

Neste tutorial, vimos como adicionar o tratamento de exceções a um fluxo de trabalho editável de atualização de DataList adicionando um Try ... Catch bloco ao manipulador de UpdateCommand eventos. Se uma exceção for gerada durante o fluxo de trabalho de atualização, o código dentro do bloco Catch será executado, exibindo informações úteis no ExceptionDetails Rótulo.

Neste ponto, o DataList não faz nenhum esforço para evitar que ocorram exceções desde o início. Embora saibamos que um preço negativo resultará em uma exceção, ainda não adicionamos nenhuma funcionalidade para impedir proativamente que um usuário insira essa entrada inválida. Em nosso próximo tutorial, veremos como ajudar a reduzir as exceções causadas pela entrada inválida do usuário adicionando controles de validação no EditItemTemplate.

Feliz Programação!

Leitura adicional

Para obter mais informações sobre os tópicos discutidos neste tutorial, consulte os seguintes recursos:

Sobre o Autor

Scott Mitchell, autor de sete livros sobre ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias Web da Microsoft desde 1998. Scott trabalha como consultor, formador e escritor independente. Seu último livro é Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Ele pode ser contatado em mitchell@4GuysFromRolla.com.

Um agradecimento especial a

Esta série de tutoriais foi revisada por muitos revisores úteis. O revisor principal deste tutorial foi Ken Pespisa. Interessado em rever meus próximos artigos do MSDN? Se for o caso, envie-me uma mensagem para mitchell@4GuysFromRolla.com.