Skip to content

SAIF.NetCore.ErrorHandler architecture

SAIF.NetCore.ErrorHandler is an implementation-layer library that centralizes exception translation and formatting for two hosting models: ASP.NET Core HTTP pipelines, through ErrorHandler/IErrorHandler, and Windows Service hosts, through WindowsServiceErrorHandler/IWindowsServiceErrorHandler; it codes only against SAIF.NetCore.ServiceContracts interfaces and relies on the host application to supply the logging and environment implementations and to wire it into the pipeline.

Responsibilities

  • Translate exceptions into HTTP responses: log the exception through ISaifLogService, capture the returned log ID as ErrorID, clear the response, add Error-ID/Server-Name headers, set the status code and content type, and write a handled or unhandled body (ErrorHandler.LogAndReturnException).
  • Provide a legacy, [Obsolete]-marked conventional middleware entry point (ErrorHandler.Invoke) that classifies exceptions as HttpStatusCodeException, SAIFException, or any other Exception, in that precedence order.
  • Build and log a formatted, multi-line Windows Service error (WindowsServiceErrorHandler.HandleError), raising BeginErrorHandling and ErrorHandled events so a host can veto logging, add context objects, or suppress special actions.
  • Execute pluggable, fire-conditional special error actions (SpecialErrorAction/SpecialErrorAction<T>) that return a SpecialErrorActionResult; only the wrapped delegate call is contained in a try/catch — the fire-condition predicate, a non-conforming ISpecialErrorAction override, and the Error-level failure-logging call can all still throw uncaught, stopping the remaining actions and the subsequent ErrorHandled event from running (ExceptionExtensions).
  • Flatten exception stack traces across the inner-exception chain and extract SAIFException.LogDetails as strings (ExceptionExtensions).

Component boundaries

  • ErrorHandler / IErrorHandler: ASP.NET Core-facing exception-to-response translator; implements the IErrorHandleable marker from ServiceContracts.
  • WindowsServiceErrorHandler / IWindowsServiceErrorHandler (ServiceContracts): Windows Service-facing exception handler; owns BeginErrorHandling/ErrorHandled events, the SpecialErrorActions list, and the ShutdownExemptExceptionTypes list.
  • SpecialErrorAction / SpecialErrorAction<T>: delegate wrappers with an optional fire-condition predicate, invoked by WindowsServiceErrorHandler.
  • ContextContainer (IErrorContextContainer): string-keyed object bag passed to special actions during error handling.
  • WindowsServiceError (IWindowsServiceError/IStandardErrorLogInfo): formats the identity, timestamp, exception, and log details into the logged error text.
  • ExceptionExtensions: static helpers for stack-trace flattening and SAIFException.LogDetails extraction.
  • This library has no DI registration extensions, no middleware Use* extension, and no hosted service of its own; every wiring point lives in SAIF.NetCore.ServiceExtensions and, for Windows Service hosts, SAIF.NetCore.WindowsService.

Interaction model

  • For HTTP hosts, SAIF.NetCore.ServiceExtensions registers IErrorHandleable/ErrorHandler and wraps the pipeline with its own DynamicErrorHandler middleware, which catches HttpStatusCodeException, SAIFException, or any other exception, classifies status/content-type/handled accordingly, and calls IErrorHandler.LogAndReturnException in this library to produce the response.
  • For Windows Service hosts, SAIF.NetCore.ServiceExtensions registers WindowsServiceErrorHandler as a singleton IWindowsServiceErrorHandler, and SAIF.NetCore.WindowsService's ServiceWorker.HandleTaskError first computes IsExceptionExemptFromShutdown and builds the error message, then calls HandleError(message, ex), and only afterward conditionally stops the host using the previously computed exemption result.
  • Both handlers resolve their logging dependency (ISaifLogService/ISaifWindowsServiceLogService) and IEnvironmentClient purely as ServiceContracts interfaces supplied at construction time; outbound calls to the SAIF Logging API happen inside SAIF.NetCore.Logging's own implementation, not inside this library.

Architecture diagram

The following diagram shows the two hosting paths this library serves and the ServiceContracts interfaces each depends on; all concrete implementations are supplied by the consuming host.

flowchart TD
    HTTP["ASP.NET Core host<br>(DynamicErrorHandler middleware,<br>SAIF.NetCore.ServiceExtensions)"] -->|IErrorHandler.LogAndReturnException| EH["ErrorHandler<br>(SAIF.NetCore.ErrorHandler)"]
    WS["Windows Service host<br>(ServiceWorker, SAIF.NetCore.WindowsService)"] -->|HandleError| WSEH["WindowsServiceErrorHandler<br>(SAIF.NetCore.ErrorHandler)"]
    EH -->|Error / Warning| LOG["ISaifLogService<br>(ServiceContracts contract)"]
    WSEH -->|Error| WSLOG["ISaifWindowsServiceLogService<br>(ServiceContracts contract)"]
    WSEH --> ACTIONS["SpecialErrorAction / SpecialErrorAction&lt;T&gt;"]
    WSEH -->|ApplicationName / ApplicationHost / TrackName| ENV["IEnvironmentClient<br>(ServiceContracts contract)"]

Sequence diagram

The following diagram shows the Windows Service error-handling sequence, including the event hooks and special actions.

sequenceDiagram
    participant ServiceWorker
    participant WindowsServiceErrorHandler
    participant ISaifWindowsServiceLogService
    participant SpecialErrorAction
    ServiceWorker->>ServiceWorker: IsExceptionExemptFromShutdown? (computed first)
    ServiceWorker->>ServiceWorker: BuildErrorMessage(ex, exemptFromShutdown)
    ServiceWorker->>WindowsServiceErrorHandler: HandleError(message, ex)
    WindowsServiceErrorHandler->>WindowsServiceErrorHandler: Raise BeginErrorHandling
    alt not Handled by subscriber
        WindowsServiceErrorHandler->>ISaifWindowsServiceLogService: Error(ex, formattedText)
    end
    alt FireSpecialActions
        WindowsServiceErrorHandler->>SpecialErrorAction: Invoke(ex, context)
        SpecialErrorAction-->>WindowsServiceErrorHandler: SpecialErrorActionResult
    end
    WindowsServiceErrorHandler->>WindowsServiceErrorHandler: Raise ErrorHandled
    WindowsServiceErrorHandler-->>ServiceWorker: return
    ServiceWorker->>ServiceWorker: if not exemptFromShutdown, stop host (using value computed before HandleError)

Design constraints

  • No project references between libraries in this repository; the only cross-library dependency is the SAIF.NetCore.ServiceContracts NuGet package, consistent with the repository-wide layering in Architecture.md.
  • BuildHandledResponseMessage calls contentType.ToLower() without a null check; an HttpStatusCodeException with a null ContentType would throw after the response headers are already written, leaving the client with the status code and an empty body*.
  • WindowsServiceErrorHandler.HandleError throws before logging when a SAIFException's LogDetails is null, because GetLogDetailsForSAIfException calls .Select on null; the exception then escapes unlogged into ServiceWorker.HandleTaskError*.
  • A local IStandardErrorContent interface duplicates the ServiceContracts IStandardErrorLogInfo contract minus ID, with no in-repository consumer found*.

Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts. Statements marked with ** could not be confirmed; treat as unknown until verified.

Sources

  • src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/ErrorHandler.cs
  • src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/ExceptionExtensions.cs
  • src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/WindowsService/WindowsServiceErrorHandler.cs
  • src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/WindowsService/SpecialErrorAction.cs
  • src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/WindowsService/ContextContainer.cs
  • src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/WindowsService/WindowsServiceError.cs
  • src/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/IErrorHandleable.cs, ISaifLogService.cs, ISaifWindowsServiceLogService.cs, IEnvironmentClient.cs, IWindowsServiceErrorHandler.cs
  • src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceWorker.cs
  • Architecture.md