Skip to content

SAIF.NetCore.ErrorHandler business rules

This page catalogs every business rule this library enforces, identified by stable rule IDs referenced from operations and API reference pages.

EH-BR-01 An error response is not written once the HTTP response has started

Field Value
Statement An error response is not written once the HTTP response has started. A warning is logged and the original exception is re-thrown.
Trigger LogAndReturnException with Response.HasStarted == true
Enforcement ErrorHandler.IsTooHotToHandle
Outcome Warning logged, exception propagates, and no headers or body are changed
Source src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/ErrorHandler.cs
Operations Log an exception and write the HTTP error response, Legacy conventional middleware

EH-BR-02 Every handled HTTP error is logged at Error level

Field Value
Statement Every handled HTTP error is logged at Error level with the exception and its message, and the logger's returned ID becomes the error's correlation ID.
Trigger Any LogAndReturnException call
Enforcement ErrorHandler.LogAndReturnException
Outcome ErrorID is set to the logger's returned log ID
Source src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/ErrorHandler.cs
Operations Log an exception and write the HTTP error response

EH-BR-03 Every error response carries Error-ID and Server-Name headers

Field Value
Statement Every error response carries an Error-ID header (the log ID) and a Server-Name header (the host machine name).
Trigger Any LogAndReturnException call
Enforcement ErrorHandler.LogAndReturnException
Outcome Client can correlate with the logs; machine name is disclosed
Source src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/ErrorHandler.cs
Operations Log an exception and write the HTTP error response

EH-BR-04 Status code and content type come exactly from the caller

Field Value
Statement The response status code and content type are exactly those supplied by the caller. For HttpStatusCodeException they come from the exception; otherwise they are 500 / text/plain.
Trigger LogAndReturnException
Enforcement ErrorHandler.LogAndReturnException; values chosen in ErrorHandler.Invoke (legacy) or DynamicErrorHandler.InvokeAsync (ServiceExtensions)
Outcome Status/content type set
Source src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/ErrorHandler.cs / src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/Middleware/DynamicErrorHandler.cs
Operations Log an exception and write the HTTP error response, Legacy conventional middleware

EH-BR-05 Handled-exception body format depends on content type

Field Value
Statement For a handled exception, a non-text/plain content type (for example JSON or XML) gets the raw ex.Message as the body so the payload format is preserved. A text/plain content type gets the message followed by "\nPlease see error: {ErrorID}."
Trigger isHandled == true
Enforcement ErrorHandler.BuildHandledResponseMessage
Outcome Body format depends on the content type
Source src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/ErrorHandler.cs
Operations Log an exception and write the HTTP error response

EH-BR-06 Unhandled exception produces a generic-prefixed body

Field Value
Statement An unhandled exception produces the body "Oops! Something went wrong.\n{ex.Message}\nPlease see error: {ErrorID}."
Trigger isHandled == false
Enforcement ErrorHandler.BuildUnhandledResponseMessage
Outcome Generic prefix, but the raw exception message is still disclosed
Source src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/ErrorHandler.cs
Operations Log an exception and write the HTTP error response

EH-BR-07 The legacy middleware requires a non-null next delegate

Field Value
Statement The legacy middleware requires a non-null next delegate.
Trigger Invoke with _next == null
Enforcement ErrorHandler.Invoke
Outcome ArgumentNullException is caught by its own generic handler, giving an unhandled 500 response
Source src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/ErrorHandler.cs
Operations Legacy conventional middleware

EH-BR-08 Exception classification precedence for HTTP hosts

Field Value
Statement Exception classification precedence: HttpStatusCodeException (handled, own status and content type, log details), then SAIFException (handled, 500, text/plain, log details), then any other exception (unhandled, 500, text/plain).
Trigger Exception from the downstream pipeline
Enforcement ErrorHandler.Invoke (legacy); re-implemented in DynamicErrorHandler.InvokeAsync (ServiceExtensions)
Outcome Selects the isHandled, status, and content type for the response
Source src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/ErrorHandler.cs / src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/Middleware/DynamicErrorHandler.cs
Operations Legacy conventional middleware

EH-BR-09 Windows Service stack trace flattens the inner-exception chain

Field Value
Statement A Windows Service error's stack trace includes every exception in the inner-exception chain, each prefixed by TypeName: Message.
Trigger HandleError with a non-null ex
Enforcement ExceptionExtensions.StackTrace; called at WindowsServiceErrorHandler.GetWindowsServiceError
Outcome Flattened trace in the logged text
Source 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
Operations Handle a Windows Service error, Exception utilities

EH-BR-10 SAIFException log details are copied into the Windows Service error

Field Value
Statement SAIFException.LogDetails entries are copied, as strings, into the Windows Service error's log details. Other exception types contribute none.
Trigger HandleError with ex is SAIFException
Enforcement ExceptionExtensions.GetLogDetailsForSAIfException; WindowsServiceErrorHandler.GetWindowsServiceError
Outcome "Log Details:" section in the logged text. A null LogDetails throws.
Source 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
Operations Handle a Windows Service error, Exception utilities

EH-BR-11 A BeginErrorHandling subscriber may suppress logging or actions

Field Value
Statement A BeginErrorHandling subscriber may suppress logging (Handled = true) and/or suppress special actions (FireSpecialActions = false). By default both run.
Trigger HandleError
Enforcement WindowsServiceErrorHandler.HandleError; defaults in ServiceContracts BeginErrorHandlingEventArgs
Outcome Log and/or actions skipped
Source src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/WindowsService/WindowsServiceErrorHandler.cs / src/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/BeginErrorHandlingEventArgs.cs
Operations Handle a Windows Service error

EH-BR-12 Special actions run in registration order and continue after a Fail result only if failure logging succeeds

Field Value
Statement When special actions fire, each registered action runs in order, and execution proceeds to the next action after a Fail result only if the Error-level failure-logging call for that result does not itself throw. A thrown fire-condition predicate, a custom ISpecialErrorAction.Invoke override that throws, or a throwing logger call all stop the loop early, preventing any remaining actions — and the subsequent ErrorHandled event — from running.
Trigger FireSpecialActions == true
Enforcement WindowsServiceErrorHandler.HandleError
Outcome All results collected only when no action, predicate, or failure-logging call throws; otherwise the loop and HandleError itself terminate early
Source 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
Operations Handle a Windows Service error

EH-BR-13 A failed special action is logged at Error level

Field Value
Statement A failed special action is logged at Error level as "Special Error Action Failed: {Title}" with the action's exception.
Trigger Action result Status == Fail
Enforcement WindowsServiceErrorHandler.HandleError
Outcome Extra error log entry
Source src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/WindowsService/WindowsServiceErrorHandler.cs
Operations Handle a Windows Service error

EH-BR-14 ErrorHandled is raised after handling completes without an earlier escape

Field Value
Statement After the special-actions loop finishes, ErrorHandled is raised with the exception, the Handled flag, all collected action results, and the context container — but only if nothing earlier in HandleError (the BeginErrorHandling subscribers, the initial Error-level log call, a fire-condition predicate, a custom action, or a failure-logging call) threw and escaped first (see EH-BR-12).
Trigger End of HandleError, reached only when no earlier step threw
Enforcement WindowsServiceErrorHandler.OnErrorHandled
Outcome Subscribers notified when HandleError runs to completion; otherwise the exception propagates out of HandleError and no ErrorHandled event fires
Source src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/WindowsService/WindowsServiceErrorHandler.cs
Operations Handle a Windows Service error

EH-BR-15 A typed special action fires only on an exact type match

Field Value
Statement A typed special action fires only when the exception's runtime type is exactly T. Subclasses do not match, and a null exception never matches.
Trigger SpecialErrorAction<T>.Invoke
Enforcement SpecialErrorAction<T>.Invoke
Outcome NotExectued result when there is no match
Source src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/WindowsService/SpecialErrorAction.cs
Operations Execute a special error action

EH-BR-16 A special action fires only when its fire-condition predicate allows it

Field Value
Statement A special action fires only when its optional fire-condition predicate is absent or returns true for the context container.
Trigger SpecialErrorAction.Invoke
Enforcement SpecialErrorAction.Invoke
Outcome NotExectued result when the predicate is false
Source src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/WindowsService/SpecialErrorAction.cs
Operations Execute a special error action

EH-BR-17 The built-in action wrapper catches only its own wrapped delegate

Field Value
Statement The base SpecialErrorAction.Invoke catches an exception only from the wrapped invoke delegate call itself, returning it as a Fail result. The fire-condition predicate (testFireCondition) is evaluated outside that try block, so a throwing predicate propagates out of Invoke uncaught. A custom type that implements ISpecialErrorAction/overrides Invoke directly (such as SpecialErrorAction<T>'s own overridden Invoke body before it delegates to the base) is not bound by this containment at all.
Trigger Delegate throws (caught); predicate or an overriding Invoke throws (not caught)
Enforcement SpecialErrorAction.Invoke
Outcome Success/Fail result for a wrapped-delegate exception; an uncaught exception for a predicate or non-conforming override, which stops the enclosing action loop (see EH-BR-12)
Source src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/WindowsService/SpecialErrorAction.cs
Operations Execute a special error action

EH-BR-18 Windows Service error ID format and lazy generation

Field Value
Statement A Windows Service error ID is {GUID}-{yyyyMMddHHmmssffffzzz} with : replaced by -. It is generated once, on first access, and that access stamps ErrorTime.
Trigger First read of WindowsServiceError.ID
Enforcement WindowsServiceError.ID / BuildErrorId
Outcome Stable ID per error object
Source src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/WindowsService/WindowsServiceError.cs
Operations Format a Windows Service error

EH-BR-19 Logged Windows Service error text always includes a fixed field set

Field Value
Statement The logged Windows Service error text always includes the ID, current time, application, host, track, machine, user@domain, source, exception name, message, and stack trace, plus log details when present.
Trigger Logging step of HandleError
Enforcement WindowsServiceError.GetFormattedErrorString
Outcome Standard multi-line error text
Source src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/WindowsService/WindowsServiceError.cs
Operations Handle a Windows Service error, Format a Windows Service error

EH-BR-20 Context objects are unique by key, first registration wins

Field Value
Statement Context objects are unique by key, and the first registration wins. Later adds with the same key are silently ignored.
Trigger ContextContainer.AddContextObject
Enforcement ContextContainer.AddContextObject(string, object)
Outcome No overwrite and no error
Source src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/WindowsService/ContextContainer.cs
Operations Pass error context to actions

Rules enforced outside this library over this library's data

  • Shutdown exemption. The service stops unless the exception's exact type is listed in ShutdownExemptExceptionTypes and that entry's IsAllowed(ex) returns true. This is enforced by SAIF.NetCore.WindowsService.ServiceWorker.IsExceptionExemptFromShutdown (src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceWorker.cs), not by this library.
  • Hook failure aggregation. If any IErrorHandlerHook throws, ErrorHandler receives an AggregateException (hook exceptions plus the original) instead of the original. This is enforced by SAIF.NetCore.ServiceExtensions.Middleware.DynamicErrorHandler.LogAndReturnException (src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/Middleware/DynamicErrorHandler.cs), not by this library.

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/WindowsServiceError.cs
  • src/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/SAIF.NetCore.ErrorHandler/WindowsService/ContextContainer.cs
  • src/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/BeginErrorHandlingEventArgs.cs
  • src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/Middleware/DynamicErrorHandler.cs
  • src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceWorker.cs