DEV Community

Cover image for Página web para el informe de datos con DotVVM Business Pack
Daniel Gomez for DotVVM

Posted on • Edited on

Página web para el informe de datos con DotVVM Business Pack

En muchas ocasiones cuando trabajamos con sistemas que tienen como objetivo realizar operaciones sobre una base de datos, existe la necesidad de incluir una sección dentro de estos sistemas para visualizar los datos correspondientes. Dentro de las páginas web, normalmente se emplean tablas para representar a la información, secciones de búsqueda para filtrar la información, entre otros elementos.

En este articulo aprenderemos como diseñar de una manera sencilla, una página web para visualizar ciertos datos alojados en tablas de una base de datos relaciona a través de ASP.NET Core y DotVVM. En artículos anteriores, pudimos aprender de manera general como utilizar controles predefinidos de DotVVM para la visualización de datos a manera de reporte. Estos son algunos de esos artículos:

Asimismo, cuando se manejan formularios para administrar información, es necesario crear tablas para poder visualizar los datos tratados. Estos son algunos artículos previos por si deseas aprender como diseñar formularios con HTML con DotVVM:

En esta ocasión aprenderemos los fundamentos para visualizar determinados datos y establecer algunos criterios de búsqueda con C# y HTML, a través de los controles premium de DotVVM sobre ASP.NET Core, denominados como DotVVM Business Pack.

Nota: el código fuente del proyecto que analizaremos en este articulo lo puedes encontrar en este repositorio de GitHub: Reports in DotVVM with Business Pack controls.

El patrón de diseño Modelo, Vista, Vistamodelo - MVVM

DotVVM se fundamenta en el patrón de diseño Modelo, Vista, Vistamodelo sobre .NET para la comunicación entre HTML (páginas web) y C# (código fuente). La finalidad de estas partes son las siguientes:

  • El modelo. — es responsable de todos los datos de la aplicación y de la lógica de negocios relacionada.
  • La vista. — Representaciones para el usuario final del modelo de la aplicación. La vista es responsable de mostrar los datos al usuario y de permitir la manipulación de los datos de la aplicación.
  • Modelo-Vista o Vista-Modelo. — uno o más por vista; el modelo-vista es responsable de implementar el comportamiento de la vista para responder a las acciones del usuario y de exponer los datos del modelo fácilmente.

¿Cómo se puede acceder a DotVVM Business Pack?

Business Pack es un NuGet privado, en el cual, podemos hacer uso de los competentes premium ya establecidos por DotVVM para la construcción de aplicaciones web en el ámbito empresarial.

Para la instalación de la versión Business Pack de DotVVM, es necesario realizar una configuración de unos pocos minutos para poder emplear estas funcionalidades. Todo se resume en lo siguiente:

  • Instalar la extensión de DotVVM para Visual Studio 2019.
  • Adquirir Business Pack (existe la versión de prueba) en la siguiente dirección: DotVVM Business Pack.
  • Iniciar sesión en la extensión de DotVVM para Visual Studio 2019. Para ello, podemos dirigirnos al menú de opciones de Visual Studio en la ruta: Extensiones -> DotVVM -> About. Y listo, eso será todo.

Reporte con ASP.NET Core y DotVVM

Para ejemplificar la utilización de algunos controles Business Pack de DotVVM para la realización de un reporte, tendemos una pequeña aplicación como esta:

Teniendo en cuenta el patrón MVVM – Modelo, Vista, Vistamodelo, analizaremos de forma general cada una de estas partes para este proyecto, que tiene como objetivo mostrar los datos de usuarios determinados.

Modelo

Los datos de la aplicación y de la lógica de negocios relacionada se maneja en esta sección. En este sentido, vamos a ver cómo se manejan los datos y los servicios correspondientes.

La base de datos está conformada por dos tablas: Person y PersonType.

Las sentencias SQL para la creación de estas tablas, sus atributos y la inserción de algunos registros son las siguientes:

CREATE SCHEMA IF NOT EXISTS `dbperson` DEFAULT CHARACTER SET utf8;
USE `dbperson` ;

CREATE TABLE IF NOT EXISTS `dbperson`.`PersonType` (
  `Id` INT NOT NULL,
  `Name` VARCHAR(45) NOT NULL,
  `Description` VARCHAR(45) NOT NULL,
  PRIMARY KEY (`Id`))
;

CREATE TABLE IF NOT EXISTS `dbperson`.`Person` (
  `Id` INT NOT NULL AUTO_INCREMENT,
  `FirstName` VARCHAR(45) NOT NULL,
  `LastName` VARCHAR(45) NOT NULL,
  `IdPersonType` INT NOT NULL,
  PRIMARY KEY (`Id`),
  FOREIGN KEY (`IdPersonType`) REFERENCES `dbperson`.`PersonType` (`Id`))
;

INSERT INTO `persontype` (`Id`, `Name`, `Description`) VALUES ('1', 'Type A', '');
INSERT INTO `persontype` (`Id`, `Name`, `Description`) VALUES ('2', 'Type B', '');

INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('1', 'Sergey', 'Brin', '1');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('2', 'Larry', 'Page', '1');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('3', 'Tim', 'Barners', '2');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('4', 'Linus', 'Torvalds', '1');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('5', 'Larry', 'Ellison', '1');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('6', 'Steve', 'Ballmer', '2');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('7', 'Steve', 'Jobs', '2');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('8', 'Marc', 'Benioff', '1');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('9', 'Ray', 'Ozzie', '2');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('10', 'Nicholas', 'Negroponte', '2');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('11', 'Diane', 'Green', '1');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('12', 'Sam', 'Palmisano', '1');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('13', 'Blake', 'Ross', '2');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('14', 'Ralph', 'Szygenda', '2');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('15', 'Rick', 'Dalzell', '2');
Enter fullscreen mode Exit fullscreen mode

Con la base de datos establecida, la parte correspondiente a la capa de acceso de datos hace referencia a la definición de las clases para trabajar con las entidades de la base de datos y al contexto para establecer la comunicación entre ASP.NET Core y la base de datos, que, en este caso, MySQL es la que se esta utilizando.

Para este propósito, es necesario instalar tres paquetes NuGet:

  • Microsoft.EntityFrameworkCore.Design
  • Microsoft.EntityFrameworkCore.Tools
  • MySql.Data.EntityFrameworkCore

En caso de que se esté trabajando con SQL Server, el paquete NuGet a instalar será: Microsoft.EntityFrameworkCore.SQLServer.

Posteriormente, es necesario utilizar la consola de administración de paquetes para realizar scaffolding desde la base de datos (generar automáticamente el contexto y las clases de las entidades) a través del siguiente comando:

Scaffold-DbContext "server=servername;port=portnumber;user=username;password=pass;database=databasename" MySql.Data.EntityFrameworkCore -OutputDir Entities -f
Enter fullscreen mode Exit fullscreen mode

Con esta primera parte, la conexión a la base de datos esta lista. Lo que prosigue a continuación es la definición de modelos con los cuales se trabajará en la página web. Estos modelos son:

public class PersonModel
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int IdPersonType { get; set; }
    public string NamePersonType { get; set; }
}
Enter fullscreen mode Exit fullscreen mode
public class PersonTypeModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Para cada uno de estos modelos se cuenta con un servicio, los cuales tienen las siguientes operaciones:

PersonService:

  • GetAllPersonsAsync()
  • GetPersonByIdAsync(int personId)
  • GetPersonByIdAndTypeAsync(int personId, int personTypeId)
  • GetAllPersonsByTypeAsync(int personTypeId)

PersonTypeService:

  • GetAllPersonTypesAsync()
  • GetPersonTypeByIdAsync(int personTypeId)

En Visual Studio 2019 tendremos algo como esto:

Vistamodelo

public class DefaultViewModel : MasterPageViewModel
{
    private readonly PersonService personService;
    public BusinessPackDataSet<PersonModel> Persons { get; set; } = new BusinessPackDataSet<PersonModel>();

    public List<int> PersonTypes { get; set; } = new List<int>();
    public string IdSearch { get; set; }
    public bool SearchByTextVisible { get; set; } = false;
    public bool IsWindowDisplayed { get; set; }

    public DefaultViewModel(PersonService personService)
    {
        this.personService = personService;
    }

    public async Task UpdatePersonList()
    {
        IdSearch = null;

        if (PersonTypes.Count == 2)
        {
            Persons.Items = await personService.GetAllPersonsAsync();
            SearchByTextVisible = true;
        }
        else if (PersonTypes.Count == 1)
        {
            int IdPersonType = PersonTypes.FirstOrDefault();
            Persons.Items = await personService.GetAllPersonsByTypeAsync(IdPersonType);
            SearchByTextVisible = true;
        }
        else
        {
            Persons.Items.Clear();
            SearchByTextVisible = false;
        }
    }

    public async Task SearchById()
    {
        if (PersonTypes.Count == 2)
        {
            if (!string.IsNullOrEmpty(IdSearch))
            {
                List<PersonModel> list = new List<PersonModel>(); ;
                list.Add(await personService.GetPersonByIdAsync(Int32.Parse(IdSearch)));
                Persons.Items = list;
            }
            else
            {
                Persons.Items = await personService.GetAllPersonsAsync();
            }
        }
        else if (PersonTypes.Count == 1)
        {
            if (!string.IsNullOrEmpty(IdSearch))
            {
                int IdPersonType = PersonTypes.FirstOrDefault();
                List<PersonModel> list = new List<PersonModel>(); ;
                list.Add(await personService.GetPersonByIdAndTypeAsync(Int32.Parse(IdSearch), IdPersonType));
                Persons.Items = list;
            }
            else
            {
                int IdPersonType = PersonTypes.FirstOrDefault();
                Persons.Items = await personService.GetAllPersonsByTypeAsync(IdPersonType);
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Vista

<dot:Content ContentPlaceHolderID="MainContent">

    <div class="content">

        <img src="/Resources/Images/tree.svg" class="content__background-image content__background-image--left" />

        <a href="https://www.dotvvm.com/" target="_blank">
            <img src="/Resources/Images/text.svg" class="content__image" />
        </a>
        <h1>PERSON REPORT FORM</h1>

        <img src="~/icon.png" width="15%" height="15%" />
        <div class="content__text">

            <bp:Window IsDisplayed="{value: IsWindowDisplayed}"
                       HeaderText="Reporting form"
                       CloseOnEscape="false"
                       CloseOnOutsideClick="false">

                <p>

                    <h1>Person report</h1>
                </p>
                <p>
                    <h4>Search by type:</h4>
                <p />
                <bp:CheckBox CheckedItems="{value: PersonTypes}"
                             Changed="{command: UpdatePersonList()}"
                             CheckedValue="{value: 1}" Text="Type A" />
                <br />
                <bp:CheckBox CheckedItems="{value: PersonTypes}"
                             Changed="{command: UpdatePersonList()}"
                             CheckedValue="{value: 2}" Text="Type B" />
                </p>

                <p>
                    <h4>Search by text:</h4>
                <p />
                ID Number:
                <bp:TextBox Text="{value: IdSearch}" Type="Number" class="page-input" Visible="{value: SearchByTextVisible}" />
                <bp:Button Text="Search" Click="{command: SearchById()}" class="page-button" Visible="{value: SearchByTextVisible}" />
                <p />

                <h4>Report:</h4>

                <bp:GridView DataSource="{value: Persons}" class="page-grid">
                    <Columns>
                        <bp:GridViewTextColumn Value="{value: Id}" HeaderText="Id" />
                        <bp:GridViewTextColumn Value="{value: FirstName}" HeaderText="Firstname" />
                        <bp:GridViewTextColumn Value="{value: LastName}" HeaderText="LastName" />
                        <bp:GridViewTextColumn Value="{value: NamePersonType}" HeaderText="Type" />
                    </Columns>
                    <EmptyDataTemplate>
                        There are no search results.
                    </EmptyDataTemplate>
                </bp:GridView>

            </bp:Window>

            <bp:Button Text="LOAD REPORT"
                       Click="{command: IsWindowDisplayed = true}" />

        </div>

        <img src="/Resources/Images/tree.svg" class="content__background-image content__background-image content__background-image--right" />
    </div>
</dot:Content>
Enter fullscreen mode Exit fullscreen mode

Análisis de la aplicación

En el siguiente GIF se puede visualizar de manera general la interacción con esta pequeña página web.

El primer elemento que analizaremos es el componente Window, el cual, representa a una ventana de diálogo de tipo modal, como en HTML. Este control nos permite personalizar directamente desde sus atributos como se visualizará la ventana. Si estuviésemos trabajando con los controles base de DotVVM, para lograr esta funcionalidad tendríamos que hacer uso de algunas funcionalidades de Javascript directamente para establecer la ventana. En este ejemplo, el título de la ventana se puede asignar. Asimismo, se pueden personalizar ciertas propiedades, por ejemplo, no permitir que la ventana se cierre al presionar la tecla Escape o dar clic fuera del recuadro de la ventana.

En este ejemplo, el atributo booleano IsWindowDisplayed, de acuerdo con su valor true o false, permitirá visualizar o no la ventana establecida.

<bp:Window IsDisplayed="{value: IsWindowDisplayed}"
            HeaderText="Reporting form"
            CloseOnEscape="false"
            CloseOnOutsideClick="false">
Enter fullscreen mode Exit fullscreen mode

Esta es la definición del atributo IsWindowDisplayed para la visualización de la ventana:

public bool IsWindowDisplayed { get; set; }
Enter fullscreen mode Exit fullscreen mode

Para mostrar la ventana, se hace uso de un botón. Este botón también es otro de los componentes Business Pack. La versión premium permite realizar ciertas personalizaciones en cuanto a sus estilos, por ejemplo, activar/desactivar el botón, asignar un icono, entre otras funcionalidades: Button/2.0.

El resultado es el siguiente:

Dentro de esta ventana, el elemento mas importante corresponde a la tabla que permite listar a los usuarios registrados en la base de datos. Para este objetivo se utiliza el elemento GridView, otro control de DotVVM que nos permite crear tablas para representar datos en específico. Como parte principal, el control nos permite indicar la fuente de datos a través de la propiedad DataSource, en este caso, la fuente de datos se define de la siguiente manera en el Viewmodel:

public GridViewDataSet<PersonModel> Persons { get; set; } = new GridViewDataSet<PersonModel>();
Enter fullscreen mode Exit fullscreen mode

Para la definición de las columnas se utiliza la etiqueta GridViewTextColumn. En este caso, podemos encontrar las columnas Id, FirstName, LastName y Type. Estos nombres vienen del tipo de dato de la fuente de datos, en este caso, del modelo PersonModel.

<bp:GridView DataSource="{value: Persons}" class="page-grid">
    <Columns>
        <bp:GridViewTextColumn Value="{value: Id}" HeaderText="Id" />
        <bp:GridViewTextColumn Value="{value: FirstName}" HeaderText="Firstname" />
        <bp:GridViewTextColumn Value="{value: LastName}" HeaderText="LastName" />
        <bp:GridViewTextColumn Value="{value: NamePersonType}" HeaderText="Type" />
    </Columns>
    <EmptyDataTemplate>
        There are no search results.
    </EmptyDataTemplate>
</bp:GridView>
Enter fullscreen mode Exit fullscreen mode

Una de las sub-etiquetas de GridView es EmptyDataTemplate, la cual está incluida también en los controles base de DotVVM. Esta etiqueta permite mostrar algún contenido HTML en caso de que el listado de elementos se encuentre vacío. A la final, con GridView visualizaremos algo como esto:

Más información sobre el componente GridView aquí: GridView/2.0.

Muy bien, con esta tabla tenemos la parte más importante del reporte. A partir de esto, podemos agregar componentes adicionales para establecer criterios de búsqueda por ejemplo y actualizar esta tabla según la búsqueda.

El primer caso es utilizando la versión premium del control CheckBox de DotVVM. Al igual que en HTML o cualquier otro entorno de diseño, el CheckBox tiene el rol como casilla de verificación para seleccionar elementos en un conjunto de opciones. Para este ejemplo, el objetivo es tener dos casillas de verificación, los cuales corresponden a los tipos de personas. Según la selección, ya sea del tipo A, del tipo B, o de los dos, la tabla de registros se actualizará de acuerdo con esta decisión.

En la parte de la vista, nos encontramos con la propiedad CheckedItems que almacenara el valor de los elementos que se encuentren seleccionados. Asimismo, nos encontramos con la propiedad Changed, la cual permite especificar el método que realizara las acciones al momento que este elemento sea activado o desactivado.

<bp:CheckBox CheckedItems="{value: PersonTypes}"
                Changed="{command: UpdatePersonList()}"
                CheckedValue="{value: 1}" Text="Type A" />

<bp:CheckBox CheckedItems="{value: PersonTypes}"
                Changed="{command: UpdatePersonList()}"
                CheckedValue="{value: 2}" Text="Type B" />
Enter fullscreen mode Exit fullscreen mode

En el método de actualización de los registros de la tabla, si seleccionados uno de los dos tipos, entonces realizaremos una consulta en la base de datos de acuerdo con el servicio definido: PersonService, para obtener el listado de personas según el id seleccionado. Con este listado recuperado, actualizaremos la base de datos al establecer nuevamente los ítems de la fuente de datos del GridView.

Persons.Items.Clear();
Enter fullscreen mode Exit fullscreen mode

Como vimos en el GIF, el resultado de utilizar el control CheckBox es el siguiente:

Más información sobre el componente CheckBox aquí: CheckBox/2.0.

Otro de los controles que nos permiten seguir agregando funcionalidades al GridView para establecer criterios de búsqueda a este reporte son los elementos TextBox y Button. En este caso, estos componentes pueden ser de utilizad para buscar algún elemento específico del reporte a través de una entrada de texto. Para ejemplificar el uso de estos elementos en la aplicación, los controles sirven para encontrar a una persona especifica según su Id.

ID Number:

<bp:TextBox Text="{value: IdSearch}" Type="Number" class="page-input" Visible="{value: SearchByTextVisible}" />

<bp:Button Text="Search" Click="{command: SearchById()}" class="page-button" Visible="{value: SearchByTextVisible}" />
Enter fullscreen mode Exit fullscreen mode

La actualización de los elementos del GridView es similar al caso del CheckBox. El resultado es el siguiente:

Toda la información sobre el control TextBox la podemos encontrar en: TextBox/2.0. Y la del control Button en: Button/2.0.

¿Qué sigue?

Con este artículo, hemos aprendido ciertas características de los componentes Windows, GridView, CheckBox, TextBox y Button del conjunto de controles Business Pack de DotVVM para visualizar un listado de datos y establecer criterios de búsqueda a través del patrón de diseño Modelo, Vista, Vistamodelo en ASP.NET Core y DotVVM.

El código fuente de esta implementación está disponible en este repositorio: Reports in DotVVM with Business Pack controls.

Recursos adicionales

Deseas seguir adquiriendo nuevos conocimientos sobre ASP.NET Core y DotVVM, estos recursos podrían ser de tu interés:

Gracias:

Si tienes alguna inquietud o necesitas ayuda en algo particular, será un gusto poder ayudar.

Nos vemos en Twitter!! :)

¡Hasta pronto!

Top comments (0)