Interceptores
Los interceptores permiten ejecutar lógica personalizada del lado del servidor antes y después de las operaciones de Dataverse. Al implementar la ITableRecordInterceptor interfaz, puedes conectarte al ciclo de vida de la creación de registros, actualizaciones, eliminaciones, asociaciones y disociaciones.
Resumen
Los casos de uso comunes de los interceptores incluyen:
- Establecer valores predeterminados de campo antes de que se cree un registro (por ejemplo, un estado inicial o un nombre de visualización derivado de otro campo)
- Validar o transformar datos antes de que se conserven
- Hacer cumplir reglas de negocio que van más allá de la validación a nivel de campo
- Registro de auditoría después de crear, actualizar o eliminar registros
- Efectos secundarios desencadenantes como enviar notificaciones o actualizar registros relacionados
Nota
Los interceptores se ejecutan en el servidor y se aplican a todas las operaciones de todas las tablas. Usa la
TableRecord.TableNamepropiedad para filtrar la lógica a tablas específicas.
Nota
Para registrar quién creó una fila, no se establece la columna propietaria en un interceptor — descríbela en el acceso de la tabla con
OwnedByoRowsOwnedByContacten su lugar (ver Seguridad de la Tabla). El framework entonces establece la columna después de las comprobaciones de permisos, desde el usuario iniciado sesión en lugar de desde la solicitud, y rechaza una actualización posterior que entregaría la fila a otra persona. Un gancho antes se ejecuta antes de las comprobaciones de permisos, por lo que un valor que establece se juzga como si el usuario lo hubiera enviado, y nada impide que una actualización posterior lo cambie.
Empezando
1. Crear un interceptor
Crea una clase que implemente ITableRecordInterceptor y proporcione implementaciones para cada método. Devuélvelo Task.CompletedTask por cualquier ganchos que no necesites.
public class MyInterceptor : ITableRecordInterceptor
{
public Task OnBeforeCreateAsync(TableRecord record)
{
if (record.TableName == "contact")
{
// Establecer un valor predeterminado antes de crear el registro
record.Properties["statuscode"] = new ChoiceValue(1);
}
return Task.CompletedTask;
}
public Task OnAfterCreateAsync(TableRecord record) => Task.CompletedTask;
public Task OnBeforeUpdateAsync(TableRecord record) => Task.CompletedTask;
public Task OnAfterUpdateAsync(TableRecord record) => Task.CompletedTask;
public Task OnBeforeDeleteAsync(TableRecordReference record) => Task.CompletedTask;
public Task OnAfterDeleteAsync(TableRecordReference record) => Task.CompletedTask;
public Task OnBeforeAssociateAsync(TableRecord record) => Task.CompletedTask;
public Task OnAfterAssociateAsync(TableRecord record) => Task.CompletedTask;
public Task OnBeforeDisassociateAsync(TableRecord record) => Task.CompletedTask;
public Task OnAfterDisassociateAsync(TableRecord record) => Task.CompletedTask;
}
2. Registrar en la inyección de dependencias
Registra tu interceptor en el contenedor DI del archivo de Program.cs tu proyecto:
builder.Services.AddTransient<ITableRecordInterceptor, MyInterceptor>();
Dado que los interceptores se resuelven desde el contenedor DI, puedes inyectar cualquier servicio necesario mediante inyección de constructores.
Ganchos del ciclo de vida
La interfaz proporciona ganchos antes y después para cinco tipos de operaciones:
Crear
OnBeforeCreateAsync y OnAfterCreateAsync correr por la creación de nuevos discos. El gancho antes es ideal para establecer valores predeterminados o validar campos requeridos.
public Task OnBeforeCreateAsync(TableRecord record)
{
if (record.TableName == "ppp_file")
{
// Muestra el nombre del archivo subido, sin su extensión, en la columna de visualización
var file = record.Properties.Values.OfType<FileValue>().FirstOrDefault();
if (file is not null)
{
record["ppp_filename"] = new StringValue
{
Value = Path.GetFileNameWithoutExtension(file.FileName)
};
}
}
return Task.CompletedTask;
}
Actualización
OnBeforeUpdateAsync y OnAfterUpdateAsync que se corran para registrar actualizaciones. Utiliza el gancho antes para hacer cumplir reglas de negocio o modificar valores antes de que se mantengan.
Borrar
OnBeforeDeleteAsync y OnAfterDeleteAsync evitar la eliminación de registros. Cabe señalar que estos ganchos reciben un TableRecordReference (nombre de tabla e ID) en lugar de un archivo completo TableRecord.
Asociado y Disociado
OnBeforeAssociateAsync / OnAfterAssociateAsync y OnBeforeDisassociateAsync / OnAfterDisassociateAsync se ejecutan cuando se crean o eliminan relaciones de muchos-a-muchos.
Servicios de inyección
Como los interceptores están registrados en el contenedor DI, puedes inyectar servicios mediante inyección de constructores. Esto es útil para acceder al estado de autenticación, registro u otros servicios de aplicación.
internal class FileUploadLimitInterceptor(
AuthenticationStateProvider authStateProvider) : ITableRecordInterceptor
{
public async Task OnBeforeCreateAsync(TableRecord record)
{
var authState = await authStateProvider.GetAuthenticationStateAsync();
// Usa authState para aplicar una regla por usuario, como una cuota...
}
// ... otros métodos devuelven Task.CompletedTask
}
Referencia API
ITableRecordInterceptor Interface
Métodos
Nombre | Parámetros | Tipo | Descripción |
|---|---|---|---|
OnAfterAssociateAsync | TableRecord record | Task | Invocado después de que un registro se haya asociado con otro disco a través de una relación de muchos a muchos. Útil para actualizar agregados relacionados, emitiendo eventos de dominio, o manteniendo la integridad referencial. |
OnAfterCreateAsync | TableRecord record | Task | Invocado inmediatamente después de que se haya creado un nuevo registro. Úsalo para acciones posteriores a la creación como registros, notificaciones, o activar flujos de trabajo posteriores. |
OnAfterDeleteAsync | TableRecordReference record | Task | Invocado después de que un registro haya sido eliminado. Útil para tareas de limpieza, registro de auditorías o cascada de eventos de dominio. |
OnAfterDisassociateAsync | TableRecord record | Task | Invocado después de que un registro haya sido disociado de otro récord. Útil para limpiar, actualizar agregados, o desencadenar procesos de seguimiento. |
OnAfterUpdateAsync | TableRecord record | Task | Invocado después de que se haya actualizado un registro existente. Útil para registro de auditorías, invalidación de caché o disparos Procesos de seguimiento. |
OnBeforeAssociateAsync | TableRecord record | Task | Invocado antes de que un registro esté asociado con otro Graba a través de una relación de muchos a muchos. Usa esto para validar la asociación, hacer cumplir normas de relaciones, o evitar enlaces inválidos. |
OnBeforeCreateAsync | TableRecord record | Task | Invocado inmediatamente antes de que se cree un nuevo registro. Utiliza esto para validar, mutar o preparar el registro antes de la persistencia. |
OnBeforeDeleteAsync | TableRecordReference record | Task | Invocado antes de que se elimine un registro. Utiliza esto para hacer cumplir las reglas de borrado, realizar conversiones de eliminación suave, o bloquear la eliminación bajo ciertas condiciones. |
OnBeforeDisassociateAsync | TableRecord record | Task | Invocado antes de que un registro se disocie de otro Registro. Usa esto para validar la disociación, hacer cumplir restricciones, o eliminación de bloqueos de relaciones requeridas. |
OnBeforeUpdateAsync | TableRecord record | Task | Invocado antes de que se actualice un registro existente. Úsalo para validar cambios, hacer cumplir reglas de negocio o modificar el registro anterior a la actualización se mantuvo. |
OnAfterAssociateAsyncOnAfterCreateAsyncOnAfterDeleteAsyncOnAfterDisassociateAsyncOnAfterUpdateAsyncOnBeforeAssociateAsyncOnBeforeCreateAsyncOnBeforeDeleteAsyncOnBeforeDisassociateAsyncOnBeforeUpdateAsync