Click here to Skip to main content
15,888,031 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have to perform global error handling for that I have created a custom middle ware
but with error handling I have to log entire request also so in catch block I am logging the request also but in catch block the request body parameter is always blank where as in try block I am able to get the request body object

What I have tried:

C#
public class HTTPStatuseCodeExceptionMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly IErrorLogApplicationService _ErrorLogApplicationService;
        public HTTPStatuseCodeExceptionMiddleware(RequestDelegate next, IErrorLogApplicationService ErrorLogApplicationService)
        {
            _next = next ?? throw new ArgumentNullException(nameof(next));
            _ErrorLogApplicationService = ErrorLogApplicationService;
        }

        public async Task Invoke(HttpContext context)
        {
            try
            {
                string IPAddress = GetIPAddress();
                string Request = FormatRequest(context.Request).Result;
                await _next(context);
            }
            catch (HTTPStatusCodeException ex)
            {
                context.Response.Clear();
                context.Response.StatusCode = ex.StatusCode;
                context.Response.ContentType = ex.ContentType;

                await context.Response.WriteAsync(ex.Message);
               // ErrorLog(context, ex);
                return;
            }
            catch(Exception ex)
            {
                
                string Request = FormatRequest(context.Request).Result;
                // ErrorLog(context, ex);
            }

        }

//Format Request method

private async Task<string> FormatRequest(HttpRequest request)
        {
            var body = request.Body;

            //This line allows us to set the reader for the request back at the beginning of its stream.
            request.EnableRewind();

            //We now need to read the request stream.  First, we create a new byte[] with the same length as the request stream...
            var buffer = new byte[Convert.ToInt32(request.ContentLength)];

            //...Then we copy the entire request stream into the new buffer.
            await request.Body.ReadAsync(buffer, 0, buffer.Length);

            //We convert the byte[] into a string using UTF8 encoding...
            var bodyAsText = Encoding.UTF8.GetString(buffer);

            //..and finally, assign the read body back to the request body, which is allowed because of EnableRewind()
            request.Body = body;

            return $"{request.Scheme} {request.Host}{request.Path} {request.QueryString} {bodyAsText}";
        }
Posted
Updated 25-Oct-19 0:08am
v2

1 solution

Don't use middleware, use a request filter instead.

Middleware should be used to handle exceptions. It should have always consider the response to be complete. We have a similar middleware that logs all traffic in and out of the service. We have filters that handle exceptions and turn them into graceful responses after logging the issue.

C#
public class GeneralExceptionFilterAttribute : ExceptionFilterAttribute {

        public override void OnException(HttpActionExecutedContext context) {
            FilterHandlerProvider.Instance.Handle(this, context);
        }

    }

I won't go into to much detail about FilterHandlerProvider.Instance, because we use a DI factory to handle different exception types. In this specific case, the Instance is set as our GeneralExceptionFilterAttribute.

C#
public class GeneralExceptionFilterAttributeHandler : IHandlesFilterAttribute<GeneralExceptionFilterAttribute,
        HttpActionExecutedContext> {

        private readonly ILogger _logger;

        public GeneralExceptionFilterAttributeHandler(ILogger logger) {
            _logger = logger;
        }

        public void Handle(GeneralExceptionFilterAttribute filter, HttpActionExecutedContext context) {

            var extraInformation = new List<object>();
#if DEBUG
            //We want to handle all exceptions when they occur so we break the debugger here to take a look at an unhandled general exception and try to handle it
            Debugger.Break();
#endif
            if (context.Exception is HttpResponseException responseException) {
                context.Response = responseException.Response;
            }
            else if (context.Exception is InvalidAggregateOperationException invalidAggregateOperationException) {
                extraInformation.Add(invalidAggregateOperationException.AggregateId);
                if (invalidAggregateOperationException.InnerException != null) {
                    if (context.Exception.InnerException is ItemsNotAvailableException itemsNotAvailableException) {
                        extraInformation.Add(itemsNotAvailableException.Type);
                    }
                }
            }
            else {
                context.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError);
            }

            _logger.LogException(context.Exception, extraInformation.ToArray());
        }

    }


Our ILogger is a DI instance so you may want to do that differently.

Most importantly, any exception coming from a controller is handled, logged and a graceful response is set.

Here's some more reading on filters:
Understanding Filters in MVC[^]

Hope that helps ^_^
 
Share this answer
 
Comments
Member 12749751 25-Oct-19 6:28am    
But with exception i have to log entire request with parameters..then how can i do that
Andy Lanng 25-Oct-19 6:31am    
Right, you still have access to the context request in the filter.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900