9.6 Guardando el historial de cambios

Puedes agregar otro action filter para ir registrando todos los cambios que realizan los usuarios al sistema. Vamos a registrar el usuario, la fecha en que se realiza el cambio, y un campo adicional para agregar opciones adicionales, como por ejemplo mostrar el valor anterior.

Agregamos nuestra clase HistorialDAO para registrar el historial de los usuarios. El método borrar va a borrar la información del historial del registro que se esta borrando.

HistorialDAOcs
public class HistorialDAO
{
    private readonly CaducaContext contexto;
    private readonly LocService localizacion;

    public HistorialDAO(CaducaContext context, LocService locService)
    {
        this.contexto = context;
        this.localizacion = locService;
    }

    public async Task<bool> AgregarAsync(int usuarioId, 
                                            int actividad,
                                            string nombreTabla, 
                                            int origenId,
                                            string observaciones)
    {
        var tablaId = await ObtenerIdTablaAsync(nombreTabla);
        Historial historial = new Historial
        {
            Actividad = actividad,
            FechaHora = DateTime.Now,
            Observa = observaciones,
            OrigenId = origenId,
            TablaId = tablaId,
            UsuarioId = usuarioId
        };
        contexto.Historial.Add(historial);
        contexto.SaveChanges();
        return true;
    }

    private async Task<int> ObtenerIdTablaAsync(string nombreTabla)
    {
        Tabla tabla = await contexto.Tabla
                .FirstOrDefaultAsync(e => e.Nombre == nombreTabla);
        if (tabla == null)
        {
            return -1;
        }
        return tabla.Id;
    }
    
    public async Task<bool> BorraAsync( string nombreTabla, 
                                         int origenId)
    {
        var tablaId = await ObtenerIdTablaAsync(nombreTabla);
        var consulta = await (from historial in contexto.Historial
                        where historial.TablaId == tablaId
                        && historial.OrigenId == origenId                 
                        select historial).ToListAsync();
        contexto.Historial.RemoveRange(consulta);
        contexto.SaveChanges();
        return true;
    }
}

Agregamos una Enumeración ActividadEnumeration con los tipos de actividades que los usuarios pueden realizar.

ActividadEnumeration.cs
public enum ActividadEnumeration
{
        Borrar      = -1,
        Insertar    = 1,
        Modificar   = 2,
        Autorizar   = 3,
        Cancelar    = 4 
}

Para esto agregamos una propiedad llamada Id de tipo entero a nuestra clase BaseController, aqui vamos a agregar el Id de cada registro que se este actualizando

BaseController.cs
public class BaseController : Controller
{
    public int Id;
    public string Observaciones;
}

En ProductosController a los métodos Post, Put y Delete vamos a agregar el Id del registro y agregamos nuestro filtro historial

ProductosController.cs
[TypeFilter(typeof(HistorialFilter))]
public class ProductosController : BaseController
{
    [HttpPost]
    public async Task<IActionResult> PostProducto(
                                       [FromBody] Producto producto)
    {
        if (!await productoDAO.AgregarAsync(producto))
        {
            return StatusCode(productoDAO.customError.StatusCode,
                                  productoDAO.customError.Message);
        }
        Id = producto.Id;
        return CreatedAtAction("GetCategoria", 
                              new { id = producto.Id }, producto);
    }
    
    [HttpPut("{id}")]
    public async Task<IActionResult> PutProducto([FromRoute] int id, 
                                        [FromBody] Producto producto)
    {
        if (!ModelState.IsValid)
            return BadRequest(ModelState);

        if (id != producto.Id)
             return BadRequest();

        if (!await productoDAO.ModificarAsync(producto))
        {
            return StatusCode(productoDAO.customError.StatusCode,
                                  productoDAO.customError.Message);
        }
        Id = producto.Id;
        return NoContent();
    }
    
    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteProducto([FromRoute] int id)
    {
        if (!ModelState.IsValid)
            return BadRequest(ModelState);
        if (!await productoDAO.BorraAsync(id))
        {
                return StatusCode(productoDAO.customError.StatusCode,
                                  productoDAO.customError.Message);
        }
        Id = id;
        return Ok();
    }

En nuestra carpeta Filters agregamos un nueva clase HistorialFilter

HistorialFilter.cs
using System;
using System.Linq;
using System.Security.Claims;
using CaducaRest.Controllers;
using CaducaRest.Core;
using CaducaRest.DAO;
using CaducaRest.Models;
using CaducaRest.Resources;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace CaducaRest.Filters;

public class HistorialFilter : IActionFilter
{
    private readonly LocService _localizer;
    private readonly CaducaContext _context;

    public HistorialFilter(CaducaContext context, 
                           LocService localizer)
    {
        this._localizer = localizer;
        this._context = context;
    }
    //Este método se ejecuta al terminar el código de cada
    //método
    public void OnActionExecuted(ActionExecutedContext context)
    {
        bool correcto = false;
        //Si la acción se realiza correctamente
        correcto = context.Result is OkObjectResult
            || context.Result is NoContentResult
            || context.Result is CreatedAtActionResult;

        if (correcto)
        {
            ClaimsPrincipal Usuario = context.HttpContext.User;
            //Obtenemos nuestro controlador
            var controller = context.Controller as BaseController;
            //Obtenemos el método que se ejecutó (POST, PUT, 
            //DELETE, etc)
            string metodo = controller.Request.Method.ToLower();
            //Identificamos de acuerdo al método la acción
            //realizada
            int actividad;
            switch (metodo)
            {
                case "post":
                    actividad = (int)ActividadEnumeration.Insertar;
                    break;
                case "put":
                case "patch":
                    actividad = (int)ActividadEnumeration.Modificar;
                    break;
                case "delete":
                    actividad = (int)ActividadEnumeration.Borrar;
                    break;
                default:
                    actividad = 0;
                    break;
            }
            int UsuarioId = 0;
            if (correcto)
            {
                int.TryParse(Usuario.Claims
                  .FirstOrDefault(x => x.Type == ClaimTypes.Sid)
                  .Value, out UsuarioId);
                if (UsuarioId > 0 && controller.Id > 0)
                {
                    //Si es una acción de alta o edición
                    //agregamos un registro al historial
                    HistorialDAO historialDAO = 
                         new HistorialDAO(_context, _localizer);
                    if (actividad > 0)
                        _ = historialDAO.AgregarAsync(UsuarioId,
                                  actividad,
                                  controller.permiso.Tabla,
                                  controller.Id,
                                  controller.Observaciones).Result;
                    else
                    {
                        //Borramos el historial del registro
                        if (actividad < 0)
                            _ = historialDAO
                            .BorraAsync(controller.permiso.Tabla,
                                     controller.Id).Result;
                    }
                }
            }
        }
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
    }
}

De esta manera cada vez que se guarda, modifica, o borra algún registro guardamos el historial de cambios del registro.

Last updated