/// <summary> /// Unpacks any exceptions in the given <see cref="HttpError"/> and adds /// them into a collection of name-value pairs that can be composed into a single string. /// </summary> /// <remarks> /// This helper also iterates over all inner exceptions and unpacks them too. /// </remarks> /// <param name="httpError">The <see cref="HttpError"/> to unpack.</param> /// <param name="messages">A collection of messages to which the new information should be added.</param> private static void AddExceptions(HttpError httpError, List <string> messages) { Contract.Assert(httpError != null); Contract.Assert(messages != null); object exceptionMessageObject = null; object exceptionTypeObject = null; object stackTraceObject = null; object innerExceptionObject = null; for (int i = 0; httpError != null; i++) { // For uniqueness, key names append the depth of inner exception string indexText = i == 0 ? String.Empty : Error.Format("[{0}]", i); if (httpError.TryGetValue(HttpErrorKeys.ExceptionTypeKey, out exceptionTypeObject)) { messages.Add( Error.Format(HttpErrorExceptionTypeFormat, indexText, exceptionTypeObject) ); } if ( httpError.TryGetValue( HttpErrorKeys.ExceptionMessageKey, out exceptionMessageObject ) ) { messages.Add( Error.Format( HttpErrorExceptionMessageFormat, indexText, exceptionMessageObject ) ); } if (httpError.TryGetValue(HttpErrorKeys.StackTraceKey, out stackTraceObject)) { messages.Add( Error.Format(HttpErrorStackTraceFormat, indexText, stackTraceObject) ); } if ( !httpError.TryGetValue( HttpErrorKeys.InnerExceptionKey, out innerExceptionObject ) ) { break; } Contract.Assert(!Object.ReferenceEquals(httpError, innerExceptionObject)); httpError = innerExceptionObject as HttpError; } }
/// <summary> /// Unwraps an arbitrarily deep collection of inner exceptions inside an /// <see cref="HttpError"/> instance into a list of error messages. /// </summary> /// <param name="httpError">The input <see cref="HttpError"/>.</param> /// <param name="messages">The list of messages to which the exceptions should be added.</param> private static void AddExceptions(HttpError httpError, List <string> messages) { object exceptionMessageObject = null; object exceptionTypeObject = null; object stackTraceObject = null; object innerExceptionObject = null; for (int i = 0; httpError != null; i++) { // For uniqueness, key names append the depth of inner exception string indexText = i == 0 ? String.Empty : String.Format("[{0}]", i); if (httpError.TryGetValue(ExceptionTypeKey, out exceptionTypeObject)) { messages.Add(String.Format(SRResources.HttpErrorExceptionTypeFormat, indexText, exceptionTypeObject)); } if (httpError.TryGetValue(ExceptionMessageKey, out exceptionMessageObject)) { messages.Add(String.Format(SRResources.HttpErrorExceptionMessageFormat, indexText, exceptionMessageObject)); } if (httpError.TryGetValue(StackTraceKey, out stackTraceObject)) { messages.Add(String.Format(SRResources.HttpErrorStackTraceFormat, indexText, stackTraceObject)); } if (!httpError.TryGetValue(InnerExceptionKey, out innerExceptionObject)) { break; } httpError = innerExceptionObject as HttpError; } }
public static ModelStateDictionary GetModelState(this HttpError httpError) { // Ensure.Argument.NotNull(httpError, "httpError"); object serialized; if (httpError.TryGetValue("ModelState", out serialized)) { var modelState = new ModelStateDictionary(); var errors = (HttpError)httpError["ModelState"]; foreach (var error in errors) { foreach (var message in error.Value as string[]) { modelState.AddModelError(error.Key, message); } } return(modelState); } return(null); }
/// <summary> /// Map the HTTP error to a JsonApiError. /// </summary> /// <param name="httpError">The HTTP error to map.</param> /// <returns>The JSON API error that was mapped from the HTTP Error.</returns> static JsonApiError Map(HttpError httpError) { var error = new JsonApiError { Status = "500", Code = "500" }; if (httpError.TryGetValue("Message", out object value)) { error.Title = value.ToString(); } if (httpError.TryGetValue("ExceptionMessage", out value)) { error.Detail = value.ToString(); } return(error); }
private void LogExceptionDetails(HttpError error) { if (Logger.IsDebugEnabled) { object detail; if (error.TryGetValue("ExceptionType", out detail)) { Logger.DebugFormat("Remote Exception Type: {0}", detail); } Logger.Debug(error.ExceptionMessage ?? error.Message); if (error.TryGetValue("StackTrace", out detail)) { Logger.DebugFormat("Remote Stack Trace: {0}", detail); } } }
/// <summary> /// Deserializes the HTTP error. /// </summary> /// <param name="existingError">The existing error.</param> /// <returns></returns> public static HttpError DeserializeHttpError(HttpError existingError) { if (existingError == null) { return(null); } var error = new HttpError( ); object value; if (existingError.TryGetValue(HttpErrorKeys.MessageKey, out value)) { error.Message = GetStringValue(value); } if (existingError.TryGetValue(HttpErrorKeys.ExceptionMessageKey, out value)) { error.ExceptionMessage = GetStringValue(value); } if (existingError.TryGetValue(HttpErrorKeys.ExceptionTypeKey, out value)) { error.ExceptionType = GetStringValue(value); } if (existingError.TryGetValue(HttpErrorKeys.StackTraceKey, out value)) { error.StackTrace = GetStringValue(value); } if (existingError.TryGetValue(AdditionalInfoKey, out value)) { error [AdditionalInfoKey] = GetStringValue(value); } if (existingError.TryGetValue(PasswordExpiredKey, out value)) { error [PasswordExpiredKey] = GetStringValue(value); } if (existingError.TryGetValue(ValidationErrorKey, out value)) { error [ValidationErrorKey] = GetStringValue(value); } return(error); }
/// <summary> /// Unpacks any exceptions in the given <see cref="HttpError"/> and adds /// them into a collection of name-value pairs that can be composed into a single string. /// </summary> /// <remarks> /// This helper also iterates over all inner exceptions and unpacks them too. /// </remarks> /// <param name="httpError">The <see cref="HttpError"/> to unpack.</param> /// <param name="messages">A collection of messages to which the new information should be added.</param> private static void AddExceptions(HttpError httpError, List<string> messages) { Contract.Assert(httpError != null); Contract.Assert(messages != null); object exceptionMessageObject = null; object exceptionTypeObject = null; object stackTraceObject = null; object innerExceptionObject = null; for (int i = 0; httpError != null; i++) { // For uniqueness, key names append the depth of inner exception string indexText = i == 0 ? String.Empty : Error.Format("[{0}]", i); if (httpError.TryGetValue(ExceptionTypeKey, out exceptionTypeObject)) { messages.Add(Error.Format(SRResources.HttpErrorExceptionTypeFormat, indexText, exceptionTypeObject)); } if (httpError.TryGetValue(ExceptionMessageKey, out exceptionMessageObject)) { messages.Add(Error.Format(SRResources.HttpErrorExceptionMessageFormat, indexText, exceptionMessageObject)); } if (httpError.TryGetValue(StackTraceKey, out stackTraceObject)) { messages.Add(Error.Format(SRResources.HttpErrorStackTraceFormat, indexText, stackTraceObject)); } if (!httpError.TryGetValue(InnerExceptionKey, out innerExceptionObject)) { break; } Contract.Assert(!Object.ReferenceEquals(httpError, innerExceptionObject)); httpError = innerExceptionObject as HttpError; } }
/// <summary> /// Examines the given <see cref="TraceRecord"/> to determine whether it /// contains an <see cref="HttpResponseException"/> and if so, modifies /// the <see cref="TraceRecord"/> to capture more detailed information. /// </summary> /// <param name="traceRecord">The <see cref="TraceRecord"/> to examine and modify.</param> public static void TranslateHttpResponseException(TraceRecord traceRecord) { Contract.Assert(traceRecord != null); HttpResponseException httpResponseException = ExtractHttpResponseException( traceRecord.Exception ); if (httpResponseException == null) { return; } HttpResponseMessage response = httpResponseException.Response; Contract.Assert(response != null); // If the status has been set already, do not overwrite it, // otherwise propagate the status into the record. if (traceRecord.Status == 0) { traceRecord.Status = response.StatusCode; } traceRecord.Level = GetMappedTraceLevel(httpResponseException) ?? traceRecord.Level; // HttpResponseExceptions often contain HttpError instances that carry // detailed information that may be filtered out by IncludeErrorDetailPolicy // before reaching the client. Capture it here for the trace. ObjectContent objectContent = response.Content as ObjectContent; if (objectContent == null) { return; } HttpError httpError = objectContent.Value as HttpError; if (httpError == null) { return; } object messageObject = null; object messageDetailsObject = null; List <string> messages = new List <string>(); if (httpError.TryGetValue(HttpErrorKeys.MessageKey, out messageObject)) { messages.Add(Error.Format(HttpErrorUserMessageFormat, messageObject)); } if (httpError.TryGetValue(HttpErrorKeys.MessageDetailKey, out messageDetailsObject)) { messages.Add(Error.Format(HttpErrorMessageDetailFormat, messageDetailsObject)); } // Extract the exception from this HttpError and then incrementally // walk down all inner exceptions. AddExceptions(httpError, messages); // ModelState errors are handled with a nested HttpError object modelStateErrorObject = null; if (httpError.TryGetValue(HttpErrorKeys.ModelStateKey, out modelStateErrorObject)) { HttpError modelStateError = modelStateErrorObject as HttpError; if (modelStateError != null) { messages.Add(FormatModelStateErrors(modelStateError)); } } traceRecord.Message = String.Join(", ", messages); }
/// <summary> /// If the given <see cref="TraceRecord"/> contains an <see cref="HttpResponseException"/>, /// this method unwraps the information inside into a more human-readable form for tracing. /// </summary> /// <param name="traceRecord">The <see cref="TraceRecord"/> to examine and optionally modify.</param> /// <remarks> /// The WebAPI stack uses <see cref="HttpResponseException"/> to emit an /// <see cref="HttpResponseMessage"/> due to an recoverable error condition, /// such as an invalid user request. /// </remarks> private static void TranslateHttpResponseException(TraceRecord traceRecord) { HttpResponseException httpResponseException = traceRecord.Exception as HttpResponseException; if (httpResponseException != null) { HttpResponseMessage response = httpResponseException.Response; // If the status has been set already, do not overwrite it, // otherwise propagate the status into the record. if (traceRecord.Status == 0) { traceRecord.Status = response.StatusCode; } // Client level errors are downgraded to TraceLevel.Warn if ((int)response.StatusCode < (int)HttpStatusCode.InternalServerError) { traceRecord.Level = TraceLevel.Warn; } // HttpResponseExceptions often contain HttpError instances that carry // detailed information that may be filtered out by IncludeErrorDetailPolicy // before reaching the client. Capture it here for the trace. ObjectContent objectContent = response.Content as ObjectContent; if (objectContent != null) { HttpError httpError = objectContent.Value as HttpError; if (httpError != null) { // Having a structured HttpError replaces the normal // exception in the record because it has more user-directed // information. traceRecord.Exception = null; object messageObject = null; object messageDetailsObject = null; List <string> messages = new List <string>(); if (httpError.TryGetValue(MessageKey, out messageObject)) { messages.Add(String.Format(SRResources.HttpErrorUserMessageFormat, messageObject)); } if (httpError.TryGetValue(MessageDetailKey, out messageDetailsObject)) { messages.Add(String.Format(SRResources.HttpErrorMessageDetailFormat, messageDetailsObject)); } // Extract the exception from this HttpError and then incrementally // walk down all inner exceptions. AddExceptions(httpError, messages); // ModelState errors are handled with a nested HttpError object modelStateErrorObject = null; if (httpError.TryGetValue(ModelStateKey, out modelStateErrorObject)) { HttpError modelStateError = modelStateErrorObject as HttpError; if (modelStateError != null) { messages.Add(FormatModelStateErrors(modelStateError)); } } traceRecord.Message = String.Join(", ", messages); } } } }
/// <summary> /// Examines the given <see cref="TraceRecord"/> to determine whether it /// contains an <see cref="HttpResponseException"/> and if so, modifies /// the <see cref="TraceRecord"/> to capture more detailed information. /// </summary> /// <param name="traceRecord">The <see cref="TraceRecord"/> to examine and modify.</param> public virtual void TranslateHttpResponseException(TraceRecord traceRecord) { if (traceRecord == null) { throw Error.ArgumentNull("traceRecord"); } var httpResponseException = ExtractHttpResponseException(traceRecord); if (httpResponseException == null) { return; } HttpResponseMessage response = httpResponseException.Response; Contract.Assert(response != null); // If the status has been set already, do not overwrite it, // otherwise propagate the status into the record. if (traceRecord.Status == 0) { traceRecord.Status = response.StatusCode; } // Client level errors are downgraded to TraceLevel.Warn if ((int)response.StatusCode < (int)HttpStatusCode.InternalServerError) { traceRecord.Level = TraceLevel.Warn; } // Non errors are downgraded to TraceLevel.Info if ((int)response.StatusCode < (int)HttpStatusCode.BadRequest) { traceRecord.Level = TraceLevel.Info; } // HttpResponseExceptions often contain HttpError instances that carry // detailed information that may be filtered out by IncludeErrorDetailPolicy // before reaching the client. Capture it here for the trace. ObjectContent objectContent = response.Content as ObjectContent; if (objectContent == null) { return; } HttpError httpError = objectContent.Value as HttpError; if (httpError == null) { return; } object messageObject = null; object messageDetailsObject = null; List <string> messages = new List <string>(); if (httpError.TryGetValue(MessageKey, out messageObject)) { messages.Add(Error.Format(SRResources.HttpErrorUserMessageFormat, messageObject)); } if (httpError.TryGetValue(MessageDetailKey, out messageDetailsObject)) { messages.Add(Error.Format(SRResources.HttpErrorMessageDetailFormat, messageDetailsObject)); } // Extract the exception from this HttpError and then incrementally // walk down all inner exceptions. AddExceptions(httpError, messages); // ModelState errors are handled with a nested HttpError object modelStateErrorObject = null; if (httpError.TryGetValue(ModelStateKey, out modelStateErrorObject)) { HttpError modelStateError = modelStateErrorObject as HttpError; if (modelStateError != null) { messages.Add(FormatModelStateErrors(modelStateError)); } } traceRecord.Message = String.Join(", ", messages); }