aspnetcore: Customize error handling for [ApiController]
Is this a Bug or Feature request?:
Feature Request / Question
Steps to reproduce or link to a repro project:
[ApiController]
[Produces("application/json")]
[Route("api/v1/value")]
public class ValueApiController : Controller
{
[HttpGet]
public ActionResult<string[]> Get()
{
throw new Exception("bam");
}
}
Startup.cs
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseStatusCodePagesWithReExecute("/Error");
}
Description of the problem:
When an error occurs in Controller classes marked with [ApiController]
, I don’t want them to return HTML but JSON instead:
-
In development, instead of Developer Exception Page, ideally the API Controller should return stack trace in plain text / JSON.
-
In production, instead of a custom HTML error response, ideally the API Controller should return a plain text / JSON with like
"An error occurred while processing your request."
When using Core MVC < 2.1, I have been able to do this by using code like:
app.UseWhen(context => context.Request.Path.Value.StartsWith("/api", StringComparison.OrdinalIgnoreCase), builder =>
{
builder.UseExceptionHandler(configure =>
{
configure.UseMiddleware<ApiExceptionHandlerMiddleware>(env.IsDevelopment());
});
});
app.UseWhen(context => context.Request.Path.Value.StartsWith("/api", StringComparison.OrdinalIgnoreCase) == false, builder =>
{
if (env.IsDevelopment())
{
builder.UseDeveloperExceptionPage();
}
else
{
builder.UseExceptionHandler("/error");
builder.UseStatusCodePagesWithReExecute("/error");
}
});
However, seeing that the purpose of the [ApiController]
is: (written on the XML doc)
Indicates that a type and all derived types are used to serve HTTP API responses. The presence of this attribute can be used to target conventions, filters and other behaviors based on the purpose of the controller.
, I would like to know how to alter the error behavior when this attribute is encountered. (Instead of checking whether the request starts with /api
)
Version of Microsoft.AspNetCore.Mvc
or Microsoft.AspNetCore.App
or Microsoft.AspNetCore.All
:
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0-rc1-final" />
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Comments: 15 (10 by maintainers)
All behavior related to the
ApiControllerAttribute
is defined in theApiBehaviorApplicationModelProvider
:https://github.com/aspnet/Mvc/blob/504da3c565a9a159365b4564dba5f2cd7d059e7f/src/Microsoft.AspNetCore.Mvc.Core/Internal/ApiBehaviorApplicationModelProvider.cs#L57-L91
AFAIK, the
ApiControllerAttribute
doesn’t affect exception handling. You might be referring to theModelStateInvalidFilter
, which lets you remove the usual MVC validation boilerplate:https://github.com/aspnet/Mvc/blob/504da3c565a9a159365b4564dba5f2cd7d059e7f/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/ModelStateInvalidFilter.cs#L51-L58
The default implementation of
InvalidModelStateResponseFactory
just creates a newBadRequestObjectResult
with theModelState
dictionary:https://github.com/aspnet/Mvc/blob/ec31ff0c28961be64ad0b8228eba3a084086f60b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ApiBehaviorOptionsSetup.cs#L25-L33
If you want to customize this behavior, you can set
InvalidModelStateResponseFactory
:Those are official libraries. Not official from Microsoft, but official from the .NET community. Not good enough?
You don’t. Look no further. The functionality has been provided by the community. You’re welcome 😉
I like this. Please allow us to customize the response. Today we are using a custom Middleware that adds a global exception filter. The exception filter then creates a response that conforms with RFC 7807. It all gets setup with a builder like this:
app.UseApiExceptionResponse(bool devEnv);
If we can do something like this nativly in MVC that will be great.
Like @ryanelian points out, the model state response factory addresses one aspect of the error handling viz model validation. Handling errors is just as interesting. Speaking to @rynowak, to support Api Controllers over routing would involve
a) Set a flag (maybe a Http feature) as part of executing an API controller b) Use this in the error handler (Template update)
Speaking to @rynowak, dispatcher should solve the first requirement. This would make for a pretty nice enhancement with the rest of the API work we’d do for 2.2
There’s also https://www.nuget.org/packages/Hellang.Middleware.ProblemDetails. See this sample; https://github.com/khellang/Middleware/blob/master/samples/ProblemDetails.Sample/Program.cs