Interceptors

Interceptors allow you to run custom server-side logic before and after Dataverse operations. By implementing the ITableRecordInterceptor interface, you can hook into the lifecycle of record creation, updates, deletions, associations, and disassociations.

Overview

Common use cases for interceptors include:

Note

Interceptors run on the server and apply to all operations for all tables. Use the TableRecord.TableName property to filter logic to specific tables.

Getting Started

1. Create an Interceptor

Create a class that implements ITableRecordInterceptor and provide implementations for each method. Return Task.CompletedTask for any hooks you don't need.

public class MyInterceptor : ITableRecordInterceptor
{
    public Task OnBeforeCreateAsync(TableRecord record)
    {
        if (record.TableName == "contact")
        {
            // Set a default value before the record is created
            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. Register in Dependency Injection

Register your interceptor in the DI container in your project's Program.cs file:

builder.Services.AddTransient<ITableRecordInterceptor, MyInterceptor>();

Since interceptors are resolved from the DI container, you can inject any required services through constructor injection.

Lifecycle Hooks

The interface provides before and after hooks for five types of operations:

Create

OnBeforeCreateAsync and OnAfterCreateAsync run around new record creation. The before hook is ideal for setting default values or validating required fields.

public async Task OnBeforeCreateAsync(TableRecord record)
{
    if (record.TableName == "contact")
    {
        // Assign the current user as the owning contact
        var authState = await _authStateProvider.GetAuthenticationStateAsync();
        var userId = authState.User.GetUserId();
        if (userId != null)
        {
            record.Properties["ppp_owningcontact"] = new LookupValue
            {
                TableName = "contact",
                Value = userId.Value
            };
        }
    }
}

Update

OnBeforeUpdateAsync and OnAfterUpdateAsync run around record updates. Use the before hook to enforce business rules or modify values before they are persisted.

Delete

OnBeforeDeleteAsync and OnAfterDeleteAsync run around record deletion. Note that these hooks receive a TableRecordReference (table name and ID) rather than a full TableRecord.

Associate & Disassociate

OnBeforeAssociateAsync / OnAfterAssociateAsync and OnBeforeDisassociateAsync / OnAfterDisassociateAsync run when many-to-many relationships are created or removed.

Injecting Services

Because interceptors are registered in the DI container, you can inject services via constructor injection. This is useful for accessing authentication state, logging, or other application services.

internal class SetOwnerInterceptor(
    AuthenticationStateProvider authStateProvider) : ITableRecordInterceptor
{
    public async Task OnBeforeCreateAsync(TableRecord record)
    {
        var authState = await authStateProvider.GetAuthenticationStateAsync();
        // Use authState to set owner fields...
    }

    // ... other methods return Task.CompletedTask
}

API Reference

ITableRecordInterceptor Class

Methods

Name
Parameters
Type
Description
OnAfterAssociateAsyncTableRecord record
Task
Invoked after a record has been associated with
another record via a many-to-many relationship. Useful for updating related aggregates,
emitting domain events, or maintaining referential integrity.
OnAfterCreateAsyncTableRecord record
Task
Invoked immediately after a new record has been created.
Use this for post‑creation actions such as logging, notifications,
or triggering downstream workflows.
OnAfterDeleteAsyncTableRecordReference record
Task
Invoked after a record has been deleted.
Useful for cleanup tasks, audit logging, or cascading domain events.
OnAfterDisassociateAsyncTableRecord record
Task
Invoked after a record has been disassociated from
another record. Useful for cleanup, updating aggregates,
or triggering follow‑up processes.
OnAfterUpdateAsyncTableRecord record
Task
Invoked after an existing record has been updated.
Useful for audit logging, cache invalidation, or triggering
follow‑up processes.
OnBeforeAssociateAsyncTableRecord record
Task
Invoked before a record is associated with another
record via a many-to-many relationship. Use this to validate the association, enforce
relationship rules, or prevent invalid links.
OnBeforeCreateAsyncTableRecord record
Task
Invoked immediately before a new record is created.
Use this to validate, mutate, or prepare the record prior to persistence.
OnBeforeDeleteAsyncTableRecordReference record
Task
Invoked before a record is deleted.
Use this to enforce deletion rules, perform soft‑delete conversions,
or block deletion under certain conditions.
OnBeforeDisassociateAsyncTableRecord record
Task
Invoked before a record is disassociated from another
record. Use this to validate the disassociation, enforce
constraints, or block removal of required relationships.
OnBeforeUpdateAsyncTableRecord record
Task
Invoked before an existing record is updated.
Use this to validate changes, enforce business rules, or modify
the record prior to the update being persisted.
Name: OnAfterAssociateAsync
Parameters: TableRecord record
Type: Task
Description: Invoked after a record has been associated with
another record via a many-to-many relationship. Useful for updating related aggregates,
emitting domain events, or maintaining referential integrity.
Name: OnAfterCreateAsync
Parameters: TableRecord record
Type: Task
Description: Invoked immediately after a new record has been created.
Use this for post‑creation actions such as logging, notifications,
or triggering downstream workflows.
Name: OnAfterDeleteAsync
Parameters: TableRecordReference record
Type: Task
Description: Invoked after a record has been deleted.
Useful for cleanup tasks, audit logging, or cascading domain events.
Name: OnAfterDisassociateAsync
Parameters: TableRecord record
Type: Task
Description: Invoked after a record has been disassociated from
another record. Useful for cleanup, updating aggregates,
or triggering follow‑up processes.
Name: OnAfterUpdateAsync
Parameters: TableRecord record
Type: Task
Description: Invoked after an existing record has been updated.
Useful for audit logging, cache invalidation, or triggering
follow‑up processes.
Name: OnBeforeAssociateAsync
Parameters: TableRecord record
Type: Task
Description: Invoked before a record is associated with another
record via a many-to-many relationship. Use this to validate the association, enforce
relationship rules, or prevent invalid links.
Name: OnBeforeCreateAsync
Parameters: TableRecord record
Type: Task
Description: Invoked immediately before a new record is created.
Use this to validate, mutate, or prepare the record prior to persistence.
Name: OnBeforeDeleteAsync
Parameters: TableRecordReference record
Type: Task
Description: Invoked before a record is deleted.
Use this to enforce deletion rules, perform soft‑delete conversions,
or block deletion under certain conditions.
Name: OnBeforeDisassociateAsync
Parameters: TableRecord record
Type: Task
Description: Invoked before a record is disassociated from another
record. Use this to validate the disassociation, enforce
constraints, or block removal of required relationships.
Name: OnBeforeUpdateAsync
Parameters: TableRecord record
Type: Task
Description: Invoked before an existing record is updated.
Use this to validate changes, enforce business rules, or modify
the record prior to the update being persisted.