Novedades de los formularios Web Forms en ASP.NET 4.5

por el equipo de Web Camps

La nueva versión de ASP.NET Web Forms presenta una serie de mejoras centradas en mejorar la experiencia del usuario al trabajar con datos.

En versiones anteriores de Web Forms, al usar el enlace de datos para emitir el valor de un miembro de objeto, usó las expresiones de enlace de datos Bind() o Eval(). En la nueva versión de ASP.NET, puede declarar a qué tipo de datos se va a enlazar un control mediante una nueva propiedad ItemType. Establecer esta propiedad le permitirá usar una variable fuertemente tipada para recibir las ventajas completas de la experiencia de desarrollo de Visual Studio, como IntelliSense, navegación de miembros y comprobación en tiempo de compilación.

Con los controles enlazados a datos, ahora también puede especificar sus propios métodos personalizados para seleccionar, actualizar, eliminar e insertar datos, simplificando la interacción entre los controles de página y la lógica de la aplicación. Además, se han agregado funcionalidades de enlace de modelos a ASP.NET, lo que significa que puede asignar datos de la página directamente a parámetros de tipo de método.

La validación de la entrada del usuario también debe ser más fácil con la versión más reciente de Web Forms. Ahora puede anotar las clases de modelo con atributos de validación de los System.ComponentModel.DataAnnotations espacio de nombres y solicitar que todos los controles de sitio validen la entrada del usuario con esa información. La validación del lado cliente en formularios Web Forms ahora se integra con jQuery, lo que proporciona código de cliente más limpio y características de JavaScript discretas.

En el área de validación de solicitudes, se han realizado mejoras para facilitar la desactivación selectiva de la validación de solicitudes para partes específicas de las aplicaciones o leer datos de solicitud invalidados.

Se han realizado algunas mejoras en los controles de servidor de Web Forms para aprovechar las nuevas características de HTML5:

  • La propiedad TextMode del control TextBox se ha actualizado para admitir los nuevos tipos de entrada HTML5, como correo electrónico, fecha y hora, etc.
  • El control FileUpload ahora admite varias cargas de archivos desde exploradores que admiten esta característica HTML5.
  • Los controles de validador ahora admiten la validación de elementos de entrada HTML5.
  • Nuevos elementos HTML5 que tienen atributos que representan una dirección URL ahora admiten runat="server". Como resultado, puede usar convenciones de ASP.NET en rutas de dirección URL, como el operador ~ para representar la raíz de la aplicación (por ejemplo, <video runat="server" src="~/myVideo.wmv"></video>).
  • El control UpdatePanel se ha corregido para admitir la publicación de campos de entrada HTML5.

En el portal oficial de ASP.NET puede encontrar más ejemplos de las nuevas características de ASP.NET WebForms 4.5: Novedades de ASP.NET 4.5 y Visual Studio 2012

Todos los fragmentos de código y código de ejemplo se incluyen en el kit de entrenamiento de Web Camps.

Objetivos

En este laboratorio práctico, aprenderá a:

  • Uso de expresiones de enlace de datos fuertemente tipadas
  • Uso de nuevas características de enlace de modelos en formularios Web Forms
  • Usar proveedores de valores para asignar datos de página a métodos de código subyacente
  • Uso de anotaciones de datos para la validación de entrada del usuario
  • Aproveche las ventajas de la validación discreta del lado cliente con jQuery en formularios Web Forms
  • Implementación de la validación de solicitudes pormenorizadas
  • Implementación del procesamiento asincrónico de páginas en formularios Web Forms

Requisitos previos

Debe tener los siguientes elementos para completar este laboratorio:

Configuración

Instalación de fragmentos de código

Para mayor comodidad, gran parte del código que va a administrar a lo largo de este laboratorio está disponible como fragmentos de código de Visual Studio. Para instalar los fragmentos de código, ejecute archivo.\Source\Setup\CodeSnippets.vsi.

Si no está familiarizado con los fragmentos de código de Visual Studio Code y quiere obtener información sobre cómo usarlos, puede consultar el apéndice de este documento "Apéndice C: Usar fragmentos de código".

Ejercicios

Este laboratorio práctico incluye los siguientes ejercicios:

  1. Ejercicio 1: Enlace de modelos en ASP.NET Web Forms
  2. Ejercicio 2: Validación de datos
  3. Ejercicio 3: Procesamiento asincrónico de páginas en ASP.NET Web Forms

Nota:

Cada ejercicio va acompañado de una carpeta End que contiene la solución resultante que debe obtener después de completar los ejercicios. Puede usar esta solución como guía si necesita ayuda adicional para trabajar con los ejercicios.

Tiempo estimado para completar este laboratorio: 60 minutos.

Ejercicio 1: Enlace de modelos en ASP.NET Web Forms

La nueva versión de ASP.NET Web Forms presenta una serie de mejoras centradas en mejorar la experiencia al trabajar con datos. En este ejercicio, obtendrá información sobre los controles de datos fuertemente tipados y el enlace de modelos.

Tarea 1: Usar enlaces de datos fuertemente tipados

En esta tarea, detectará los nuevos enlaces fuertemente tipados disponibles en ASP.NET 4.5.

  1. Abra la solución Begin ubicada en carpeta Source/Ex1-ModelBinding/Begin/.

    1. Tendrá que descargar algunos paquetes NuGet que faltan antes de continuar. Para ello, haga clic en el menú Proyecto y seleccione Administrar paquetes NuGet.

    2. En el cuadro de diálogo Administrar paquetes NuGet, haga clic en Restaurar para descargar los paquetes que faltan.

    3. Por último, para compilar la solución, haga clic en Compilar | solución de compilación.

      Nota:

      Una de las ventajas de usar NuGet es que no es necesario enviar todas las bibliotecas del proyecto, lo que reduce el tamaño del proyecto. Con NuGet Power Tools, especificando las versiones del paquete en el archivo Packages.config, podrá descargar todas las bibliotecas necesarias la primera vez que ejecute el proyecto. Este es el motivo por el que tendrá que ejecutar estos pasos después de abrir una solución existente desde este laboratorio.

  2. Abra la página Customers.aspx. Coloque una lista sin numerar en el control principal e incluya un control repetidor dentro para enumerar cada cliente. Establezca el nombre del repetidor en customersRepeater tal como se muestra en el código siguiente.

    En versiones anteriores de formularios Web Forms, al usar el enlace de datos para emitir el valor de un miembro en un objeto al que está enlazando datos, usaría una expresión de enlace de datos, junto con una llamada al método Eval, pasando el nombre del miembro como una cadena.

    En tiempo de ejecución, estas llamadas a Eval usarán la reflexión en el objeto enlazado actualmente para leer el valor del miembro con el nombre especificado y mostrarán el resultado en el HTML. Este enfoque facilita el enlace de datos con datos arbitrarios y sin formato.

    Desafortunadamente, pierde muchas de las excelentes características de experiencia en tiempo de desarrollo en Visual Studio, incluido IntelliSense para nombres de miembro, compatibilidad con la navegación (como Ir a definición) y comprobación en tiempo de compilación.

    ...
    <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 el archivo Customers.aspx.cs.

  4. Agregue la siguiente instrucción using.

    using System.Linq;
    
  5. En el método Page_Load, agregue código para rellenar el repetidor con la lista de clientes.

    (Fragmento de código: Laboratorio de formularios Web Forms: Ex01: enlazar orígenes de datos 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();
        }
    }
    

    La solución usa EntityFramework junto con CodeFirst para crear y acceder a la base de datos. En el código siguiente, customersRepeater está enlazado a una consulta materializada que devuelve todos los clientes de la base de datos.

  6. Presione F5 para ejecutar la solución y vaya a la página Clientes para ver el repetidor en acción. A medida que la solución usa CodeFirst, la base de datos se creará y rellenará en la instancia local de SQL Express al ejecutar la aplicación.

    Listing the customers with a repeater

    Enumeración de los clientes con un repetidor

    Nota:

    En Visual Studio 2012, IIS Express es el servidor de desarrollo web predeterminado.

  7. Cierre el explorador y vuelva a Visual Studio.

  8. Ahora reemplace la implementación para usar enlaces fuertemente tipados. Abra la página Customers.aspx y use el nuevo atributo ItemType en el repetidor para establecer el tipo de Customer como tipo de enlace.

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

    La propiedad ItemType permite declarar a qué tipo de datos se va a enlazar el control y permite usar enlaces fuertemente tipados dentro del control enlazado a datos.

  9. Reemplace el contenido ItemTemplate por el código siguiente.

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

    Una desventaja de los enfoques anteriores es que las llamadas a Eval() y Bind() están enlazadas en tiempo de ejecución, lo que significa que se pasan cadenas para representar los nombres de propiedad. Esto significa que no obtiene IntelliSense para los nombres de miembro, compatibilidad con la navegación de código (por ejemplo, Ir a definición) ni la compatibilidad con la comprobación en tiempo de compilación.

    Establecer la propiedad ItemType hace que se generen dos nuevas variables con tipo en el ámbito de las expresiones de enlace de datos: Item y BindItem. Puede usar estas variables fuertemente tipadas en las expresiones de enlace de datos y obtener las ventajas completas de la experiencia de desarrollo de Visual Studio.

    La ": " que se usa en la expresión codificará automáticamente la salida para evitar problemas de seguridad (por ejemplo, ataques de scripting entre sitios). Esta notación estaba disponible desde .NET 4 para la escritura de respuestas, pero ahora también está disponible en expresiones de enlace de datos.

    Nota:

    El miembro Item funciona para el enlace unidireccional. Si desea realizar un enlace bidireccional, use el miembro BindItem.

    IntelliSense support in strongly-typed binding

    Compatibilidad con IntelliSense en enlaces fuertemente tipados

  10. Presione F5 para ejecutar la solución y vaya a la página Clientes para asegurarse de que los cambios funcionan según lo previsto.

    Listing customer details

    Enumerar los detalles del cliente

  11. Cierre el explorador y vuelva a Visual Studio.

Tarea 2: Introducción al enlace de modelos en formularios Web Forms

En versiones anteriores de ASP.NET Web Forms, cuando quería realizar un enlace de datos bidireccional, tanto recuperando como actualizando datos, necesitaba usar un objeto de origen de datos. Esto podría ser un origen de datos de objeto, un origen de datos SQL, un origen de datos LINQ, etc. Sin embargo, si el escenario requería código personalizado para controlar los datos, necesitaba usar el origen de datos del objeto y esto trajo algunas desventajas. Por ejemplo, necesitaba evitar tipos complejos y necesitaba controlar las excepciones al ejecutar la lógica de validación.

En la nueva versión de ASP.NET Web Forms, los controles enlazados a datos admiten el enlace de modelos. Esto significa que puede especificar métodos de selección, actualizar, insertar y eliminar directamente en el control enlazado a datos para llamar a lógica desde el archivo de código subyacente o desde otra clase.

Para obtener información sobre esto, usará una clase GridView para enumerar las categorías de productos mediante el nuevo atributo SelectMethod. Este atributo permite especificar un método para recuperar los datos de GridView.

  1. Abra la página de Products.aspx e incluya un GridView. Configure GridView como se muestra a continuación para usar enlaces fuertemente tipados y habilitar la ordenación y la paginación.

    <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 el nuevo atributo SelectMethod para configurar GridView para llamar a un método GetCategories para seleccionar los datos.

    <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 el archivo Products.aspx.cs código subyacente y agregue las siguientes instrucciones using.

    (Fragmento de código: Laboratorio de Formularios Web Forms - Ex01 - Espacios de nombres)

    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    using System.Linq;
    using WebFormsLab.Model;
    
  4. Agregue un miembro privado en la clase Products y asigne una nueva instancia de ProductsContext. Esta propiedad almacenará el contexto de datos de Entity Framework que le permite conectarse a la base de datos.

    public partial class Products : System.Web.UI.Page
    {
        private ProductsContext db = new ProductsContext();
        ...
    
  5. Cree un método GetCategories para recuperar la lista de categorías mediante LINQ. La consulta incluirá la propiedad Products para que GridView pueda mostrar la cantidad de productos de cada categoría. Observe que el método devuelve un objeto IQueryable sin procesar que representa la consulta que se va a ejecutar más adelante en el ciclo de vida de la página.

    (Fragmento de código: Laboratorio de formularios Web Forms - Ex01 - GetCategories)

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

    Nota:

    En versiones anteriores de ASP.NET Web Forms, habilitando la ordenación y paginación mediante su propia lógica de repositorio dentro de un contexto de origen de datos de objeto, necesario para escribir su propio código personalizado y recibir todos los parámetros necesarios. Ahora, como los métodos de enlace de datos pueden devolver IQueryable y esto representa una consulta que todavía se va a ejecutar, ASP.NET puede encargarse de modificar la consulta para agregar los parámetros de ordenación y paginación adecuados.

  6. Presione F5 para iniciar la depuración del sitio y vaya a la página Productos. Debería ver que GridView se rellena con las categorías devueltas por el método GetCategories.

    Populating a GridView using model binding

    Rellenar un control GridView mediante el enlace de modelos

  7. Presione SHIFT+F5 Detener depuración.

Tarea 3: Proveedores de valores en el enlace de modelos

El enlace de modelos no solo permite especificar métodos personalizados para trabajar con los datos directamente en el control enlazado a datos, sino que también permite asignar datos de la página a parámetros de estos métodos. En el parámetro de método, puede usar atributos de proveedor de valores para especificar el origen de datos del valor. Por ejemplo:

  • Controles de la página
  • Valores de cadena de consulta
  • Visualización de datos
  • Estado de sesión
  • Cookies
  • Datos de formulario publicados
  • Ver estado
  • También se admiten proveedores de valores personalizados

Si ha usado ASP.NET MVC 4, observará que la compatibilidad con enlaces de modelos es similar. De hecho, estas características se tomaron de ASP.NET MVC y se trasladaron al ensamblado de System.Web para poder usarlos también en Web Forms.

En esta tarea, actualizará GridView para filtrar sus resultados por la cantidad de productos de cada categoría, recibiendo el parámetro de filtro con enlace de modelo.

  1. Vuelva a la página de Products.aspx.

  2. En la parte superior de GridView, agregue una Etiqueta y un ComboBox para seleccionar el número de productos de cada categoría, como se muestra a continuación.

    <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. Agregue un EmptyDataTemplate a GridView para mostrar un mensaje cuando no haya categorías con el número seleccionado de productos.

    <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 el Products.aspx.cs código subyacente y agregue la siguiente instrucción using.

    using System.Web.ModelBinding;
    
  5. Modifique el método GetCategories para recibir un argumento minProductsCount entero y filtre los resultados devueltos. Para ello, reemplace el método por el código siguiente.

    (Fragmento de código: Laboratorio de formularios Web Forms - 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;
    }
    

    El nuevo atributo [Control] en el argumento minProductsCount permitirá que ASP.NET sepa que su valor debe rellenarse mediante un control en la página. ASP.NET buscará cualquier control que coincida con el nombre del argumento (minProductsCount) y realizará la asignación y conversión necesarias para rellenar el parámetro con el valor del control.

    Como alternativa, el atributo proporciona un constructor sobrecargado que permite especificar el control desde dónde obtener el valor.

    Nota:

    Un objetivo de las características de enlace de datos es reducir la cantidad de código que debe escribirse para la interacción de la página. Aparte del proveedor de valores [Control], puede usar otros proveedores de enlace de modelos en los parámetros del método. Algunos de ellos se enumeran en la introducción de la tarea.

  6. Presione F5 para iniciar la depuración del sitio y vaya a la página Productos. Seleccione una serie de productos en la lista desplegable y observe cómo se actualiza GridView.

    Filtering the GridView with a drop-down list value

    Filtrado de GridView con un valor de lista desplegable

  7. Detenga la depuración.

Tarea 4: Uso del enlace de modelos para el filtrado

En esta tarea, agregará un segundo elemento GridView secundario para mostrar los productos dentro de la categoría seleccionada.

  1. Abra la página Products.aspx y actualice las categorías GridView para generar automáticamente el botón Seleccionar.

    <asp:GridView ID="categoriesGrid" runat="server"
      AutoGenerateColumns="false"
      ItemType="WebFormsLab.Model.Category" DataKeyNames="CategoryId"
      SelectMethod="GetCategories"
      AutoGenerateSelectButton="true">
    
  2. Agregue un segundo GridView denominado productsGrid en la parte inferior. Establezca el ItemType en WebFormsLab.Model.Product, el DataKeyNames en ProductId y SelectMethod en GetProducts. Establezca AutoGenerateColumns en false y agregue las columnas para ProductId, ProductName, Description y 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 el archivo de código subyacente Products.aspx.cs. Implemente el método GetProducts para recibir el identificador de categoría de la categoría GridView y filtrar los productos. El enlace de modelos establecerá el valor del parámetro mediante la fila seleccionada en las categoriesGrid. Dado que el nombre del argumento y el nombre del control no coinciden, debe especificar el nombre del control en el proveedor de valores control.

    (Fragmento de código: Laboratorio de Formularios Web Forms - Ex01 - GetProducts)

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

    Nota:

    Este enfoque facilita la prueba unitaria de estos métodos. En un contexto de prueba unitaria, donde Web Forms no se está ejecutando, el atributo [Control] no realizará ninguna acción específica.

  4. Abra la página Products.aspx y busque los productos GridView. Actualice los productos GridView para mostrar un vínculo para editar el producto seleccionado.

    <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 el código subyacente de la página ProductDetails.aspx y reemplace el método SelectProduct por el código siguiente.

    (Fragmento de código: Laboratorio de Formularios Web Forms - Ex01 - SelectProduct (método)

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

    Nota:

    Observe que el atributo [QueryString] se usa para rellenar el parámetro de método de un parámetro productId en la cadena de consulta.

  6. Presione F5 para iniciar la depuración del sitio y vaya a la página Productos. Seleccione cualquier categoría de las categorías GridView y observe que los productos GridView se actualizan.

    Showing products from the selected category

    Mostrar productos de la categoría seleccionada

  7. Haga clic en el vínculo Ver de un producto para abrir la página de ProductDetails.aspx.

    Observe que la página está recuperando el producto con SelectMethod mediante el parámetro productId de la cadena de consulta.

    Viewing the product details

    Visualización de los detalles del producto

    Nota:

    La capacidad de escribir una descripción HTML se implementará en el ejercicio siguiente.

Tarea 5: Uso del enlace de modelos para operaciones de actualización

En la tarea anterior, ha usado el enlace de modelos principalmente para seleccionar datos, en esta tarea aprenderá a usar el enlace de modelos en las operaciones de actualización.

Actualizará las categorías GridView para permitir que el usuario actualice las categorías.

  1. Abra la página Products.aspx y actualice las categorías GridView para generar automáticamente el botón Editar y use el nuevo atributo UpdateMethod para especificar un método UpdateCategory para actualizar el elemento seleccionado.

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

    El atributo DataKeyNames de GridView define cuáles son los miembros que identifican de forma única el objeto enlazado al modelo y, por lo tanto, cuáles son los parámetros que el método de actualización debe recibir al menos.

  2. Abra el archivo de código subyacente Products.aspx.cs e implemente el método UpdateCategory. El método debe recibir el identificador de categoría para cargar la categoría actual, rellenar los valores de GridView y, a continuación, actualizar la categoría.

    (Fragmento de código: Laboratorio de Formularios Web Forms - Ex01 - UpdateCategory)

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

    El nuevo método TryUpdateModel de la clase Page es responsable de rellenar el objeto de modelo mediante los valores de los controles de la página. En este caso, reemplazará los valores actualizados de la fila GridView actual que se está editando en el objeto category.

    Nota:

    En el ejercicio siguiente se explica el uso de ModelState.IsValid para validar los datos introducidos por el usuario al editar el objeto.

  3. Ejecute el sitio y vaya a la página Productos. Edite una categoría. Escriba un nombre nuevo y, a continuación, haga clic en Actualizar para conservar los cambios.

    Editing categories

    Edición de categorías

Ejercicio 2: Validación de datos

En este ejercicio, obtendrá información sobre las nuevas características de validación de datos en ASP.NET 4.5. Revisará las nuevas características de validación discretas en Web Forms. Usará anotaciones de datos en las clases del modelo de aplicación para la validación de entrada de usuario y, por último, aprenderá a activar o desactivar la validación de solicitudes a controles individuales de una página.

Tarea 1: Validación discreta

Los formularios con datos complejos, incluidos los validadores, tienden a generar demasiado código JavaScript en la página, lo que puede representar aproximadamente el 60 % del código. Con la validación discreta habilitada, el código HTML tendrá un aspecto más limpio y ordenado.

En esta sección, habilitará la validación discreta en ASP.NET para comparar el código HTML generado por ambas configuraciones.

  1. Abra Visual Studio 2012 y abra la solución Begin ubicada en la carpeta Source\Ex2-Validation\Begin de este laboratorio. Como alternativa, puede seguir trabajando en la solución existente desde el ejercicio anterior.

    1. Si abrió la solución Begin proporcionada, deberá descargar algunos paquetes NuGet que faltan antes de continuar. Para ello, en el Explorador de soluciones, haga clic en el proyecto WebFormsLab de Administrar paquetes NuGet.

    2. En el cuadro de diálogo Administrar paquetes NuGet, haga clic en Restaurar para descargar los paquetes que faltan.

    3. Por último, para compilar la solución, haga clic en Compilar | solución de compilación.

      Nota:

      Una de las ventajas de usar NuGet es que no es necesario enviar todas las bibliotecas del proyecto, lo que reduce el tamaño del proyecto. Con NuGet Power Tools, especificando las versiones del paquete en el archivo Packages.config, podrá descargar todas las bibliotecas necesarias la primera vez que ejecute el proyecto. Este es el motivo por el que tendrá que ejecutar estos pasos después de abrir una solución existente desde este laboratorio.

  2. Presione F5 para iniciar la aplicación web. Vaya a la página Clientes y haga clic en el vínculo Agregar un nuevo cliente.

  3. Haga clic con el botón derecho en la página del explorador y seleccione opción Ver origen para abrir el código HTML generado por la aplicación.

    Showing the page HTML code

    Mostrar el código HTML de la página

  4. Desplácese por el código fuente de la página y observe que ASP.NET ha insertado código JavaScript y validadores de datos en la página para realizar las validaciones y mostrar la lista de errores.

    Validation JavaScript code in CustomerDetails page

    Validación de código JavaScript en la página CustomerDetails

  5. Cierre el explorador y vuelva a Visual Studio.

  6. Ahora habilitará la validación discreta. Abra Web.Config y busque ValidationSettings:UnobtrusiveValidationMode en la sección AppSettings. Establezca el valor de clave en WebForms.

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

    Nota:

    También puede establecer esta propiedad en el evento "Page_Load" en caso de que desee habilitar la validación discreta solo para algunas páginas.

  7. Abra CustomerDetails.aspx y presione F5 para iniciar la aplicación web.

  8. Presione la tecla F12 para abrir las herramientas de desarrollo de IE. Una vez abiertas las herramientas de desarrollo, seleccione la pestaña script. Seleccione CustomerDetails.aspx en el menú y tome nota de que los scripts necesarios para ejecutar jQuery en la página se han cargado en el explorador desde el sitio local.

    Loading the jQuery JavaScript files directly from the local IIS server

    Carga de los archivos JavaScript de jQuery directamente desde el servidor IIS local

  9. Cierre el explorador para volver a Visual Studio. Abra de nuevo el archivo Site.Master y busque el ScriptManager. Agregue el atributo propiedad EnableCdn con el valor True. Esto obligará a que jQuery se cargue desde la dirección URL en línea, no desde la dirección URL del sitio local.

  10. Abra CustomerDetails.aspx en Visual Studio. Presione la tecla F5 para ejecutar el sitio. Una vez que se abra Internet Explorer, presione la tecla F12 para abrir las herramientas de desarrollo. Seleccione la pestaña Script y, a continuación, eche un vistazo a la lista desplegable. Tenga en cuenta que los archivos JavaScript de jQuery ya no se cargan desde el sitio local, sino desde la red CDN de jQuery en línea.

    Loading the jQuery JavaScript files from the CDN

    Carga de los archivos JavaScript de jQuery desde el CDN

  11. Vuelva a abrir el código fuente de la página HTML con la opción Ver origen en el explorador. Tenga en cuenta que, al habilitar la validación discreta ASP.NET ha reemplazado el código JavaScript insertado por los atributos data- *.

    Unobtrusive validation code

    Código de validación no discreto

    Nota:

    En este ejemplo, ha visto cómo se ha simplificado un resumen de validación con anotaciones de datos a solo algunas líneas HTML y JavaScript. Anteriormente, sin validación discreta, más controles de validación agregue, más grande aumentará el código de validación de JavaScript.

Tarea 2: Validación del modelo con anotaciones de datos

ASP.NET 4.5 presenta la validación de anotaciones de datos para Web Forms. En lugar de tener un control de validación en cada entrada, ahora puede definir restricciones en las clases de modelo y usarlas en toda la aplicación web. En esta sección, aprenderá a usar anotaciones de datos para validar un formulario de cliente nuevo o editar.

  1. Abra la páginaCustomerDetail.aspx. Tenga en cuenta que el nombre del cliente y el segundo nombre del EditItemTemplate y secciones InsertItemTemplate se validan mediante controles RequiredFieldValidator. Cada validador está asociado a una condición determinada, por lo que debe incluir tantos validadores como condiciones para comprobar.

  2. Agregue anotaciones de datos para validar la clase modelo Customer. Abra Customer.cs clase en la carpeta Model y decore cada propiedad mediante atributos de anotación de datos.

    (Fragmento de código: Laboratorio de formularios Web Forms: Ex02 - Anotaciones de datos)

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

    Nota:

    .NET Framework 4.5 ha ampliado la colección de anotaciones de datos existente. Estas son algunas de las anotaciones de datos que puede usar: [CreditCard], [Phone], [EmailAddress], [Range], [Compare], [Url], [FileExtensions], [Required], [Key], [RegularExpression].

    Algunos ejemplos de uso:

    [Clave]: Especifica que un atributo es el identificador único.

    [Range(0.4, 0.5, ErrorMessage="{Write an error message}"]: Rango doble

    [EmailAddress(ErrorMessage="Correo electrónico no válido"), MaxLength(56)]: Dos anotaciones en la misma línea.

    También puede definir sus propios mensajes de error dentro de cada atributo.

  3. Abra CustomerDetails.aspx y quite todos los campos RequiredFieldValidators para los campos de nombre y apellido en las secciones EditItemTemplate e InsertItemTemplate del control 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>
      ...
    

    Nota:

    Una ventaja de usar anotaciones de datos es que la lógica de validación no está duplicada en las páginas de la aplicación. La define una vez en el modelo y la usa en todas las páginas de aplicación que manipulan los datos.

  4. Abra CustomerDetails.aspx código subyacente y busque el método SaveCustomer. Se llama a este método al insertar un nuevo cliente y recibe el parámetro Customer de los valores de control FormView. Cuando se produce la asignación entre los controles de página y el objeto de parámetro, ASP.NET ejecutará la validación del modelo en todos los atributos de anotación de datos y rellenará el diccionario ModelState con los errores detectados, si los hubiera.

    ModelState.IsValid solo devolverá true si todos los campos del modelo son válidos después de realizar la validación.

    public void SaveCustomer(Customer customer) 
    {
        if (this.ModelState.IsValid)
        { 
            using (var db = new ProductsContext())
            {
                ...
    
  5. Agregue un control ValidationSummary al final de la página CustomerDetails para mostrar la lista de errores del modelo.

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

    El ShowModelStateErrors es una nueva propiedad en el control ValidationSummary que cuando se establece en true, el control mostrará los errores del diccionario ModelState. Estos errores proceden de la validación de anotaciones de datos.

  6. Presione F5 para ejecutar la aplicación web. Complete el formulario con algunos valores erróneos y haga clic en Guardar para ejecutar la validación. Observe el resumen del error en la parte inferior.

    Validation with Data Annotations

    Validación con anotaciones de datos

Tarea 3: Control de errores de base de datos personalizados con ModelState

En la versión anterior de Web Forms, el control de errores de base de datos, como una cadena demasiado larga o una infracción de clave única, podría implicar la iniciación de excepciones en el código del repositorio y, a continuación, controlar las excepciones en el código subyacente para mostrar un error. Se requiere una gran cantidad de código para hacer algo relativamente sencillo.

En Web Forms 4.5, el objeto ModelState se puede usar para mostrar los errores en la página, ya sea desde el modelo o desde la base de datos, de forma coherente.

En esta tarea, agregará código para controlar correctamente las excepciones de base de datos y mostrará el mensaje adecuado al usuario mediante el objeto ModelState.

  1. Mientras la aplicación sigue en ejecución, intente actualizar el nombre de una categoría mediante un valor duplicado.

    Updating a category with a duplicated name

    Actualización de una categoría con un nombre duplicado

    Observe que se produce una excepción debido a la restricción "única" de la columna CategoryName.

    Exception for duplicated category names

    Excepción para nombres de categoría duplicados

  2. Detenga la depuración. En el archivo de código subyacente de Products.aspx.cs, actualice el método UpdateCategory para controlar las excepciones producidas por la base de datos llamada al método db.SaveChanges() y agregue un error al objeto ModelState.

    El nuevo método TryUpdateModel actualiza el objeto de categoría recuperado de la base de datos mediante los datos del formulario proporcionados por el usuario.

    (Fragmento de código: Laboratorio de formularios Web Forms - Ex02 - UpdateCategory Handle Errors)

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

    Nota:

    Lo ideal es que tenga que identificar la causa de DbUpdateException y comprobar si la causa principal es la infracción de una restricción de clave única.

  3. Abra Products.aspx y agregue un control ValidationSummary debajo de las categorías GridView para mostrar la lista de errores del modelo.

    <asp:GridView ID="categoriesGrid" runat="server"
      ...
    </asp:GridView>
    
    <asp:ValidationSummary ID="ValidationSummary1" runat="server" ShowModelStateErrors="true" />
    
    <h3>Products</h3>
    
  4. Ejecute el sitio y vaya a la página Productos. Intente actualizar el nombre de una categoría mediante un valor duplicado.

    Observe que la excepción se controló y el mensaje de error aparece en el control ValidationSummary.

    Duplicated category error

    Error de categoría duplicada

Tarea 4: Validación de solicitudes en ASP.NET Web Forms 4.5

La característica de validación de solicitudes de ASP.NET proporciona un determinado nivel de protección predeterminada frente a ataques de scripting entre sitios (XSS). En versiones anteriores de ASP.NET, la validación de solicitudes estaba habilitada de forma predeterminada y solo se podía deshabilitar para toda una página. Con la nueva versión de ASP.NET Web Forms ahora puede deshabilitar la validación de solicitudes para un solo control, realizar la validación diferida de solicitudes o acceder a datos de solicitud no validados (tenga cuidado si lo hace).

  1. Presione Ctrl+F5 para iniciar el sitio sin depurar y vaya a la página Productos. Seleccione una categoría y, a continuación, haga clic en el vínculo Editar en cualquiera de los productos.

  2. Escriba una descripción que contenga contenido potencialmente peligroso, por ejemplo, incluidas las etiquetas HTML. Observe la excepción producida debido a la validación de la solicitud.

    Editing a product with potentially dangerous content

    Edición de un producto con contenido potencialmente peligroso

    Exception thrown due to request validation

    Excepción producida debido a la validación de solicitudes

  3. Cierre la página y, en Visual Studio, presione SHIFT+F5 para detener la depuración.

  4. Abra la página ProductDetails.aspx y busque el Descripción TextBox.

  5. Agregue la nueva propiedad ValidateRequestMode al TextBox y establezca su valor en Disabled.

    El nuevo atributo ValidateRequestModepermite deshabilitar la validación de solicitudes de forma granular en cada control. Esto resulta útil cuando desea usar una entrada que pueda recibir código HTML, pero desea mantener la validación funcionando para el resto de la página.

    <p>
      <asp:TextBox runat="server" ID="Description" TextMode="MultiLine" 
                Cols="60" Rows="8" Text='<%# BindItem.Description %>' 
        ValidateRequestMode="Disabled" />
    </p>
    
  6. Presione F5 para ejecutar la aplicación. Vuelva a abrir la página editar producto y complete una descripción del producto, incluidas las etiquetas HTML. Observe que ahora puede agregar contenido HTML a la descripción.

    Request validation disabled for the product description

    Solicitud de validación deshabilitada para la descripción del producto

    Nota:

    En una aplicación de producción, debe sanear el código HTML escrito por el usuario para asegurarse de que solo se escriben etiquetas HTML seguras (por ejemplo, no hay etiquetas <script>). Para ello, puede usar Biblioteca de protección Web de Microsoft.

  7. Vuelva a editar el producto. Escriba código HTML en el campo Nombre y haga clic en Guardar. Tenga en cuenta que la validación de solicitudes solo está deshabilitada para el campo Descripción y el resto de los campos se siguen validando con el contenido potencialmente peligroso.

    Request validation enabled in the rest of the fields

    Validación de solicitudes habilitada en el resto de los campos

    ASP.NET Web Forms 4.5 incluye un nuevo modo de validación de solicitudes para realizar la validación diferida de solicitudes. Con el modo de validación de solicitudes establecido en 4.5, si un fragmento de código accede a Request.Form["key"], ASP.NET 4.5 la validación de solicitudes solo desencadenará la validación de solicitudes para ese elemento específico de la colección de formularios.

    Además, ASP.NET 4.5 ahora incluye rutinas de codificación básicas de Microsoft Anti-XSS Library v4.0. Las nuevas rutinas de codificación anti-XSS se implementan mediante el nuevo tipo de AntiXssEncoderque se encuentra en el nuevo espacio de nombres System.Web.Security.AntiXss. Con el parámetro encoderType configurado para usar AntiXssEncoder, toda la codificación de salida dentro de ASP.NET usa automáticamente las nuevas rutinas de codificación.

  8. ASP.NET validación de solicitudes 4.5 también admite el acceso no validado para solicitar datos. ASP.NET 4.5 agrega una nueva propiedad de colección al objeto HttpRequest denominado Unvalidated. Al navegar a HttpRequest.Unvalidated tiene acceso a todos los datos comunes de solicitud, incluidos Formularios, QueryStrings, Cookies, direcciones URL, etc.

    Request.Unvalidated object

    Objeto Request.Unvalidated

    Nota:

    Use la propiedad HttpRequest.Unvalidated con precaución. Asegúrese de realizar cuidadosamente una validación personalizada en los datos de solicitud sin procesar para asegurarse de que el texto peligroso no se realiza de ida y vuelta y se representa de vuelta a los clientes no especificados.

Ejercicio 3: Procesamiento asincrónico de páginas en ASP.NET Web Forms

En este ejercicio, se le presentará las nuevas características de procesamiento de páginas asincrónicas en ASP.NET Web Forms.

Tarea 1: Actualización de la página Detalles del producto para cargar y mostrar imágenes

En esta tarea, actualizará la página de detalles del producto para permitir al usuario especificar una dirección URL de imagen para el producto y mostrarla en la vista de solo lectura. Para crear una copia local de la imagen especificada, descárguelo sincrónicamente. En la siguiente tarea, actualizará esta implementación para que funcione de forma asincrónica.

  1. Abra Visual Studio 2012 y cargue la solución Begin ubicada en Source\Ex3-Async\Begin desde la carpeta de este laboratorio. Como alternativa, puede seguir trabajando en la solución existente a partir de los ejercicios anteriores.

    1. Si abrió la solución Begin proporcionada, deberá descargar algunos paquetes NuGet que faltan antes de continuar. Para ello, en el Explorador de soluciones, haga clic en el proyecto WebFormsLab y seleccione Administrar paquetes NuGet.

    2. En el cuadro de diálogo Administrar paquetes NuGet, haga clic en Restaurar para descargar los paquetes que faltan.

    3. Por último, para compilar la solución, haga clic en Compilar | solución de compilación.

      Nota:

      Una de las ventajas de usar NuGet es que no es necesario enviar todas las bibliotecas del proyecto, lo que reduce el tamaño del proyecto. Con NuGet Power Tools, especificando las versiones del paquete en el archivo Packages.config, podrá descargar todas las bibliotecas necesarias la primera vez que ejecute el proyecto. Este es el motivo por el que tendrá que ejecutar estos pasos después de abrir una solución existente desde este laboratorio.

  2. Abra el origen de la página de ProductDetails.aspx y agregue un campo en ItemTemplate de FormView para mostrar la imagen del producto.

    <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. Agregue un campo para especificar la dirección URL de la imagen en EditTemplate de 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 el archivo de código subyacente ProductDetails.aspx.cs y agregue las siguientes directivas de espacio de nombres.

    (Fragmento de código: Laboratorio de Formularios Web Forms - Ex03 - Espacios de nombres)

    using System.IO;
    using System.Net;
    using System.Web;
    
  5. Cree un método UpdateProductImage para almacenar imágenes remotas en la carpeta local Imágenes y actualizar la entidad del producto con el nuevo valor de ubicación de imagen.

    (Fragmento de código: Laboratorio de Formularios 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. Actualice el método UpdateProduct para llamar al método UpdateProductImage.

    (Fragmento de código: Laboratorio de Formularios Web Forms - Ex03 - Llamada a 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. Ejecute la aplicación e intente cargar una imagen para un producto.

    Setting an image for a product

    Establecimiento de una imagen para un producto

Tarea 2: Agregar procesamiento asincrónico a la página Detalles del producto

En esta tarea, actualizará la página de detalles del producto para que funcione de forma asincrónica. Mejorará una tarea de larga duración (el proceso de descarga de imágenes) mediante el procesamiento de páginas asincrónico de ASP.NET 4.5.

Los métodos asincrónicos de las aplicaciones web se pueden usar para optimizar la forma en que se usan los grupos de subprocesos ASP.NET. En ASP.NET hay un número limitado de subprocesos en el grupo de subprocesos para asistir a solicitudes, por lo tanto, cuando todos los subprocesos están ocupados, ASP.NET comienza a rechazar nuevas solicitudes, envía mensajes de error de aplicación y hace que el sitio no esté disponible.

Las operaciones que consumen mucho tiempo en el sitio web son excelentes candidatas para la programación asincrónica porque ocupan el subproceso asignado durante mucho tiempo. Esto incluye solicitudes de larga duración, páginas con muchos elementos y páginas diferentes que requieren operaciones sin conexión, como consultar una base de datos o acceder a un servidor web externo. La ventaja es que si usa métodos asincrónicos para estas operaciones, mientras la página está procesando, el subproceso se libera y se devuelve al grupo de subprocesos y se puede usar para asistir a una nueva solicitud de página. Esto significa que la página comenzará a procesarse en un subproceso desde el grupo de subprocesos y podría completar el procesamiento en otro, una vez completado el procesamiento asincrónico.

  1. Abra la página ProductDetails.aspx. Agregue el atributo Async en el elemento Page y establézcalo en true. Este atributo indica a ASP.NET implementar la interfaz IHttpAsyncHandler.

    <%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true"
        CodeBehind="ProductDetails.aspx.cs" Inherits="WebFormsLab.ProductDetails"
        Async="true" %>
    
  2. Agregue una etiqueta en la parte inferior de la página para mostrar los detalles de los subprocesos que ejecutan la página.

    <EmptyDataTemplate>Product not found</EmptyDataTemplate>
      </asp:FormView>
    
      <asp:Label ID="threadsMessageLabel" runat="server" />
    </asp:Content>
    
  3. Abra ProductDetails.aspx.cs y agregue las siguientes directivas de espacio de nombres.

    (Fragmento de código: Laboratorio de formularios Web Forms - Ex03 - Espacios de nombres 2)

    using System.Web.UI;
    using System.Threading;
    
  4. Modifique el método UpdateProductImage para descargar la imagen con una tarea asincrónica. Reemplazará el método WebClientDownloadFile por el método DownloadFileTaskAsync e incluirá la palabra clave await.

    (Fragmento de código: Laboratorio de Formularios Web Forms - 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));
                }
            }));
        }
    }
    

    RegisterAsyncTask registra una nueva tarea asincrónica de página que se va a ejecutar en un subproceso diferente. Recibe una expresión lambda con la tarea (t) que se va a ejecutar. La palabra clave await del método DownloadFileTaskAsync convierte el resto del método en una devolución de llamada que se invoca de forma asincrónica después de que se haya completado el método DownloadFileTaskAsync. ASP.NET reanudará la ejecución del método manteniendo automáticamente todos los valores originales de la solicitud HTTP. El nuevo modelo de programación asincrónica en .NET 4.5 permite escribir código asincrónico similar al código sincrónico y permitir que el compilador controle las complicaciones de las funciones de devolución de llamada o el código de continuación.

    Nota:

    RegisterAsyncTask y PageAsyncTask ya estaban disponibles desde .NET 2.0. La palabra clave await es nueva del modelo de programación asincrónica de .NET 4.5 y se puede usar junto con los nuevos métodos TaskAsync del objeto WebClient de .NET.

  5. Agregue código para mostrar los subprocesos en los que se inició y finalizó la ejecución del código. Para ello, actualice el método UpdateProductImage con el código siguiente.

    (Fragmento de código: Laboratorio de formularios Web Forms - Ex03 - Espacios de nombres 2)

    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 el archivo Web.config del sitio web. Agregue la siguiente variable appSetting.

    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
    
  7. Presione F5 para ejecutar la aplicación y cargar una imagen para el producto. Observe que el identificador de subprocesos donde se inició y finalizó el código puede ser diferente. Esto se debe a que las tareas asincrónicas se ejecutan en un subproceso independiente de ASP.NET grupo de subprocesos. Cuando se completa la tarea, ASP.NET vuelve a colocar la tarea en la cola y asigna cualquiera de los subprocesos disponibles.

    Downloading an image asynchronously

    Descargar una imagen de forma asincrónica

Nota:

Además, puede implementar esta aplicación en Azure siguiendo Apéndice B: Publicación de una aplicación de ASP.NET MVC 4 mediante Web Deploy.


Resumen

En este laboratorio práctico, se han abordado y demostrado los siguientes conceptos:

  • Uso de expresiones de enlace de datos fuertemente tipadas
  • Uso de nuevas características de enlace de modelos en formularios Web Forms
  • Usar proveedores de valores para asignar datos de página a métodos de código subyacente
  • Uso de anotaciones de datos para la validación de entrada del usuario
  • Aproveche las ventajas de la validación discreta del lado cliente con jQuery en formularios Web Forms
  • Implementación de la validación de solicitudes pormenorizadas
  • Implementación del procesamiento asincrónico de páginas en formularios Web Forms

Apéndice A: Instalación de Visual Studio Express 2012 para Web

Puede instalar Microsoft Visual Studio Express 2012 para Web u otra versión "Express" mediante el Instalador de plataforma web de Microsoft . Las instrucciones siguientes le guían por los pasos necesarios para instalar Visual Studio Express 2012 para Web mediante Instalador de plataforma web de Microsoft.

  1. Vaya a [https://go.microsoft.com/?linkid=9810169](https://go.microsoft.com/?linkid=9810169). Como alternativa, si ya ha instalado el Instalador de plataforma web, puede abrirlo y buscar el producto "Visual Studio Express 2012 for Web con Azure SDK".

  2. Haga clic en Instalar ahora. Si no tiene Instalador de plataforma web se le redirigirá para descargarlo e instalarlo primero.

  3. Una vez que Instalador de plataforma web está abierto, haga clic en Instalar para iniciar la instalación.

    Install Visual Studio Express

    Instalar Visual Studio Express

  4. Lea todas las licencias y términos de los productos y haga clic en Acepto continuar.

    Accepting the license terms

    Aceptar los términos de licencia

  5. Espere hasta que finalice el proceso de descarga e instalación.

    Installation progress

    Progreso de la instalación

  6. Cuando finalice la instalación, haga clic en Finalizar.

    Installation completed

    Instalación completada

  7. Haga clic en Salir para cerrar el Instalador de plataforma web.

  8. Para abrir Visual Studio Express for Web, vaya a la pantalla Inicio y empiece a escribir "VS Express", haga clic en el icono de VS Express for Web.

    VS Express for Web tile

    Icono de VS Express para Web

Apéndice B: Publicación de una aplicación de ASP.NET MVC 4 mediante Web Deploy

En este apéndice se muestra cómo crear un nuevo sitio web desde Azure Portal y publicar la aplicación que obtuvo siguiendo el laboratorio, aprovechando la característica de publicación Web Deploy proporcionada por Azure.

Tarea 1: Creación de un nuevo sitio web desde Azure Portal

  1. Vaya al Portal de administración de Azure e inicie sesión con las credenciales de Microsoft asociadas a la suscripción.

    Nota:

    Con Azure puede hospedar 10 ASP.NET sitios web de forma gratuita y, a continuación, escalar a medida que crece el tráfico. Puede registrarse aquí.

    Log on to Windows Azure portal

    Inicio de sesión en el Portal

  2. Haga clic en Nuevo en la barra de comandos.

    Creating a new Web Site

    Crear un nuevo sitio web

  3. Haga clic en Proceso | Sitio web. A continuación, seleccione opción Creación rápida. Proporcione una dirección URL disponible para el nuevo sitio web y haga clic en Crear sitio web.

    Nota:

    Azure es el host de una aplicación web que se ejecuta en la nube que puede controlar y administrar. La opción Creación rápida permite implementar una aplicación web completada en Azure desde fuera del portal. No incluye pasos para configurar una base de datos.

    Creating a new Web Site using Quick Create

    Crear un nuevo sitio web mediante la creación rápida

  4. Espere hasta que se cree la nueva Sitio web.

  5. Una vez creado el sitio web, haga clic en el vínculo de la columna dirección URL. Compruebe que el nuevo sitio web funciona.

    Browsing to the new web site

    Exploración a la nueva aplicación web

    Web site running

    Sitio web que ejecuta

  6. Volver al portal y haga clic en el nombre del sitio web en la columna Nombre para mostrar las páginas de administración.

    Opening the web site management pages

    Abrir las páginas de administración del sitio web

  7. En la página Panel, en la sección de vista rápida, haga clic en el vínculo Descargar perfil de publicación.

    Nota:

    El perfil de publicación contiene toda la información necesaria para publicar una aplicación web en Azure para cada método de publicación habilitado. El perfil de publicación contiene las direcciones URL, las credenciales de usuario y las cadenas de base de datos necesarias para conectarse y autenticarse en cada uno de los puntos de conexión para los que está habilitado un método de publicación. Microsoft WebMatrix 2, Microsoft Visual Studio Express for Web y Microsoft Visual Studio 2012 admiten la lectura de perfiles de publicación para automatizar la configuración de estos programas para publicar aplicaciones web en Azure.

    Downloading the web site publish profile

    Descargar el perfil de publicación del sitio web

  8. Descargue el archivo de perfil de publicación en una ubicación conocida. Además, en este ejercicio verá cómo usar este archivo para publicar una aplicación web en Azure desde Visual Studio.

    Saving the publish profile file

    Guardar el archivo de perfil de publicación

Tarea 2: Configuración del servidor de bases de datos

Si la aplicación usa bases de datos de SQL Server, deberá crear un servidor de SQL Database. Si desea implementar una aplicación sencilla que no use SQL Server, puede omitir esta tarea.

  1. Necesitará un servidor de SQL Database para almacenar la base de datos de la aplicación. Puede ver los servidores de SQL Database desde la suscripción en el Portal de administración de Azure en Sql Databases | Servers | Server's Dashboard. Si no tiene un servidor creado, puede crear uno mediante el botón Agregar de la barra de comandos. Tome nota del nombre y la dirección URL del servidor , el nombre de inicio de sesión de administrador y la contraseña, ya que los usará en las tareas siguientes. Aún no cree la base de datos, ya que se creará en una fase posterior.

    SQL Database Server Dashboard

    Panel de SQL Database Server

  2. En la siguiente tarea probará la conexión de base de datos desde Visual Studio, por ese motivo debe incluir la dirección IP local en la lista de Direcciones IP permitidas. Para ello, haga clic en Configurar, seleccione la dirección IP de dirección IP del cliente actual y péguela en el Dirección IP de inicio y cuadros de texto Dirección IP final y haga clic en el botón add-client-ip-address-ok-button.

    Adding Client IP Address

    Adición de la dirección IP del cliente

  3. Una vez agregada la Dirección IP del cliente a la lista de direcciones IP permitidas, haga clic en Guardar para confirmar los cambios.

    Confirm Changes

    Confirmar cambios

Tarea 3: Publicación de una aplicación de ASP.NET MVC 4 mediante Web Deploy

  1. Vuelva a la solución ASP.NET MVC 4. En el Explorador de soluciones, haga clic con el botón derecho en el proyecto de sitio web y seleccione Publicar.

    Publishing the Application

    Publicación del sitio web

  2. Importe el perfil de publicación que guardó en la primera tarea.

    Importing the publish profile

    Importación del perfil de publicación

  3. Haga clic en Validar conexión. Una vez completada la validación, haga clic en Siguiente.

    Nota:

    La validación se completa una vez que aparezca una marca de verificación verde junto al botón Validar conexión.

    Validating connection

    Validar conexión

  4. En la página Configuración, en la sección Bases de datos, haga clic en el botón situado junto al cuadro de texto de la conexión de base de datos (es decir, DefaultConnection).

    Web deploy configuration

    Configuración de Web deploy

  5. Configure la conexión de base de datos de la siguiente manera:

    • En Nombre del servidor, escriba la dirección URL del servidor SQL Database con el prefijo tcp:.

    • En nombre de usuario escriba el nombre de inicio de sesión del administrador del servidor.

    • En Contraseña escriba la contraseña de inicio de sesión del administrador del servidor.

    • Escriba un nuevo nombre de base de datos.

      Configuring destination connection string

      Configuración de la cadena de conexión de destino

  6. A continuación, haga clic en Aceptar. Cuando se le pida que cree la base de datos, haga clic en .

    Creating the database

    Creación de la base de datos

  7. La cadena de conexión que usará para conectarse a SQL Database en Azure se muestra en el cuadro de texto Conexión predeterminada. A continuación, haga clic en Siguiente.

    Connection string pointing to SQL Database

    Cadena de conexión que apunta a SQL Database

  8. En la página Versión preliminar, haga clic en Publicar.

    Publishing the web application

    Publicación de la aplicación web

  9. Una vez finalizado el proceso de publicación, el explorador predeterminado abrirá el sitio web publicado.

Apéndice C: Uso de fragmentos de código

Con fragmentos de código, tiene todo el código que necesita a su alcance. El documento de laboratorio le indicará exactamente cuándo puede usarlos, como se muestra en la ilustración siguiente.

Using Visual Studio code snippets to insert code into your project

Usar fragmentos de código de Visual Studio para insertar código en el proyecto

Para agregar un fragmento de código mediante el teclado (solo C#)

  1. Coloque el cursor donde desea insertar el código.
  2. Empiece a escribir el nombre del fragmento de código (sin espacios o guiones).
  3. Vea como IntelliSense muestra los nombres de los fragmentos de código coincidentes.
  4. Seleccione el fragmento de código correcto (o siga escribiendo hasta que se seleccione el nombre completo del fragmento de código).
  5. Presione la tecla Tab dos veces para insertar el fragmento de código en la ubicación del cursor.

Start typing the snippet name

Empezar a escribir el nombre del fragmento de código

Press Tab to select the highlighted snippet

Presione la pestaña para seleccionar el fragmento de código resaltado

Press Tab again and the snippet will expand

Presione la pestaña de nuevo y el fragmento de código se expandirá

Para agregar un fragmento de código mediante el mouse (C#, Visual Basic y XML) 1. Haga clic con el botón derecho en el lugar donde desea insertar el fragmento de código.

  1. Seleccione Insertar fragmento de código seguido de Mis fragmentos de código.
  2. Seleccione el fragmento de código correspondiente de la lista haciendo clic en él.

Right-click where you want to insert the code snippet and select Insert Snippet

Haga clic con el botón derecho en el lugar donde desea insertar el fragmento de código y seleccione Insertar fragmento de código

Pick the relevant snippet from the list, by clicking on it

Seleccionar el fragmento de código correspondiente de la lista, haciendo clic en él