DEV Community

Cover image for Desarrollo de aplicaciones web con ASP.NET Core, y PostgreSQL
Daniel Gomez
Daniel Gomez

Posted on • Edited on

Desarrollo de aplicaciones web con ASP.NET Core, y PostgreSQL

DotVVM es un marco de trabajo de ASP.NET que nos permite crear aplicaciones web utilizando el patrón de diseño MVVM (Modelo Vista Vista-Modelo) empleando C# y HTML. En este tutorial aprenderemos como crear operaciones CRUD (Crear, Leer, Actualizar y Borrar) empleando una base de datos relacional con PostgreSQL, desde ASP.NET Core.

¿Deseas saber cuáles son los pasos para crear una aplicación DotVVM? Para ello puedes revisar este articulo: Pasos a seguir para crear una aplicación MVVM (Modelo Vista Vista-Modelo) con DotVVM y ASP.NET Core.

Introducción a ADO.NET Entity Framework

ADO.NET Entity Framework es un marco de asignación relacional de objetos (ORM). Está diseñado para permitirnos crear aplicaciones de acceso a datos mediante la programación en un modelo de aplicación conceptual en lugar de programar directamente en un esquema de almacenamiento relacional. El objetivo es reducir la cantidad de código y mantenimiento necesarios para las aplicaciones orientadas a datos.

Recursos necesarios

Para trabajar con PostgreSQL sobre ASP.NET Core con DotVVM, las herramientas recomendadas para establecer nuestro entorno de trabajo son las que se listan a continuación:

La base de datos en PostgreSQL

Para este articulo tutorial, vamos a crear una base de datos de ejemplo en PostgreSQL, la cual nos permita trabajar con datos de usuario y posteriormente implementar operaciones CRUD en ASP.NET Core.

Para establecer nuestra base de datos podemos utilizar la herramienta pgAdmin4, la cual suele ser incluida al instalar PostgreSQL. Al crear el esquema, el código SQL para crear nuestra tabla de usuario es el siguiente:



CREATE SEQUENCE id_seq
    INCREMENT 1
    START 1
    MINVALUE 1
    MAXVALUE 9223372036854775807
    CACHE 1;

CREATE TABLE person
(
    id_ integer NOT NULL DEFAULT nextval('id_seq'::regclass),
    firstname character varying(45) COLLATE pg_catalog."default" NOT NULL,
    lastname character varying(45) COLLATE pg_catalog."default" NOT NULL,
    username character varying(45) COLLATE pg_catalog."default" NOT NULL,
    city character varying(45) COLLATE pg_catalog."default" NOT NULL,
    country character varying(45) COLLATE pg_catalog."default" NOT NULL,
    postalcode integer NOT NULL,
    about character varying(45) COLLATE pg_catalog."default" NOT NULL,
    enrollmentdate timestamp without time zone NOT NULL,
    CONSTRAINT person_pkey PRIMARY KEY (id_)
)



Enter fullscreen mode Exit fullscreen mode

Aquí la clave primaria id_ se encuentra con una secuencia para que el valor de esta clave sea autoincrementadle.

Proyecto en Visual Studio 2019

Ahora que la base de datos se encuentra establecida, a continuación, podemos empezar a desarrollar nuestra solución en Visual Studio. En este nuevo proyecto contaremos con tres partes:

  • DAL (Data Access Layer): para manejar la conexión a PostgreSQL y el acceso a la base de datos.
  • BL (Business Layer): para el manejo de los servicios y la lógica del dominio de la aplicación.
  • PL: para trabajar con la capa de presentación de la aplicación, en este caso, con DotVVM.

Para empezar, crearemos un nuevo proyecto en Visual Studio 2019 de tipo DotVVM Web Application:

Al crear el proyecto, el asistente de configuración de DotVVM nos permitirá seleccionar una serie de opciones con ajustes, estilos y plantillas ya preestablecidas:

En este caso dejaremos todo como esta y crearemos el proyecto. Al crear una carpeta DAL y BL para la capa de acceso de datos y la lógica de negocios respectivamente, en la solución tendremos algo como esto:

La conexión con PostgreSQL

Muy bien, como primer punto vamos a relacionar a nuestro proyecto con la base de datos creada en PostgreSQL. En Entity Framework existen dos enfoques, el primero Code-First, el cual nos permite generar la base de datos a traves de clases, y el segundo, Database-First, el cual nos permite generar las clases de entidades desde una base de datos existente. Como es de esperarse, en este caso utilizaremos el enfoque Database-First. Para cumplir con este objetivo, será necesario instalar tres paquetes Nuget:

  • Microsoft.EntityFrameworkCore.Design
  • Microsoft.EntityFrameworkCore.Tools
  • Npgsql.EntityFrameworkCore.PostgreSQL

Luego necesitaremos insertar un comando desde la consola de administración de paquetes. Esta consola la podemos activar desde el Menú de opciones -> Ver -> Otras Ventanas -> Consola de Administración de Paquetes.

En esta consola insertaremos el siguiente comando:



Scaffold-DbContext "Host=hostname;port=portnumber;Username=username;Password=pass;Database=databasename" Npgsql.EntityFrameworkCore.PostgreSQL DAL/Entities -f


Enter fullscreen mode Exit fullscreen mode

Donde:

  • Hostname, es el nombre del servidor de donde se encuentra la base de datos. Ejemplo: localhost.
  • Portnumber, puerto del host. Generalmente PostgreSQL se encuentra en el puerto 5432.
  • Username, nombre de usuario de la base de datos.
  • Password, contraseña del usuario que va a acceder a la base de datos.
  • Database, nombre de la base de datos.

Asimismo,

  • -f, con esta abreviación podemos indicar donde serán generados los archivos.
  • -Table, abreviación adicional en caso de que se deseen indicar las tablas especificas a generar en nuestra capa de acceso de datos.

Al introducir el comando correctamente, tendremos algo como esto:

Donde Person es la clase que se encuentra asociada a la entidad con su mismo nombre en la base de datos y el DBContext es donde se encuentran las configuraciones correspondientes.

La clase Person está definida de la siguiente manera:



public partial class Person
{
    public int Id { get; set; }
    public string Firstname { get; set; }
    public string Lastname { get; set; }
    public string Username { get; set; }
    public string City { get; set; }
    public string Country { get; set; }
    public int Postalcode { get; set; }
    public string About { get; set; }
    public DateTime Enrollmentdate { get; set; }
}


Enter fullscreen mode Exit fullscreen mode

Y el DBContext, el cual tiene la configuración con la base de datos, cuyo método principal OnConfiguring se verá algo como esto:



protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {                optionsBuilder.UseMySQL("host=localhost;port=5432;username=<Username>;password=;database=<Database_name>");
            }
        }



Enter fullscreen mode Exit fullscreen mode

Ahora, no es lo más adecuado que la cadena de conexión a la base de datos se encuentre especificada en este método OnConfiguring, para ello, especificaremos la cadena de conexión en el archivo appsettings.json de la siguiente manera:



"AllowedHosts": "*",
"ConnectionStrings": {
  "DefaultConnection": "host=localhost;port=5432;username=<Username>;password=;database=<Database_name>");
}



Enter fullscreen mode Exit fullscreen mode

Luego, en la clase Startup en método ConfigureServices agregamos como servicio al DBContext y hacemos referencia a la propiedad DefaultConnection especificada en el archivo appsettings.json:



public void ConfigureServices(IServiceCollection services)
{
    services.AddEntityFrameworkNpgsql ()
        .AddDbContext<DBContext>(options =>
        {
            options. UseNpgsql(Configuration.GetConnectionString("DefaultConnection"));
        });
}



Enter fullscreen mode Exit fullscreen mode

En este caso, regresando a la clase del DBContext, borramos la cadena de conexión especificada en el método OnConfiguring. A la final tendríamos el método vacío:



protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{}


Enter fullscreen mode Exit fullscreen mode

Y el constructor del DBContext estaría definido de la siguiente manera:



public DBContext(DbContextOptions<DBContext> options)
    : base(options) {}


Enter fullscreen mode Exit fullscreen mode

Con estos pasos ya tenemos lista la conexión y las configuraciones necesarias para trabajar con la base de datos PostgreSQL en ASP.NET Core con la ayuda de Entity Framework.

Los servicios para trabajar sobre los datos

Ahora nos toca definir los modelos y crear los servicios para manejar la lógica de nuestra aplicación. En este caso, lo que se busca es tener un listado general de los usuarios y la información específica de cada uno de ellos.

Modelos

Los modelos nos permitirán representar con que datos vamos a querer trabajar al momento de diseñar nuestra página web. En este caso, los modelos serán los siguientes

A. UserListModel



public class UserListModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string City { get; set; }
    public string Country { get; set; }
    public DateTime Enrollmentdate { get; set; }
}


Enter fullscreen mode Exit fullscreen mode

B. UserDetailModel



public class UserDetailModel
{
    public int Id { get; set; }
    public string Firstname { get; set; }
    public string Lastname { get; set; }
    public string Username { get; set; }
    public string City { get; set; }
    public string Country { get; set; }
    public int Postalcode { get; set; }
    public string About { get; set; }
    public DateTime Enrollmentdate { get; set; }
}


Enter fullscreen mode Exit fullscreen mode

Servicios

En segunda instancia, es necesario definir los servicios de nuestra aplicación, los cuales contaran con los métodos necesarios para acceder y guardar datos sobre los usuarios en la base de datos. En este caso tenemos un servicio de usuarios que nos permitirá realizar operaciones CRUD.

Para realizar operaciones sobre los datos utilizaremos LINQ - Language Integrated Query, un componente de la plataforma Microsoft .NET que agrega capacidades de consulta a datos de manera nativa a los lenguajes .NET. En otras palabras, LINQ nos permite realizar consultas sobre colecciones de objetos (las entidades definidas en el DAL) para manejar la información y realizar operaciones sobre la base de datos.

Teniendo en cuenta estas consideraciones, los ajustes iniciales y los métodos para tratar los datos son los siguientes:

A. Ajustes iniciales



private readonly DBContext DbContext;

public UserService(DBContext DbContext)
{
    this.DbContext = DbContext;
}


Enter fullscreen mode Exit fullscreen mode

B. Obtener todos los usuarios registrados



public async Task<List<UserListModel>> GetAllUsersAsync()
{

    return await DbContext.Person.Select(
        s => new UserListModel
        {
            Id = s.Id,
            Name = s.Firstname + " " + s.Lastname,
            City = s.City,
            Country = s.Country,
            Enrollmentdate = s.Enrollmentdate
        }
    ).ToListAsync();
}


Enter fullscreen mode Exit fullscreen mode

C. Obtener un usuario en específico por su Id



public async Task<UserDetailModel> GetUserByIdAsync(int UserId)
{
    return await DbContext.Person.Select(
            s => new UserDetailModel
            {
                Id = s.Id,
                Firstname = s.Firstname,
                Lastname = s.Lastname,
                Username = s.Username,
                City = s.City,
                Country = s.Country,
                Postalcode = s.Postalcode,
                Enrollmentdate = s.Enrollmentdate,
                About = s.About
            })
        .FirstOrDefaultAsync(s => s.Id == UserId);
}


Enter fullscreen mode Exit fullscreen mode

D. Insertar un nuevo usuario



public async Task InsertUserAsync(UserDetailModel User)
{
    var entity = new Person()
    {
        Firstname = User.Firstname,
        Lastname = User.Lastname,
        Username = User.Username,
        City = User.City,
        Country = User.Country,
        Postalcode = User.Postalcode,
        Enrollmentdate = User.Enrollmentdate,
        About = User.About
    };

    DbContext.Person.Add(entity);
    await DbContext.SaveChangesAsync();
}



Enter fullscreen mode Exit fullscreen mode

E. Actualizar los datos de un usuario



public async Task UpdateUserAsync(UserDetailModel User)
{
    var entity = await DbContext.Person.FirstOrDefaultAsync(s => s.Id == User.Id);

    entity.Firstname = User.Firstname;
    entity.Lastname = User.Lastname;
    entity.Username = User.Username;
    entity.City = User.City;
    entity.Country = User.Country;
    entity.Postalcode = User.Postalcode;
    entity.Enrollmentdate = User.Enrollmentdate;
    entity.About = User.About;

    await DbContext.SaveChangesAsync();
}


Enter fullscreen mode Exit fullscreen mode

F. Eliminar un usuario



public async Task DeleteUserAsync(int UserId)
        {
            var entity = new Person()
            {
                Id = UserId
            };
            DbContext.Person.Attach(entity);
            DbContext.Person.Remove(entity);
            await DbContext.SaveChangesAsync();
        }



Enter fullscreen mode Exit fullscreen mode

Para ver más a detalle el funcionamiento de LINQ puedes consultar la documentación de Microsoft en: https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/linq-to-entities.

Para finalizar con esta sección, este servicio deberá ser referenciado en la clase Startup, en el método ConfigureServices (el mismo donde se realizo el ajuste con EntityFramework). Aquí debemos agregar la siguiente sentencia:



services.AddTransient(typeof(UserService));


Enter fullscreen mode Exit fullscreen mode

Nota: en caso de generar más servicios, todos ellos deberán ser especificados en este método de la clase Startup.

Al final, la solución en Visual Studio sobre la sección de la capa lógica de negocios se verá así:

Representación de los datos en una aplicación web

Ahora que ya tenemos definidas las capas de acceso de datos y la lógica del negocio, ahora podemos realizar el diseño de la página web para que las personas puedan interactuar con ella y en este caso, utilizar las operaciones CRUD implementadas para el manejo de usuarios.

En esta sección vamos a ver como diseñar un dashboard para ingresar los datos a través de formularios y listarlos en tablas. Este proceso es descrito en el siguiente articulo: Construyendo un Dashboard con ASP.NET Core y DotVVM.

El resultado final del diseño empleando DotVVM y los servicios implementados anteriormente que acceden a PostgreSQL, es el siguiente:

Plus: Alojar la base de datos de PostgreSQL en Azure

Hoy en día la tendencia está en publicar las páginas web en la nube, para ello existen diversos servicios que nos permiten cumplir con estos objetivos, sea cual sea el gestor de base de datos que se esté utilizando, la base de datos también deberá estar en la nube para que la página web pueda funcionar. Para el caso de PostgreSQL, en Azure podemos encontrar el recurso: Azure Database for PostgreSQL servers.

Para crear el recurso en Azure necesitaremos lo siguiente:

Una suscripción de Azure, especificar los detalles del servidor (nombre, fuente, ubicación, versión y características de computo y almacenamiento), y las credenciales para poder acceder a esta base de datos como administrador.

Una vez que se haya creado, podemos dirigirnos al recurso en la sección Connection Strings y encontrar la cadena de conexión que deberemos cambiar en nuestro proyecto, en Azure podemos copiar la cadena que se encuentra en la sección ADO.NET y adaptarla a la cadena que ya tenemos establecida en el archivo appsettings.json.

¿Qué sigue?

A continuación, como se mostró anteriormente, puedes seguir con la segunda parte de este artículo en donde podrás ver paso a paso como generar un dashboard con DotVVM: Construyendo un Dashboard con ASP.NET Core y DotVVM.

El código fuente de todo el proyecto para la construcción del dashboard con ASP.NET Core y DotVVM con PostgreSQL está disponible en el siguiente repositorio: User Dashboard.

Como recurso adicional, en este articulo puedes ver paso a paso como desplegar una aplicación web a Azure: Despliegue de aplicaciones web DotVVM y .NET Core en Azure.

Muchas gracias por leer.

Si tienes alguna pregunta o alguna idea que necesites discutir, será un gusto poder colaborarte y juntos intercambiar conocimientos entre sí.

¡Nos vemos en Twitter! :)

Top comments (0)