Custom Interaction Hooks
Implement IInteractionHook to add your own cross-cutting behavior to the interaction lifecycle. Custom hooks follow the same contract as built-in hooks — they run in registration order and can inspect, modify, enrich, or block interactions.
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
Implement both methods
Both OnBeforePublish and OnAfterRespond must be implemented. Return Task.CompletedTask if your hook only uses one of the two.
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.
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.
Respect CancellationToken
Always pass the CancellationToken to async operations. The pipeline cancels the token on server shutdown.
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.