public async Task ExceptionHandler_logs_and_returns_errorId() { // Arrange var expectedException = new Exception("Any exception..."); var logger = new Mock <ILogger <ExceptionHandlerMiddleware> >(); var exceptionHandler = new ExceptionHandlerMiddleware( (innerHttpContext) => { throw expectedException; }, logger.Object ); var context = GetContext(); // Act await exceptionHandler.Invoke(context); var resultMessage = GetResultMessage(context); // Assert Assert.NotEqual(Guid.Empty, resultMessage.ErrorId); logger.Verify(l => l.Log( LogLevel.Error, 0, It.Is <FormattedLogValues>(v => v.ToString() == $"[ErrorId={resultMessage.ErrorId}] {context.Request.Method} {context.Request.Path}"), It.Is <Exception>(e => e == expectedException), It.IsAny <Func <object, Exception, string> >()) ); }
public async Task WhenInfrastrucureExceptionIsRaised_ExceptionHandlerMiddlewareShouldHandleItToCustomErrorResponseAndBadRequestHttpStatus() { // Arrange var middleware = new ExceptionHandlerMiddleware((innerHttpContext) => { throw new InfrastructureException("Test", "Test"); }); var context = new DefaultHttpContext(); context.Response.Body = new MemoryStream(); //Act await middleware.Invoke(context, _fixture.CurrentEnvironment); context.Response.Body.Seek(0, SeekOrigin.Begin); var reader = new StreamReader(context.Response.Body); var streamText = reader.ReadToEnd(); var response = JsonConvert.DeserializeObject <ErrorResponse>(streamText); //Assert response.ShouldNotBe(null); response.ShouldBeOfType <ErrorResponse>(); response.Code.ShouldBe("Test"); response.Message.ShouldBe("Test"); context.Response.StatusCode.ShouldBe((int)HttpStatusCode.BadRequest); }
public async Task OnlyLogsOnce() { var uuid = string.Empty; var optionsMock = new Mock <IOptions <RollbarOptions> >(); var rollbarClientMock = new Mock <RollbarClient>(optionsMock.Object); rollbarClientMock.SetupSequence(m => m.Send(It.IsAny <Payloads.Payload>())) .Returns(() => ReturnItem("test")) .Returns(() => ReturnItem("fail")); var httpContextMock = new Mock <HttpContext>(); httpContextMock .Setup(h => h.Features.Set(It.IsAny <IRollbarResponseFeature>())); var rollbar = new Rollbar(new IBuilder[] { }, new IExceptionBuilder[] { }, rollbarClientMock.Object); var middleware = new ExceptionHandlerMiddleware(context => { try { throw new Exception("Middleware tests"); } catch (Exception exception) { rollbar.SendException(exception).Wait(); throw; } }); await Assert.ThrowsAsync <Exception>(async() => await middleware.Invoke(httpContextMock.Object, rollbar)); rollbarClientMock.Verify(m => m.Send(It.IsAny <Payloads.Payload>()), Times.Once()); httpContextMock.Verify(m => m.Features.Set(It.Is <IRollbarResponseFeature>(f => f.Uuid == "test"))); }
public async Task WhenAnUnexpectedExceptionIsRaised_AnExceptionErrorWillBeReturned_WithInternalServerErrorHttpStatus() { // Arrange var thrownException = new Exception("Exception with a parameter: {Param1}"); ExceptionError expectedResponse = new ExceptionError(System.Net.HttpStatusCode.InternalServerError, thrownException, string.Empty); var middleware = new ExceptionHandlerMiddleware((innerHttpContext) => { throw thrownException; }, _logger); var context = new DefaultHttpContext(); context.Response.Body = new MemoryStream(); //Act await middleware.Invoke(context); context.Response.Body.Seek(0, SeekOrigin.Begin); var reader = new StreamReader(context.Response.Body); var streamText = reader.ReadToEnd(); var actualResponse = JsonConvert.DeserializeObject <ExceptionError>(streamText); //Assert Assert.Equal(expectedResponse.StatusCode, actualResponse.StatusCode); Assert.Equal(expectedResponse.StatusCode, context.Response.StatusCode); Assert.Equal(expectedResponse.StatusMessage, actualResponse.StatusMessage); Assert.Equal(expectedResponse.ErrorMessage, actualResponse.ErrorMessage); }
public async Task InvokeAsyncThrowsExceptionTest() { var problemDetailsFactory = SetupProblemDetailsFactory(); var expectedProblemDetails = problemDetailsFactory.InternalServerError(); var expectedSerializedProblemDetails = JsonSerializer.Serialize(expectedProblemDetails); var expectedProblemDetailsBytes = Encoding.UTF8.GetBytes(expectedSerializedProblemDetails); var expectedArgumentException = new ArgumentException("Test Message"); var headers = SetupHeaders(); var mockLogger = new Mock <ILogger <ExceptionHandlerMiddleware> >(); var mockHttpRequest = mockLogger.SetupHttpRequest(); var mockHttpResponse = SetupHttpResponse(mockLogger, headers, expectedProblemDetailsBytes); var mockConnectionInfo = mockLogger.SetupConnectionInfo(); var mockHttpContext = mockLogger.SetupHttpContext(mockHttpRequest, mockHttpResponse, mockConnectionInfo); var mockRequestDelegate = SetupRequestDelegate(mockHttpContext, expectedArgumentException); var middleware = new ExceptionHandlerMiddleware(mockRequestDelegate.Object, mockLogger.Object, problemDetailsFactory); await middleware.InvokeAsync(mockHttpContext.Object); VerifyRequestDelegate(mockHttpContext, mockRequestDelegate); AssertHeaders(headers); VerifyContext(mockHttpContext); VerifyHttpResponse(mockHttpResponse, expectedProblemDetailsBytes); VerifyLogs(mockLogger, expectedSerializedProblemDetails, expectedArgumentException); mockLogger.VerifyBeginScope("Internal Server Error"); mockLogger.VerifyLogResponse(); }
public async Task ExceptionHandler_returns_ExceptionResultMessage() { // Arrange var expectedException = new Exception("Any exception..."); var logger = new Mock <ILogger <ExceptionHandlerMiddleware> >(); var exceptionHandler = new ExceptionHandlerMiddleware( (innerHttpContext) => { throw expectedException; }, logger.Object ); var context = GetContext(); // Act await exceptionHandler.Invoke(context); var resultMessage = GetResultMessage(context); // Assert Assert.NotNull(resultMessage); Assert.NotEqual(Guid.Empty, resultMessage.ErrorId); Assert.Equal( "An error occurred and your message couldn't be processed. If the error persists, contact the admin informing the error id provided.", resultMessage.Message ); }
public async Task WhenAnApiBaseExceptionIsRaised_AExceptionErrorWillBeReturned_WithAProvidedHttpStatus() { // Arrange ApiBaseException thrownException = new ApiBaseException(System.Net.HttpStatusCode.GatewayTimeout, "A Test Exception"); ExceptionError expectedResponse = new ExceptionError(System.Net.HttpStatusCode.GatewayTimeout, thrownException, string.Empty); var middleware = new ExceptionHandlerMiddleware((innerHttpContext) => { throw thrownException; }, _logger); var context = new DefaultHttpContext(); context.Response.Body = new MemoryStream(); //Act await middleware.Invoke(context); context.Response.Body.Seek(0, SeekOrigin.Begin); var reader = new StreamReader(context.Response.Body); var streamText = reader.ReadToEnd(); var actualResponse = JsonConvert.DeserializeObject <ExceptionError>(streamText); //Assert Assert.Equal(expectedResponse.StatusCode, actualResponse.StatusCode); Assert.Equal(expectedResponse.StatusCode, context.Response.StatusCode); Assert.Equal(expectedResponse.StatusMessage, actualResponse.StatusMessage); Assert.Equal(expectedResponse.ErrorMessage, actualResponse.ErrorMessage); }
public async Task InvokeAsync_ThrowsExceptionWhenNextIsNotSet() { ExceptionHandlerMiddleware middleware = new ExceptionHandlerMiddleware(); var context = this.GetContext(); var exception = await ShouldThrowAsyncExtensions.ShouldThrowAsync <MiddlewarePipelineException>(() => middleware.InvokeAsync(context)); exception.Message.ShouldContain("must have a Next middleware"); }
public async Task InvokeAsync_NoExceptionFromNextMiddleware() { ExceptionHandlerMiddleware middleware = new ExceptionHandlerMiddleware() { Next = new DummyMiddleware() }; var context = this.GetContext(); await middleware.InvokeAsync(context); context.Response.StatusCode.ShouldBe(202); }
public async Task WhenAModelStateValidationExceptionIsRaised_AValidationErrorWillBeReturned_WithBadRequestHttpStatus() { // Arrange var requestDTO = new RequestModelBasic() { Id = 0, Message = string.Empty, CreatedOn = DateTime.Now }; // Perform a validation using ModelState var modelState = new ModelStateDictionary(); modelState.AddModelError("Error_1", "Input string '1.3' is not a valid integer. Path 'userId', line 2, position 17."); modelState["Error_1"].RawValue = "1.3"; modelState.AddModelError("Error_2", "Could not convert string to DateTime: 2018:10. Path 'momentsDate', line 4, position 28."); ValidationException thrownException = new ValidationException("bad_request", modelState, string.Empty); ValidationError expectedResponse = new ValidationError(thrownException.ValidationFailures, string.Empty); var middleware = new ExceptionHandlerMiddleware((innerHttpContext) => { throw thrownException; }, _logger); var context = new DefaultHttpContext(); context.Response.Body = new MemoryStream(); //Act await middleware.Invoke(context); context.Response.Body.Seek(0, SeekOrigin.Begin); var reader = new StreamReader(context.Response.Body); var streamText = reader.ReadToEnd(); var actualResponse = JsonConvert.DeserializeObject <ValidationError>(streamText); //Assert Assert.Equal(expectedResponse.StatusCode, actualResponse.StatusCode); Assert.Equal(expectedResponse.StatusCode, context.Response.StatusCode); Assert.Equal(expectedResponse.StatusMessage, actualResponse.StatusMessage); Assert.NotNull(actualResponse.Errors); Assert.Equal(expectedResponse.Errors.Count, actualResponse.Errors.Count); for (int i = 0; i < actualResponse.Errors.Count; i++) { Assert.Equal(expectedResponse.Errors[i].Code, actualResponse.Errors[i].Code); Assert.Equal(expectedResponse.Errors[i].Message, actualResponse.Errors[i].Message); Assert.Equal(expectedResponse.Errors[i].AttemptedValue, actualResponse.Errors[i].AttemptedValue); Assert.Equal(expectedResponse.Errors[i].Field, actualResponse.Errors[i].Field); } }
private ExceptionHandlerMiddleware CreateMiddleware( RequestDelegate next, IOptions <ExceptionHandlerOptions> options) { next ??= c => Task.CompletedTask; var listener = new DiagnosticListener("Microsoft.AspNetCore"); var middleware = new ExceptionHandlerMiddleware( next, NullLoggerFactory.Instance, options, listener); return(middleware); }
public async Task WhenAFluentValidationExceptionIsRaised_AValidationErrorWillBeReturned_WithBadRequestHttpStatus() { // Arrange var requestDTO = new RequestModelBasic() { Id = 0, Message = string.Empty, CreatedOn = DateTime.Now }; // Perform a validation using a FluentValidator var validator = new RequestModelBasicValidator(); FluentValidation.Results.ValidationResult validationResult = validator.Validate(requestDTO); ValidationException thrownException = new ValidationException(validationResult.Errors, string.Empty); ValidationError expectedResponse = new ValidationError(validationResult.Errors, string.Empty); var middleware = new ExceptionHandlerMiddleware((innerHttpContext) => { throw thrownException; }, _logger); var context = new DefaultHttpContext(); context.Response.Body = new MemoryStream(); //Act await middleware.Invoke(context); context.Response.Body.Seek(0, SeekOrigin.Begin); var reader = new StreamReader(context.Response.Body); var streamText = reader.ReadToEnd(); var actualResponse = JsonConvert.DeserializeObject <ValidationError>(streamText); //Assert Assert.Equal(expectedResponse.StatusCode, actualResponse.StatusCode); Assert.Equal(expectedResponse.StatusCode, context.Response.StatusCode); Assert.Equal(expectedResponse.StatusMessage, actualResponse.StatusMessage); Assert.NotNull(actualResponse.Errors); Assert.Equal(expectedResponse.Errors.Count, actualResponse.Errors.Count); for (int i = 0; i < actualResponse.Errors.Count; i++) { Assert.Equal(expectedResponse.Errors[i].Code, actualResponse.Errors[i].Code); Assert.Equal(expectedResponse.Errors[i].Message, actualResponse.Errors[i].Message); Assert.Equal(expectedResponse.Errors[i].AttemptedValue.ToString(), actualResponse.Errors[i].AttemptedValue.ToString()); Assert.Equal(expectedResponse.Errors[i].Field, actualResponse.Errors[i].Field); } }
public void SetUp() { var serviceCollection = new ServiceCollection(); var config = new ConfigurationRoot(new List <IConfigurationProvider>()); var builder = new OcelotBuilder(serviceCollection, config); var services = serviceCollection.BuildServiceProvider(); var loggerFactory = services.GetService <IOcelotLoggerFactory>(); var configRepo = services.GetService <IInternalConfigurationRepository>(); var repo = services.GetService <IRequestScopedDataRepository>(); _next = async context => { await Task.CompletedTask; throw new Exception("BOOM"); }; _middleware = new ExceptionHandlerMiddleware(_next, loggerFactory, configRepo, repo); _downstreamContext = new DownstreamContext(new DefaultHttpContext()); }
public async Task InvokeAsyncSuccessTest() { var mockHttpContext = new Mock <HttpContext>(); var mockRequestDelegate = new Mock <RequestDelegate>(); mockRequestDelegate.Setup(requestDelegate => requestDelegate.Invoke(mockHttpContext.Object)); var mockLogger = new Mock <ILogger <ExceptionHandlerMiddleware> >(); var middleware = new ExceptionHandlerMiddleware(mockRequestDelegate.Object, mockLogger.Object, null); await middleware.InvokeAsync(mockHttpContext.Object); mockRequestDelegate.Verify(requestDelegate => requestDelegate.Invoke(mockHttpContext.Object), Times.Once); // If an exception was thrown, then this test will fail with null references as the required objects were not setup. // We could setup additional mocks to verify the methods weren't called. // However, due to complications with extension methods, as detailed in the throws exception case below, // I am fine with leaving this scenario simple with the null reference exceptions. }
public async Task WhenAnUnExpectedExceptionIsRaised_CustomExceptionMiddlewareShouldHandleItToInternalServerErrorHttpStatus() { // Arrange var middleware = new ExceptionHandlerMiddleware(next: (innerHttpContext) => { throw new Exception(); }); var context = new DefaultHttpContext(); context.Response.Body = new MemoryStream(); //Act await middleware.Invoke(context, _fixture.CurrentEnvironment); //Assert context.Response.StatusCode.ShouldBe((int)HttpStatusCode.InternalServerError); }
static async Task Awaited(ExceptionHandlerMiddleware middleware, HttpContext context, Task task) { ExceptionDispatchInfo?edi = null; try { await task; } catch (Exception exception) { // Get the Exception, but don't continue processing in the catch block as its bad for stack usage. edi = ExceptionDispatchInfo.Capture(exception); } if (edi != null) { await middleware.HandleException(context, edi); } }
public async Task InvokeAsync_CallLogExceptionAsync() { Exception loggedException = null; ExceptionHandlerMiddleware middleware = new ExceptionHandlerMiddleware() { Next = new FaultyMiddleware(), LogExceptionAsync = (Exception e) => { loggedException = e; return(Task.CompletedTask); } }; var context = this.GetContext(); await middleware.InvokeAsync(context); var typedLoggedException = loggedException.ShouldBeOfType <ApplicationException>(); typedLoggedException.Message.ShouldBe("oh no!"); }
public async Task WhenUnauthorizedExceptionIsRaised_ExceptionHandlerMiddlewareShouldHandleItToUnauthorizedHttpStatus() { // Arrange var middleware = new ExceptionHandlerMiddleware((innerHttpContext) => { throw new UnauthorizedAccessException(); }); var context = new DefaultHttpContext(); context.Response.Body = new MemoryStream(); //Act await middleware.Invoke(context, _fixture.CurrentEnvironment); context.Response.Body.Seek(0, SeekOrigin.Begin); //Assert context.Response.StatusCode.ShouldBe((int)HttpStatusCode.Unauthorized); }
public async Task InvokeAsync_NoExceptionHandler() { ExceptionHandlerMiddleware middleware = new ExceptionHandlerMiddleware() { Next = new FaultyMiddleware() }; var context = this.GetContext(); await middleware.InvokeAsync(context); context.Response.StatusCode.ShouldBe(500); context.Response.Body.Position = 0; var contents = context.Response.Body.ReadAsString(); var response = JsonConvert.DeserializeObject <ErrorResponse>(contents); response.ShouldNotBeNull(); response.CorrelationId.ShouldNotBeNullOrWhiteSpace(); response.Error.ShouldNotBeNull(); response.Error.Code.ShouldBe("INTERNAL_SERVER_ERROR"); response.Error.Message.ShouldBe("An internal server error occurred"); }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app) { app.UseExceptionHandler(ExceptionHandlerMiddleware.ExceptionHandler()); app.UseRouting(); app.UseCors(); app.UseAuthentication(); app.UseAuthorization(); app.UseMiddleware <RequestResponseLoggingMiddleware>(); app.UseSwagger(); app.UseSwaggerUI(new CustomSwaggerUIOptions()); app.UseEndpoints(endpointRouterBuilder => endpointRouterBuilder.MapControllers()); }
public ExceptionHandlerMiddlewareTests() { _configRepo = new Mock <IInternalConfigurationRepository>(); _repo = new Mock <IRequestScopedDataRepository>(); _downstreamContext = new DownstreamContext(new DefaultHttpContext()); _loggerFactory = new Mock <IOcelotLoggerFactory>(); _logger = new Mock <IOcelotLogger>(); _loggerFactory.Setup(x => x.CreateLogger <ExceptionHandlerMiddleware>()).Returns(_logger.Object); _next = async context => { await Task.CompletedTask; if (_shouldThrowAnException) { throw new Exception("BOOM"); } context.HttpContext.Response.StatusCode = (int)HttpStatusCode.OK; }; _middleware = new ExceptionHandlerMiddleware(_next, _loggerFactory.Object, _configRepo.Object, _repo.Object); }
public async Task InvokeAsync_DefaultExceptionHandler_BadRequest() { ExceptionHandlerMiddleware middleware = new ExceptionHandlerMiddleware() { Next = new BadRequestMiddleware(), ExceptionHandler = ExceptionHandlerMiddleware.DefaultExceptionHandler }; var context = this.GetContext(); await middleware.InvokeAsync(context); context.Response.StatusCode.ShouldBe(400); context.Response.Body.Position = 0; var contents = context.Response.Body.ReadAsString(); var response = JsonConvert.DeserializeObject <ErrorResponse>(contents); response.ShouldNotBeNull(); response.CorrelationId.ShouldNotBeNullOrWhiteSpace(); response.Error.ShouldNotBeNull(); response.Error.Code.ShouldBe("BAD_REQUEST"); response.Error.Message.ShouldBe("oh no!"); }
public async Task ExceptionHandlerMiddleware_CatchException() { // Arrange var exHandler = new Mock <IExceptionHandler>(); int expectedStatusCode = 500; string expectedResponseContent = "test"; exHandler.Setup(x => x.CreateResponseContent()).Returns(expectedResponseContent); exHandler.Setup(x => x.GetHttpStatusCode()).Returns(expectedStatusCode); var exHandlerFactory = new Mock <IExceptionHandlerFactory>(); Exception ex = new Exception(); exHandlerFactory.Setup(x => x.GetExceptionHandler(ex)).Returns(exHandler.Object); var middleware = new ExceptionHandlerMiddleware(exHandlerFactory.Object, (innerHttpContext) => { throw ex; }); var context = new DefaultHttpContext(); context.Response.Body = new MemoryStream(); // Act await middleware.Invoke(context); // Assert context.Response.Body.Seek(0, SeekOrigin.Begin); var reader = new StreamReader(context.Response.Body); var responseContent = reader.ReadToEnd(); responseContent.Should().BeEquivalentTo(expectedResponseContent); context.Response.StatusCode.Should().Be(expectedStatusCode); }
public ExceptionHandlerMiddlewareTests() { _next = A.Fake <RequestDelegate>(); _executor = A.Fake <IActionResultExecutor <ObjectResult> >(); _middleware = new ExceptionHandlerMiddleware(_next, _executor, A.Fake <ILogger <ExceptionHandlerMiddleware> >()); }
public ExceptionHandlerMiddlewareTest() { _next = new Mock <RequestDelegate>(); _exceptionMiddleware = new ExceptionHandlerMiddleware(_next.Object); }