forked from aspnet/AspNetWebStack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathWebHostExceptionHandler.cs
More file actions
130 lines (108 loc) · 5.41 KB
/
WebHostExceptionHandler.cs
File metadata and controls
130 lines (108 loc) · 5.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.ExceptionHandling;
using System.Web.Http.Results;
using System.Web.Http.WebHost.Properties;
namespace System.Web.Http.WebHost
{
/// <summary>Provides the default implementation for handling exceptions within Web API web host.</summary>
/// <remarks>
/// This class preserves the legacy behavior of catch blocks and is the the default registered IExceptionHandler
/// for web host.
/// </remarks>
internal class WebHostExceptionHandler : IExceptionHandler
{
private readonly IExceptionHandler _innerHandler;
public WebHostExceptionHandler(IExceptionHandler innerHandler)
{
Contract.Assert(innerHandler != null);
_innerHandler = innerHandler;
}
public IExceptionHandler InnerHandler
{
get { return _innerHandler; }
}
public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
ExceptionContext exceptionContext = context.ExceptionContext;
Contract.Assert(exceptionContext != null);
if (exceptionContext.CatchBlock ==
WebHostExceptionCatchBlocks.HttpControllerHandlerBufferContent)
{
HandleWebHostBufferedContentException(context);
return TaskHelpers.Completed();
}
return _innerHandler.HandleAsync(context, cancellationToken);
}
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope",
Justification = "We already shipped this code; avoiding even minor breaking changes in error handling.")]
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
Justification = "All exceptions caught here become error responses")]
private static void HandleWebHostBufferedContentException(ExceptionHandlerContext context)
{
Contract.Assert(context != null);
ExceptionContext exceptionContext = context.ExceptionContext;
Contract.Assert(exceptionContext != null);
Exception exception = exceptionContext.Exception;
Contract.Assert(exception != null);
HttpRequestMessage request = exceptionContext.Request;
if (request == null)
{
throw new ArgumentException(Error.Format(SRResources.TypePropertyMustNotBeNull,
typeof(ExceptionContext).Name, "Request"), "context");
}
HttpResponseMessage response = exceptionContext.Response;
if (response == null)
{
throw new ArgumentException(Error.Format(SRResources.TypePropertyMustNotBeNull,
typeof(ExceptionContext).Name, "Response"), "context");
}
HttpContent responseContent = response.Content;
if (responseContent == null)
{
throw new ArgumentException(Error.Format(SRResources.TypePropertyMustNotBeNull,
typeof(HttpResponseMessage).Name, "Content"), "context");
}
HttpResponseMessage errorResponse;
// Create a 500 response with content containing an explanatory message and
// stack trace, subject to content negotiation and policy for error details.
try
{
MediaTypeHeaderValue mediaType = responseContent.Headers.ContentType;
string messageDetails = (mediaType != null)
? Error.Format(
SRResources.Serialize_Response_Failed_MediaType,
responseContent.GetType().Name,
mediaType)
: Error.Format(
SRResources.Serialize_Response_Failed,
responseContent.GetType().Name);
errorResponse = request.CreateErrorResponse(
HttpStatusCode.InternalServerError,
new InvalidOperationException(messageDetails, exception));
// CreateErrorResponse will choose 406 if it cannot find a formatter,
// but we want our default error response to be 500 always
errorResponse.StatusCode = HttpStatusCode.InternalServerError;
}
catch
{
// Failed creating an HttpResponseMessage for the error response.
// This can happen for missing config, missing conneg service, etc.
// Create an empty error response and return a non-faulted task.
errorResponse = request.CreateResponse(HttpStatusCode.InternalServerError);
}
context.Result = new ResponseMessageResult(errorResponse);
}
}
}