public static HttpResponseMessage CreateHttpResponseMessage(Exception exception) { var error = ServiceErrorUtility.CreateInternalErrorForException(exception); var statusCode = HttpServiceErrors.TryGetHttpStatusCode(error.Code) ?? HttpStatusCode.InternalServerError; return(new HttpResponseMessage(statusCode) { Content = JsonHttpContentSerializer.Instance.CreateHttpContent(error), }); }
/// <summary> /// Called to create an error object from an unexpected exception. /// </summary> protected virtual ServiceErrorDto CreateErrorFromException(Exception exception) => ServiceErrorUtility.CreateInternalErrorForException(exception);
/// <summary> /// Invokes the middleware. /// </summary> /// <remarks>This method translates the ASP.NET Core request into an HttpRequestMessage, /// uses the ServiceHttpHandler to handle the message, and then converts the HttpResponseMessage /// into an ASP.NET Core response. We borrowed code from Microsoft.AspNetCore.Mvc.WebApiCompatShim /// (HttpRequestMessageFeature and HttpResponseMessageOutputFormatter) to make sure we got it right /// and to avoid requiring an dependency on ASP.NET Core MVC and WebApiCompatShim.</remarks> public async Task Invoke(HttpContext httpContext) { var httpRequest = httpContext.Request; var uriString = httpRequest.Scheme + "://" + httpRequest.Host + httpRequest.PathBase + httpRequest.Path + httpRequest.QueryString; var requestMessage = new HttpRequestMessage(new HttpMethod(httpRequest.Method), uriString); // This allows us to pass the message through APIs defined in legacy code and then // operate on the HttpContext inside. requestMessage.Properties[nameof(HttpContext)] = httpContext; requestMessage.Content = new StreamContent(httpRequest.Body); foreach (var header in httpRequest.Headers) { // Every header should be able to fit into one of the two header collections. // Try message.Headers first since that accepts more of them. if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.AsEnumerable())) { requestMessage.Content.Headers.TryAddWithoutValidation(header.Key, header.Value.AsEnumerable()); } } HttpResponseMessage responseMessage; try { responseMessage = await m_handler.TryHandleHttpRequestAsync(requestMessage, httpContext.RequestAborted).ConfigureAwait(false); } catch (Exception exception) { var error = ServiceErrorUtility.CreateInternalErrorForException(exception); var statusCode = HttpServiceErrors.TryGetHttpStatusCode(error.Code) ?? HttpStatusCode.InternalServerError; responseMessage = new HttpResponseMessage(statusCode) { Content = JsonHttpContentSerializer.Instance.CreateHttpContent(error) }; } if (responseMessage != null) { using (responseMessage) { var response = httpContext.Response; response.StatusCode = (int)responseMessage.StatusCode; var responseHeaders = responseMessage.Headers; // Ignore the Transfer-Encoding header if it is just "chunked". // We let the host decide about whether the response should be chunked or not. if (responseHeaders.TransferEncodingChunked == true && responseHeaders.TransferEncoding.Count == 1) { responseHeaders.TransferEncoding.Clear(); } foreach (var header in responseHeaders) { response.Headers.Append(header.Key, header.Value.ToArray()); } if (responseMessage.Content != null) { var contentHeaders = responseMessage.Content.Headers; // Copy the response content headers only after ensuring they are complete. // We ask for Content-Length first because HttpContent lazily computes this // and only afterwards writes the value into the content headers. var unused = contentHeaders.ContentLength; foreach (var header in contentHeaders) { response.Headers.Append(header.Key, header.Value.ToArray()); } await responseMessage.Content.CopyToAsync(response.Body).ConfigureAwait(false); } } } else { await m_next(httpContext).ConfigureAwait(false); } }
private async Task HostAsync(HttpContext httpContext) { var httpRequest = httpContext.Request; var requestUrl = httpRequest.GetEncodedUrl(); var apiHandler = new ConformanceApiHttpHandler(new ConformanceApiService(m_tests)); var requestMessage = new HttpRequestMessage(new HttpMethod(httpRequest.Method), requestUrl) { Content = new StreamContent(httpRequest.Body), }; foreach (var header in httpRequest.Headers) { // Every header should be able to fit into one of the two header collections. // Try message.Headers first since that accepts more of them. if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.AsEnumerable())) { requestMessage.Content.Headers.TryAddWithoutValidation(header.Key, header.Value.AsEnumerable()); } } HttpResponseMessage?responseMessage = null; ServiceErrorDto? error = null; try { responseMessage = await apiHandler.TryHandleHttpRequestAsync(requestMessage, httpContext.RequestAborted).ConfigureAwait(false); if (responseMessage == null) { error = ServiceErrors.CreateInvalidRequest($"Test not found for {httpRequest.Method} {requestUrl}"); } } catch (Exception exception) { error = ServiceErrorUtility.CreateInternalErrorForException(exception); } if (error != null) { var statusCode = HttpServiceErrors.TryGetHttpStatusCode(error.Code) ?? HttpStatusCode.InternalServerError; responseMessage = new HttpResponseMessage(statusCode) { Content = JsonHttpContentSerializer.Instance.CreateHttpContent(error) }; } if (responseMessage != null) { using (responseMessage) { var response = httpContext.Response; response.StatusCode = (int)responseMessage.StatusCode; var responseHeaders = responseMessage.Headers; // Ignore the Transfer-Encoding header if it is just "chunked". // We let the host decide about whether the response should be chunked or not. if (responseHeaders.TransferEncodingChunked == true && responseHeaders.TransferEncoding.Count == 1) { responseHeaders.TransferEncoding.Clear(); } foreach (var header in responseHeaders) { response.Headers.Append(header.Key, header.Value.ToArray()); } // ReSharper disable once ConditionIsAlwaysTrueOrFalse if (responseMessage.Content != null) { var contentHeaders = responseMessage.Content.Headers; // Copy the response content headers only after ensuring they are complete. // We ask for Content-Length first because HttpContent lazily computes this // and only afterwards writes the value into the content headers. _ = contentHeaders.ContentLength; foreach (var header in contentHeaders) { response.Headers.Append(header.Key, header.Value.ToArray()); } await responseMessage.Content.CopyToAsync(response.Body).ConfigureAwait(false); } } } }