Пример #1
0
        public async Task Invoke(HttpContext context)
        {
            try {
                await _next(context);
            }
            catch (Exception exception) {
                if (context.Response.HasStarted)
                {
                    throw new Exception($"An exception was caught after the response started.", exception);
                }

                HttpException error;

                if (exception is HttpException)
                {
                    error = exception as HttpException;
                }
                else
                {
                    error = new HttpInternalServerError(exception);
                }

                context.Response.Clear();

                context.Response.StatusCode = error.StatusCode;
                context.Response.Headers.Clear();

                context.Response.ContentType = error.ContentType;

                await context.Response.WriteAsync(exception.ToString());

                return;
            }
        }
Пример #2
0
        /// <summary>
        /// Sets up a custom exception handler in the application's pipeline.
        /// </summary>
        /// <param name="app">A class which allows configuration of the application's request pipeline.</param>
        protected void SetupExceptionHandler(IApplicationBuilder app)
        {
            // As per https://docs.microsoft.com/en-us/aspnet/core/fundamentals/error-handling?view=aspnetcore-5.0#exception-handler-lambda
            app.UseExceptionHandler(errorApp =>
            {
                var exceptionToHttpStatusCodeConverter          = (ExceptionToHttpStatusCodeConverter)app.ApplicationServices.GetService(typeof(ExceptionToHttpStatusCodeConverter));
                var exceptionToHttpInternalServerErrorConverter = (ExceptionToHttpInternalServerErrorConverter)app.ApplicationServices.GetService(typeof(ExceptionToHttpInternalServerErrorConverter));

                errorApp.Run(async context =>
                {
                    // Get the exception
                    var exceptionHandlerPathFeature = context.Features.Get <IExceptionHandlerPathFeature>();
                    Exception exception             = exceptionHandlerPathFeature.Error;

                    if (exception != null)
                    {
                        context.Response.ContentType = jsonHttpContentType;
                        context.Response.StatusCode  = (Int32)exceptionToHttpStatusCodeConverter.Convert(exception);
                        HttpInternalServerError httpInternalServerError = exceptionToHttpInternalServerErrorConverter.Convert(exception);
                        var serializer = new HttpInternalServerErrorJsonSerializer();
                        await context.Response.WriteAsync(serializer.Serialize(httpInternalServerError).ToString());
                    }
                    else
                    {
                        // Not sure if this situation can arise, but will leave this handler in while testing
                        throw new Exception("'exceptionHandlerPathFeature.Error' was null whilst handling exception.");
                    }
                });
            });
        }
Пример #3
0
        public void Convert_ArgumentException()
        {
            Exception testException = null;

            try
            {
                throw new ArgumentException("Test argument exception message.", "TestArgumentName");
            }
            catch (Exception e)
            {
                testException = e;
            }

            HttpInternalServerError result = testExceptionToHttpInternalServerErrorConverter.Convert(testException);

            Assert.AreEqual("ArgumentException", result.Code);
            Assert.AreEqual("Test argument exception message. (Parameter 'TestArgumentName')", result.Message);
            Assert.AreEqual("Convert_ArgumentException", result.Target);
            Assert.AreEqual(1, result.Attributes.Count());
            var attributes = new List <Tuple <String, String> >(result.Attributes);

            Assert.AreEqual("ParameterName", attributes[0].Item1);
            Assert.AreEqual("TestArgumentName", attributes[0].Item2);
            Assert.IsNull(result.InnerError);
        }
Пример #4
0
        public void Serialize_HttpInternalServerErrorWithCodeMessageAndAttributes()
        {
            var serverError = new HttpInternalServerError
                              (
                typeof(ArgumentException).Name,
                "A mapping between user 'user1' and group 'group1' already exists.",
                new List <Tuple <String, String> >()
            {
                new Tuple <String, String>("user", "user1"),
                new Tuple <String, String>("group", "group1")
            }
                              );
            string expectedJsonString = @"
            {
                ""error"" : {
                    ""code"" : ""ArgumentException"", 
                    ""message"" : ""A mapping between user 'user1' and group 'group1' already exists."", 
                    ""attributes"" : 
                    [
                        { ""name"": ""user"", ""value"": ""user1"" }, 
                        { ""name"": ""group"", ""value"": ""group1"" }
                    ]
                }
            }
            ";
            var    expectedJson       = JObject.Parse(expectedJsonString);

            JObject result = testHttpInternalServerErrorJsonSerializer.Serialize(serverError);

            Assert.AreEqual(expectedJson, result);
        }
Пример #5
0
        public void Serialize_HttpInternalServerErrorWithCodeMessageAndInnerError()
        {
            var serverError = new HttpInternalServerError
                              (
                typeof(ArgumentException).Name,
                "A mapping between user 'user1' and group 'group1' already exists.",
                new HttpInternalServerError
                (
                    typeof(ArgumentException).Name,
                    "An edge already exists between vertices 'child' and 'parent'."
                )
                              );
            string expectedJsonString = @"
            {
                ""error"" : {
                    ""code"" : ""ArgumentException"", 
                    ""message"" : ""A mapping between user 'user1' and group 'group1' already exists."", 
                    ""innererror"" : 
                    {
                        ""code"" : ""ArgumentException"", 
                        ""message"" : ""An edge already exists between vertices 'child' and 'parent'."",
                    }
                }
            }
            ";
            var    expectedJson       = JObject.Parse(expectedJsonString);

            JObject result = testHttpInternalServerErrorJsonSerializer.Serialize(serverError);

            Assert.AreEqual(expectedJson, result);
        }
Пример #6
0
        public void Convert_ConversionFunctionDefinedForBaseClass()
        {
            Func <Exception, HttpInternalServerError> derivedExceptionConversionFunction = (Exception exception) =>
            {
                var derivedException = (DerivedException)exception;
                if (exception.TargetSite == null)
                {
                    return(new HttpInternalServerError
                           (
                               exception.GetType().Name,
                               exception.Message,
                               new List <Tuple <String, String> >()
                    {
                        new Tuple <String, String>(nameof(derivedException.NumericProperty), derivedException.NumericProperty.ToString())
                    }
                           ));
                }
                else
                {
                    return(new HttpInternalServerError
                           (
                               exception.GetType().Name,
                               exception.Message,
                               exception.TargetSite.Name,
                               new List <Tuple <String, String> >()
                    {
                        new Tuple <String, String>(nameof(derivedException.NumericProperty), derivedException.NumericProperty.ToString())
                    }
                           ));
                }
            };

            testExceptionToHttpInternalServerErrorConverter.AddConversionFunction(typeof(DerivedException), derivedExceptionConversionFunction);

            Exception testException = null;

            try
            {
                throw new SecondLevelDerivedException("Second level derived exception message.", 456, 'B');
            }
            catch (Exception e)
            {
                testException = e;
            }

            HttpInternalServerError result = testExceptionToHttpInternalServerErrorConverter.Convert(testException);

            Assert.AreEqual("SecondLevelDerivedException", result.Code);
            Assert.AreEqual("Second level derived exception message.", result.Message);
            Assert.AreEqual("Convert_ConversionFunctionDefinedForBaseClass", result.Target);
            Assert.AreEqual(1, result.Attributes.Count());
            var attributes = new List <Tuple <String, String> >(result.Attributes);

            Assert.AreEqual("NumericProperty", attributes[0].Item1);
            Assert.AreEqual("456", attributes[0].Item2);
            Assert.IsNull(result.InnerError);
        }
Пример #7
0
        public void Convert_UnthrownException()
        {
            // Unlikely to encounter this case in the real world, but tests that the 'TargetSite' property of the Exception is not included when null (i.e. when the Exception is just 'newed' rather th than being thrown).
            HttpInternalServerError result = testExceptionToHttpInternalServerErrorConverter.Convert(new Exception("Test exception message."));

            Assert.AreEqual("Exception", result.Code);
            Assert.AreEqual("Test exception message.", result.Message);
            Assert.IsNull(result.Target);
            Assert.AreEqual(0, result.Attributes.Count());
            Assert.IsNull(result.InnerError);
        }
Пример #8
0
        public void Convert_AggregateException()
        {
            var       innerException1 = new Exception("Plain exception inner exception.");
            var       innerException2 = new ArgumentException("Argument exception inner exception.", "ArgumentExceptionParameterName");
            var       innerException3 = new ArgumentNullException("ArgumentNullExceptionParameterName", "Argument null exception inner exception.");
            Exception testException   = null;

            try
            {
                throw new AggregateException
                      (
                          "Test aggreate exception message.",
                          new List <Exception>()
                {
                    innerException1, innerException2, innerException3
                }
                      );
            }
            catch (Exception e)
            {
                testException = e;
            }

            HttpInternalServerError result = testExceptionToHttpInternalServerErrorConverter.Convert(testException);

            Assert.AreEqual("AggregateException", result.Code);
            Assert.AreEqual(testException.Message, result.Message);
            Assert.AreEqual("Convert_AggregateException", result.Target);
            Assert.AreEqual(6, result.Attributes.Count());
            var attributes = new List <Tuple <String, String> >(result.Attributes);

            Assert.AreEqual("InnerException1Code", attributes[0].Item1);
            Assert.AreEqual("Exception", attributes[0].Item2);
            Assert.AreEqual("InnerException1Message", attributes[1].Item1);
            Assert.AreEqual("Plain exception inner exception.", attributes[1].Item2);
            Assert.AreEqual("InnerException2Code", attributes[2].Item1);
            Assert.AreEqual("ArgumentException", attributes[2].Item2);
            Assert.AreEqual("InnerException2Message", attributes[3].Item1);
            Assert.AreEqual("Argument exception inner exception. (Parameter 'ArgumentExceptionParameterName')", attributes[3].Item2);
            Assert.AreEqual("InnerException3Code", attributes[4].Item1);
            Assert.AreEqual("ArgumentNullException", attributes[4].Item2);
            Assert.AreEqual("InnerException3Message", attributes[5].Item1);
            Assert.AreEqual("Argument null exception inner exception. (Parameter 'ArgumentNullExceptionParameterName')", attributes[5].Item2);
            Assert.IsNotNull(result.InnerError);
            Assert.AreEqual("Exception", result.InnerError.Code);
            Assert.AreEqual("Plain exception inner exception.", result.InnerError.Message);
            Assert.AreEqual(0, result.InnerError.Attributes.Count());
            Assert.IsNull(result.InnerError.InnerError);
        }
Пример #9
0
        public void Convert_InnerExceptionStack()
        {
            Exception testException = null;

            try
            {
                try
                {
                    try
                    {
                        throw new IndexOutOfRangeException("Test index out of range exception message.");
                    }
                    catch (Exception e)
                    {
                        throw new ArgumentException("Test argument exception message.", "testParameterName", e);;
                    }
                }
                catch (Exception e)
                {
                    throw new Exception("Outermost exception.", e);;
                }
            }
            catch (Exception e)
            {
                testException = e;
            }

            HttpInternalServerError result = testExceptionToHttpInternalServerErrorConverter.Convert(testException);

            Assert.AreEqual("Exception", result.Code);
            Assert.AreEqual("Outermost exception.", result.Message);
            Assert.AreEqual("Convert_InnerExceptionStack", result.Target);
            Assert.AreEqual(0, result.Attributes.Count());
            Assert.IsNotNull(result.InnerError);
            Assert.AreEqual("ArgumentException", result.InnerError.Code);
            Assert.AreEqual("Test argument exception message. (Parameter 'testParameterName')", result.InnerError.Message);
            Assert.AreEqual("Convert_InnerExceptionStack", result.InnerError.Target);
            Assert.AreEqual(1, result.InnerError.Attributes.Count());
            var attributes = new List <Tuple <String, String> >(result.InnerError.Attributes);

            Assert.AreEqual("ParameterName", attributes[0].Item1);
            Assert.AreEqual("testParameterName", attributes[0].Item2);
            Assert.IsNotNull(result.InnerError.InnerError);
            Assert.AreEqual("IndexOutOfRangeException", result.InnerError.InnerError.Code);
            Assert.AreEqual("Test index out of range exception message.", result.InnerError.InnerError.Message);
            Assert.AreEqual("Convert_InnerExceptionStack", result.InnerError.InnerError.Target);
            Assert.AreEqual(0, result.InnerError.InnerError.Attributes.Count());
            Assert.IsNull(result.InnerError.InnerError.InnerError);
        }
Пример #10
0
        public void AddConversionFunction()
        {
            Func <Exception, HttpInternalServerError> exceptionHandler = (Exception exception) =>
            {
                return(new HttpInternalServerError("CustomCode", "CustomeMessage"));
            };

            testExceptionToHttpInternalServerErrorConverter.AddConversionFunction(typeof(Exception), exceptionHandler);

            HttpInternalServerError result = testExceptionToHttpInternalServerErrorConverter.Convert(new Exception("Fake Exception"));

            Assert.AreEqual("CustomCode", result.Code);
            Assert.AreEqual("CustomeMessage", result.Message);
            Assert.IsNull(result.Target);
            Assert.AreEqual(0, result.Attributes.Count());
            Assert.IsNull(result.InnerError);
        }
Пример #11
0
        public void Serialize_HttpInternalServerErrorWithAllProperties()
        {
            var serverError = new HttpInternalServerError
                              (
                typeof(ArgumentException).Name,
                "Failed to add edge to graph.",
                "graph",
                new List <Tuple <String, String> >()
            {
                new Tuple <String, String>("fromVertex", "child"),
                new Tuple <String, String>("toVertex", "parent")
            },
                new HttpInternalServerError
                (
                    typeof(ArgumentException).Name,
                    "An edge already exists between vertices 'child' and 'parent'."
                )
                              );
            string expectedJsonString = @"
            {
                ""error"" : {
                    ""code"" : ""ArgumentException"", 
                    ""message"" : ""Failed to add edge to graph."", 
                    ""target"" : ""graph"", 
                    ""attributes"" : 
                    [
                        { ""name"": ""fromVertex"", ""value"": ""child"" }, 
                        { ""name"": ""toVertex"", ""value"": ""parent"" }
                    ], 
                    ""innererror"" : 
                    {
                        ""code"" : ""ArgumentException"", 
                        ""message"" : ""An edge already exists between vertices 'child' and 'parent'."",
                    }
                }
            }
            ";
            var    expectedJson       = JObject.Parse(expectedJsonString);

            JObject result = testHttpInternalServerErrorJsonSerializer.Serialize(serverError);

            Assert.AreEqual(expectedJson, result);
        }
Пример #12
0
        public void Convert_NoConversionFunctionDefined()
        {
            Exception testException = null;

            try
            {
                throw new DerivedException("Test derived exception message.", 123);
            }
            catch (Exception e)
            {
                testException = e;
            }

            HttpInternalServerError result = testExceptionToHttpInternalServerErrorConverter.Convert(testException);

            Assert.AreEqual("DerivedException", result.Code);
            Assert.AreEqual("Test derived exception message.", result.Message);
            Assert.AreEqual("Convert_NoConversionFunctionDefined", result.Target);
            Assert.AreEqual(0, result.Attributes.Count());
            Assert.IsNull(result.InnerError);
        }
Пример #13
0
        public void Convert_IndexOutOfRangeException()
        {
            Exception testException = null;

            try
            {
                throw new IndexOutOfRangeException("Test index out of range exception message.");
            }
            catch (Exception e)
            {
                testException = e;
            }

            HttpInternalServerError result = testExceptionToHttpInternalServerErrorConverter.Convert(testException);

            Assert.AreEqual("IndexOutOfRangeException", result.Code);
            Assert.AreEqual("Test index out of range exception message.", result.Message);
            Assert.AreEqual("Convert_IndexOutOfRangeException", result.Target);
            Assert.AreEqual(0, result.Attributes.Count());
            Assert.IsNull(result.InnerError);
        }
Пример #14
0
        public void Serialize_HttpInternalServerErrorWithCodeAndMessage()
        {
            var serverError = new HttpInternalServerError
                              (
                typeof(ArgumentException).Name,
                "Argument 'recordCount' must be greater than or equal to 0."
                              );
            string expectedJsonString = @"
            {
                ""error"" : {
                    ""code"" : ""ArgumentException"", 
                    ""message"" : ""Argument 'recordCount' must be greater than or equal to 0.""
                }
            }
            ";
            var    expectedJson       = JObject.Parse(expectedJsonString);

            JObject result = testHttpInternalServerErrorJsonSerializer.Serialize(serverError);

            Assert.AreEqual(expectedJson, result);
        }
Пример #15
0
        public void Convert_Exception()
        {
            // Need to actually throw the test exception otherwise the 'TargetSite' property is not set.
            Exception testException = null;

            try
            {
                throw new Exception("Test exception message.");
            }
            catch (Exception e)
            {
                testException = e;
            }

            HttpInternalServerError result = testExceptionToHttpInternalServerErrorConverter.Convert(testException);

            Assert.AreEqual("Exception", result.Code);
            Assert.AreEqual("Test exception message.", result.Message);
            Assert.AreEqual("Convert_Exception", result.Target);
            Assert.AreEqual(0, result.Attributes.Count());
            Assert.IsNull(result.InnerError);
        }
Пример #16
0
        public void Convert_GenericException()
        {
            Func <Exception, HttpInternalServerError> genericExceptionConversionFunction = (Exception exception) =>
            {
                var genericException = (GenericException <Int32>)exception;
                if (exception.TargetSite == null)
                {
                    return(new HttpInternalServerError
                           (
                               exception.GetType().Name,
                               exception.Message,
                               new List <Tuple <String, String> >()
                    {
                        new Tuple <String, String>("Int32 Value", genericException.GenericParameter.ToString())
                    }
                           ));
                }
                else
                {
                    return(new HttpInternalServerError
                           (
                               exception.GetType().Name,
                               exception.Message,
                               exception.TargetSite.Name,
                               new List <Tuple <String, String> >()
                    {
                        new Tuple <String, String>("Int32 Value", genericException.GenericParameter.ToString())
                    }
                           ));
                }
            };

            testExceptionToHttpInternalServerErrorConverter.AddConversionFunction(typeof(GenericException <Int32>), genericExceptionConversionFunction);

            Exception testException = null;

            try
            {
                throw new GenericException <Int32>("Test generic string type exception message.", 123);
            }
            catch (Exception e)
            {
                testException = e;
            }

            HttpInternalServerError result = testExceptionToHttpInternalServerErrorConverter.Convert(testException);

            Assert.AreEqual("GenericException`1", result.Code);
            Assert.AreEqual("Test generic string type exception message.", result.Message);
            Assert.AreEqual("Convert_GenericException", result.Target);
            Assert.AreEqual(1, result.Attributes.Count());
            var attributes = new List <Tuple <String, String> >(result.Attributes);

            Assert.AreEqual("Int32 Value", attributes[0].Item1);
            Assert.AreEqual("123", attributes[0].Item2);
            Assert.IsNull(result.InnerError);


            // Test that the conversion function for plain Exceptions is used if the generic type doesn't match
            try
            {
                throw new GenericException <Char>("Test generic char type exception message.", 'A');
            }
            catch (Exception e)
            {
                testException = e;
            }

            result = testExceptionToHttpInternalServerErrorConverter.Convert(testException);

            Assert.AreEqual("GenericException`1", result.Code);
            Assert.AreEqual("Test generic char type exception message.", result.Message);
            Assert.AreEqual("Convert_GenericException", result.Target);
            Assert.AreEqual(0, result.Attributes.Count());
            Assert.IsNull(result.InnerError);
        }