public static void UseErikTheCoderExceptionHandling(this IApplicationBuilder ApplicationBuilder, Action <ExceptionHandlingOptions> ConfigureOptions = null) { var options = new ExceptionHandlingOptions(); ConfigureOptions?.Invoke(options); ExceptionHandlingMiddleware.Enable(ApplicationBuilder, options); }
/// <summary> /// Handles exceptions based upon the indicated behavior and rethrows the Exception /// </summary> /// <param name="exception"></param> /// <param name="exceptionBehavior"></param> /// <param name="log"></param> /// <param name="msg"></param> /// <param name="parameters"></param> public static void Handle(this Exception exception, ExceptionHandlingOptions exceptionBehavior, ILogWrapper log = null, string msg = "", params object[] parameters) { var caller = GetCaller(); if (exceptionBehavior == ExceptionHandlingOptions.RecordOnly || exceptionBehavior == ExceptionHandlingOptions.RecordAndThrow) { ILogWrapper logger = log ?? new LogWrapper(LogManager.GetLogger(caller), LogLevel.Error); if (string.IsNullOrEmpty(msg)) { logger.Error(exception); } else { logger.Error(String.Format(msg, parameters), exception); } } if (exceptionBehavior == ExceptionHandlingOptions.RecordAndThrow || exceptionBehavior == ExceptionHandlingOptions.ThrowOnly) { throw exception; } }
public static void Enable(IApplicationBuilder ApplicationBuilder, ExceptionHandlingOptions Options) { ApplicationBuilder.UseExceptionHandler(AlternatePipeline => { // Run terminates the middleware pipeline. AlternatePipeline.Run(async Context => { var logger = ApplicationBuilder.ApplicationServices.GetRequiredService <ILogger>(); try { await HandleException(Context, Options, logger); } catch (Exception exception) { logger?.Log(Context.GetCorrelationId(), $"Exception occurred in {nameof(ExceptionHandlingMiddleware)}. {exception.GetSummary(true, true)}"); throw; } }); }); }
public void HandleTest(ExceptionHandlingOptions options, string msg, bool throwLoggingException) { var logger = A.Fake <ILogWrapper>(); if (throwLoggingException) { A.CallTo(() => logger.Error(A <object> .Ignored, A <Exception> .Ignored)) .Throws(new InvalidOperationException("Unit test should not get an exception of this type")); } else { A.CallTo(() => logger.Error(A <object> .Ignored, A <Exception> .Ignored)); } try { throw new Exception(msg); } catch (Exception ex) { ex.Handle(options, logger, msg); } }
/// <summary> /// Handles exceptions based upon the indicated behavior and throws a new exception of the given /// type, assigning the original exception as the InnerException /// </summary> public static void Handle <T>(this Exception exception, ExceptionHandlingOptions exceptionBehavior, ILogWrapper log = null, string msg = "", params object[] parameters) where T : Exception { var caller = GetCaller(); if (exceptionBehavior == ExceptionHandlingOptions.RecordOnly || exceptionBehavior == ExceptionHandlingOptions.RecordAndThrow) { ILogWrapper logger = log ?? new LogWrapper(LogManager.GetLogger(caller), LogLevel.Error); if (string.IsNullOrEmpty(msg)) { logger.Error(exception); } else { logger.Error(String.Format(msg, parameters), exception); } } if (exceptionBehavior == ExceptionHandlingOptions.RecordAndThrow || exceptionBehavior == ExceptionHandlingOptions.ThrowOnly) { throw (T)Activator.CreateInstance(typeof(T), string.Format("Exception occurred in {0}", caller), exception); } }
protected virtual RemoteServiceErrorInfo CreateErrorInfoWithoutCode(Exception exception, ExceptionHandlingOptions options) { if (options.SendExceptionsDetailsToClients) { return(CreateDetailedErrorInfoFromException(exception, options.SendStackTraceToClients)); } exception = TryToGetActualException(exception); if (exception is RemoteCallException remoteCallException && remoteCallException.Error != null) { return(remoteCallException.Error); } if (exception is DbConcurrencyException) { return(new RemoteServiceErrorInfo(L["DbConcurrencyErrorMessage"])); } if (exception is EntityNotFoundException) { return(CreateEntityNotFoundError(exception as EntityNotFoundException)); } var errorInfo = new RemoteServiceErrorInfo(); if (exception is UserFriendlyException || exception is RemoteCallException) { errorInfo.Message = exception.Message; errorInfo.Details = (exception as IHasErrorDetails)?.Details; } if (exception is IHasValidationErrors) { if (errorInfo.Message.IsNullOrEmpty()) { errorInfo.Message = L["ValidationErrorMessage"]; } if (errorInfo.Details.IsNullOrEmpty()) { errorInfo.Details = GetValidationErrorNarrative(exception as IHasValidationErrors); } errorInfo.ValidationErrors = GetValidationErrorInfos(exception as IHasValidationErrors); } TryToLocalizeExceptionMessage(exception, errorInfo); if (errorInfo.Message.IsNullOrEmpty()) { errorInfo.Message = L["InternalServerErrorMessage"]; } errorInfo.Data = exception.Data; return(errorInfo); }
public async Task Index_Test() { using (var loggerFactory = new NullLoggerFactory()) { var exceptionHandlingOptions = new ExceptionHandlingOptions(); var errorController = await this.CreateErrorControllerAsync(exceptionHandlingOptions, loggerFactory); var actionResult = await errorController.Index(); var objectResult = (ObjectResult)actionResult; var problemDetails = (ProblemDetails)objectResult.Value; Assert.IsNotNull(problemDetails); Assert.IsNull(problemDetails.Detail); Assert.AreEqual("Error", problemDetails.Title); exceptionHandlingOptions = new ExceptionHandlingOptions { Detailed = true }; errorController = await this.CreateErrorControllerAsync(exceptionHandlingOptions, loggerFactory); actionResult = await errorController.Index(); objectResult = (ObjectResult)actionResult; problemDetails = (ProblemDetails)objectResult.Value; Assert.IsNotNull(problemDetails); Assert.IsNull(problemDetails.Detail); Assert.AreEqual("Error", problemDetails.Title); exceptionHandlingOptions = new ExceptionHandlingOptions(); errorController = await this.CreateErrorControllerAsync(exceptionHandlingOptions, loggerFactory, new InvalidOperationException("Test-exception")); actionResult = await errorController.Index(); objectResult = (ObjectResult)actionResult; problemDetails = (ProblemDetails)objectResult.Value; Assert.IsNotNull(problemDetails); Assert.IsNull(problemDetails.Detail); Assert.AreEqual("Error", problemDetails.Title); exceptionHandlingOptions = new ExceptionHandlingOptions { Detailed = true }; errorController = await this.CreateErrorControllerAsync(exceptionHandlingOptions, loggerFactory, new InvalidOperationException("Test-exception")); actionResult = await errorController.Index(); objectResult = (ObjectResult)actionResult; problemDetails = (ProblemDetails)objectResult.Value; Assert.IsNotNull(problemDetails); Assert.AreEqual("System.InvalidOperationException: Test-exception", problemDetails.Detail); Assert.AreEqual("Error", problemDetails.Title); exceptionHandlingOptions = new ExceptionHandlingOptions(); errorController = await this.CreateErrorControllerAsync(exceptionHandlingOptions, loggerFactory, new ServiceException("Test-exception")); actionResult = await errorController.Index(); objectResult = (ObjectResult)actionResult; problemDetails = (ProblemDetails)objectResult.Value; Assert.IsNotNull(problemDetails); Assert.IsNull(problemDetails.Detail); Assert.AreEqual("Test-exception", problemDetails.Title); exceptionHandlingOptions = new ExceptionHandlingOptions { Detailed = true }; errorController = await this.CreateErrorControllerAsync(exceptionHandlingOptions, loggerFactory, new ServiceException("Test-exception")); actionResult = await errorController.Index(); objectResult = (ObjectResult)actionResult; problemDetails = (ProblemDetails)objectResult.Value; Assert.IsNotNull(problemDetails); Assert.AreEqual("HansKindberg.RoleService.Models.ServiceException: Test-exception", problemDetails.Detail); Assert.AreEqual("Test-exception", problemDetails.Title); } }
protected internal virtual async Task <IOptionsMonitor <ExceptionHandlingOptions> > CreateExceptionHandlingOptionsMonitorAsync(ExceptionHandlingOptions exceptionHandlingOptions) { var exceptionHandlingOptionsMonitorMock = new Mock <IOptionsMonitor <ExceptionHandlingOptions> >(); exceptionHandlingOptionsMonitorMock.Setup(exceptionHandlingOptionsMonitor => exceptionHandlingOptionsMonitor.CurrentValue).Returns(exceptionHandlingOptions); return(await Task.FromResult(exceptionHandlingOptionsMonitorMock.Object)); }
protected internal virtual async Task <ErrorController> CreateErrorControllerAsync(ExceptionHandlingOptions exceptionHandlingOptions, ILoggerFactory loggerFactory, Exception exception = null) { return(await this.CreateErrorControllerAsync(exceptionHandlingOptions, await this.CreateExceptionHandlerFeatureAsync(exception), loggerFactory)); }
protected internal virtual async Task <ErrorController> CreateErrorControllerAsync(ExceptionHandlingOptions exceptionHandlingOptions, IExceptionHandlerFeature exceptionHandlerFeature, ILoggerFactory loggerFactory) { var features = new FeatureCollection(); features.Set(exceptionHandlerFeature); return(await this.CreateErrorControllerAsync(exceptionHandlingOptions, new DefaultHttpContext(features), loggerFactory)); }
protected internal virtual async Task <ErrorController> CreateErrorControllerAsync(ExceptionHandlingOptions exceptionHandlingOptions, HttpContext httpContext, ILoggerFactory loggerFactory) { var exceptionHandlingOptionsMonitorMock = new Mock <IOptionsMonitor <ExceptionHandlingOptions> >(); exceptionHandlingOptionsMonitorMock.Setup(exceptionHandlingOptionsMonitor => exceptionHandlingOptionsMonitor.CurrentValue).Returns(exceptionHandlingOptions); var errorController = new ErrorController(loggerFactory, await this.CreateExceptionHandlingOptionsMonitorAsync(exceptionHandlingOptions)) { ControllerContext = new ControllerContext() { HttpContext = httpContext } }; return(await Task.FromResult(errorController)); }
private static async Task HandleException(HttpContext Context, ExceptionHandlingOptions Options, ILogger Logger) { if (Options.ResponseHandler != null) { if (Options.ExceptionResponseFormat.HasValue || Options.IncludeDetails) { throw new ArgumentException($"If setting an {nameof(Options.ResponseHandler)}, do not set an {nameof(Options.ExceptionResponseFormat)} or set {nameof(Options.IncludeDetails)} to true."); } } // Get correlation ID. var correlationId = Context.GetCorrelationId(); // Get exception. var exceptionHandlerFeature = Context.Features.Get <IExceptionHandlerFeature>(); SimpleException innerException; if (exceptionHandlerFeature.Error is ApiException apiException) { // Exception occurred when a Refit proxy called a service method. // Deserialize exception from JSON response. try { var refitException = await apiException.GetContentAsAsync <SimpleException>() ?? new SimpleException(apiException, correlationId, Options.AppName, Options.ProcessName); innerException = new SimpleException(refitException, correlationId, Options.AppName, Options.ProcessName, "An exception occurred when a Refit proxy called a service method."); } catch { // Ignore exception when deserializing JSON response. innerException = new SimpleException(apiException, correlationId, Options.AppName, Options.ProcessName); innerException = new SimpleException(innerException, correlationId, Options.AppName, Options.ProcessName, $"Failed to deserialize exception from service method response. Ensure the service's {nameof(ExceptionHandlingMiddleware)} is configured to use {nameof(ExceptionResponseFormat)}.{nameof(ExceptionResponseFormat.Json)}."); } } else { innerException = new SimpleException(exceptionHandlerFeature.Error, correlationId, Options.AppName, Options.ProcessName); } // Log exception. var exception = new SimpleException(innerException, correlationId, Options.AppName, Options.ProcessName, $"{Context.Request.Method} with {Context.Request.ContentType ?? "unknown"} content type to {Context.Request.Path} resulted in HTTP status code {Context.Response.StatusCode}."); Logger.Log(correlationId, exception); Logger.LogMetric(correlationId, Context.Request.Path, "Critical Error", 1); // Respond to caller. if (Options.ResponseHandler != null) { // Respond with customer handler. Options.ResponseHandler(Context, exception); return; } // Respond with HTML or JSON. // ReSharper disable once SwitchStatementMissingSomeCases switch (Options.ExceptionResponseFormat) { case ExceptionResponseFormat.Html: await RespondWithHtml(Context, exception, Options.IncludeDetails); break; case ExceptionResponseFormat.Json: await RespondWithJson(Context, exception, Options.IncludeDetails); break; default: throw new Exception($"{nameof(ExceptionResponseFormat)} {Options.ExceptionResponseFormat} not supported."); } }
public static void Enable(IApplicationBuilder ApplicationBuilder, ExceptionHandlingOptions Options) { if (Options.ResponseHandler != null) { if (Options.ExceptionResponseFormat.HasValue || Options.IncludeDetails) { throw new ArgumentException($"If setting an {nameof(Options.ResponseHandler)}, do not set an {nameof(Options.ExceptionResponseFormat)} or set {nameof(Options.IncludeDetails)} to true."); } } ApplicationBuilder.UseExceptionHandler(AlternatePipeline => { // Run terminates the middleware pipeline. AlternatePipeline.Run(async HttpContext => { // Get correlation ID. Guid correlationId = HttpContext.GetCorrelationId(); // Get exception. IExceptionHandlerFeature exceptionHandlerFeature = HttpContext.Features.Get <IExceptionHandlerFeature>(); SimpleException innerException; if (exceptionHandlerFeature.Error is ApiException apiException) { // Exception occurred when a Refit proxy called a service method. // Deserialize exception from JSON response. try { SimpleException refitException = apiException.GetContentAs <SimpleException>() ?? new SimpleException(apiException, correlationId, Options.AppName, Options.ProcessName); innerException = new SimpleException(refitException, correlationId, Options.AppName, Options.ProcessName, "An exception occurred when a Refit proxy called a service method."); } catch { // Ignore exception when deserializing JSON response. innerException = new SimpleException(apiException, correlationId, Options.AppName, Options.ProcessName); innerException = new SimpleException(innerException, correlationId, Options.AppName, Options.ProcessName, $"Failed to deserialize exception from service method response. Ensure the service's {nameof(ExceptionHandlingMiddleware)} is configured to use {nameof(ExceptionResponseFormat)}.{nameof(ExceptionResponseFormat.Json)}."); } } else { innerException = new SimpleException(exceptionHandlerFeature.Error, correlationId, Options.AppName, Options.ProcessName); } // Log exception. SimpleException exception = new SimpleException(innerException, correlationId, Options.AppName, Options.ProcessName, $"{HttpContext.Request.Method} with {HttpContext.Request.ContentType ?? "unknown"} content type to {HttpContext.Request.Path} resulted in HTTP status code {HttpContext.Response.StatusCode}."); ILogger logger = ApplicationBuilder.ApplicationServices.GetRequiredService <ILogger>(); logger.Log(correlationId, exception); logger.LogMetric(correlationId, HttpContext.Request.Path, "Critical Error", 1); // Respond to caller. if (Options.ResponseHandler != null) { // Respond with customer handler. Options.ResponseHandler(HttpContext, exception); return; } // Respond with HTML or JSON. // ReSharper disable once SwitchStatementMissingSomeCases switch (Options.ExceptionResponseFormat) { case ExceptionResponseFormat.Html: await RespondWithHtml(HttpContext, exception, Options.IncludeDetails); break; case ExceptionResponseFormat.Json: await RespondWithJson(HttpContext, exception, Options.IncludeDetails); break; default: throw new Exception($"{nameof(ExceptionResponseFormat)} {Options.ExceptionResponseFormat} not supported."); } }); }); }