I have a Exception middleware on ASP.NET Core application that do this:
try
{
await _next(httpContext);
}
catch (MyException exception)
{
httpContext.Response.ContentType = "application/json";
httpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
await httpContext.Response.WriteAsync(exception.Message);
}
On this example, we send "Forbidden" (403 http status code) but I always receive 500. I inspect this on Swagger and Google Chrome and I don't understand the reason.
You have probably got your middleware registered in the wrong place in the pipeline. The order you place your middleware in startup.cs
makes a difference. For example:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Use(async (context, next) =>
{
try
{
await next();
}
catch (Exception ex)
{
context.Response.StatusCode = StatusCodes.Status403Forbidden;
await context.Response.WriteAsync(ex.Message);
}
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc();
}
In the code above I have registered middleware similar to yours at the start of the pipeline. ASP.NET Core will process any requests in the order you place them in, so my custom middleware will run first for a request. However, the responses are handled from the bottom upwards. So, in the example, when an exception is thrown in a controller (or anywhere) the UseDeveloperExceptionPage
or UseExceptionHandler
will receive any exception first, handle it and change the status code to 500.
If we change the order to this:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.Use(async (context, next) =>
{
try
{
await next();
}
catch (Exception ex)
{
context.Response.StatusCode = StatusCodes.Status403Forbidden;
await context.Response.WriteAsync(ex.Message);
}
});
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc();
}
Now we have registered our handler to be after the built-in exception handler for a request but, more importantly, before them for a response. So, in this case, when a controller throws an exception, our handler will catch it, process it and change the status code to what we want. The other exception handlers will not see the exception (unless another middleware handler throws an exception after us).