Portal Community

Implementing IInteractionHook

// Full custom hook implementation
public class BusinessComplianceHook : IInteractionHook
{
    private readonly IComplianceService _compliance;
    private readonly ILogger<BusinessComplianceHook> _logger;

    public BusinessComplianceHook(
        IComplianceService compliance,
        ILogger<BusinessComplianceHook> logger)
    {
        _compliance = compliance;
        _logger = logger;
    }

    /// Pre-send: runs before delivery to EdgeStream
    public async Task OnBeforePublish(
        InteractionRequest request,
        CancellationToken ct)
    {
        // Only apply to approval interactions
        if (request.Type != InteractionTypes.Approval)
            return;

        // Verify requester is authorized to send approvals
        var canSend = await _compliance.CanSendApprovalAsync(
            requesterId: request.Metadata.GetValueOrDefault("requestedBy"),
            targetId: request.TargetUserId,
            ct: ct);

        if (!canSend)
        {
            throw new InteractionBlockedException(
                "Requester is not authorized to send approval interactions to this user.");
        }

        // Enrich with compliance metadata
        request.Metadata["complianceCheckPassed"] = "true";
        request.Metadata["complianceCheckedAt"] = DateTimeOffset.UtcNow.ToString("O");
    }

    /// Post-receive: runs after a valid response
    public async Task OnAfterRespond(
        InteractionRequest request,
        InteractionResponse response,
        CancellationToken ct)
    {
        // Record the approval decision in the compliance system
        try
        {
            await _compliance.RecordApprovalDecisionAsync(new ApprovalDecisionRecord
            {
                InteractionId = request.InteractionId,
                CorrelationId = request.CorrelationId,
                Decision = response.Outcome,
                DecidedBy = response.RespondedBy,
                DecidedAt = response.Timestamp
            }, ct);
        }
        catch (Exception ex)
        {
            // Log but do not rethrow — the response cycle must complete
            _logger.LogError(ex, "Failed to record approval decision for {InteractionId}",
                request.InteractionId);
        }
    }
}

Registration

// Program.cs — register with full DI support
builder.Services.AddInteractionHook<BusinessComplianceHook>();

// With options (if your hook needs configuration)
builder.Services.Configure<BusinessComplianceHookOptions>(
    builder.Configuration.GetSection("EdgeInteract:ComplianceHook"));

Hook Checklist

1

Implement both methods

Both OnBeforePublish and OnAfterRespond must be implemented. Return Task.CompletedTask if your hook only uses one of the two.

2

Filter by type early

Use a type check at the top of each method and early-return for types you don't handle. This keeps hooks fast and reduces unnecessary processing.

3

Never throw in OnAfterRespond

Exceptions in OnAfterRespond are caught by the pipeline and logged, but the cycle continues. However, to avoid silent failures, catch exceptions internally and log them explicitly.

4

Respect CancellationToken

Always pass the CancellationToken to async operations. The pipeline cancels the token on server shutdown.

5

Keep it fast

Target under 50ms for OnBeforePublish (it's on the publish critical path). For slow operations in OnAfterRespond, queue a background job instead.