public async Task <ActionResult <PaginatedList <EmployeeDetailsDto> > > GetEmployeeList(int pageNumber, int pageSize)
        {
            try
            {
                if (pageNumber < 0)
                {
                    return(BadRequest("The pageNumber must be greather than 0."));
                }

                if (pageSize < 0)
                {
                    return(BadRequest("The pageSize must be greather than 0."));
                }

                pageNumber = pageNumber == 0 ? 1 : pageNumber;
                pageSize   = pageSize == 0 ? 10 : pageSize;
                PaginatedList <EmployeeDetailsDto> employeeList = await _employeeService.GetListAsync(pageNumber, pageSize);

                return(employeeList);
            }
            catch (Exception exception)
            {
                await _exceptionLogger.LogAsync(exception);

                return(StatusCode(StatusCodes.Status500InternalServerError));
            }
        }
Ejemplo n.º 2
0
        public async Task OnExceptionAsync(ExceptionContext context)
        {
            string message;
            int    statusCode;

            if (context.Exception is HttpResponseException ex)
            {
                message    = ex.Message;
                statusCode = ex.StatusCode;
            }
            else
            {
                message    = INTERNAL_SERVER_ERROR_MESSAGE;
                statusCode = HttpStatusCode.INTERNAL_SERVER_ERROR;
            }

            context.Result = new ObjectResult(new MessageResponse(message))
            {
                StatusCode = statusCode
            };

            context.ExceptionHandled = true;

            await _exceptionLogger.LogAsync(context.Exception);
        }
Ejemplo n.º 3
0
        private static async Task AssertDelegatesToAsync(
            Mock <IExceptionLogger> expected,
            IExceptionLogger actual
            )
        {
            Assert.NotNull(actual);

            ExceptionLoggerContext context = new ExceptionLoggerContext(
                new ExceptionContext(new Exception(), ExceptionCatchBlocks.HttpServer)
                );
            CancellationToken cancellationToken = CancellationToken.None;

            expected
            .Setup(
                (l) =>
                l.LogAsync(
                    It.IsAny <ExceptionLoggerContext>(),
                    It.IsAny <CancellationToken>()
                    )
                )
            .Returns(CreateCanceledTask());

            await Assert.ThrowsAsync <TaskCanceledException>(
                () => actual.LogAsync(context, cancellationToken)
                );

            expected.Verify((l) => l.LogAsync(context, cancellationToken), Times.Once());
        }
Ejemplo n.º 4
0
        public async Task LogAsync_DelegatesToLoggers()
        {
            // Arrange
            Mock <IExceptionLogger> exceptionLogger1Mock = new Mock <IExceptionLogger>(MockBehavior.Strict);
            Mock <IExceptionLogger> exceptionLogger2Mock = new Mock <IExceptionLogger>(MockBehavior.Strict);

            exceptionLogger1Mock
            .Setup(l => l.LogAsync(It.IsAny <ExceptionLoggerContext>(), It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(0));
            exceptionLogger2Mock
            .Setup(l => l.LogAsync(It.IsAny <ExceptionLoggerContext>(), It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(0));
            IEnumerable <IExceptionLogger> loggers = new IExceptionLogger[]
            {
                exceptionLogger1Mock.Object,
                exceptionLogger2Mock.Object
            };
            IExceptionLogger product = CreateProductUnderTest(loggers);

            ExceptionLoggerContext expectedContext           = CreateMinimalValidContext();
            CancellationToken      expectedCancellationToken = CreateCancellationToken();

            // Act
            await product.LogAsync(expectedContext, expectedCancellationToken);

            // Assert
            exceptionLogger1Mock.Verify(l => l.LogAsync(expectedContext, expectedCancellationToken), Times.Once());
            exceptionLogger2Mock.Verify(l => l.LogAsync(expectedContext, expectedCancellationToken), Times.Once());
        }
Ejemplo n.º 5
0
        public void LogAsync_IfShouldLogReturnsTrue_DelegatesToLogAsyncCore()
        {
            // Arrange
            Mock <ExceptionLogger> mock = new Mock <ExceptionLogger> {
                CallBase = true
            };
            Task expectedTask = CreateCompletedTask();

            mock.Setup(h => h.ShouldLog(It.IsAny <ExceptionLoggerContext>())).Returns(true);
            mock
            .Setup(h => h.LogAsync(It.IsAny <ExceptionLoggerContext>(), It.IsAny <CancellationToken>()))
            .Returns(expectedTask);

            IExceptionLogger product = mock.Object;

            ExceptionLoggerContext expectedContext = CreateMinimalValidLoggerContext();

            using (CancellationTokenSource tokenSource = CreateTokenSource())
            {
                CancellationToken expectedCancellationToken = tokenSource.Token;

                // Act
                Task task = product.LogAsync(expectedContext, expectedCancellationToken);

                // Assert
                Assert.Same(expectedTask, task);
                mock.Verify(h => h.ShouldLog(expectedContext), Times.Once());
                mock.Verify(h => h.LogAsync(expectedContext, expectedCancellationToken), Times.Once());
            }
        }
        public void LogAsync_DelegatesToLoggers()
        {
            // Arrange
            Mock <IExceptionLogger> exceptionLogger1Mock = new Mock <IExceptionLogger>(MockBehavior.Strict);
            Mock <IExceptionLogger> exceptionLogger2Mock = new Mock <IExceptionLogger>(MockBehavior.Strict);

            exceptionLogger1Mock
            .Setup(l => l.LogAsync(It.IsAny <ExceptionLoggerContext>(), It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(0));
            exceptionLogger2Mock
            .Setup(l => l.LogAsync(It.IsAny <ExceptionLoggerContext>(), It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(0));
            IEnumerable <IExceptionLogger> loggers = new IExceptionLogger[]
            {
                exceptionLogger1Mock.Object,
                exceptionLogger2Mock.Object
            };
            IExceptionLogger product = CreateProductUnderTest(loggers);

            ExceptionLoggerContext expectedContext           = CreateContext();
            CancellationToken      expectedCancellationToken = CreateCancellationToken();

            // Act
            Task task = product.LogAsync(expectedContext, expectedCancellationToken);

            Assert.NotNull(task);
            task.WaitUntilCompleted();

            // Assert
            Assert.Equal(TaskStatus.RanToCompletion, task.Status);
            exceptionLogger1Mock.Verify(l => l.LogAsync(expectedContext, expectedCancellationToken), Times.Once());
            exceptionLogger2Mock.Verify(l => l.LogAsync(expectedContext, expectedCancellationToken), Times.Once());
        }
Ejemplo n.º 7
0
        public void LogAsync_IfShouldLogReturnsFalse_ReturnsCompletedTask()
        {
            // Arrange
            Mock <ExceptionLogger> mock = new Mock <ExceptionLogger> {
                CallBase = true
            };

            mock.Setup(h => h.ShouldLog(It.IsAny <ExceptionLoggerContext>())).Returns(false);

            IExceptionLogger product = mock.Object;

            ExceptionLoggerContext expectedContext           = CreateMinimalValidLoggerContext();
            CancellationToken      expectedCancellationToken = CancellationToken.None;

            // Act
            Task task = product.LogAsync(expectedContext, expectedCancellationToken);

            // Assert
            Assert.NotNull(task);
            Assert.True(task.IsCompleted);
            Assert.Equal(TaskStatus.RanToCompletion, task.Status);
            mock.Verify(h => h.ShouldLog(expectedContext), Times.Once());
            mock.Verify(h => h.LogAsync(It.IsAny <ExceptionLoggerContext>(), It.IsAny <CancellationToken>()),
                        Times.Never());
        }
        public async Task <HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
        {
            ExceptionDispatchInfo exceptionInfo;

            try
            {
                return(await _innerResult.ExecuteAsync(cancellationToken));
            }
            catch (Exception e)
            {
                exceptionInfo = ExceptionDispatchInfo.Capture(e);
            }

            // This code path only runs if the task is faulted with an exception
            Exception exception = exceptionInfo.SourceException;

            Debug.Assert(exception != null);

            ExceptionContext exceptionContext = new ExceptionContext(exception, ExceptionCatchBlocks.IExceptionFilter,
                                                                     _context);

            await _exceptionLogger.LogAsync(exceptionContext, canBeHandled : true,
                                            cancellationToken : cancellationToken);

            HttpActionExecutedContext executedContext = new HttpActionExecutedContext(_context, exception);

            // Note: exception filters need to be scheduled in the reverse order so that
            // the more specific filter (e.g. Action) executes before the less specific ones (e.g. Global)
            for (int i = _filters.Length - 1; i >= 0; i--)
            {
                IExceptionFilter exceptionFilter = _filters[i];
                await exceptionFilter.ExecuteExceptionFilterAsync(executedContext, cancellationToken);
            }

            if (executedContext.Response == null)
            {
                executedContext.Response = await _exceptionHandler.HandleAsync(exceptionContext, cancellationToken);
            }

            if (executedContext.Response != null)
            {
                return(executedContext.Response);
            }
            else
            {
                // Preserve the original stack trace when the exception is not changed by any filter.
                if (exception == executedContext.Exception)
                {
                    exceptionInfo.Throw();
                }

                // If the exception is changed by a filter, throw the new exception instead.
                throw executedContext.Exception;
            }
        }
Ejemplo n.º 9
0
        public void LogAsync_IfContextIsNull_Throws()
        {
            // Arrange
            Mock <ExceptionLogger> mock    = new Mock <ExceptionLogger>(MockBehavior.Strict);
            IExceptionLogger       product = mock.Object;

            ExceptionLoggerContext context           = null;
            CancellationToken      cancellationToken = CancellationToken.None;

            // Act & Assert
            Assert.ThrowsArgumentNull(() => product.LogAsync(context, cancellationToken), "context");
        }
Ejemplo n.º 10
0
        private static async Task WriteErrorResponseContentAsync(
            HttpResponseBase httpResponseBase,
            HttpRequestMessage request,
            HttpResponseMessage errorResponse,
            CancellationToken cancellationToken,
            IExceptionLogger exceptionLogger
            )
        {
            HttpRequestMessage ignoreUnused = request;

            try
            {
                Exception exception = null;
                cancellationToken.ThrowIfCancellationRequested();

                try
                {
                    // Asynchronously write the content of the new error HttpResponseMessage
                    await errorResponse.Content.CopyToAsync(httpResponseBase.OutputStream);

                    return;
                }
                catch (OperationCanceledException)
                {
                    // Propogate the canceled task without calling exception loggers.
                    throw;
                }
                catch (Exception ex)
                {
                    exception = ex;
                }

                Contract.Assert(exception != null);

                ExceptionContext exceptionContext = new ExceptionContext(
                    exception,
                    WebHostExceptionCatchBlocks.HttpControllerHandlerBufferError,
                    request,
                    errorResponse
                    );
                await exceptionLogger.LogAsync(exceptionContext, cancellationToken);

                // Failure writing the error response.  Likely cause is a formatter
                // serialization exception.  Create empty error response and
                // return a non-faulted task.
                SetEmptyErrorResponse(httpResponseBase);
            }
            finally
            {
                // Dispose the temporary HttpResponseMessage carrying the error response
                errorResponse.Dispose();
            }
        }
        /// <summary>
        /// Invokes the next <see cref="RequestDelegate"/>, catches any exception thrown,
        /// reports the exception to the  Stackdriver Error Reporting API and rethrows
        /// the exception.
        /// </summary>
        public async Task Invoke(HttpContext httpContext)
        {
            try
            {
                await _next(httpContext).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                await _logger.LogAsync(exception, httpContext).ConfigureAwait(false);

                throw;
            }
        }
Ejemplo n.º 12
0
        public void LogAsync_IfLoggerIsNull_Throws()
        {
            // Arrange
            IEnumerable <IExceptionLogger> loggers = new IExceptionLogger[] { null };
            IExceptionLogger product = CreateProductUnderTest(loggers);

            ExceptionLoggerContext context           = CreateMinimalValidContext();
            CancellationToken      cancellationToken = CreateCancellationToken();

            // Act & Assert
            Assert.Throws <InvalidOperationException>(() => product.LogAsync(context, cancellationToken),
                                                      "The IExceptionLogger instance must not be null.");
        }
        /// <summary>
        /// Invokes the next <see cref="RequestDelegate"/>, catches any exception thrown,
        /// reports the exception to the  Stackdriver Error Reporting API and rethrows
        /// the exception.
        /// </summary>
        public async Task Invoke(HttpContext httpContext)
        {
            try
            {
                await _next(httpContext);
            }
            catch (Exception exception)
            {
                await _logger.LogAsync(httpContext, exception);

                throw;
            }
        }
Ejemplo n.º 14
0
        internal static async Task WriteStreamedResponseContentAsync(
            HttpContextBase httpContextBase,
            HttpRequestMessage request,
            HttpResponseMessage response,
            IExceptionLogger exceptionLogger,
            CancellationToken cancellationToken
            )
        {
            Contract.Assert(httpContextBase != null);
            Contract.Assert(httpContextBase.Response != null);
            Contract.Assert(request != null);
            Contract.Assert(response != null);
            Contract.Assert(response.Content != null);

            Exception exception = null;

            cancellationToken.ThrowIfCancellationRequested();

            try
            {
                // Copy the HttpContent into the output stream asynchronously.
                await response.Content.CopyToAsync(httpContextBase.Response.OutputStream);

                return;
            }
            catch (OperationCanceledException)
            {
                // Propogate the canceled task without calling exception loggers.
                throw;
            }
            catch (Exception ex)
            {
                exception = ex;
            }

            Contract.Assert(exception != null);

            ExceptionContextCatchBlock catchBlock =
                WebHostExceptionCatchBlocks.HttpControllerHandlerStreamContent;
            ExceptionContext exceptionContext = new ExceptionContext(
                exception,
                catchBlock,
                request,
                response
                );
            await exceptionLogger.LogAsync(exceptionContext, cancellationToken);

            // Streamed content may have been written and cannot be recalled.
            // Our only choice is to abort the connection.
            httpContextBase.Request.Abort();
        }
        public void LogAsync_ReturnsCompletedTask()
        {
            // Arrange
            IExceptionLogger       product           = CreateProductUnderTest();
            ExceptionLoggerContext context           = CreateContext();
            CancellationToken      cancellationToken = CancellationToken.None;

            // Act
            Task task = product.LogAsync(context, cancellationToken);

            // Assert
            Assert.NotNull(task);
            Assert.Equal(TaskStatus.RanToCompletion, task.Status);
        }
Ejemplo n.º 16
0
        public async Task <ActionResult> Error()
        {
            try
            {
                IExceptionHandlerFeature context = HttpContext.Features.Get <IExceptionHandlerFeature>();
                await _exceptionLogger.LogAsync(context.Error);

                return(StatusCode(StatusCodes.Status500InternalServerError));
            }
            catch (Exception exception)
            {
                _logger.LogCritical(exception, exception.Message);
                return(StatusCode(StatusCodes.Status500InternalServerError));
            }
        }
Ejemplo n.º 17
0
        public void LogAsync_IfExceptionIsNull_Throws()
        {
            // Arrange
            Mock <ExceptionLogger> mock    = new Mock <ExceptionLogger>(MockBehavior.Strict);
            IExceptionLogger       product = mock.Object;

            ExceptionLoggerContext context = CreateContext(CreateExceptionContext());

            Assert.Null(context.ExceptionContext.Exception); // Guard
            CancellationToken cancellationToken = CancellationToken.None;

            // Act & Assert
            Assert.ThrowsArgument(() => product.LogAsync(context, cancellationToken), "context",
                                  "ExceptionContext.Exception must not be null.");
        }
Ejemplo n.º 18
0
        /// <summary>Calls an exception logger.</summary>
        /// <param name="logger">The unhandled exception logger.</param>
        /// <param name="context">The exception context.</param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        /// <returns>A task representing the asynchronous exception logging operation.</returns>
        public static Task LogAsync(this IExceptionLogger logger, ExceptionContext context, CancellationToken cancellationToken)
        {
            if (logger == null)
            {
                throw Error.ArgumentNull("logger");
            }

            if (context == null)
            {
                throw Error.ArgumentNull("context");
            }

            ExceptionLoggerContext loggerContext = new ExceptionLoggerContext(context);

            return(logger.LogAsync(loggerContext, cancellationToken));
        }
        /// <summary>Calls an exception logger.</summary>
        /// <param name="logger">The unhandled exception logger.</param>
        /// <param name="context">The exception context.</param>
        /// <param name="canBeHandled">A value indicating whether the exception can subsequently be handled.</param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        /// <returns>A task representing the asynchronous exception logging operation.</returns>
        public static Task LogAsync(this IExceptionLogger logger, ExceptionContext context, bool canBeHandled,
                                    CancellationToken cancellationToken)
        {
            if (logger == null)
            {
                throw new ArgumentNullException("logger");
            }

            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            ExceptionLoggerContext loggerContext = new ExceptionLoggerContext(context, canBeHandled);

            return(logger.LogAsync(loggerContext, cancellationToken));
        }
 /// <summary>
 /// Invokes the next <see cref="RequestDelegate"/>, catches any exception thrown,
 /// reports the exception to the  Stackdriver Error Reporting API and rethrows
 /// the exception.
 /// </summary>
 public async Task Invoke(HttpContext httpContext)
 {
     try
     {
         await _next(httpContext).ConfigureAwait(false);
     }
     catch (Exception exception)
     {
         try
         {
             await _logger.LogAsync(exception, httpContext).ConfigureAwait(false);
         }
         catch (Exception innerException)
         {
             throw new AggregateException(innerException, exception);
         }
         throw;
     }
 }
        private static void AssertDelegatesTo(Mock <IExceptionLogger> expected, IExceptionLogger actual)
        {
            Assert.NotNull(actual);

            ExceptionLoggerContext context           = new ExceptionLoggerContext(new ExceptionContext(new Exception(), ExceptionCatchBlocks.HttpServer));
            CancellationToken      cancellationToken = CancellationToken.None;

            expected
            .Setup((l) => l.LogAsync(It.IsAny <ExceptionLoggerContext>(), It.IsAny <CancellationToken>()))
            .Returns(CreateCanceledTask());

            Task task = actual.LogAsync(context, cancellationToken);

            Assert.NotNull(task);
            task.WaitUntilCompleted();
            Assert.Equal(TaskStatus.Canceled, task.Status);

            expected.Verify((l) => l.LogAsync(context, cancellationToken), Times.Once());
        }
Ejemplo n.º 22
0
        public async Task <ActionResult <List <DepartmentDetailsDto> > > GetDepartmentList()
        {
            try
            {
                List <DepartmentDetailsDto> departmentDetailsDtos = await _departmentService.GetListAsync();

                return(departmentDetailsDtos);
            }
            catch (Exception exception)
            {
                await _exceptionLogger.LogAsync(exception);

                return(StatusCode(StatusCodes.Status500InternalServerError));
            }
        }
Ejemplo n.º 23
0
        private static async Task WriteErrorResponseContentAsync(HttpResponseBase httpResponseBase,
            HttpRequestMessage request, HttpResponseMessage errorResponse, CancellationToken cancellationToken,
            IExceptionLogger exceptionLogger)
        {
            HttpRequestMessage ignoreUnused = request;

            try
            {
                Exception exception = null;
                cancellationToken.ThrowIfCancellationRequested();

                try
                {
                    // Asynchronously write the content of the new error HttpResponseMessage
                    await errorResponse.Content.CopyToAsync(httpResponseBase.OutputStream);
                    return;
                }
                catch (Exception ex)
                {
                    exception = ex;
                }

                Contract.Assert(exception != null);

                ExceptionContext exceptionContext = new ExceptionContext(exception,
                    WebHostExceptionCatchBlocks.HttpControllerHandlerBufferError, request, errorResponse);
                await exceptionLogger.LogAsync(exceptionContext, cancellationToken);

                // Failure writing the error response.  Likely cause is a formatter
                // serialization exception.  Create empty error response and
                // return a non-faulted task.
                SetEmptyErrorResponse(httpResponseBase);
            }
            finally
            {
                // Dispose the temporary HttpResponseMessage carrying the error response
                errorResponse.Dispose();
            }
        }
Ejemplo n.º 24
0
        internal static async Task<bool> CopyErrorResponseAsync(ExceptionContextCatchBlock catchBlock,
            HttpContextBase httpContextBase, HttpRequestMessage request, HttpResponseMessage response,
            Exception exception, IExceptionLogger exceptionLogger, IExceptionHandler exceptionHandler,
            CancellationToken cancellationToken)
        {
            Contract.Assert(httpContextBase != null);
            Contract.Assert(httpContextBase.Response != null);
            Contract.Assert(request != null);
            Contract.Assert(exception != null);
            Contract.Assert(catchBlock != null);
            Contract.Assert(catchBlock.CallsHandler);

            HttpResponseBase httpResponseBase = httpContextBase.Response;
            HttpResponseMessage errorResponse = null;
            HttpResponseException responseException = exception as HttpResponseException;

            // Ensure all headers and content are cleared to eliminate any partial results.
            ClearContentAndHeaders(httpResponseBase);

            // If the exception we are handling is HttpResponseException,
            // that becomes the error response.
            if (responseException != null)
            {
                errorResponse = responseException.Response;
            }
            else
            {
                ExceptionContext exceptionContext = new ExceptionContext(exception, catchBlock, request)
                {
                    Response = response
                };
                await exceptionLogger.LogAsync(exceptionContext, cancellationToken);
                errorResponse = await exceptionHandler.HandleAsync(exceptionContext, cancellationToken);

                if (errorResponse == null)
                {
                    return false;
                }
            }

            Contract.Assert(errorResponse != null);
            if (!await CopyResponseStatusAndHeadersAsync(httpContextBase, request, errorResponse, exceptionLogger,
                cancellationToken))
            {
                // Don't rethrow the original exception unless explicitly requested to do so. In this case, the
                // exception handler indicated it wanted to handle the exception; it simply failed create a stable
                // response to send.
                return true;
            }

            // The error response may return a null content if content negotiation
            // fails to find a formatter, or this may be an HttpResponseException without
            // content.  In either case, cleanup and return a completed task.

            if (errorResponse.Content == null)
            {
                errorResponse.Dispose();
                return true;
            }

            CopyHeaders(errorResponse.Content.Headers, httpContextBase);

            await WriteErrorResponseContentAsync(httpResponseBase, request, errorResponse, cancellationToken,
                exceptionLogger);
            return true;
        }
Ejemplo n.º 25
0
        internal static async Task WriteStreamedResponseContentAsync(HttpContextBase httpContextBase,
            HttpRequestMessage request, HttpResponseMessage response, IExceptionLogger exceptionLogger,
            CancellationToken cancellationToken)
        {
            Contract.Assert(httpContextBase != null);
            Contract.Assert(httpContextBase.Response != null);
            Contract.Assert(request != null);
            Contract.Assert(response != null);
            Contract.Assert(response.Content != null);

            Exception exception = null;
            cancellationToken.ThrowIfCancellationRequested();

            try
            {
                // Copy the HttpContent into the output stream asynchronously.
                await response.Content.CopyToAsync(httpContextBase.Response.OutputStream);
                return;
            }
            catch (Exception ex)
            {
                exception = ex;
            }

            Contract.Assert(exception != null);

            ExceptionContextCatchBlock catchBlock = WebHostExceptionCatchBlocks.HttpControllerHandlerStreamContent;
            ExceptionContext exceptionContext = new ExceptionContext(exception, catchBlock, request, response);
            await exceptionLogger.LogAsync(exceptionContext, cancellationToken);

            // Streamed content may have been written and cannot be recalled.
            // Our only choice is to abort the connection.
            httpContextBase.Request.Abort();
        }
Ejemplo n.º 26
0
        internal static async Task<bool> PrepareHeadersAsync(HttpResponseBase responseBase, HttpRequestMessage request,
            HttpResponseMessage response, IExceptionLogger exceptionLogger, CancellationToken cancellationToken)
        {
            Contract.Assert(response != null);
            HttpResponseHeaders responseHeaders = response.Headers;
            Contract.Assert(responseHeaders != null);
            HttpContent content = response.Content;
            bool isTransferEncodingChunked = responseHeaders.TransferEncodingChunked == true;
            HttpHeaderValueCollection<TransferCodingHeaderValue> transferEncoding = responseHeaders.TransferEncoding;

            if (content != null)
            {
                HttpContentHeaders contentHeaders = content.Headers;
                Contract.Assert(contentHeaders != null);

                if (isTransferEncodingChunked)
                {
                    // According to section 4.4 of the HTTP 1.1 spec, HTTP responses that use chunked transfer
                    // encoding must not have a content length set. Chunked should take precedence over content
                    // length in this case because chunked is always set explicitly by users while the Content-Length
                    // header can be added implicitly by System.Net.Http.
                    contentHeaders.ContentLength = null;
                }
                else
                {
                    Exception exception = null;

                    // 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.
                    try
                    {
                        var unused = contentHeaders.ContentLength;
                    }
                    catch (Exception ex)
                    {
                        exception = ex;
                    }

                    if (exception != null)
                    {
                        ExceptionContext exceptionContext = new ExceptionContext(exception,
                            WebHostExceptionCatchBlocks.HttpControllerHandlerComputeContentLength, request, response);
                        await exceptionLogger.LogAsync(exceptionContext, cancellationToken);

                        SetEmptyErrorResponse(responseBase);
                        return false;
                    }
                }

                // Select output buffering based on the user-controlled buffering policy
                bool isBuffered = _bufferPolicySelector.Value != null ?
                    _bufferPolicySelector.Value.UseBufferedOutputStream(response) : true;
                responseBase.BufferOutput = isBuffered;
            }

            // Ignore the Transfer-Encoding header if it is just "chunked"; the host will provide it when no
            // Content-Length is present and BufferOutput is disabled (and this method guarantees those conditions).
            // HttpClient sets this header when it receives chunked content, but HttpContent does not include the
            // frames. The ASP.NET contract is to set this header only when writing chunked frames to the stream.
            // A Web API caller who desires custom framing would need to do a different Transfer-Encoding (such as
            // "identity, chunked").
            if (isTransferEncodingChunked && transferEncoding.Count == 1)
            {
                transferEncoding.Clear();

                // In the case of a conflict between a Transfer-Encoding: chunked header and the output buffering
                // policy, honor the Transnfer-Encoding: chunked header and ignore the buffer policy.
                // If output buffering is not disabled, ASP.NET will not write the TransferEncoding: chunked header.
                responseBase.BufferOutput = false;
            }

            return true;
        }
        internal static async Task <bool> PrepareHeadersAsync(HttpResponseBase responseBase, HttpRequestMessage request,
                                                              HttpResponseMessage response, IExceptionLogger exceptionLogger, CancellationToken cancellationToken)
        {
            Contract.Assert(response != null);
            HttpResponseHeaders responseHeaders = response.Headers;

            Contract.Assert(responseHeaders != null);
            HttpContent content = response.Content;
            bool        isTransferEncodingChunked = responseHeaders.TransferEncodingChunked == true;
            HttpHeaderValueCollection <TransferCodingHeaderValue> transferEncoding = responseHeaders.TransferEncoding;

            if (content != null)
            {
                HttpContentHeaders contentHeaders = content.Headers;
                Contract.Assert(contentHeaders != null);

                if (isTransferEncodingChunked)
                {
                    // According to section 4.4 of the HTTP 1.1 spec, HTTP responses that use chunked transfer
                    // encoding must not have a content length set. Chunked should take precedence over content
                    // length in this case because chunked is always set explicitly by users while the Content-Length
                    // header can be added implicitly by System.Net.Http.
                    contentHeaders.ContentLength = null;
                }
                else
                {
                    Exception exception = null;

                    // 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.
                    try
                    {
                        var unused = contentHeaders.ContentLength;
                    }
                    catch (Exception ex)
                    {
                        exception = ex;
                    }

                    if (exception != null)
                    {
                        ExceptionContext exceptionContext = new ExceptionContext(exception,
                                                                                 WebHostExceptionCatchBlocks.HttpControllerHandlerComputeContentLength, request, response);
                        await exceptionLogger.LogAsync(exceptionContext, cancellationToken);

                        SetEmptyErrorResponse(responseBase);
                        return(false);
                    }
                }

                // Select output buffering based on the user-controlled buffering policy
                bool isBuffered = _bufferPolicySelector.Value != null?
                                  _bufferPolicySelector.Value.UseBufferedOutputStream(response) : true;

                responseBase.BufferOutput = isBuffered;
            }

            // Ignore the Transfer-Encoding header if it is just "chunked"; the host will provide it when no
            // Content-Length is present and BufferOutput is disabled (and this method guarantees those conditions).
            // HttpClient sets this header when it receives chunked content, but HttpContent does not include the
            // frames. The ASP.NET contract is to set this header only when writing chunked frames to the stream.
            // A Web API caller who desires custom framing would need to do a different Transfer-Encoding (such as
            // "identity, chunked").
            if (isTransferEncodingChunked && transferEncoding.Count == 1)
            {
                transferEncoding.Clear();

                // In the case of a conflict between a Transfer-Encoding: chunked header and the output buffering
                // policy, honor the Transnfer-Encoding: chunked header and ignore the buffer policy.
                // If output buffering is not disabled, ASP.NET will not write the TransferEncoding: chunked header.
                responseBase.BufferOutput = false;
            }

            return(true);
        }
        internal static async Task <bool> CopyErrorResponseAsync(ExceptionContextCatchBlock catchBlock,
                                                                 HttpContextBase httpContextBase, HttpRequestMessage request, HttpResponseMessage response,
                                                                 Exception exception, IExceptionLogger exceptionLogger, IExceptionHandler exceptionHandler,
                                                                 CancellationToken cancellationToken)
        {
            Contract.Assert(httpContextBase != null);
            Contract.Assert(httpContextBase.Response != null);
            Contract.Assert(request != null);
            Contract.Assert(exception != null);
            Contract.Assert(catchBlock != null);
            Contract.Assert(catchBlock.CallsHandler);

            HttpResponseBase      httpResponseBase  = httpContextBase.Response;
            HttpResponseMessage   errorResponse     = null;
            HttpResponseException responseException = exception as HttpResponseException;

            // Ensure all headers and content are cleared to eliminate any partial results.
            ClearContentAndHeaders(httpResponseBase);

            // If the exception we are handling is HttpResponseException,
            // that becomes the error response.
            if (responseException != null)
            {
                errorResponse = responseException.Response;
            }
            else
            {
                ExceptionContext exceptionContext = new ExceptionContext(exception, catchBlock, request)
                {
                    Response = response
                };
                await exceptionLogger.LogAsync(exceptionContext, cancellationToken);

                errorResponse = await exceptionHandler.HandleAsync(exceptionContext, cancellationToken);

                if (errorResponse == null)
                {
                    return(false);
                }
            }

            Contract.Assert(errorResponse != null);
            if (!await CopyResponseStatusAndHeadersAsync(httpContextBase, request, errorResponse, exceptionLogger,
                                                         cancellationToken))
            {
                // Don't rethrow the original exception unless explicitly requested to do so. In this case, the
                // exception handler indicated it wanted to handle the exception; it simply failed create a stable
                // response to send.
                return(true);
            }

            // The error response may return a null content if content negotiation
            // fails to find a formatter, or this may be an HttpResponseException without
            // content.  In either case, cleanup and return a completed task.

            if (errorResponse.Content == null)
            {
                errorResponse.Dispose();
                return(true);
            }

            CopyHeaders(errorResponse.Content.Headers, httpContextBase);

            await WriteErrorResponseContentAsync(httpResponseBase, request, errorResponse, cancellationToken,
                                                 exceptionLogger);

            return(true);
        }
        private async Task <HttpResponseMessage> BufferResponseContentAsync(HttpRequestMessage request,
                                                                            HttpResponseMessage response, CancellationToken cancellationToken)
        {
            ExceptionDispatchInfo exceptionInfo;

            cancellationToken.ThrowIfCancellationRequested();

            try
            {
                await response.Content.LoadIntoBufferAsync();

                return(response);
            }
            catch (OperationCanceledException)
            {
                // Propogate the canceled task without calling exception loggers or handlers.
                throw;
            }
            catch (Exception exception)
            {
                exceptionInfo = ExceptionDispatchInfo.Capture(exception);
            }

            // If the content can't be buffered, create a buffered error response for the exception
            // This code will commonly run when a formatter throws during the process of serialization

            Debug.Assert(exceptionInfo.SourceException != null);

            ExceptionContext exceptionContext = new ExceptionContext(exceptionInfo.SourceException,
                                                                     AspNetCoreExceptionCatchBlocks.HttpMessageHandlerAdapterBufferContent, request, response);

            await _exceptionLogger.LogAsync(exceptionContext, cancellationToken);

            HttpResponseMessage errorResponse = await _exceptionHandler.HandleAsync(exceptionContext,
                                                                                    cancellationToken);

            response.Dispose();

            if (errorResponse == null)
            {
                exceptionInfo.Throw();
                return(null);
            }

            // We have an error response to try to buffer and send back.

            response = errorResponse;
            cancellationToken.ThrowIfCancellationRequested();

            Exception errorException;

            try
            {
                // Try to buffer the error response and send it back.
                await response.Content.LoadIntoBufferAsync();

                return(response);
            }
            catch (OperationCanceledException)
            {
                // Propogate the canceled task without calling exception loggers.
                throw;
            }
            catch (Exception exception)
            {
                errorException = exception;
            }

            // We tried to send back an error response with content, but we couldn't. It's an edge case; the best we
            // can do is to log that exception and send back an empty 500.

            ExceptionContext errorExceptionContext = new ExceptionContext(errorException,
                                                                          AspNetCoreExceptionCatchBlocks.HttpMessageHandlerAdapterBufferError, request, response);
            await _exceptionLogger.LogAsync(errorExceptionContext, cancellationToken);

            response.Dispose();
            return(request.CreateResponse(HttpStatusCode.InternalServerError));
        }
        private static void AssertDelegatesTo(Mock<IExceptionLogger> expected, IExceptionLogger actual)
        {
            Assert.NotNull(actual);

            ExceptionLoggerContext context = new ExceptionLoggerContext(new ExceptionContext(new Exception(), ExceptionCatchBlocks.HttpServer));
            CancellationToken cancellationToken = CancellationToken.None;

            expected
                .Setup((l) => l.LogAsync(It.IsAny<ExceptionLoggerContext>(), It.IsAny<CancellationToken>()))
                .Returns(CreateCanceledTask());

            Task task = actual.LogAsync(context, cancellationToken);

            Assert.NotNull(task);
            task.WaitUntilCompleted();
            Assert.Equal(TaskStatus.Canceled, task.Status);

            expected.Verify((l) => l.LogAsync(context, cancellationToken), Times.Once());
        }
        internal static async Task <bool> CopyErrorResponseAsync(ExceptionContextCatchBlock catchBlock,
                                                                 HttpContextBase httpContextBase, HttpRequestMessage request, HttpResponseMessage response,
                                                                 Exception exception, CancellationToken cancellationToken, IExceptionLogger exceptionLogger,
                                                                 IExceptionHandler exceptionHandler)
        {
            Contract.Assert(httpContextBase != null);
            Contract.Assert(httpContextBase.Response != null);
            Contract.Assert(request != null);
            Contract.Assert(exception != null);

            HttpResponseBase      httpResponseBase  = httpContextBase.Response;
            HttpResponseMessage   errorResponse     = null;
            HttpResponseException responseException = exception as HttpResponseException;

            // Ensure all headers and content are cleared to eliminate any partial results.
            ClearContentAndHeaders(httpResponseBase);

            // If the exception we are handling is HttpResponseException,
            // that becomes the error response.
            if (responseException != null)
            {
                errorResponse = responseException.Response;
            }
            else
            {
                ExceptionContext exceptionContext = new ExceptionContext(exception, catchBlock, request)
                {
                    Response = response
                };
                await exceptionLogger.LogAsync(exceptionContext, canBeHandled : true,
                                               cancellationToken : cancellationToken);

                errorResponse = await exceptionHandler.HandleAsync(exceptionContext, cancellationToken);

                if (errorResponse == null)
                {
                    return(false);
                }
            }

            Contract.Assert(errorResponse != null);
            CopyResponseStatusAndHeaders(httpContextBase, errorResponse);

            // The error response may return a null content if content negotiation
            // fails to find a formatter, or this may be an HttpResponseException without
            // content.  In either case, cleanup and return a completed task.

            if (errorResponse.Content == null)
            {
                errorResponse.Dispose();
                return(true);
            }

            // Copy the headers from the newly generated HttpResponseMessage.
            // We must ask the content for its content length because Content-Length
            // is lazily computed and added to the headers.
            var unused = errorResponse.Content.Headers.ContentLength;

            CopyHeaders(errorResponse.Content.Headers, httpContextBase);

            await WriteErrorResponseContentAsync(httpResponseBase, request, errorResponse, cancellationToken,
                                                 exceptionLogger);

            return(true);
        }