Partilhar via


Novidades em Web Forms no ASP.NET 4.5

by Equipe de Web Camps

A nova versão do ASP.NET Web Forms apresenta uma série de melhorias focadas em melhorar a experiência do usuário ao trabalhar com dados.

Nas versões anteriores do Web Forms, ao usar a vinculação de dados para emitir o valor de um membro do objeto, você usava as expressões de vinculação de dados Bind() ou Eval(). Na nova versão do ASP.NET, você pode declarar a que tipo de dados um controle será associado usando uma nova propriedade ItemType. Definir essa propriedade permitirá que você use uma variável fortemente tipada para receber todos os benefícios da experiência de desenvolvimento do Visual Studio, como IntelliSense, navegação de membros e verificação em tempo de compilação.

Com os controles associados a dados, agora você também pode especificar seus próprios métodos personalizados para selecionar, atualizar, excluir e inserir dados, simplificando a interação entre os controles de página e a lógica do aplicativo. Além disso, os recursos de associação de modelos foram adicionados ao ASP.NET, o que significa que você pode mapear dados da página diretamente para parâmetros de tipo de método.

A validação da entrada do usuário também deve ser mais fácil com a versão mais recente do Web Forms. Agora você pode anotar suas classes de modelo com atributos de validação do namespace System.ComponentModel.DataAnnotations e solicitar que todos os controles do site validem a entrada do usuário usando essas informações. A validação do lado do cliente em Web Forms agora está integrada ao jQuery, fornecendo código mais limpo do lado do cliente e recursos JavaScript discretos.

Na área de validação de solicitação, foram feitas melhorias para facilitar a desativação seletiva da validação de solicitação para partes específicas de seus aplicativos ou a leitura de dados de solicitação invalidados.

Algumas melhorias foram feitas nos controles do servidor Web Forms para aproveitar os novos recursos do HTML5:

  • A propriedade TextMode do controle TextBox foi atualizada para dar suporte aos novos tipos de entrada HTML5, como email, datetime e assim por diante.
  • O controle FileUpload agora dá suporte a vários uploads de arquivos de navegadores que dão suporte a esse recurso HTML5.
  • Os controles validadores agora dão suporte à validação de elementos de entrada HTML5.
  • Novos elementos HTML5 que têm atributos que representam uma URL agora suportam runat="server". Como resultado, você pode usar convenções de ASP.NET em caminhos de URL, como o operador ~ para representar a raiz do aplicativo (por exemplo, <video runat="server" src="~/myVideo.wmv"></video>).
  • O controle UpdatePanel foi corrigido para dar suporte à postagem de campos de entrada HTML5.

No portal oficial do ASP.NET, você pode encontrar mais exemplos dos novos recursos do ASP.NET WebForms 4.5: Novidades no ASP.NET 4.5 e no Visual Studio 2012

Todos os códigos de exemplo e snippets estão incluídos no Kit de Treinamento do Web Camps.

Objetivos

Neste laboratório prático, você aprenderá a:

  • Usar expressões de associação de dados fortemente tipadas
  • Usar novos recursos de vinculação de modelo em Web Forms
  • Usar provedores de valor para mapear dados de página para métodos code-behind
  • Usar anotações de dados para validação de entrada do usuário
  • Aproveite a validação discreta do lado do cliente com jQuery em Web Forms
  • Implementar validação de solicitação granular
  • Implementar o processamento assíncrono de páginas em Web Forms

Pré-requisitos

Você deve ter os seguintes itens para concluir este laboratório:

Instalação

Instalando trechos de código

Por conveniência, grande parte do código que você gerenciará ao longo deste laboratório está disponível como trechos de código do Visual Studio. Para instalar os snippets de código, execute o arquivo .\Source\Setup\CodeSnippets.vsi .

Se você não estiver familiarizado com os Snippets de Código do Visual Studio e quiser aprender a usá-los, consulte o apêndice deste documento "Apêndice C: Usando Snippets de Código".

Exercícios

Este laboratório prático inclui os seguintes exercícios:

  1. Exercício 1: Associação de modelos em ASP.NET Web Forms
  2. Exercício 2: Validação de dados
  3. Exercício 3: Processamento assíncrono de páginas em ASP.NET Web Forms

Observação

Cada exercício é acompanhado por uma pasta End contendo a solução resultante que você deve obter após concluir os exercícios. Você pode usar esta solução como um guia se precisar de ajuda adicional para trabalhar nos exercícios.

Tempo estimado para concluir este laboratório: 60 minutos.

Exercício 1: Associação de modelos em ASP.NET Web Forms

A nova versão do ASP.NET Web Forms apresenta uma série de aprimoramentos focados em melhorar a experiência ao trabalhar com dados. Ao longo deste exercício, você aprenderá sobre controles de dados fortemente tipados e associação de modelos.

Tarefa 1 – Usando associações de dados fortemente tipadas

Nesta tarefa, você descobrirá as novas associações fortemente tipadas disponíveis no ASP.NET 4.5.

  1. Abra a solução Begin localizada na pasta Source/Ex1-ModelBinding/Begin/ .

    1. Você precisará baixar alguns pacotes NuGet ausentes antes de continuar. Para fazer isso, clique no menu Projeto e selecione Gerenciar Pacotes NuGet.

    2. Na caixa de diálogo Gerenciar Pacotes NuGet, clique em Restaurar para baixar pacotes ausentes.

    3. Por fim, crie a solução clicando em Compilar | Compilar Solução.

      Observação

      Uma das vantagens de usar o NuGet é que você não precisa enviar todas as bibliotecas em seu projeto, reduzindo o tamanho do projeto. Com o NuGet Power Tools, especificando as versões do pacote no arquivo Packages.config, você poderá baixar todas as bibliotecas necessárias na primeira vez que executar o projeto. É por isso que você terá que executar essas etapas depois de abrir uma solução existente neste laboratório.

  2. Abra a página Customers.aspx . Coloque uma lista não numerada no controle principal e inclua um controle repetidor dentro para listar cada cliente. Defina o nome do repetidor como customersRepeater , conforme mostrado no código a seguir.

    Nas versões anteriores do Web Forms, ao usar a vinculação de dados para emitir o valor de um membro em um objeto ao qual você está vinculando dados, você usaria uma expressão de vinculação de dados, juntamente com uma chamada para o método Eval, passando o nome do membro como uma cadeia de caracteres.

    Em tempo de execução, essas chamadas para Eval usarão a reflexão em relação ao objeto associado no momento para ler o valor do membro com o nome fornecido e exibir o resultado no HTML. Essa abordagem facilita muito a associação de dados com dados arbitrários e sem forma.

    Infelizmente, você perde muitos dos excelentes recursos de experiência de tempo de desenvolvimento no Visual Studio, incluindo o IntelliSense para nomes de membros, suporte para navegação (como Ir para Definição) e verificação em tempo de compilação.

    ...
    <asp:Content ID="Content3" ContentPlaceHolderID="MainContent" runat="server">
      <h3>Customers</h3>
      <ul>
        <asp:Repeater ID="customersRepeater" runat="server">
          <ItemTemplate>
                <li>
                    <%# Eval("FirstName") %>
                    <%# Eval("LastName") %>
                </li>
          </ItemTemplate>
        </asp:Repeater>
      </ul>
      <a href="CustomerDetails.aspx">Add a New Customer</a>
    </asp:Content>
    
  3. Abra o arquivo Customers.aspx.cs .

  4. Adicione a seguinte instrução using.

    using System.Linq;
    
  5. No método Page_Load, adicione o código para preencher o repetidor com a lista de clientes.

    (Trecho de código - Web Forms Lab - Ex01 - Vincular fonte de dados de clientes)

    protected void Page_Load(object sender, EventArgs e)
    {
        using (var db = new WebFormsLab.Model.ProductsContext())
        {
            this.customersRepeater.DataSource = db.Customers.ToList();
            this.customersRepeater.DataBind();
        }
    }
    

    A solução usa o EntityFramework junto com o CodeFirst para criar e acessar o banco de dados. No código a seguir, o customersRepeater está associado a uma consulta materializada que retorna todos os clientes do banco de dados.

  6. Pressione F5 para executar a solução e vá para a página Clientes para ver o repetidor em ação. Como a solução está usando o CodeFirst, o banco de dados será criado e preenchido em sua instância local do SQL Express ao executar o aplicativo.

    Listando os clientes com um repetidor

    Listando os clientes com um repetidor

    Observação

    No Visual Studio 2012, o IIS Express é o servidor de desenvolvimento Web padrão.

  7. Feche o navegador e volte para o Visual Studio.

  8. Agora substitua a implementação para usar associações fortemente tipadas. Abra a página Customers.aspx e use o novo atributo ItemType no repetidor para definir o tipo Customer como o tipo de associação.

    <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
      <ul>
        <asp:Repeater ID="customersRepeater" 
                      ItemType="WebFormsLab.Model.Customer" 
                      runat="server">
          <ItemTemplate>
             ...
          </ItemTemplate>
        </asp:Repeater>
      </ul>
      <a href="CustomerDetails.aspx">Add a New Customer</a>
    </asp:Content>
    

    A propriedade ItemType permite que você declare a qual tipo de dados o controle será associado e permite que você use a associação fortemente tipada dentro do controle associado a dados.

  9. Substitua o conteúdo ItemTemplate pelo código a seguir.

    <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
      ...
      <ul>
        <asp:Repeater ID="customersRepeater" ItemType="WebFormsLab.Model.Customer" runat="server">
          <ItemTemplate>
            <li>
              <a href="CustomerDetails.aspx?id=<%#: Item.Id %>">
                <%#: Item.FirstName %> <%#: Item.LastName %>
              </a>
            </li>
          </ItemTemplate>
        </asp:Repeater>
      </ul>
      <a href="CustomerDetails.aspx">Add a New Customer</a>
    </asp:Content>
    

    Uma desvantagem com as abordagens acima é que as chamadas para Eval() e Bind() são associadas tardiamente - o que significa que você passa strings para representar os nomes das propriedades. Isso significa que você não obtém o Intellisense para os nomes de membro, suporte para navegação de código (como Ir para Definição) nem suporte à verificação em tempo de compilação.

    Definir a propriedade ItemType faz com que duas novas variáveis tipadas sejam geradas no escopo das expressões de associação de dados: Item e BindItem. Você pode usar essas variáveis fortemente tipadas nas expressões de associação de dados e obter todos os benefícios da experiência de desenvolvimento do Visual Studio.

    O ": " usado na expressão codificará automaticamente a saída em HTML para evitar problemas de segurança (por exemplo, ataques de script entre sites). Essa notação estava disponível desde o .NET 4 para gravação de resposta, mas agora também está disponível em expressões de associação de dados.

    Observação

    O membro Item funciona para associação unidirecional. Se você quiser executar a associação bidirecional, use o membro BindItem .

    Suporte ao IntelliSense em associação fortemente tipada

    Suporte ao IntelliSense em associação fortemente tipada

  10. Pressione F5 para executar a solução e vá para a página Clientes para garantir que as alterações funcionem conforme o esperado.

    Listando detalhes do cliente

    Listando detalhes do cliente

  11. Feche o navegador e volte para o Visual Studio.

Tarefa 2 – Introdução à vinculação de modelos em Web Forms

Nas versões anteriores do ASP.NET Web Forms, quando você queria executar a vinculação de dados bidirecional, recuperando e atualizando dados, era necessário usar um objeto Fonte de Dados. Pode ser uma fonte de dados de objeto, uma fonte de dados SQL, uma fonte de dados LINQ e assim por diante. No entanto, se o seu cenário exigisse código personalizado para lidar com os dados, você precisaria usar a Fonte de Dados do Objeto e isso trazia algumas desvantagens. Por exemplo, você precisava evitar tipos complexos e lidar com exceções ao executar a lógica de validação.

Na nova versão do ASP.NET Web Forms, os controles associados a dados dão suporte à associação de modelos. Isso significa que você pode especificar métodos select, update, insert e delete diretamente no controle associado a dados para chamar a lógica do arquivo code-behind ou de outra classe.

Para saber mais sobre isso, você usará um GridView para listar as categorias de produto usando o novo atributo SelectMethod . Esse atributo permite que você especifique um método para recuperar os dados do GridView.

  1. Abra a página Products.aspx e inclua um GridView. Configure o GridView conforme mostrado abaixo para usar associações fortemente tipadas e habilitar a classificação e a paginação.

    <asp:Content ID="Content3" ContentPlaceHolderID="MainContent" runat="server">
     <asp:GridView ID="categoriesGrid" runat="server"
        AutoGenerateColumns="false"
        ItemType="WebFormsLab.Model.Category" DataKeyNames="CategoryID">
        <Columns>
          <asp:BoundField DataField="CategoryId" HeaderText="ID" SortExpression="CategoryId" />
          <asp:BoundField DataField="CategoryName" HeaderText="Name" SortExpression="CategoryName" />
          <asp:BoundField DataField="Description" HeaderText="Description" />
          <asp:TemplateField HeaderText="# of Products">
            <ItemTemplate><%#: Item.Products.Count %></ItemTemplate>
          </asp:TemplateField>
        </Columns>
      </asp:GridView>
    </asp:Content>
    
  2. Use o novo atributo SelectMethod para configurar o GridView para chamar um método GetCategories para selecionar os dados.

    <asp:GridView ID="categoriesGrid" runat="server"
        AutoGenerateColumns="false"
        ItemType="WebFormsLab.Model.Category" DataKeyNames="CategoryId"
        SelectMethod="GetCategories">
      <Columns>
        <asp:BoundField DataField="CategoryId" HeaderText="ID" SortExpression="CategoryId" />
        <asp:BoundField DataField="CategoryName" HeaderText="Name" SortExpression="CategoryName" />
        <asp:BoundField DataField="Description" HeaderText="Description" />
        <asp:TemplateField HeaderText="# of Products">
          <ItemTemplate><%#: Item.Products.Count %></ItemTemplate>
        </asp:TemplateField>
      </Columns>
    </asp:GridView>
    
  3. Abra o arquivo code-behind Products.aspx.cs e adicione as seguintes instruções using.

    (Trecho de código - Web Forms Lab - Ex01 - Namespaces)

    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    using System.Linq;
    using WebFormsLab.Model;
    
  4. Adicione um membro privado na classe Products e atribua uma nova instância de ProductsContext. Essa propriedade armazenará o contexto de dados do Entity Framework que permite que você se conecte ao banco de dados.

    public partial class Products : System.Web.UI.Page
    {
        private ProductsContext db = new ProductsContext();
        ...
    
  5. Crie um método GetCategories para recuperar a lista de categorias usando LINQ. A consulta incluirá a propriedade Products para que o GridView possa mostrar a quantidade de produtos para cada categoria. Observe que o método retorna um objeto IQueryable bruto que representa a consulta a ser executada posteriormente no ciclo de vida da página.

    (Trecho de código - Laboratório de Web Forms - Ex01 - GetCategories)

    public IQueryable<Category> GetCategories()
    {
      var query = this.db.Categories
        .Include(c => c.Products);
    
      return query;
    }
    

    Observação

    Nas versões anteriores do ASP.NET Web Forms, habilitar a classificação e a paginação usando sua própria lógica de repositório em um contexto de Fonte de Dados de Objeto era necessário para escrever seu próprio código personalizado e receber todos os parâmetros necessários. Agora, como os métodos de vinculação de dados podem retornar IQueryable e isso representa uma consulta ainda a ser executada, ASP.NET pode se encarregar de modificar a consulta para adicionar os parâmetros de classificação e paginação adequados.

  6. Pressione F5 para iniciar a depuração do site e vá para a página Produtos. Você deve ver que o GridView é preenchido com as categorias retornadas pelo método GetCategories.

    Preenchendo um GridView usando a associação de modelo

    Preenchendo um GridView usando a associação de modelo

  7. Pressione SHIFT+F5 Parar a depuração.

Tarefa 3 – Provedores de valor na associação de modelo

A associação de modelos não apenas permite que você especifique métodos personalizados para trabalhar com seus dados diretamente no controle associado a dados, mas também permite mapear dados da página para parâmetros desses métodos. No parâmetro method, você pode usar atributos do provedor de valor para especificar a fonte de dados do valor. Por exemplo:

  • Controles na página
  • Valores de cadeia de caracteres de consulta
  • Exibir dados
  • Estado de sessão
  • Cookies
  • Dados de formulário lançados
  • Estado da vista
  • Provedores de valor personalizados também são suportados

Se você tiver usado ASP.NET MVC 4, observará que o suporte à associação de modelo é semelhante. Na verdade, esses recursos foram retirados do MVC e movidos para ASP.NET assembly System.Web para poder usá-los também em Web Forms.

Nesta tarefa, você atualizará o GridView para filtrar seus resultados pela quantidade de produtos para cada categoria, recebendo o parâmetro de filtro com associação de modelo.

  1. Volte para a página Products.aspx .

  2. Na parte superior do GridView, adicione um Label e um ComboBox para selecionar o número de produtos para cada categoria, conforme mostrado abaixo.

    <h3>Categories</h3>
    <asp:Label ID="Label1" runat="server" AssociatedControlID="minProductsCount">
         Show categories with at least this number of products:
    </asp:Label>
    <asp:DropDownList runat="server" ID="minProductsCount" AutoPostBack="true">
      <asp:ListItem Value="" Text="-" />
      <asp:ListItem Text="1" />
      <asp:ListItem Text="3" />
      <asp:ListItem Text="5" />
    </asp:DropDownList>
    <br/>
    
  3. Adicione um EmptyDataTemplate ao GridView para mostrar uma mensagem quando não houver categorias com o número selecionado de produtos.

    <asp:GridView ID="categoriesGrid" runat="server"
        AutoGenerateColumns="false"
        ItemType="WebFormsLab.Model.Category" DataKeyNames="CategoryId"
        SelectMethod="GetCategories">
      <Columns>
        <asp:BoundField DataField="CategoryId" HeaderText="ID" />
        <asp:BoundField DataField="CategoryName" HeaderText="Name" />
        <asp:BoundField DataField="Description" HeaderText="Description" />
        <asp:TemplateField HeaderText="# of Products">
          <ItemTemplate><%#: Item.Products.Count %></ItemTemplate>
        </asp:TemplateField>
      </Columns>
      <EmptyDataTemplate>
          No categories found with a product count of <%#: minProductsCount.SelectedValue %>
      </EmptyDataTemplate>
    </asp:GridView>
    
  4. Abra o Products.aspx.cs code-behind e adicione a seguinte instrução using.

    using System.Web.ModelBinding;
    
  5. Modifique o método GetCategories para receber um argumento minProductsCount inteiro e filtre os resultados retornados. Para fazer isso, substitua o método pelo código a seguir.

    (Trecho de código - Laboratório de Formulários Web - Ex01 - GetCategories 2)

    public IQueryable<Category> GetCategories([Control]int? minProductsCount)
    {
        var query = this.db.Categories
        .Include(c => c.Products);
    
        if (minProductsCount.HasValue)
        {
            query = query.Where(c => c.Products.Count >= minProductsCount);
        }
    
        return query;
    }
    

    O novo atributo [Control] no argumento minProductsCount permitirá que ASP.NET saiba que seu valor deve ser preenchido usando um controle na página. ASP.NET procurará qualquer controle que corresponda ao nome do argumento (minProductsCount) e executará o mapeamento e a conversão necessários para preencher o parâmetro com o valor do controle.

    Como alternativa, o atributo fornece um construtor sobrecarregado que permite especificar o controle de onde obter o valor.

    Observação

    Um objetivo dos recursos de vinculação de dados é reduzir a quantidade de código que precisa ser escrito para interação de página. Além do provedor de valor [Control], você pode usar outros provedores de associação de modelo em seus parâmetros de método. Alguns deles estão listados na introdução da tarefa.

  6. Pressione F5 para iniciar a depuração do site e vá para a página Produtos. Selecione vários produtos na lista suspensa e observe como o GridView agora é atualizado.

    Filtrando o GridView com um valor de lista suspensa

    Filtrando o GridView com um valor de lista suspensa

  7. Interrompa a depuração.

Tarefa 4 – Usando a associação de modelos para filtragem

Nesta tarefa, você adicionará um segundo GridView filho para mostrar os produtos dentro da categoria selecionada.

  1. Abra a página Products.aspx e atualize as categorias GridView para gerar automaticamente o botão Selecionar.

    <asp:GridView ID="categoriesGrid" runat="server"
      AutoGenerateColumns="false"
      ItemType="WebFormsLab.Model.Category" DataKeyNames="CategoryId"
      SelectMethod="GetCategories"
      AutoGenerateSelectButton="true">
    
  2. Adicione um segundo GridView chamado productsGrid na parte inferior. Defina o ItemType como WebFormsLab.Model.Product, o DataKeyNames como ProductId e o SelectMethod como GetProducts. Defina AutoGenerateColumns como false e adicione as colunas para ProductId, ProductName, Description e UnitPrice.

    <h3>Products</h3>
    <asp:GridView ID="productsGrid" runat="server" 
        CellPadding="4"
        AutoGenerateColumns="false"
        ItemType="WebFormsLab.Model.Product"
        DataKeyNames="ProductId"
        SelectMethod="GetProducts">
        <Columns>
            <asp:BoundField DataField="ProductId" HeaderText="ID" />
            <asp:BoundField DataField="ProductName" HeaderText="Name" />
            <asp:BoundField DataField="Description" HeaderText="Description" HtmlEncode="false" />
            <asp:BoundField DataField="UnitPrice" HeaderText="Price" />
        </Columns>
        <EmptyDataTemplate>
            Select a category above to see its products
        </EmptyDataTemplate>
    </asp:GridView>
    
  3. Abra o arquivo code-behind Products.aspx.cs . Implemente o método GetProducts para receber a ID da categoria GridView e filtrar os produtos. A associação de modelo definirá o valor do parâmetro usando a linha selecionada no categoriesGrid. Como o nome do argumento e o nome do controle não correspondem, você deve especificar o nome do controle no provedor de valor Control.

    (Trecho de código - Laboratório de Formulários Web - Ex01 - GetProducts)

    public IEnumerable<Product> GetProducts([Control("categoriesGrid")]int? categoryId)
    {
        return this.db.Products.Where(p => p.CategoryId == categoryId);
    }
    

    Observação

    Essa abordagem facilita o teste de unidade desses métodos. Em um contexto de teste de unidade, em que o Web Forms não está em execução, o atributo [Control] não executará nenhuma ação específica.

  4. Abra a página Products.aspx e localize os produtos GridView. Atualize o GridView de produtos para mostrar um link para editar o produto selecionado.

    <h3>Products</h3>
    <asp:GridView ID="productsGrid" runat="server" 
      CellPadding="4"
      AutoGenerateColumns="false"
      ItemType="WebFormsLab.Model.Product"
      DataKeyNames="ProductId"
      SelectMethod="GetProducts">
      <Columns>
        <asp:TemplateField>
          <ItemTemplate>
            <a href="ProductDetails.aspx?productId=<%#: Item.ProductId %>">View</a>
          </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField DataField="ProductId" HeaderText="ID" />
        <asp:BoundField DataField="ProductName" HeaderText="Name" />
        <asp:BoundField DataField="Description" HeaderText="Description" HtmlEncode="false" />
        <asp:BoundField DataField="UnitPrice" HeaderText="Price" />
      </Columns>
      <EmptyDataTemplate>
        Select a category above to see its products
      </EmptyDataTemplate>
    </asp:GridView>
    
  5. Abra o code-behind da página ProductDetails.aspx e substitua o método SelectProduct pelo código a seguir.

    (Trecho de código - Laboratório de Web Forms - Ex01 - Método SelectProduct)

    public Product SelectProduct([QueryString]int? productId)
    {
        return this.db.Products.Find(productId);
    }
    

    Observação

    Observe que o atributo [QueryString] é usado para preencher o parâmetro de método de um parâmetro productId na cadeia de caracteres de consulta.

  6. Pressione F5 para iniciar a depuração do site e vá para a página Produtos. Selecione qualquer categoria das categorias GridView e observe que os produtos GridView são atualizados.

    Mostrando produtos da categoria selecionada

    Mostrando produtos da categoria selecionada

  7. Clique no link Exibir em um produto para abrir a página ProductDetails.aspx.

    Observe que a página está recuperando o produto com o SelectMethod usando o parâmetro productId da cadeia de caracteres de consulta.

    Visualizando os detalhes do produto

    Visualizando os detalhes do produto

    Observação

    A capacidade de digitar uma descrição HTML será implementada no próximo exercício.

Tarefa 5 – Usando a associação de modelo para operações de atualização

Na tarefa anterior, você usou a associação de modelos principalmente para selecionar dados, nesta tarefa você aprenderá a usar a associação de modelos em operações de atualização.

Você atualizará as categorias GridView para permitir que o usuário atualize categorias.

  1. Abra a página Products.aspx e atualize as categorias GridView para gerar automaticamente o botão Editar e use o novo atributo UpdateMethod para especificar um método UpdateCategory para atualizar o item selecionado.

    <asp:GridView ID="categoriesGrid" runat="server"
        AutoGenerateColumns="false"
        ItemType="WebFormsLab.Model.Category" DataKeyNames="CategoryId"
        SelectMethod="GetCategories"
        AutoGenerateSelectButton="true"
        AutoGenerateEditButton="true"
        UpdateMethod="UpdateCategory">
    

    O atributo DataKeyNames no GridView define quais são os membros que identificam exclusivamente o objeto associado ao modelo e, portanto, quais são os parâmetros que o método de atualização deve receber pelo menos.

  2. Abra o arquivo code-behind Products.aspx.cs e implemente o método UpdateCategory . O método deve receber a ID da categoria para carregar a categoria atual, preencher os valores do GridView e atualizar a categoria.

    (Trecho de código - Laboratório de Formulários da Web - Ex01 - UpdateCategory)

    public void UpdateCategory(int categoryId)
    {
        var category = this.db.Categories.Find(categoryId);
    
        this.TryUpdateModel(category);
    
        if (this.ModelState.IsValid)
        {
            this.db.SaveChanges();
        }
    }
    

    O novo método TryUpdateModel na classe Page é responsável por preencher o objeto de modelo usando os valores dos controles na página. Nesse caso, ele substituirá os valores atualizados da linha GridView atual que está sendo editada no objeto de categoria .

    Observação

    O próximo exercício explicará o uso do ModelState.IsValid para validar os dados inseridos pelo usuário ao editar o objeto.

  3. Execute o site e vá para a página Produtos. Edite uma categoria. Digite um novo nome e clique em Atualizar para manter as alterações.

    Editando categorias

    Editando categorias

Exercício 2: Validação de dados

Neste exercício, você aprenderá sobre os novos recursos de validação de dados no ASP.NET 4.5. Você verificará os novos recursos de validação discretos no Web Forms. Você usará anotações de dados nas classes de modelo de aplicativo para validação de entrada do usuário e, por fim, aprenderá a ativar ou desativar a validação de solicitação para controles individuais em uma página.

Tarefa 1 - Validação discreta

Formulários com dados complexos, incluindo validadores, tendem a gerar muito código JavaScript na página, o que pode representar cerca de 60% do código. Com a validação discreta ativada, seu código HTML ficará mais limpo e organizado.

Nesta seção, você habilitará a validação discreta em ASP.NET para comparar o código HTML gerado por ambas as configurações.

  1. Abra o Visual Studio 2012 e abra a solução Begin localizada na pasta Source\Ex2-Validation\Begin deste laboratório. Como alternativa, você pode continuar trabalhando na solução existente do exercício anterior.

    1. Se você abriu a solução Begin fornecida, precisará baixar alguns pacotes NuGet ausentes antes de continuar. Para fazer isso, no Gerenciador de Soluções, clique no projeto WebFormsLab Gerenciar Pacotes NuGet.

    2. Na caixa de diálogo Gerenciar Pacotes NuGet, clique em Restaurar para baixar pacotes ausentes.

    3. Por fim, crie a solução clicando em Compilar | Compilar Solução.

      Observação

      Uma das vantagens de usar o NuGet é que você não precisa enviar todas as bibliotecas em seu projeto, reduzindo o tamanho do projeto. Com o NuGet Power Tools, especificando as versões do pacote no arquivo Packages.config, você poderá baixar todas as bibliotecas necessárias na primeira vez que executar o projeto. É por isso que você terá que executar essas etapas depois de abrir uma solução existente neste laboratório.

  2. Pressione F5 para iniciar o aplicativo Web. Vá para a página Clientes e clique no link Adicionar um novo cliente .

  3. Clique com o botão direito do mouse na página do navegador e selecione a opção Exibir código-fonte para abrir o código HTML gerado pelo aplicativo.

    Mostrando o código HTML da página

    Mostrando o código HTML da página

  4. Percorra o código-fonte da página e observe que ASP.NET injetou código JavaScript e validadores de dados na página para realizar as validações e mostrar a lista de erros.

    Código JavaScript de validação na página CustomerDetails

    Código JavaScript de validação na página CustomerDetails

  5. Feche o navegador e volte para o Visual Studio.

  6. Agora você habilitará a validação discreta. Abra Web.Config e localize a chave ValidationSettings:UnobtrusiveValidationMode na seção AppSettings . Defina o valor da chave como WebForms.

    <configuration>
      ...
      <appSettings>
        <add key="aspnet:uselegacysynchronizationcontext" value="false" />
        <add key="ValidationSettings:UnobtrusiveValidationMode" value="WebForms"/>
    

    Observação

    Você também pode definir essa propriedade no evento "Page_Load" caso queira habilitar a validação discreta apenas para algumas páginas.

  7. Abra CustomerDetails.aspx e pressione F5 para iniciar o aplicativo Web.

  8. Pressione a tecla F12 para abrir as ferramentas de desenvolvedor do IE. Quando as ferramentas do desenvolvedor estiverem abertas, selecione a guia de script. Selecione CustomerDetails.aspx no menu e observe que os scripts necessários para executar o jQuery na página foram carregados no navegador a partir do site local.

    Carregando os arquivos JavaScript do jQuery diretamente do servidor IIS local

    Carregando os arquivos JavaScript do jQuery diretamente do servidor IIS local

  9. Feche o navegador para retornar ao Visual Studio. Abra o arquivo Site.Master novamente e localize o ScriptManager. Adicione a propriedade EnableCdn de atributo com o valor True. Isso forçará o jQuery a ser carregado a partir da URL online, não da URL do site local.

  10. Abra CustomerDetails.aspx no Visual Studio. Pressione a tecla F5 para executar o site. Quando o Internet Explorer abrir, pressione a tecla F12 para abrir as ferramentas de desenvolvedor. Selecione a guia Script e dê uma olhada na lista suspensa. Observe que os arquivos JavaScript do jQuery não estão mais sendo carregados do site local, mas sim do CDN do jQuery online.

    Carregando os arquivos JavaScript do jQuery da CDN

    Carregando os arquivos JavaScript do jQuery da CDN

  11. Abra o código-fonte da página HTML novamente usando a opção Exibir código-fonte no navegador. Observe que, ao habilitar a validação discreta, ASP.NET substituiu o código JavaScript injetado por data- *attributes.

    Código de validação discreto

    Código de validação discreto

    Observação

    Neste exemplo, você viu como um resumo de validação com anotações de dados foi simplificado para apenas algumas linhas HTML e JavaScript. Anteriormente, sem validação discreta, quanto mais controles de validação você adicionar, maior será o seu código de validação JavaScript.

Tarefa 2 – Validando o modelo com anotações de dados

ASP.NET 4.5 introduz a validação de anotações de dados para Web Forms. Em vez de ter um controle de validação em cada entrada, agora você pode definir restrições em suas classes de modelo e usá-las em todo o seu aplicativo Web. Nesta seção, você aprenderá a usar anotações de dados para validar um formulário de cliente novo/editado.

  1. Abra CustomerDetail.aspx página. Observe que o nome e o nome do cliente nas seções EditItemTemplate e InsertItemTemplate são validados usando controles RequiredFieldValidator. Cada validador está associado a uma condição específica, portanto, você precisa incluir tantos validadores quanto as condições a serem verificadas.

  2. Adicione anotações de dados para validar a classe de modelo Customer. Abra Customer.cs classe na pasta Model e decore cada propriedade usando atributos de anotação de dados.

    (Trecho de código - Web Forms Lab - Ex02 - Anotações de Dados)

    namespace WebFormsLab.Model
    {
      using System.Collections.Generic;
      using System.ComponentModel.DataAnnotations;
    
      public class Customer
      {
         [Key]
         public int Id { get; set; }
    
         [Required]
         public string FirstName { get; set; }
    
         [Required]
         public string LastName { get; set; }
    
         [Range(0, 130)]
         public int Age { get; set; }
    
         public Address Address { get; set; }
    
         [Phone]
         public string DaytimePhone { get; set; }
    
         [EmailAddress, StringLength(256)]
         public string EmailAddress { get; set; }
      }
    }
    

    Observação

    O .NET Framework 4.5 estendeu a coleção de anotações de dados existente. Estas são algumas das anotações de dados que você pode usar: [CreditCard], [Phone], [EmailAddress], [Range], [Compare], [Url], [FileExtensions], [Required], [Key], [RegularExpression].

    Alguns exemplos de uso:

    [Chave]: Especifica que um atributo é o identificador exclusivo

    [Range(0.4, 0.5, ErrorMessage="{Escreva uma mensagem de erro}"]: Intervalo duplo

    [EmailAddress(ErrorMessage="Invalid Email"), MaxLength(56)]: duas anotações na mesma linha.

    Você também pode definir suas próprias mensagens de erro dentro de cada atributo.

  3. Abra CustomerDetails.aspx e remova todos os RequiredFieldValidators para os campos de nome e sobrenome nas seções EditItemTemplate e InsertItemTemplate do controle FormView.

    <EditItemTemplate>
      <fieldset>
         <p><asp:Label runat="server" AssociatedControlID="firstName">First Name: </asp:Label></p>
         <p><asp:TextBox runat="server" ID="firstName" Text='<%#: BindItem.FirstName %>' />
            &nbsp;<asp:RequiredFieldValidator runat="server" ControlToValidate="firstName" ErrorMessage="Please enter a value for First Name" ForeColor="Red" />
        </p>
    
         <p><asp:Label runat="server" AssociatedControlID="lastName">Last Name: </asp:Label></p>
         <p><asp:TextBox runat="server" ID="lastName" Text='<%#: BindItem.LastName %>' />
              &nbsp;<asp:RequiredFieldValidator runat="server" ControlToValidate="lastName" ErrorMessage="Please enter a value for Last Name" ForeColor="Red" />
        </p>
      ...
    <InsertItemTemplate>        
     <fieldset>
       <p><asp:Label runat="server" AssociatedControlID="firstName">First Name: </asp:Label></p>
       <p><asp:TextBox runat="server" ID="firstName" Text='<%#: BindItem.FirstName %>' />           
         &nbsp;<asp:RequiredFieldValidator runat="server" ControlToValidate="firstName" ErrorMessage="Please enter a value for First Name" ForeColor="Red" />
        </p>
    
       <p><asp:Label runat="server" AssociatedControlID="lastName">Last Name: </asp:Label></p>                
        <p><asp:TextBox runat="server" ID="lastName" Text='<%#: BindItem.LastName %>' />
         &nbsp;<asp:RequiredFieldValidator runat="server" ControlToValidate="lastName" ErrorMessage="Please enter a value for Last Name" ForeColor="Red" />
        </p>
      ...
    

    Observação

    Uma vantagem de usar anotações de dados é que a lógica de validação não é duplicada nas páginas do aplicativo. Você o define uma vez no modelo e o usa em todas as páginas do aplicativo que manipulam dados.

  4. Abra CustomerDetails.aspx code-behind e localize o método SaveCustomer. Esse método é chamado ao inserir um novo cliente e recebe o parâmetro Customer dos valores de controle FormView. Quando ocorrer o mapeamento entre os controles de página e o objeto de parâmetro, ASP.NET executará a validação do modelo em todos os atributos de anotação de dados e preencherá o dicionário ModelState com os erros encontrados, se houver.

    O ModelState.IsValid só retornará true se todos os campos em seu modelo forem válidos após a execução da validação.

    public void SaveCustomer(Customer customer) 
    {
        if (this.ModelState.IsValid)
        { 
            using (var db = new ProductsContext())
            {
                ...
    
  5. Adicione um controle ValidationSummary no final da página CustomerDetails para mostrar a lista de erros de modelo.

    </fieldset>
        </InsertItemTemplate>
      </asp:FormView>
    
      <asp:ValidationSummary runat="server" ShowModelStateErrors="true" 
           ForeColor="Red" HeaderText="Please check the following errors:"/>
    </asp:Content>
    

    O ShowModelStateErrors é uma nova propriedade no controle ValidationSummary que, quando definido como true, o controle mostrará os erros do dicionário ModelState. Esses erros vêm da validação das anotações de dados.

  6. Pressione F5 para executar o aplicativo Web. Preencha o formulário com alguns valores incorretos e clique em Salvar para executar a validação. Observe o resumo do erro na parte inferior.

    Validação com anotações de dados

    Validação com anotações de dados

Tarefa 3 – Manipulando erros de banco de dados personalizados com ModelState

Na versão anterior do Web Forms, o tratamento de erros de banco de dados, como uma cadeia de caracteres muito longa ou uma violação de chave exclusiva, poderia envolver o lançamento de exceções no código do repositório e, em seguida, o tratamento das exceções no code-behind para exibir um erro. Uma grande quantidade de código é necessária para fazer algo relativamente simples.

No Web Forms 4.5, o objeto ModelState pode ser usado para exibir os erros na página, seja do seu modelo ou do banco de dados, de maneira consistente.

Nesta tarefa, você adicionará código para manipular corretamente as exceções do banco de dados e mostrar a mensagem apropriada ao usuário usando o objeto ModelState.

  1. Enquanto o aplicativo ainda estiver em execução, tente atualizar o nome de uma categoria usando um valor duplicado.

    Atualizando uma categoria com um nome duplicado

    Atualizando uma categoria com um nome duplicado

    Observe que uma exceção é lançada devido à restrição "exclusiva" da coluna CategoryName .

    Exceção para nomes de categoria duplicados

    Exceção para nomes de categoria duplicados

  2. Interrompa a depuração. No arquivo code-behind Products.aspx.cs, atualize o método UpdateCategory para lidar com as exceções geradas pelo banco de dados. SaveChanges() e adicione um erro ao objeto ModelState.

    O novo método TryUpdateModel atualiza o objeto de categoria recuperado do banco de dados usando os dados de formulário fornecidos pelo usuário.

    (Trecho de código - Laboratório de Formulários da Web – Ex02 – Erros de Identificador UpdateCategory)

    public void UpdateCategory(int categoryId)
    {
      var category = this.db.Categories.Find(categoryId);
    
      this.TryUpdateModel(category);
    
      if (this.ModelState.IsValid)
      {
        try
        {
          this.db.SaveChanges();
        }
        catch (DbUpdateException)
        {
          var message = string.Format("A category with the name {0} already exists.", category.CategoryName);
          this.ModelState.AddModelError("CategoryName", message);
        }
      }
    }
    

    Observação

    Idealmente, você teria que identificar a causa do DbUpdateException e verificar se a causa raiz é a violação de uma restrição de chave exclusiva.

  3. Abra Products.aspx e adicione um controle ValidationSummary abaixo das categorias GridView para mostrar a lista de erros de modelo.

    <asp:GridView ID="categoriesGrid" runat="server"
      ...
    </asp:GridView>
    
    <asp:ValidationSummary ID="ValidationSummary1" runat="server" ShowModelStateErrors="true" />
    
    <h3>Products</h3>
    
  4. Execute o site e vá para a página Produtos. Tente atualizar o nome de uma categoria usando um valor duplicado.

    Observe que a exceção foi tratada e a mensagem de erro aparece no controle ValidationSummary .

    Erro de categoria duplicada

    Erro de categoria duplicada

Tarefa 4 – Validação de solicitação no ASP.NET Web Forms 4.5

O recurso de validação de solicitação no ASP.NET fornece um determinado nível de proteção padrão contra ataques de script entre sites (XSS). Nas versões anteriores do ASP.NET, a validação de solicitação era habilitada por padrão e só podia ser desabilitada para uma página inteira. Com a nova versão do ASP.NET Web Forms, agora você pode desabilitar a validação de solicitação para um único controle, executar a validação de solicitação lenta ou acessar dados de solicitação não validados (tenha cuidado se fizer isso!).

  1. Pressione Ctrl+F5 para iniciar o site sem depuração e vá para a página Produtos. Selecione uma categoria e clique no link Editar em qualquer um dos produtos.

  2. Digite uma descrição contendo conteúdo potencialmente perigoso, por exemplo, incluindo tags HTML. Observe a exceção lançada devido à validação da solicitação.

    Editando um produto com conteúdo potencialmente perigoso

    Editando um produto com conteúdo potencialmente perigoso

    Exceção lançada devido à validação da solicitação

    Exceção lançada devido à validação da solicitação

  3. Feche a página e, no Visual Studio, pressione SHIFT+F5 para interromper a depuração.

  4. Abra a página ProductDetails.aspx e localize a Caixa de Texto Descrição .

  5. Adicione a nova propriedade ValidateRequestMode ao TextBox e defina seu valor como Disabled.

    O novo atributo ValidateRequestMode permite desabilitar a validação da solicitação de forma granular em cada controle. Isso é útil quando você deseja usar uma entrada que pode receber código HTML, mas deseja manter a validação funcionando para o restante da página.

    <p>
      <asp:TextBox runat="server" ID="Description" TextMode="MultiLine" 
                Cols="60" Rows="8" Text='<%# BindItem.Description %>' 
        ValidateRequestMode="Disabled" />
    </p>
    
  6. Pressione F5 para executar o aplicativo Web. Abra a página de edição do produto novamente e preencha uma descrição do produto, incluindo tags HTML. Observe que agora você pode adicionar conteúdo HTML à descrição.

    Validação de solicitação desativada para a descrição do produto

    Validação de solicitação desativada para a descrição do produto

    Observação

    Em um aplicativo de produção, você deve limpar o código HTML inserido pelo usuário para garantir que apenas marcas HTML seguras sejam inseridas (por exemplo, não <há marcas de script> ). Para fazer isso, você pode usar a Biblioteca de Proteção da Web da Microsoft.

  7. Edite o produto novamente. Digite o código HTML no campo Nome e clique em Salvar. Observe que a Validação de solicitação só está desabilitada para o campo Descrição e o restante dos campos ainda é validado em relação ao conteúdo potencialmente perigoso.

    Validação de solicitação habilitada no restante dos campos

    Validação de solicitação habilitada no restante dos campos

    ASP.NET Web Forms 4.5 inclui um novo modo de validação de solicitação para executar a validação de solicitação lentamente. Com o modo de validação de solicitação definido como 4.5, se uma parte do código acessar Request.Form["key"], a validação de solicitação do ASP.NET 4.5 disparará apenas a validação de solicitação para esse elemento específico na coleção de formulários.

    Além disso, o ASP.NET 4.5 agora inclui rotinas de codificação principais da Microsoft Anti-XSS Library v4.0. As rotinas de codificação Anti-XSS são implementadas pelo novo tipo AntiXssEncoder encontrado no novo namespace System.Web.Security.AntiXss . Com o parâmetro encoderType configurado para usar AntiXssEncoder, toda a codificação de saída dentro ASP.NET usa automaticamente as novas rotinas de codificação.

  8. ASP.NET validação de solicitação 4.5 também oferece suporte ao acesso não validado aos dados da solicitação. ASP.NET 4.5 adiciona uma nova propriedade de coleção ao objeto HttpRequest chamada Unvalidated. Ao navegar para HttpRequest.Unvalidated , você tem acesso a todas as partes comuns de dados de solicitação, incluindo Forms, QueryStrings, Cookies, URLs e assim por diante.

    Objeto Request.Unvalidated

    Objeto Request.Unvalidated

    Observação

    Use a propriedade HttpRequest.Unvalidated com cuidado! Certifique-se de executar cuidadosamente a validação personalizada nos dados brutos da solicitação para garantir que o texto perigoso não seja devolvido a clientes desavisados!

Exercício 3: Processamento assíncrono de páginas em ASP.NET Web Forms

Neste exercício, você será apresentado aos novos recursos de processamento de página assíncrona em ASP.NET Web Forms.

Tarefa 1 – Atualizando a página de detalhes do produto para carregar e mostrar imagens

Nesta tarefa, você atualizará a página de detalhes do produto para permitir que o usuário especifique uma URL de imagem para o produto e a exiba na exibição somente leitura. Você criará uma cópia local da imagem especificada baixando-a de forma síncrona. Na próxima tarefa, você atualizará essa implementação para fazê-la funcionar de forma assíncrona.

  1. Abra o Visual Studio 2012 e carregue a solução Begin localizada em Source\Ex3-Async\Begin da pasta deste laboratório. Como alternativa, você pode continuar trabalhando na solução existente dos exercícios anteriores.

    1. Se você abriu a solução Begin fornecida, precisará baixar alguns pacotes NuGet ausentes antes de continuar. Para fazer isso, no Gerenciador de Soluções, clique no projeto WebFormsLab e selecione Gerenciar Pacotes NuGet.

    2. Na caixa de diálogo Gerenciar Pacotes NuGet, clique em Restaurar para baixar pacotes ausentes.

    3. Por fim, crie a solução clicando em Compilar | Compilar Solução.

      Observação

      Uma das vantagens de usar o NuGet é que você não precisa enviar todas as bibliotecas em seu projeto, reduzindo o tamanho do projeto. Com o NuGet Power Tools, especificando as versões do pacote no arquivo Packages.config, você poderá baixar todas as bibliotecas necessárias na primeira vez que executar o projeto. É por isso que você terá que executar essas etapas depois de abrir uma solução existente neste laboratório.

  2. Abra a fonte da página ProductDetails.aspx e adicione um campo no ItemTemplate do FormView para mostrar a imagem do produto.

    <ItemTemplate>
         <fieldset>
              <p><b><asp:Label ID="Label2" runat="server" AssociatedControlID="itemProductName">Name:</asp:Label></b></p>
              <p><asp:Label runat="server" ID="itemProductName" Text='<%#: Item.ProductName %>' /></p>
              <p><b><asp:Label ID="Label3" runat="server" AssociatedControlID="itemDescription">Description (HTML):</asp:Label></b></p>
              <p><asp:Label runat="server" ID="itemDescription" Text='<%# Item.Description %>' /></p>
              <p><b><asp:Label ID="Label4" runat="server" AssociatedControlID="itemUnitPrice">Price:</asp:Label></b></p>
              <p><asp:Label runat="server" ID="itemUnitPrice" Text='<%#: Item.UnitPrice %>' /></p>
    
              <p><b><asp:Label ID="Label5" runat="server" AssociatedControlID="itemUnitPrice">Image:</asp:Label></b></p>
              <p>
                    <img src="<%# string.IsNullOrEmpty(Item.ImagePath) ? "/Images/noimage.jpg" : 
                    Item.ImagePath %>" alt="Image" />
              </p>
    
              <br />
              <p>
                    <asp:Button ID="Button1" runat="server" CommandName="Edit" Text="Edit" />&nbsp;
                    <asp:HyperLink NavigateUrl="~/Products.aspx" Text="Back" runat="server" />
              </p>
         </fieldset>
    </ItemTemplate>
    
  3. Adicione um campo para especificar a URL da imagem no EditTemplate do FormView.

    <fieldset>
         <p><asp:Label ID="Label2" runat="server" AssociatedControlID="ProductName">Name:</asp:Label></p>
         <p><asp:TextBox runat="server" ID="ProductName" Text='<%#: BindItem.ProductName %>' /></p>
         <p><asp:Label ID="Label3" runat="server" AssociatedControlID="Description">Description (HTML):</asp:Label></p>
         <p>
              <asp:TextBox runat="server" ID="Description" TextMode="MultiLine" Cols="60" Rows="8" Text='<%# BindItem.Description %>'
                    ValidateRequestMode="Disabled" />
         </p>
         <p><asp:Label ID="Label4" runat="server" AssociatedControlID="UnitPrice">Price:</asp:Label></p>
         <p><asp:TextBox runat="server" ID="UnitPrice" Text='<%#: BindItem.UnitPrice %>' /></p>
    
         <p><asp:Label ID="Label1" runat="server" AssociatedControlID="ImagePath">Image URL:</asp:Label></p>
         <p><asp:TextBox runat="server" ID="ImagePath" Text='<%#:  BindItem.ImagePath %>' /></p>
    
         <br />
         <p>
              <asp:Button runat="server" CommandName="Update" Text="Save" />
              <asp:Button runat="server" CommandName="Cancel" Text="Cancel" CausesValidation="false" />
         </p>
    </fieldset>
    
  4. Abra o arquivo code-behind ProductDetails.aspx.cs e adicione as seguintes diretivas de namespace.

    (Trecho de código - Laboratório de Formulários da Web - Ex03 - Namespaces)

    using System.IO;
    using System.Net;
    using System.Web;
    
  5. Crie um método UpdateProductImage para armazenar imagens remotas na pasta Imagens local e atualize a entidade do produto com o novo valor de local da imagem.

    (Trecho de código - Laboratório de Web Forms - Ex03 - UpdateProductImage)

    private void UpdateProductImage(Product product)
    {
        string imageUrl = product.ImagePath;
    
        if (!string.IsNullOrEmpty(imageUrl) && !VirtualPathUtility.IsAbsolute(imageUrl))
        {
            product.ImagePath = string.Format(
                                     "/Images/{0}{1}", 
                                     product.ProductId, 
                                     Path.GetExtension(imageUrl));
    
            using (var wc = new WebClient())
            {
                wc.DownloadFile(imageUrl, Server.MapPath(product.ImagePath));
            }
        }
    }
    
  6. Atualize o método UpdateProduct para chamar o método UpdateProductImage .

    (Trecho de código - Laboratório de Formulários da Web – Ex03 – Chamada UpdateProductImage)

    public void UpdateProduct(int productId)
    {
        var product = this.db.Products.Find(productId);
    
        this.TryUpdateModel(product);
    
        this.UpdateProductImage(product);
    
        if (this.ModelState.IsValid)
        {
            this.db.SaveChanges();
        }
    }
    
  7. Execute o aplicativo e tente fazer upload de uma imagem para um produto.

    Configurando uma imagem para um produto

    Configurando uma imagem para um produto

Tarefa 2 – Adicionando processamento assíncrono à página de detalhes do produto

Nesta tarefa, você atualizará a página de detalhes do produto para fazê-la funcionar de forma assíncrona. Você aprimorará uma tarefa de longa duração - o processo de download de imagem - usando o processamento de página assíncrono do ASP.NET 4.5.

Métodos assíncronos em aplicativos Web podem ser usados para otimizar a maneira como ASP.NET pools de threads são usados. Em ASP.NET há um número limitado de threads no pool de threads para atender solicitações, portanto, quando todos os threads estão ocupados, ASP.NET começa a rejeitar novas solicitações, envia mensagens de erro do aplicativo e torna seu site indisponível.

Operações demoradas em seu site são ótimas candidatas para programação assíncrona porque ocupam o thread atribuído por um longo tempo. Isso inclui solicitações de longa duração, páginas com muitos elementos diferentes e páginas que exigem operações offline, como consultar um banco de dados ou acessar um servidor Web externo. A vantagem é que, se você usar métodos assíncronos para essas operações, enquanto a página estiver sendo processada, o thread será liberado e retornado ao pool de threads e poderá ser usado para atender a uma nova solicitação de página. Isso significa que a página começará a ser processada em um thread do pool de threads e poderá concluir o processamento em outro, após a conclusão do processamento assíncrono.

  1. Abra a página ProductDetails.aspx . Adicione o atributo Async no elemento Page e defina-o como true. Esse atributo informa ASP.NET para implementar a interface IHttpAsyncHandler .

    <%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true"
        CodeBehind="ProductDetails.aspx.cs" Inherits="WebFormsLab.ProductDetails"
        Async="true" %>
    
  2. Adicione um rótulo na parte inferior da página para mostrar os detalhes dos threads que executam a página.

    <EmptyDataTemplate>Product not found</EmptyDataTemplate>
      </asp:FormView>
    
      <asp:Label ID="threadsMessageLabel" runat="server" />
    </asp:Content>
    
  3. Abra ProductDetails.aspx.cs e adicione as seguintes diretivas de namespace.

    (Trecho de código - Laboratório de Formulários da Web - Ex03 - Namespaces 2)

    using System.Web.UI;
    using System.Threading;
    
  4. Modifique o método UpdateProductImage para baixar a imagem com uma tarefa assíncrona. Você substituirá o método WebClient DownloadFile pelo método DownloadFileTaskAsync e incluirá a palavra-chave await .

    (Trecho de código - Laboratório de Formulários da Web – Ex03 – UpdateProductImage Async)

    private void UpdateProductImage(Product product)
    {
        string imageUrl = product.ImagePath;
    
        if (!string.IsNullOrEmpty(imageUrl) && !VirtualPathUtility.IsAbsolute(imageUrl))
        {
            product.ImagePath = string.Format(
                "/Images/{0}{1}", 
                product.ProductId, 
                Path.GetExtension(imageUrl));
    
            this.RegisterAsyncTask(new PageAsyncTask(async (t) =>
            {
                using (var wc = new WebClient())
                {
                    await wc.DownloadFileTaskAsync(imageUrl, this.Server.MapPath(product.ImagePath));
                }
            }));
        }
    }
    

    O RegisterAsyncTask registra uma nova tarefa assíncrona de página a ser executada em um thread diferente. Ele recebe uma expressão lambda com a Tarefa (t) a ser executada. A palavra-chave await no método DownloadFileTaskAsync converte o restante do método em um retorno de chamada que é invocado de forma assíncrona após a conclusão do método DownloadFileTaskAsync . ASP.NET retomará a execução do método mantendo automaticamente todos os valores originais da solicitação HTTP. O novo modelo de programação assíncrona no .NET 4.5 permite que você escreva código assíncrono que se parece muito com o código síncrono e permita que o compilador lide com as complicações das funções de retorno de chamada ou do código de continuação.

    Observação

    RegisterAsyncTask e PageAsyncTask já estavam disponíveis desde o .NET 2.0. A palavra-chave await é nova do modelo de programação assíncrona do .NET 4.5 e pode ser usada junto com os novos métodos TaskAsync do objeto WebClient do .NET.

  5. Adicione código para exibir os threads nos quais o código foi iniciado e terminou de ser executado. Para fazer isso, atualize o método UpdateProductImage com o código a seguir.

    (Trecho de código - Web Forms Lab - Ex03 - Mostrar threads)

    private void UpdateProductImage(Product product)
    {
      string imageUrl = product.ImagePath;
    
      if (!string.IsNullOrEmpty(imageUrl) && !VirtualPathUtility.IsAbsolute(imageUrl))
      {
        product.ImagePath = string.Format(
             "/Images/{0}{1}", 
             product.ProductId, 
             Path.GetExtension(imageUrl));
    
        this.RegisterAsyncTask(new PageAsyncTask(async (t) =>
        {
          var startThread = Thread.CurrentThread.ManagedThreadId;
    
          using (var wc = new WebClient())
          {
            await wc.DownloadFileTaskAsync(imageUrl, this.Server.MapPath(product.ImagePath));
          }
    
          var endThread = Thread.CurrentThread.ManagedThreadId;
    
          this.threadsMessageLabel.Text = string.Format("Started on thread: {0}<br /> Finished on thread: {1}", startThread, endThread);
        }));
      }
    }
    
  6. Abra o arquivo Web.config do site. Adicione a variável appSetting a seguir.

    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
    
  7. Pressione F5 para executar o aplicativo e fazer upload de uma imagem para o produto. Observe que a ID de threads em que o código começou e terminou pode ser diferente. Isso ocorre porque as tarefas assíncronas são executadas em um thread separado de ASP.NET pool de threads. Quando a tarefa for concluída, ASP.NET colocará a tarefa de volta na fila e atribuirá qualquer um dos threads disponíveis.

    Baixando uma imagem de forma assíncrona

    Baixando uma imagem de forma assíncrona

Observação

Além disso, você pode implantar esse aplicativo no Azure seguindo o Apêndice B: Publicando um aplicativo MVC 4 ASP.NET usando a Implantação da Web.


Resumo

Neste laboratório prático, os seguintes conceitos foram abordados e demonstrados:

  • Usar expressões de associação de dados fortemente tipadas
  • Usar novos recursos de vinculação de modelo em Web Forms
  • Usar provedores de valor para mapear dados de página para métodos code-behind
  • Usar anotações de dados para validação de entrada do usuário
  • Aproveite a validação discreta do lado do cliente com jQuery em Web Forms
  • Implementar validação de solicitação granular
  • Implementar o processamento assíncrono de páginas em Web Forms

Apêndice A: Instalando o Visual Studio Express 2012 para Web

Você pode instalar o Microsoft Visual Studio Express 2012 para Web ou outra versão "Express" usando o Microsoft Web Platform Installer. As instruções a seguir orientam você pelas etapas necessárias para instalar o Visual Studio Express 2012 para Web usando o Microsoft Web Platform Installer.

  1. Vá para [https://go.microsoft.com/?linkid=9810169](https://go.microsoft.com/?linkid=9810169). Como alternativa, se você já tiver instalado o Web Platform Installer, poderá abri-lo e pesquisar o produto "Visual Studio Express 2012 para Web com SDK do Azure".

  2. Clique em Instalar agora. Se você não tiver o Web Platform Installer , será redirecionado para baixá-lo e instalá-lo primeiro.

  3. Quando o Web Platform Installer estiver aberto, clique em Instalar para iniciar a configuração.

    Instalar o Visual Studio Express

    Instalar o Visual Studio Express

  4. Leia todas as licenças e termos dos produtos e clique em Aceito para continuar.

    Aceitando os termos da licença

    Aceitando os termos da licença

  5. Aguarde até que o processo de download e instalação seja concluído.

    Andamento da instalação

    Progresso da instalação

  6. Quando a instalação for concluída, clique em Concluir.

    Instalação concluída

    Instalação concluída

  7. Clique em Sair para fechar o Web Platform Installer.

  8. Para abrir o Visual Studio Express para Web, vá para a tela Iniciar e comece a escrever "VS Express" e clique no bloco VS Express para Web .

    Bloco do VS Express para Web

    Bloco do VS Express para Web

Apêndice B: Publicando um aplicativo MVC 4 do ASP.NET usando a Implantação da Web

Este apêndice mostrará como criar um novo site no Portal do Azure e publicar o aplicativo obtido seguindo o laboratório, aproveitando o recurso de publicação de Implantação da Web fornecido pelo Azure.

Tarefa 1 – Criando um novo site no Portal do Azure

  1. Acesse o Portal de Gerenciamento do Azure e entre usando as credenciais da Microsoft associadas à sua assinatura.

    Observação

    Com o Azure, você pode hospedar 10 ASP.NET sites gratuitamente e, em seguida, dimensionar à medida que o tráfego cresce. Você pode se inscrever aqui.

    Fazer logon no portal do Windows Azure

    Faça logon no Portal

  2. Clique em Novo na barra de comandos.

    Criando um novo site

    Criando um novo site

  3. Clique em Site de Computação | . Em seguida, selecione a opção Criação rápida. Forneça uma URL disponível para o novo site e clique em Criar Site.

    Observação

    O Azure é o host de um aplicativo Web em execução na nuvem que você pode controlar e gerenciar. A opção Criação Rápida permite que você implante um aplicativo Web concluído no Azure de fora do portal. Ele não inclui etapas para configurar um banco de dados.

    Criando um novo site usando a Criação rápida

    Criando um novo site usando a Criação rápida

  4. Aguarde até que o novo site seja criado.

  5. Depois que o site for criado, clique no link na coluna URL . Verifique se o novo site está funcionando.

    Navegando para o novo site

    Navegando para o novo site

    Site em execução

    Site em execução

  6. Volte para o portal e clique no nome do site na coluna Nome para exibir as páginas de gerenciamento.

    Abrindo as páginas de gerenciamento do site

    Abrindo as páginas de gerenciamento do site

  7. Na página Painel, na seção de visão rápida, clique no link Baixar perfil de publicação.

    Observação

    O perfil de publicação contém todas as informações necessárias para publicar um aplicativo Web no Azure para cada método de publicação habilitado. O perfil de publicação contém as URLs, as credenciais de usuário e as cadeias de caracteres de banco de dados necessárias para se conectar e autenticar em cada um dos pontos de extremidade para os quais um método de publicação está habilitado. O Microsoft WebMatrix 2, o Microsoft Visual Studio Express for Web e o Microsoft Visual Studio 2012 dão suporte à leitura de perfis de publicação para automatizar a configuração desses programas para publicar aplicativos Web no Azure.

    Baixando o perfil de publicação do site

    Baixando o perfil de publicação do site

  8. Baixe o arquivo de perfil de publicação em um local conhecido. Mais adiante neste exercício, você verá como usar esse arquivo para publicar um aplicativo Web no Azure do Visual Studio.

    Salvando o arquivo de perfil de publicação

    Salvando o arquivo de perfil de publicação

Tarefa 2 – Configurando o servidor de banco de dados

Se o seu aplicativo usar bancos de dados do SQL Server, você precisará criar um servidor do Banco de Dados SQL. Se você quiser implantar um aplicativo simples que não usa o SQL Server, ignore essa tarefa.

  1. Você precisará de um servidor de Banco de Dados SQL para armazenar o banco de dados do aplicativo. Você pode exibir os servidores do Banco de Dados SQL de sua assinatura no Portal de Gerenciamento do Azure no Painel do Servidor de Servidores | de Bancos de Dados | SQL. Se você não tiver um servidor criado, poderá criar um usando o botão Adicionar na barra de comandos. Anote o nome e a URL do servidor, o nome de login e a senha do administrador, pois você os usará nas próximas tarefas. Não crie o banco de dados ainda, pois ele será criado em um estágio posterior.

    Painel do Servidor do Banco de Dados SQL

    Painel do Servidor do Banco de Dados SQL

  2. Na próxima tarefa, você testará a conexão do banco de dados do Visual Studio, por esse motivo, você precisa incluir seu endereço IP local na lista de endereços IP permitidos do servidor. Para fazer isso, clique em Configurar, selecione o endereço IP do endereço IP do cliente atual e cole-o nas caixas de texto Endereço IP inicial e Endereço IP final e clique no botão adicionar endereço IP do cliente botão.

    Adicionando o endereço IP do cliente

    Adicionando o endereço IP do cliente

  3. Depois que o endereço IP do cliente for adicionado à lista de endereços IP permitidos, clique em Salvar para confirmar as alterações.

    Confirmar alterações

    Confirmar alterações

Tarefa 3 – Publicando um aplicativo MVC 4 ASP.NET usando a Implantação da Web

  1. Volte para a solução MVC 4 ASP.NET. No Gerenciador de Soluções, clique com o botão direito do mouse no projeto de site e selecione Publicar.

    Publicando o aplicativo

    Publicando o site

  2. Importe o perfil de publicação que você salvou na primeira tarefa.

    Importando o perfil de publicação

    Importando o perfil de publicação

  3. Clique em Validar conexão. Quando a validação estiver concluída, clique em Avançar.

    Observação

    A validação é concluída quando você vê uma marca de seleção verde ao lado do botão Validar conexão.

    Validando conexão

    Validando conexão

  4. Na página Configurações, na seção Bancos de dados, clique no botão ao lado da caixa de texto da conexão com o banco de dados (ou seja, DefaultConnection).

    Configuração de implantação da Web

    Configuração de implantação da Web

  5. Configure a conexão do banco de dados da seguinte maneira:

    • No Nome do servidor, digite a URL do servidor do Banco de Dados SQL usando o prefixo tcp:.

    • Em Nome de usuário, digite o nome de logon do administrador do servidor.

    • Em Senha , digite sua senha de login de administrador do servidor.

    • Digite um novo nome de banco de dados.

      Configurando a cadeia de conexão de destino

      Configurando a cadeia de conexão de destino

  6. Em seguida, clique em OK. Quando solicitado a criar o banco de dados, clique em Sim.

    Criando o banco de dados

    Criando o banco de dados

  7. A cadeia de conexão que você usará para se conectar ao Banco de Dados SQL no Azure é mostrada na caixa de texto Conexão Padrão. Em seguida, clique em Próximo.

    Cadeia de conexão apontando para o Banco de Dados SQL

    Cadeia de conexão apontando para o Banco de Dados SQL

  8. Na página Visualização, clique em Publicar.

    Publicando o aplicativo Web

    Publicando o aplicativo Web

  9. Quando o processo de publicação terminar, seu navegador padrão abrirá o site publicado.

Apêndice C: Usando snippets de código

Com snippets de código, você tem todo o código de que precisa ao seu alcance. O documento de laboratório informará exatamente quando você pode usá-los, conforme mostrado na figura a seguir.

Usando trechos de código do Visual Studio para inserir código em seu projeto

Usando trechos de código do Visual Studio para inserir código em seu projeto

Para adicionar um snippet de código usando o teclado (somente C#)

  1. Coloque o cursor onde deseja inserir o código.
  2. Comece a digitar o nome do snippet (sem espaços ou hífens).
  3. Veja como o IntelliSense exibe os nomes dos snippets correspondentes.
  4. Selecione o snippet correto (ou continue digitando até que o nome do snippet inteiro seja selecionado).
  5. Pressione a tecla Tab duas vezes para inserir o snippet no local do cursor.

Comece a digitar o nome do snippet

Comece a digitar o nome do snippet

Pressione Tab para selecionar o snippet destacado

Pressione Tab para selecionar o snippet destacado

Pressione Tab novamente e o snippet será expandido

Pressione Tab novamente e o snippet será expandido

Para adicionar um snippet de código usando o mouse (C#, Visual Basic e XML) 1. Clique com o botão direito do mouse onde deseja inserir o snippet de código.

  1. Selecione Inserir Snippet seguido de Meus Snippets de Código.
  2. Escolha o snippet relevante da lista, clicando nele.

Clique com o botão direito do mouse onde deseja inserir o snippet de código e selecione Inserir snippet

Clique com o botão direito do mouse onde deseja inserir o snippet de código e selecione Inserir snippet

Escolha o snippet relevante da lista, clicando nele

Escolha o snippet relevante da lista, clicando nele