PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/WCFWebApi/src/Microsoft.ApplicationServer.Http/Microsoft/ApplicationServer/Http/Dispatcher/HttpResponseErrorHandler.cs

#
C# | 172 lines | 134 code | 25 blank | 13 comment | 21 complexity | 656cb3614dd6a69de7842d369e009df3 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, Apache-2.0
  1. // <copyright>
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. // </copyright>
  4. namespace Microsoft.ApplicationServer.Http.Dispatcher
  5. {
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Diagnostics.CodeAnalysis;
  9. using System.Net;
  10. using System.Net.Http;
  11. using System.Net.Http.Formatting;
  12. using System.Reflection;
  13. using System.ServiceModel;
  14. using System.ServiceModel.Web;
  15. using Microsoft.Server.Common;
  16. internal class HttpResponseErrorHandler : HttpErrorHandler
  17. {
  18. private MediaTypeFormatterCollection formatters;
  19. private Uri helpUri;
  20. private bool includeExceptionDetail;
  21. internal HttpResponseErrorHandler(IEnumerable<MediaTypeFormatter> formatters, Uri helpUri, bool includeExceptionDetail)
  22. {
  23. Fx.Assert(formatters != null, "The 'formatters' parameter should not be null.");
  24. this.formatters = new MediaTypeFormatterCollection(formatters);
  25. this.helpUri = helpUri;
  26. this.includeExceptionDetail = includeExceptionDetail;
  27. }
  28. /// <summary>
  29. /// Enables the creation of a custom <see cref="HttpResponseMessage"/> that is returned
  30. /// when an exception is encountered servicing an Http request.
  31. /// </summary>
  32. /// <param name="error">The exception thrown in the course of executing the Http request.</param>
  33. /// <param name="message">The <see cref="HttpResponseMessage"/> to return. It cannot be <c>null</c>.</param>
  34. /// <returns>A value indicating whether the message is ready to be returned.</returns>
  35. [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "disposed later.")]
  36. protected override bool OnTryProvideResponse(Exception error, ref HttpResponseMessage message)
  37. {
  38. HttpResponseMessage response = null;
  39. HttpResponseException errorAsResponseException = error as HttpResponseException;
  40. if (errorAsResponseException != null)
  41. {
  42. response = errorAsResponseException.Response;
  43. }
  44. else
  45. {
  46. WebFaultExceptionWrapper webFault = new WebFaultExceptionWrapper(error);
  47. if (webFault.IsWebFaultException)
  48. {
  49. object detailObject = webFault.DetailObject;
  50. if (detailObject != null)
  51. {
  52. response = detailObject as HttpResponseMessage;
  53. if (response == null)
  54. {
  55. response = new HttpResponseMessage();
  56. response.Content = new ObjectContent(webFault.DetailType, detailObject);
  57. }
  58. }
  59. else
  60. {
  61. response = new HttpResponseMessage();
  62. }
  63. response.StatusCode = webFault.StatusCode;
  64. }
  65. else
  66. {
  67. response = this.CreateHtmlResponse(error);
  68. }
  69. }
  70. this.PrepareHttpResponse(response);
  71. message = response;
  72. return true;
  73. }
  74. private HttpResponseMessage CreateHtmlResponse(Exception error)
  75. {
  76. HttpRequestMessage requestMessage = OperationContext.Current.GetHttpRequestMessage();
  77. HttpResponseMessage responseMessage = StandardHttpResponseMessageBuilder.CreateInternalServerErrorResponse(
  78. requestMessage,
  79. error,
  80. this.includeExceptionDetail,
  81. this.helpUri);
  82. return responseMessage;
  83. }
  84. private void PrepareHttpResponse(HttpResponseMessage response)
  85. {
  86. ObjectContent objectContent = response.Content as ObjectContent;
  87. if (objectContent != null)
  88. {
  89. foreach (MediaTypeFormatter formatter in this.formatters)
  90. {
  91. objectContent.Formatters.Add(formatter);
  92. }
  93. }
  94. if (response.RequestMessage == null)
  95. {
  96. response.RequestMessage = OperationContext.Current.GetHttpRequestMessage();
  97. }
  98. }
  99. private class WebFaultExceptionWrapper
  100. {
  101. private static readonly Type genericWebFaultExceptionType = typeof(WebFaultException<>);
  102. internal WebFaultExceptionWrapper(Exception error)
  103. {
  104. Fx.Assert(error != null, "error cannot be null");
  105. WebFaultException asWebFaultException = error as WebFaultException;
  106. Type errorType = error.GetType();
  107. bool isGenericWebFaultException = errorType.IsGenericType && errorType.GetGenericTypeDefinition() == genericWebFaultExceptionType;
  108. if (isGenericWebFaultException || asWebFaultException != null)
  109. {
  110. this.IsWebFaultException = true;
  111. if (isGenericWebFaultException)
  112. {
  113. this.InitializeFromGenericWebFaultException(error);
  114. }
  115. else
  116. {
  117. this.InitializeFromWebFaultException(asWebFaultException);
  118. }
  119. }
  120. }
  121. internal bool IsWebFaultException { get; private set; }
  122. internal object DetailObject { get; private set; }
  123. internal Type DetailType { get; private set; }
  124. internal HttpStatusCode StatusCode { get; private set; }
  125. private void InitializeFromWebFaultException(WebFaultException webFaultException)
  126. {
  127. this.StatusCode = webFaultException.StatusCode;
  128. this.DetailObject = null;
  129. this.DetailType = null;
  130. }
  131. private void InitializeFromGenericWebFaultException(Exception error)
  132. {
  133. Type exceptionType = error.GetType();
  134. this.DetailType = exceptionType.GetGenericArguments()[0];
  135. // The following 2 Reflection accessors only involve public API.
  136. // StatusCode is defined in WebFaultException<T>.
  137. PropertyInfo statusProperty = exceptionType.GetProperty("StatusCode", BindingFlags.Instance | BindingFlags.Public);
  138. Fx.Assert(statusProperty != null, "Could not get StatusCode property");
  139. this.StatusCode = (HttpStatusCode)statusProperty.GetValue(error, null);
  140. // Detail is defined in FaultException<T>
  141. PropertyInfo detailObjectProperty = exceptionType.GetProperty("Detail", BindingFlags.Instance | BindingFlags.Public);
  142. Fx.Assert(detailObjectProperty != null, "Could not get DetailObject property");
  143. this.DetailObject = detailObjectProperty.GetValue(error, null);
  144. }
  145. }
  146. }
  147. }