Skip to main content

Using Problem Details in .NET 7

When comparing API's, I see a lot of different ways how error messages are returned. With the introduction of Problem Details for HTTP APIs (https://tools.ietf.org/html/rfc7807) , we finally have a standardized error payload to return when an unhandled exception occurs.

Although the standard was introduced before .NET 7, there was no out-of-the-box way to introduce the ProblemDetails spec into your ASP.NET Core application.

A solution was to use the third party Hellang.Middleware.ProblemDetails nuget package:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Net.Http;
using System.Threading.Tasks;
using Hellang.Middleware.ProblemDetails.Mvc;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Example
{
public class Startup
{
public Startup(IWebHostEnvironment environment)
{
Environment = environment;
}
private IWebHostEnvironment Environment { get; }
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.UseEnvironment(Environments.Development)
//.UseEnvironment(Environments.Production) // Uncomment to remove exception details from responses.
.ConfigureWebHostDefaults(web =>
{
web.UseStartup<Startup>();
});
}
public void ConfigureServices(IServiceCollection services)
{
services.AddProblemDetails(ConfigureProblemDetails)
.AddControllers()
// Adds MVC conventions to work better with the ProblemDetails middleware.
.AddProblemDetailsConventions()
.AddJsonOptions(x => x.JsonSerializerOptions.IgnoreNullValues = true);
}
public void Configure(IApplicationBuilder app)
{
app.UseProblemDetails();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
private void ConfigureProblemDetails(ProblemDetailsOptions options)
{
// Only include exception details in a development environment. There's really no need
// to set this as it's the default behavior. It's just included here for completeness :)
options.IncludeExceptionDetails = (ctx, ex) => Environment.IsDevelopment();
// You can configure the middleware to re-throw certain types of exceptions, all exceptions or based on a predicate.
// This is useful if you have upstream middleware that needs to do additional handling of exceptions.
options.Rethrow<NotSupportedException>();
// This will map NotImplementedException to the 501 Not Implemented status code.
options.MapToStatusCode<NotImplementedException>(StatusCodes.Status501NotImplemented);
// This will map HttpRequestException to the 503 Service Unavailable status code.
options.MapToStatusCode<HttpRequestException>(StatusCodes.Status503ServiceUnavailable);
// Because exceptions are handled polymorphically, this will act as a "catch all" mapping, which is why it's added last.
// If an exception other than NotImplementedException and HttpRequestException is thrown, this will handle it.
options.MapToStatusCode<Exception>(StatusCodes.Status500InternalServerError);
}
}
}
view raw Startup.cs hosted with ā¤ by GitHub

Starting from .NET 7 this nuget package is no longer necessary. You only need to add the following line to your service configuration:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
view raw Program.cs hosted with ā¤ by GitHub

If someone now calls your API and an exception occurs, the returned result will look like this:

{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "Bad Request",
"status": 400
}
view raw 400Response.json hosted with ā¤ by GitHub

We can further customize the behavior through CustomizeProblemDetails:

builder.Services.AddProblemDetails(options =>
options.CustomizeProblemDetails = ctx =>
{
ctx.ProblemDetails.Extensions.Add("nodeId", Environment.MachineName));
// Add other custom problem details
}
);
view raw CustomizeErrors.cs hosted with ā¤ by GitHub

More information

Handle errors in ASP.NET Core web APIs | Microsoft Learn

Popular posts from this blog

Kubernetesā€“Limit your environmental impact

Reducing the carbon footprint and CO2 emission of our (cloud) workloads, is a responsibility of all of us. If you are running a Kubernetes cluster, have a look at Kube-Green . kube-green is a simple Kubernetes operator that automatically shuts down (some of) your pods when you don't need them. A single pod produces about 11 Kg CO2eq per year( here the calculation). Reason enough to give it a try! Installing kube-green in your cluster The easiest way to install the operator in your cluster is through kubectl. We first need to install a cert-manager: kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.5/cert-manager.yaml Remark: Wait a minute before you continue as it can take some time before the cert-manager is up & running inside your cluster. Now we can install the kube-green operator: kubectl apply -f https://github.com/kube-green/kube-green/releases/latest/download/kube-green.yaml Now in the namespace where we want t...

Azure DevOps/ GitHub emoji

Iā€™m really bad at remembering emojiā€™s. So here is cheat sheet with all emojiā€™s that can be used in tools that support the github emoji markdown markup: All credits go to rcaviers who created this list.

.NET 9 - Goodbye sln!

Although the csproj file evolved and simplified a lot over time, the Visual Studio solution file (.sln) remained an ugly file format full of magic GUIDs. With the latest .NET 9 SDK(9.0.200), we finally got an alternative; a new XML-based solution file(.slnx) got introduced in preview. So say goodbye to this ugly sln file: And meet his better looking slnx brother instead: To use this feature we first have to enable it: Go to Tools -> Options -> Environment -> Preview Features Check the checkbox next to Use Solution File Persistence Model Now we can migrate an existing sln file to slnx using the following command: dotnet sln migrate AICalculator.sln .slnx file D:\Projects\Test\AICalculator\AICalculator.slnx generated. Or create a new Visual Studio solution using the slnx format: dotnet new sln --format slnx The template "Solution File" was created successfully. The new format is not yet recognized by VSCode but it does work in Jetbr...