Faults and error pipeline¶
All six services share one uniform, purely observational fault pipeline: a [LogErrorBehavior] service behavior installs an ErrorLogErrorHandler on every channel dispatcher, that handler logs the exception and returns false, and because includeExceptionDetailInFaults="true" the caller then receives the framework's default fault carrying the full exception type, message, and stack trace. No operation declares a fault contract, and the one explicit FaultException construction in the host is unreachable dead code.
Fault surface summary¶
| Aspect | Finding |
|---|---|
| Declared fault contracts | None — no [FaultContract] anywhere in this host |
| Service behavior attributes | [LogErrorBehavior] on all 6 service classes |
IErrorHandler implementations |
ErrorLogErrorHandler (src/WCF/SAIF.Services.WCF.Host/Extensions/ErrorLogErrorHandler.cs) |
includeExceptionDetailInFaults |
true (src/WCF/SAIF.Services.WCF.Host/Web.Base.config) |
| Effect on callers | Every unhandled exception reaches the caller as a generic SOAP fault carrying full server-side exception detail — type, message, and stack trace |
Service behaviors¶
| Behavior | Applied to | Declared in | Effect |
|---|---|---|---|
[LogErrorBehavior] |
FileService, PreferenceService, WebContextService, ImagingService, FaxService, SecurityService |
src/WCF/SAIF.Services.WCF.Host/Extensions/LogErrorBehaviorAttribute.cs |
Installs ErrorLogErrorHandler on every channel dispatcher through ApplyDispatchBehavior |
<serviceDebug includeExceptionDetailInFaults="true"/> |
All services | Web.Base.config <serviceBehaviors> |
Every fault reaching a caller carries full exception detail, regardless of what ErrorLogErrorHandler does |
<serviceMetadata httpGetEnabled="true"/> |
All services | Web.Base.config <serviceBehaviors> |
WSDL is published per route via ?wsdl |
Error handler¶
| Field | Value |
|---|---|
| Type | ErrorLogErrorHandler : IErrorHandler |
| Source | src/WCF/SAIF.Services.WCF.Host/Extensions/ErrorLogErrorHandler.cs |
| Installed by | LogErrorBehaviorAttribute : IServiceBehavior — ApplyDispatchBehavior |
| Scope | Every channel dispatcher on every one of the six service classes |
HandleError return |
false — the exception is not considered handled |
ProvideFault behavior |
Empty method body — leaves the fault unchanged; WCF produces the default fault |
HandleError builds a SAIF.Core.Contracts.ApplicationExceptionDetail, hard-coding Application = "WCF" and reading the environment track, machine name, and calling user from a freshly constructed WindowsEnvironmentService, then passes it to new LogService(environmentService).LogException(exceptionDetail). It then returns false, so the framework continues to the standard fault path unchanged. Because ProvideFault has an empty body, the handler never replaces or reshapes the outgoing fault message — the pair is purely observational: it logs and never suppresses, transforms, or shapes a fault.
Logged exception detail¶
| Field | Value written | Source of the value |
|---|---|---|
| Application | "WCF" (hard-coded) |
Literal in ErrorLogErrorHandler.HandleError |
| Environment / machine / user | Environment track, machine name, calling user | new WindowsEnvironmentService() |
| Exception detail | error.GetErrorLogFormattedException(), the failing method signature, and the calling user |
Exception, error.TargetSite |
| Aspect | Finding |
|---|---|
| Log surface | LogService (new LogService(environmentService).LogException(exceptionDetail)) |
| Destination | Not determined from source — LogService is supplied by the external framework closure |
| Failure of the logger itself | HandleError dereferences error.TargetSite.DeclaringType with no null guard; TargetSite is null for some exception shapes, in which case logging itself would throw inside the error handler (see Tech debt) |
Exception messages originating from FileService and PreferenceService can contain caller-supplied path and user values, so those values reach this central exception log alongside the calling user identity.
Error pipeline diagram¶
The following diagram visualizes how an exception becomes a fault.
flowchart TD
OP["Operation throws an exception"] --> DISP["Channel dispatcher"]
DISP --> HANDLER["ErrorLogErrorHandler.HandleError"]
HANDLER --> LOG["Exception detail logged<br>via LogService"]
HANDLER --> RET["HandleError returns false"]
RET --> DEFAULT["WCF produces the default fault"]
DISP --> PROVIDE["ErrorLogErrorHandler.ProvideFault<br>empty body, fault unchanged"]
PROVIDE --> DEFAULT
DEFAULT --> DETAIL["includeExceptionDetailInFaults=true<br>type, message, stack trace included"]
DETAIL --> CALLER["Caller receives SOAP fault<br>with full exception detail"]
Declared fault contracts¶
No operation in this host declares a fault contract. Every failure reaches the caller as a generic SOAP fault whose content is determined by the error pipeline described above. The one explicit FaultException construction in the host — ImagingService.ThrowTimeoutException(int), building a FaultCode("RequestTimeout") — is private, has no call site anywhere in the host, and is unreachable dead code; no caller ever receives it (see Tech debt).
Failure modes by operation¶
| Operation | Failure | What the caller receives | Detail exposed |
|---|---|---|---|
ReadFile |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
ReadEntireFile |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
WriteFile |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
DeleteFile |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
Length |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
GetPreferences |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
SavePreferences |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
GetDefaultPrinter |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
Get |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
Save |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
CreateContext |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
QueueImage |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
ReserveImageId |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
SendFax |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
IsAuthorized |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
IsAuthorized2 |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
GetUser |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
GetSaifUserByUserId |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
GetSaifUserByEmployeeId |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
GetUserIdForEmployeeId |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
GetExternalUser |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
GetExternalUserByCustomerId |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
GetInjuredWorkerUserByCustomerId |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
GetUsersByGroup |
Unhandled exception in the operation body | Generic SOAP fault | Type, message, and stack trace (includeExceptionDetailInFaults="true") |
Swallowed failures¶
| Location | Behavior | Consequence |
|---|---|---|
SecurityService.LogRequestDetails (src/WCF/SAIF.Services.WCF.Host/Services/Security/SecurityService.cs) |
Writes a JSON fragment of the operation name and arguments to the IIS log via HttpContext.Current.Response.AppendToLog(msg), wrapped so a logging failure does not fault the caller |
A logging failure is invisible to both the caller and the operator; the intended LOG_REQUEST_DETAILS kill switch is never consulted either (see Tech debt) |
SecurityService constructor appSettings reads (src/WCF/SAIF.Services.WCF.Host/Services/Security/SecurityService.cs) |
ConfigurationManager.AppSettings reads for LOG_REQUEST_DETAILS and LDAP_EXTERNAL_KEY are each wrapped in an empty try/catch |
A missing or misconfigured key fails silently; ldap_external_key stays null and the external LDAP host silently falls back to a literal default |
Related documentation¶
- Index
- Overview
- Architecture
- Activation and hosting
- Operations
- Authentication and authorization
- Dependencies
- Configuration
- Operations and processes
- Business rules
- Data model
- Operational runbook
- Tech debt
Sources¶
- src/WCF/SAIF.Services.WCF.Host/Extensions/ErrorLogErrorHandler.cs
- src/WCF/SAIF.Services.WCF.Host/Extensions/LogErrorBehaviorAttribute.cs
- src/WCF/SAIF.Services.WCF.Host/Web.Base.config
- src/WCF/SAIF.Services.WCF.Host/Services/ImagingService.cs
- src/WCF/SAIF.Services.WCF.Host/Services/Security/SecurityService.cs