Ejemplo n.º 1
0
        /// <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);
        }