/// <summary> /// Provide the fault /// </summary> public bool ProvideFault(Exception error, RestResponseMessage response) { var errCode = WebErrorUtility.ClassifyException(error, true); var hdlr = ApplicationContext.Current.GetService <IAppletManagerService>().Applets.SelectMany(o => o.ErrorAssets).FirstOrDefault(o => o.ErrorCode == errCode); #if DEBUG var ie = error; while (ie != null) { this.m_tracer.TraceError("{0} - ({1}){2} - {3}", error == ie ? "" : "Caused By", RestOperationContext.Current.EndpointOperation?.Description.InvokeMethod.Name, ie.GetType().FullName, ie.Message); ie = ie.InnerException; } #else if (error is TargetInvocationException) { this.m_tracer.TraceError("{0} - {1} / {2}", RestOperationContext.Current.EndpointOperation.Description.InvokeMethod.Name, error.Message, error.InnerException?.Message); } else { this.m_tracer.TraceError("{0} - {1}", RestOperationContext.Current.EndpointOperation.Description.InvokeMethod.Name, error.Message); } #endif // Grab the asset handler try { if (hdlr != null) { response.Body = new MemoryStream(new byte[0]); RestOperationContext.Current.OutgoingResponse.Redirect(hdlr.Asset); } else { RestOperationContext.Current.OutgoingResponse.StatusCode = errCode; using (var sr = new StreamReader(typeof(AgsWebErrorHandlerServiceBehavior).Assembly.GetManifestResourceStream("SanteDB.DisconnectedClient.Ags.Resources.GenericError.html"))) { string errRsp = sr.ReadToEnd().Replace("{status}", response.StatusCode.ToString()) .Replace("{description}", response.StatusDescription) .Replace("{type}", error.GetType().Name) .Replace("{message}", error.Message) .Replace("{details}", error.ToString()) .Replace("{trace}", error.StackTrace); RestOperationContext.Current.OutgoingResponse.ContentType = "text/html"; response.Body = new MemoryStream(Encoding.UTF8.GetBytes(errRsp)); } } AuditUtil.AuditNetworkRequestFailure(error, RestOperationContext.Current.IncomingRequest.Url, RestOperationContext.Current.IncomingRequest.Headers.AllKeys.ToDictionary(o => o, o => RestOperationContext.Current.IncomingRequest.Headers[o]), RestOperationContext.Current.OutgoingResponse.Headers.AllKeys.ToDictionary(o => o, o => RestOperationContext.Current.OutgoingResponse.Headers[o])); return(true); } catch (Exception e) { Tracer.GetTracer(typeof(AgsWebErrorHandlerServiceBehavior)).TraceError("Could not provide fault: {0}", e.ToString()); throw; } }
/// <summary> /// Provide the fault /// </summary> /// <param name="error"></param> /// <param name="response"></param> /// <returns></returns> public bool ProvideFault(Exception error, RestResponseMessage faultMessage) { try { #if DEBUG this.m_tracer.TraceWarning("Error on pipeline: {0}", error); #else if (error is TargetInvocationException tie) { this.m_tracer.TraceWarning("{0} - {1} / {2}", RestOperationContext.Current?.EndpointOperation?.Description?.InvokeMethod?.Name, error.Message, error.InnerException?.Message); } else { this.m_tracer.TraceWarning("{0} - {1}", RestOperationContext.Current?.EndpointOperation?.Description?.InvokeMethod?.Name, error.Message); } #endif if (faultMessage == null) { if (RestOperationContext.Current.OutgoingResponse == null) { this.m_tracer.TraceWarning("Client hangup"); return(false); } this.m_tracer.TraceWarning("For some reason the fault message is null - "); faultMessage = new RestResponseMessage(RestOperationContext.Current.OutgoingResponse); } var ie = error; while (ie != null) { this.m_tracer.TraceWarning("{0} - ({1}){2} - {3}", error == ie ? "" : "Caused By", RestOperationContext.Current.EndpointOperation?.Description.InvokeMethod.Name, ie?.GetType().FullName, ie.Message); // TODO: Do we need this or can we just capture the innermost exception as the cause? if (ie is RestClientException <RestServiceFault> || ie is SecurityException || ie is DetectedIssueException || ie is FileNotFoundException || ie is KeyNotFoundException) { error = ie; } ie = ie.InnerException; } faultMessage.StatusCode = WebErrorUtility.ClassifyException(error); object fault = (error as RestClientException <RestServiceFault>)?.Result ?? new RestServiceFault(error); if (error is FaultException && error?.GetType() != typeof(FaultException)) // Special classification { fault = error?.GetType().GetRuntimeProperty("Body").GetValue(error); } var formatter = RestMessageDispatchFormatter.CreateFormatter(RestOperationContext.Current.ServiceEndpoint.Description.Contract.Type); if (formatter != null) { formatter.SerializeResponse(faultMessage, null, fault); } else { RestOperationContext.Current.OutgoingResponse.OutputStream.Write(System.Text.Encoding.UTF8.GetBytes(error.Message), 0, System.Text.Encoding.UTF8.GetByteCount(error.Message)); } try { if (ApplicationServiceContext.Current.GetService <IOperatingSystemInfoService>()?.OperatingSystem != OperatingSystemID.Android) { AuditUtil.AuditNetworkRequestFailure(error, RestOperationContext.Current.IncomingRequest.Url, RestOperationContext.Current.IncomingRequest.Headers.AllKeys.ToDictionary(o => o, o => RestOperationContext.Current.IncomingRequest.Headers[o]), RestOperationContext.Current.OutgoingResponse.Headers.AllKeys.ToDictionary(o => o, o => RestOperationContext.Current.OutgoingResponse.Headers[o])); } } catch (Exception e) { this.m_tracer.TraceError("Could not send network request failure - {0}", e); } } catch (Exception e) { this.m_tracer.TraceError("Error providing fault: {0}", e); } return(true); }