How to set custom exception with status code

Viewed 946

I'm able to get error message through my custom exception class, but it seems it always returning 500 status code.

How can I set the status code using my custom exception class?

this is the app flow:

Service:

throw new UCodeException("Already exist", StatusCodes.Status409Conflict);

UCodeException:

 public class UCodeException : UException
    {
        public override int StatusCode { get; }

        public UCodeException(string error, int statusCode) : base(error)
        {
            StatusCode = statusCode;
        }

        public UCodeException(string[] errors, int statusCode) : base(errors)
        {
            StatusCode = statusCode;
        }

    }

UException:

public abstract class UException : Exception
{
    public string[] Errors { get; }
    public abstract int StatusCode { get; }

    protected UException(string error) : base(error)
    {
        Errors = new []{error};
    }
    
    protected UException(string[] errors)
    {
        Errors = errors;
    }
} 
1 Answers

You can achieve it with Filter

  1. Create an action filter named HttpResponseExceptionFilter:
    public class HttpResponseExceptionFilter : IActionFilter, IOrderedFilter
    {
        public void OnActionExecuting(ActionExecutingContext context) { }
    
        public void OnActionExecuted(ActionExecutedContext context)
        {
            if (context.Exception is UCodeException exception)
            {
                context.Result = new ObjectResult(exception.Errors)
                {
                    StatusCode = exception.StatusCode,
                };
                context.ExceptionHandled = true;
            }
        }
    }
    
  2. In Startup.ConfigureServices, add the action filter to the filters collection:
    services.AddControllers(options =>
        options.Filters.Add(new HttpResponseExceptionFilter()));
    

Or write custom exception middleware. Create class named ExceptionMiddleare:

public class ExceptionMiddleware
{
    private readonly RequestDelegate _next;

    public ExceptionMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            if (ex is HttpResponseException exception)
            {
                context.Response.StatusCode = exception.StatusCode;
            }
        }
    }
}

In Startup.Configure add the middleware (before app.UseEndpoints):

app.UseMiddleware<ExceptionMiddleware>();
Related