Model Binding Parte 2: Filtrando datos (Serie ASP.NET vNext)

Este es el cuarto de una serie de post que estoy haciendo sobre ASP.NET vNext.

La próxima release de Visual Studio incluye un montón de nuevas características de edición de código (de las que hablaré también en el futuro). En el post de hoy veremos algunas pequeñas mejoras que incrementarán un montón la productividad con el editor de HTML a la hora de hacer las tareas más comunes.

Este post es el segundo de tres en el que hablamos sobre el nuevo soporte de Model Binding en Web Forms. Model Binding es una extensión del sistema de databinding de ASP.NET Web Forms , y ofrece un paradigma de acceso a datos centrados en el código. Hace uso de un montón de conceptos de binding que introdujimos con ASP.NET MVC - y los integra en el modelo de controles de servidor de Web Forms.

En el primer post de Model Binding vimos las bases sobre selección de datos. En el post de hoy vamos a ver cómo podemos filtrar datos previamente seleccionados basandose en la entrada de usuario, mientras mantenemos una visión de acceso a datos centrada en código. Veremos cómo podemos usar filtros con entrada de datos y valores obtenidos de un control dropdownlist.

Introducción

Empezaremos añadiendo un control <asp:GridView> a una página y lo configuraremos para que use Model Binding para mostrar algunos datos de la tabla Products de la base de datos Northwind. El siguiente GridView tiene la propiedad SelectMethod seteada a GetProducts() - que hará que se llame al método GetProducts() del code-behind, que en realidad está usando Entity Framework Code First para devolver los productos a enlazar:

<asp:GridView ID="productsGrid" SelectMethod="GetProducts" DataKeyNames="ProductID"

    AllowPaging="true" AllowSorting="true" AutoGenerateColumns="false" runat="server">

    <Columns>

        <asp:BoundField DataField="ProductID" HeaderText="ID" />

        <asp:BoundField DataField="ProductName" HeaderText="Name" SortExpression="ProductName" />

        <asp:BoundField DataField="UnitPrice" HeaderText="Unit Price" SortExpression="UnitPrice" />

        <asp:BoundField DataField="UnitsInStock" HeaderText="# in Stock" SortExpression="UnitsInStock" />

    </Columns>

</asp:GridView>

Aquí tenemos el código del code-behind (que contiene el método GetProducts()):

public partial class Products : Page

{

    Northwind db = new Northwind();

    public IQueryable<Product> GetProducts()

    {

        return db.Products;

    }

}

Si ejecutamos la página veremos la siguiente tabla de productos:

Imagen del gridView con los elementos de la tabla Products

Como estamos devolviendo un IQueryable<Product> en el método GetProducts(), la ordenación y paginación  se habilitan automáticamente (y se hacen en la base de datos que es lo más eficiente y devuelve sólo los 10 elementos que necesitamos sin pasar por ninguna capa intermedia).

Filtrando con un parametro Querystring

Vamos a añadir ahora algún soporte de filtrado básico en nuestra aplicación. En concreto, vamos a permitir a los usuarios que filtren el resultado de los productos dependiendo de si el nombre incluye un palabra. Indicaremos la palabra que usaremos en la querystring como parámetro. Por ejemplo, aquí le hemos indicado que queremos mostrar sólo los productos que contengan la palabra "chef" en su nombre:

Imagen mostrando el paso de parametros con un QueryString

Si no se indica ninguna palabra mostraremos todos los productos como en el primer ejemplo.

Actualizando el método GetProducts

Para permitir este filtrado, actualizaremos el método GetProducts() para que admita un parametro de la siguiente manera:

public IQueryable<Product> GetProducts([QueryString]string keyword)

{

    IQueryable<Product> query = db.Products;

    if (!String.IsNullOrWhiteSpace(keyword))

    {

        query = query.Where(p => p.ProductName.Contains(keyword));

    }

    return query;

}

Si la variable de entrada keyword está vacía o es nula, el método devolverá todos los productos de la base de datos. Si se indica un keyword  se filtrarán los resultados para que incluya sólo aquellos cuyo nombre incluya la palabra keyword.

Entendiendo los Value Providers

 Una de las cosas que habréis notado es que en el código anterior hay un atributo [QueryString] que le hemos aplicado al parámetro de entrada del método. Esto indica al sistema de Model Binding para que intente "enlazar" un valor de la url al parámetro en tiempo de ejecución, incluyendo cualquier tipo de conversión requerida.

Estas fuentes de datos de usuario se llaman "Value Providers" y los atributos de los parametros  indican al sistema de Model Binding qué Value Provider usar se conocen como "Value Provider Attributes". La próxima versión de Web Forms vendrá con value providers y sus correspondientes atributos para las fuentes de datos de usuario más comunes en una aplicación Web Forms, p.ej: query strings, cookies, valores de formulario, controles, viewstate, session y profiles. También podéis escribir vuestros value providers personalizados. Los value providers que escribáis puesden autorizarse para que funcionen tanto en Web Forms como en MVC.

Por defecto, el nombre del parámetro se usará como clave en la colección de value providers, como en el ejemplo, se buscará un valor en la query string con la clave "keyword", p.ej: ~/Products.aspx?keyword=chef. Este comportamiento se puede sobreescribir pasando la key deseada como argumento al atributo del parámetro. En nuestro ejemplo, podríamos quere que el usuario pueda usar la "q" común de las query strings para indicar el valor:

public IQueryable<Product> GetProducts([QueryString("q")]string keyword)

Y ahora podemos filtrar los resultados pasando una keyword en la query string:

Imagén con el paso de parámetros en la query string.

Si pensáis en cómo podeis hacer esto con código de hoy, involuclará algunas líneas de código, p.ej: para leer el valor, comporobar que no es nulo, intentar convertirlo al tipo deseado, comporvar que la conversión ha sido correcta, y finalmente usar el valor de la query. Integrar la paginación y la ordenación (dejando de lado el soporte de edición) puede ser algo más complicado. El sistema de Model Binding está pensado para reducir la necesidad de escribir este tipo de código, y donde lo necesitéis, poder usarlo de una manera limpia en vuestras aplicaciones.

Filtrando usando controles

Vamos a modificar nuestro ejemplo para que el usuario seleccione una categoría con la que filtrar los productos desde una lista desplegable:

Imagen de un filtrado de un GridView con una lista desplegable

Para hacer esto, hemos añadido una lista deplegable a la página y lo hemos configurado para que obtenga sus datos con el método GetCategories() del code-behind a través de su propiedad SelectMethod:

<asp:DropDownList ID="category" SelectMethod="GetCategories"

    AppendDataBoundItems="true" AutoPostBack="true"

     DataTextField="CategoryName" DataValueField="CategoryID"

     runat="server">

    <asp:ListItem Value="" Text="(All)" />

</asp:DropDownList> 

<asp:GridView ID="productsGrid" SelectMethod="GetProducts" DataKeyNames="ProductID"

              AllowPaging="true" AllowSorting="true" AutoGenerateColumns="false" runat="server">

    <Columns>

        <asp:BoundField DataField="ProductID" HeaderText="ID" />

        <asp:BoundField DataField="ProductName" HeaderText="Name" SortExpression="ProductName" />

        <asp:BoundField DataField="UnitPrice" HeaderText="Unit Price" SortExpression="UnitPrice" />

        <asp:BoundField DataField="UnitsInStock" HeaderText="# in Stock" SortExpression="UnitsInStock" />

    </Columns>

</asp:GridView>

Ahora actualizaremos el código del code-behind para que incluya un nuevo método GetCategories() (para obtener las categorías del control DropDownList), y actualizaremos el método GetProducts() para que filtre los resultatdos basándose en la categoría seleccionada del DropDownList:

public partial class Products : Page

{

    Northwind db = new Northwind();

    //

    // Select method for DropDownList

    public IEnumerable<Category> GetCategories()

    {

       return db.Categories.ToList();

    }

    //

    // Select method for GridView

    public IQueryable<Product> GetProducts([Control] int? category)

    {

       IQueryable<Product> query = db.Products;

      if (categoryId.HasValue)

       {

          query = query.Where(p => p.CategoryID == category);

       }

       return query;

   }

}

Fijáos que hemos modificado el método GetProducts() para que admita una categoría nullable como parámetro. Después estamos usando el atributo [Control] en el parámetro category para enlazarlo al valor category seleccionado en el control DropDownList. En el método GetProducts() estamos comprobando si se ha seleccionado el valor por defecto (Todos) - y sólo filtramos a una categoría específica si se ha seleccionado alguna categoría.

El sistema de Model Binding comprobará los valores de los parámetros para detectar si se han cambiado entre postback, y si es así, hará que el control asociado se re-enlace él mismo. Esto hace más fácil crear páginas que se enlazan sólo cuando es necesario, sin tener que escribir un montón de código o tener mucho cuidado con el ciclo de vida de las páginas Web Forms

Y ahora si ejecutamos la página otra vez, podemos seleccionar la opción por defecto (todos) en el DropDownList para mostrar todos los productos, o podemos filtrar los productos por categoría:

Imagen de un filtro por categoría

La ordenación y el paginado se habilitan automáticamente (y se hace en la base de datos para ser más eficiente), tanto si estamos filtrando como si no.

Video de filtrado con Model Binding

Damian Edwards tiene un video de 90 segundos en el que nos muestra el uso de model binding para implementar un escenario de un GridView con filtro. Podéis verlo aquí.

Resúmen

El nuevo soporte de Model Binding de ASP.NET vNext es una evolución del sistema de data-binding existente en Web Forms. Hace más fácil el filtro de datos basados en entradas de usuario usando un paradigmas de acceso a datos centrado en el código. POdéis usar los Atributos de Value Providers para indicar a Model Binding donde obtener los parámetros con los que filtrar, incluso podéis crear vuestros propios Value Providers para escenarios más complejos.

En el próximo post, veremos cómo permitir escenarios de edición usando Model Binding.

Espero que sirva.

Scott.

Traducido por: Juan María Laó Ramos.

Artículo original.

Deja un comentario