Prerequisites 🔨
Tools you have to install before create this example project:
- .NET Core 3.1 SDK - https://dotnet.microsoft.com/download/dotnet-core/3.1
- Visual Studio Code - https://code.visualstudio.com/
- Postman - https://www.postman.com/downloads/
What we have out of the box?
I have created Web API, using default .NET Core template dotnet new webapi -n SampleApi. Then you have to follow steps:
- In controller
WeatherForecastControllerGetmethod add throwing exceptionthrow new Exception("Some error appears!");🔥 - Using the Windows command prompt run application. Before
dotnet runit is important to set environment variableASPNETCORE_ENVIRONMENTtoProductionorStagingvalue. ⚠️ It is because inDevelopmentmode response will include full details about our exception and in production it is not acceptable.
set ASPNETCORE_ENVIRONMENT=Staging
dotnet run --no-launch-profile- Do GET request https://localhost:5001/weatherforecast using Postman.

What we will get in response is an internal server error. But if we think from a consumer perspective and try to deal with that error details we have. The response contains HTTP code 500 (Internal Server Error) and the response body has no content. So that is all we have, just one HTTP code. Do we have enough details in response we got from API? The answer is "No"! 😥
How to include details in error response?
To provide good quality of Web API we have to handle errors and include in response more details about the error. Microsoft already has described some guidelines on how to build a good Web API and how to format non-success response. Guidelines say that we have to return JSON response that includes error code and some self describable error details.
{
"error": {
"code": "BadArgument",
"message": "Previous passwords may not be reused",
"target": "password",
"innererror": {
"code": "PasswordError",
"innererror": {
"code": "PasswordDoesNotMeetPolicy",
"minLength": "6",
"maxLength": "64",
"characterTypes": ["lowerCase","upperCase","number","symbol"],
"minDistinctCharacterTypes": "2",
"innererror": {
"code": "PasswordReuseNotAllowed"
}
}
}
}
}To provide a JSON response we have to create a class for errors. When we have a class then we can handle all exceptions and return an instance of that error class. I changed the default controller to return BadRequest when an error appears.
[HttpGet]
public IActionResult Get()
{
try
{
throw new Exception("Some error appears!");
}
catch(Exception ex)
{
var errorResponse = new ErrorResponse
{
Error = new Error
{
Code = "unhandled",
Message = ex.Message
}
};
return BadRequest(errorResponse);
}
}WeatherForecastController return BadRequest on error.If we do GET request https://localhost:5001/weatherforecast using Postman again, we will get many more details about the error. 🎉

What I don`t like in this type of solution, that we have to create class manually. This class is coupled to current Web API. 🤔 Sure we can pack that class inside the common library and push to NuGet repository. But would it be great if .NET Core have that error class out of the box and all our Web API will have that without any additional dependencies?
Return Problem Details using .NET Core build-in feature! 🚀
To answer that question "Do .NET Core already solved this task?" I dived into Microsoft.AspNetCore.Mvc source code. Think it is very valuable to read the source code of the library you use.
After some research, I found that ControllerBase class contains public method Problem which produces a ProblemDetails class response. If we read the summary of ProblemDetails class we will see "A machine-readable format for specifying errors in HTTP API responses based on https://tools.ietf.org/html/rfc7807.", that sounds like we found what we needed.
If you visit https://tools.ietf.org/html/rfc7807 you'll see it is a standard of error processing for Web API. It means that Microsoft already implemented that standard for handling and formatting errors in Web API. Let`s try out! 🔨
I have changed WeatherForecastController to return Problem when we got an error.
[HttpGet]
public IActionResult Get()
{
try
{
throw new Exception("Some error appears!");
}
catch(Exception ex)
{
return Problem(title: ex.Message);
}
}WeatherForecastController return Problem on error.If we do GET request https://localhost:5001/weatherforecast using Postman again, we will error details in a different format. 🤩
HTTP/1.1 500 Internal Server Error
Date: Sat, 29 Aug 2020 14:22:25 GMT
Content-Type: application/problem+json; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked
{"type":"https://tools.ietf.org/html/rfc7231#section-6.6.1","title":"Some error appears!","status":500,"traceId":"|d4c87220-406514cefaf95a6e."}What is interesting that Problem method returns different Content-Type as we expect usually application/problem+json. Also, the response contains a body that contains a link to the internal error description.
Microsoft.AspNetCore.Mvc.Core library also contains validation problem implementation ValidationProblemDetails class. This class provides us to return Web API consumer validation error response in an appropriate format. Let`s try out.
I have changed WeatherForecastController to return both types of problems.
[HttpGet]
public IActionResult Get()
{
try
{
ModelState.AddModelError("parameterName", "Some parameter is not valid!");
if (!ModelState.IsValid)
{
return ValidationProblem(ModelState);
}
return Ok();
}
catch(Exception ex)
{
return Problem(title: ex.Message);
}
}WeatherForecastController return Problem on error and ValidationProblem on invalid request.If we do GET request https://localhost:5001/weatherforecast using Postman again, we will get validation error details.
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "|34f88f8e-41acdb6aeb708c8f.",
"errors": {
"parameterName": [
"Some parameter is not valid!"
]
}
}Now our error responses look`s much better. And what is more valuable than we use .NET Core build-in feature. ❤️
How we can customize build-in problem formatting behaviour? 🚧
It is also possible to customize the behavior of problem formatting. Using the extension method ConfigureApiBehaviorOptions we can change problem formatting behaviour. In the following configuration example, I will change the validation problem response type reference link. 😉
public void ConfigureServices(IServiceCollection services)
{
services
.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.ClientErrorMapping[400] = new ClientErrorData
{
Link = "https://craftbakery.dev/"
};
});
}Startup.cs change API behaviour options.If we do GET request https://localhost:5001/weatherforecast using Postman again, we will get validation error details with the changed type attribute.
{
"type": "https://craftbakery.dev/",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "|7edb3147-49c4f43826f311ce.",
"errors": {
"parameterName": [
"Some parameter is not valid!"
]
}
}For further API behavior customization see ApiBehaviorOptions realisation. 🔬
In the following post, we saw that .NET Core already has build-in features on how to deal with unhandled errors and how to return Web API consumer invalid request validation errors. That is what you can share in your organization for building APIs in which error responses are formatted using the unified and same style. You`ll save a lot of time and your API consumers will be happier!
Happy error handling! 🔥
[eof]