FodErrorHandler

Enterprise error handling with retry logic, circuit breaker pattern, and PII masking. Demonstrates resilient error management for distributed systems.

Error Popup

Modal popup for displaying HTTP errors with retry, technical details, and contact support options.

razor
<FodErrorPopup
    ErrorReport="@_errorReport"
    ShowTechnicalDetails="true"
    ShowRetryButton="true"
    ShowContactSupportButton="true"
    MaxRetryAttempts="3"
    OnRetry="HandleRetry"
    OnDismiss="HandleDismiss"
    OnContactSupport="HandleContactSupport" />

@code {
    private FodErrorReport? _errorReport;

    private void ShowError(HttpResponseMessage response)
    {
        _errorReport = new FodErrorReport
        {
            ErrorId = ErrorIdGenerator.Generate(),
            StatusCode = (int)response.StatusCode,
            ErrorTitle = "Request Failed",
            UserFriendlyMessage = "Please try again later.",
            RequestUrl = response.RequestMessage?.RequestUri?.ToString(),
            Timestamp = DateTime.UtcNow
        };
    }
}

Error Boundary

Graceful error recovery UI for unhandled exceptions with recovery actions and error ID tracking.

Note: In Blazor .NET 8 with render modes, each interactive page should wrap its content with FodErrorBoundary to catch render exceptions. The popup will show when an unhandled exception occurs.

razor
<!-- In Routes.razor - wraps entire application -->
<FodErrorBoundary>
    <ChildContent>
        <Router AppAssembly="typeof(Routes).Assembly">
            ...
        </Router>
    </ChildContent>
</FodErrorBoundary>

<!-- Custom error content (optional) -->
<FodErrorBoundary OnError="HandleError">
    <ChildContent>
        <YourComponent />
    </ChildContent>
    <ErrorContent Context="errorReport">
        <div class="my-custom-error">
            <h2>Error: @errorReport.ErrorId</h2>
            <p>@errorReport.UserFriendlyMessage</p>
        </div>
    </ErrorContent>
</FodErrorBoundary>

@code {
    private void HandleError(FodErrorReport report)
    {
        Console.WriteLine($"Error caught: {report.ErrorId}");
    }
}

PII Masking

Automatically mask personally identifiable information (IDNP, phone, email, IDNO) in error reports for GDPR compliance.

csharp
@inject IFodPiiMaskingService PiiMaskingService

@code {
    private void MaskSensitiveData()
    {
        // IDNP: "1234567890123" -> "1234567****23"
        var maskedIdnp = PiiMaskingService.MaskIdnp("1234567890123");

        // Phone: "+37369123456" -> "******3456"
        var maskedPhone = PiiMaskingService.MaskPhone("+37369123456");

        // Email: "john.doe@example.com" -> "jo***@example.com"
        var maskedEmail = PiiMaskingService.MaskEmail("john.doe@example.com");

        // IDNO: "1003600123456" -> "1003*********"
        var maskedIdno = PiiMaskingService.MaskIdno("1003600123456");

        // MPowerCode: "MPower-12345678" -> "MPower-****5678"
        var maskedMPowerCode = PiiMaskingService.MaskMPowerCode("MPower-12345678");
    }
}

Device Information

Automatically captured device and browser information included with error reports for diagnostics.

Loading device info...
csharp
public class DeviceInfo
{
    public string? Browser { get; set; }
    public string? BrowserVersion { get; set; }
    public string? OperatingSystem { get; set; }
    public string? DeviceType { get; set; }  // Desktop, Mobile, Tablet
    public string? ScreenResolution { get; set; }
    public string? TimeZone { get; set; }
    public string? Language { get; set; }
    public bool OnlineStatus { get; set; }
    public bool CookiesEnabled { get; set; }
}

// Device info is automatically captured via JavaScript interop
// and included in FodErrorReport.Device property

HTTP Interceptor

Automatically intercepts HTTP responses with configured status codes and creates error reports via ErrorHandlingHttpMessageHandler.

csharp
// Register HttpClient with error handling in Program.cs
builder.Services.AddHttpClient("DemoApi", client =>
{
    client.BaseAddress = new Uri("https://api.example.com/");
}).WithErrorHandling();

// Usage - errors are automatically intercepted
@inject IHttpClientFactory HttpClientFactory

@code {
    private async Task CallApi()
    {
        var client = HttpClientFactory.CreateClient("DemoApi");
        var response = await client.GetAsync("/api/data");
        // If status code is in InterceptStatusCodes,
        // ErrorHandlingHttpMessageHandler creates FodErrorReport automatically
    }
}

Retry Logic

Exponential backoff retry strategy with configurable attempts and delays.

csharp
public class RetryPolicy
{
    public int MaxRetries { get; set; } = 3;
    public int BaseDelayMs { get; set; } = 100;

    public async Task<T> ExecuteAsync<T>(
        Func<Task<T>> operation,
        CancellationToken ct = default)
    {
        for (int attempt = 1; attempt <= MaxRetries; attempt++)
        {
            try
            {
                return await operation();
            }
            catch when (attempt < MaxRetries)
            {
                int delayMs = (int)Math.Pow(2, attempt - 1) * BaseDelayMs;
                await Task.Delay(delayMs, ct);
            }
        }

        throw new InvalidOperationException("Max retries exceeded");
    }
}

Circuit Breaker

Automatic failure protection preventing cascading failures across services.

Closed

Circuit is closed. All requests pass through normally.

csharp
public enum CircuitState { Closed = 0, Open = 1, HalfOpen = 2 }

public class CircuitBreaker
{
    public CircuitState State { get; private set; } = CircuitState.Closed;
    public int FailureThreshold { get; set; } = 3;
    private int _failureCount;

    public async Task<T> ExecuteAsync<T>(Func<Task<T>> operation)
    {
        if (State == CircuitState.Open)
            throw new InvalidOperationException("Circuit is open");

        try
        {
            return await operation();
        }
        catch
        {
            _failureCount++;
            if (_failureCount >= FailureThreshold)
                State = CircuitState.Open;
            throw;
        }
    }

    public void Reset()
    {
        _failureCount = 0;
        State = CircuitState.Closed;
    }
}

OnErrorOccurred Event

Subscribe to global error events fired by IFodErrorHandlerService when errors are handled.

0 events received

Error Report Structure

Full FodErrorReport with all 20+ properties including context, device info, and metadata.

Configuration Options

Current FodErrorHandlerConfiguration values. Toggle options to see effect on behavior.

MaxRetryAttempts
3
InitialRetryDelaySeconds
2
MaxRetryDelaySeconds
30
BackoffMultiplier
2
UseJitter
True
IncludeSensitiveData
False
CircuitBreakerFailureThreshold
5
CircuitBreakerOpenDurationMinutes
2
EnableLocalStorageFallback
True
ErrorRetentionDays
90
InterceptStatusCodes
500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511

Requestor Context

Extract requestor context with automatic PII masking via IFodContextExtractor<FodRequestorContext>.

Beneficiary Context

Extract beneficiary context with automatic PII masking via IFodContextExtractor<FodBeneficiaryContext>.

Session Context

Extract session context including wizard step tracking via FodSessionContextExtractor.

Error Log Service

InMemoryErrorLogService for storing, retrieving, and managing error reports with GDPR deletion support.

Error Report Queue

Channel-based bounded queue for error report processing with configurable capacity.

0 queued reports

MNotify Integration

Send error reports to the MNotify notification platform. Uses MockMNotifyService in development.

Sensitive Data Detector

Detect and mask PII patterns in arbitrary text using regex-based FodSensitiveDataDetector.

Error Retention

GDPR-compliant error retention with configurable expiration policy via FodErrorRetentionService.

Retention Policy
90 days
Expiration Date (from now)
2026-08-18

User Action Tracker

Track user actions with a rolling buffer (max 20) via UserActionTracker for error context.

Error Message Service

Localized error titles and messages for HTTP status codes via IFodErrorMessageService.

Status Code Error Title Error Message
400 Something went wrong An unexpected error occurred. Please contact support.
401 Something went wrong An unexpected error occurred. Please contact support.
403 Something went wrong An unexpected error occurred. Please contact support.
404 Something went wrong An unexpected error occurred. Please contact support.
500 Something went wrong A technical error occurred. Please try again.
502 Something went wrong The service is temporarily unavailable. Try again in a few minutes.
503 Service under maintenance The service is under maintenance. Please come back later.
504 Request timed out The request timed out. Check your connection and try again.
RetryText: Try again CloseText: Close

Global Exception Handler

GlobalExceptionHandler catches unobserved task exceptions and AppDomain unhandled exceptions.

Initialized

GlobalExceptionHandler.Initialize() was called in Program.cs to register exception handlers.

API Endpoints

Available REST API endpoints for error reporting and management.

Endpoint Method Description
api/fod/errors POST Submit a new error report
api/fod/errors/{"{id}"} GET Retrieve error report by ID
api/fod/errors/recent GET Get list of recent error reports
api/fod/errors/device-info GET Get current device information
api/fod/errors/user/{"{userId}"} DELETE GDPR deletion of user error data

API Reference

Configuration options for error handling service.

No properties defined.

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please reload the page.