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.

DevToysā€“A swiss army knife for developers

As a developer there are a lot of small tasks you need to do as part of your coding, debugging and testing activities.  DevToys is an offline windows app that tries to help you with these tasks. Instead of using different websites you get a fully offline experience offering help for a large list of tasks. Many tools are available. Here is the current list: Converters JSON <> YAML Timestamp Number Base Cron Parser Encoders / Decoders HTML URL Base64 Text & Image GZip JWT Decoder Formatters JSON SQL XML Generators Hash (MD5, SHA1, SHA256, SHA512) UUID 1 and 4 Lorem Ipsum Checksum Text Escape / Unescape Inspector & Case Converter Regex Tester Text Comparer XML Validator Markdown Preview Graphic Col...