Take advantage of the open source ProblemDetails middleware in ASP.NET Core to send clients standardized, machine-readable error messages when exceptions occur Credit: Florent Darrault For an API to be maintainable and usable there should be consistency in the way responses are sent to the clients. This article talks about ProblemDetails, open source ASP.NET Core middleware from Kristian Hellang that can be used to generate detailed results for the exceptions that occur in your application. To work with the code examples provided in this article, you should have Visual Studio 2019 installed in your system. If you don’t already have a copy, you can download Visual Studio 2019 here. [ Also on InfoWorld: Rapid UI development with Flutter for Windows ] Create an ASP.NET Core MVC project in Visual Studio 2019 First off, let’s create an ASP.NET Core project in Visual Studio 2019. Assuming Visual Studio 2019 is installed in your system, follow the steps outlined below to create a new ASP.NET Core project in Visual Studio. Launch the Visual Studio IDE. Click on “Create new project.” In the “Create new project” window, select “ASP.NET Core Web Application” from the list of templates displayed. Click Next. In the “Configure your new project” window, specify the name and location for the new project. Optionally check the “Place solution and project in the same directory” check box, depending on your preferences. Click Create. In the “Create a New ASP.NET Core Web Application” window shown next, select .NET Core as the runtime and ASP.NET Core 3.1 (or later) from the drop-down list at the top. Select “Web Application (Model-View-Controller)” as the project template to create a new ASP.NET Core MVC application. Ensure that the check boxes “Enable Docker Support” and “Configure for HTTPS” are unchecked as we won’t be using those features here. Ensure that Authentication is set to “No Authentication” as we won’t be using authentication either. Click Create. This will create a new ASP.NET Core MVC project in Visual Studio 2019. Next, create a new ApiController class named ValuesController. We’ll use this class and the project in the sections that follow. What is ProblemDetails? Why do we need it? One of the goals of REST APIs is consistency, i.e., being able to emit responses in a consistent manner. When working with these APIs you might often need to define response formats for the errors that occur in your application. While you could use HTTP Status Codes for this purpose, you will often want to communicate more detailed information to the clients than they provide. For example, consider the failure of a payment in a shopping cart application. The payment might have failed for any number of reasons, such as insufficient bank funds, incorrect credit card information, wrong one-time password code, or a failure in the transaction processing system. Hence, it is imperative that there is a standard way in which these error messages can be sent to the client. The Internet Engineering Task Force (IETF) published a document in March 2016, called Problem Details For HTTP APIs, that defines a format that can be used to send out machine-readable details about the errors that occur in an application. You can take advantage of this format in the ProblemDetails middleware to define errors and error messages in HTTP API responses. Plus, all of your exceptions can be handled in one place: You can always return an instance of ProblemDetails to the consuming client irrespective of the type of error that has occurred. By using ProblemDetails to emit error response messages, you enable the consumers of the API to react to the errors more effectively. This makes your API consistent and reliable. Install the ProblemDetails NuGet package in Visual Studio The ProblemDetails middleware from Kristian Hellang handles the exceptions that occur in the request processing pipeline and converts the exception details to the IETF Problem Details format. To work with ProblemDetails you should install the Hellang.Middleware.ProblemDetails NuGet package from the NuGet Package Manager. Alternatively, you can install this package by executing the following command in the NuGet Package Manager Console: Install-Package Hellang.Middleware.ProblemDetails Configure the ProblemDetails middleware in ASP.NET Core Assuming the ProblemDetails NuGet package has been installed, you should add the required services to the DI container by calling the AddProblemDetails() method as shown in the code snippet given below. public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddProblemDetails(); // This would add the required services // to the DI container } To add the middleware to the pipeline, call the UseProblemDetails() method as shown in the code snippet given below. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseProblemDetails(); // Add the middleware to the // request processing pipeline app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); } Note that non-exception responses are converted to instances of ProblemDetails when any of the following is true: The Content-Type or the Content-Length headers are empty The HTTP Status Code of the response is between 400 and 600 Use ProblemDetails in action methods in ASP.NET Core Replace the Get method of the ValuesController class with the following code: [HttpGet("{x}")] public ActionResult Get(int x) { int i = 0; try { i = 10 / x; } catch (Exception ex) { return BadRequest(); } return Ok( i ); } For the sake of simplicity there are just a few lines of code in the Get method. If the Get method is passed a value of 0, the result of the division in the try block will be undefined and hence the runtime will throw an exception. If the value of the parameter x of the Get method has a non-zero value, the result of the division will be returned. When you execute the application and pass 0 as a parameter to the Get method of the ValuesController, you will see an error message that looks like this: IDG Figure 1 You can also create an instance of the Microsoft.AspNetCore.Mvc.ProblemDetails class and pass it back to the client as shown in the code listing given below. try { i = 10 / x; } catch (Exception ex) { var problemDetails = new Microsoft.AspNetCore.Mvc.ProblemDetails { Status = StatusCodes.Status403Forbidden, Type = "https://example.com/probs/out-of-credit", Title = "Division by zero...", Detail = ex.StackTrace, Instance = HttpContext.Request.Path }; return BadRequest(problemDetails); } IDG Figure 2 Customize the behavior of the ProblemDetails middleware in ASP.NET Core You can customize the behavior of the ProblemDetails middleware by using ProblemDetailsOptions in the ConfigureServices method as shown below. public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddProblemDetails(opts => { // Specify your configuration details here }); } Here is another example. The following configuration will make sure that exception details are included only if you’re in the development environment. public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddProblemDetails(opts => { opts.IncludeExceptionDetails = (context, ex) => { var environment = context.RequestServices.GetRequiredService <IHostEnvironment>(); return environment.IsDevelopment(); }; }); } ProblemDetails is a machine-readable format that is used to standardize error messages in API controllers and represent HTTP API responses based on the IETF Problem Details specification. The Microsoft.AspNetCore.Mvc namespace contains a ProblemDetails class you can use for sending out a machine-readable error response. Kristian Hellang’s ProblemDetails middleware makes this easy. How to do more in ASP.NET Core: How to create route constraints in ASP.NET Core How to manage user secrets in ASP.NET Core How to build gRPC applications in ASP.NET Core How to redirect a request in ASP.NET Core How to use attribute routing in ASP.NET Core How to pass parameters to action methods in ASP.NET Core MVC How to use API Analyzers in ASP.NET Core How to use route data tokens in ASP.NET Core How to use API versioning in ASP.NET Core How to use Data Transfer Objects in ASP.NET Core 3.1 How to handle 404 errors in ASP.NET Core MVC How to use dependency injection in action filters in ASP.NET Core 3.1 How to use the options pattern in ASP.NET Core How to use endpoint routing in ASP.NET Core 3.0 MVC How to export data to Excel in ASP.NET Core 3.0 How to use LoggerMessage in ASP.NET Core 3.0 How to send emails in ASP.NET Core How to log data to SQL Server in ASP.NET Core How to schedule jobs using Quartz.NET in ASP.NET Core How to return data from ASP.NET Core Web API How to format response data in ASP.NET Core How to consume an ASP.NET Core Web API using RestSharp How to perform async operations using Dapper How to use feature flags in ASP.NET Core How to use the FromServices attribute in ASP.NET Core How to work with cookies in ASP.NET Core How to work with static files in ASP.NET Core How to use URL Rewriting Middleware in ASP.NET Core How to implement rate limiting in ASP.NET Core How to use Azure Application Insights in ASP.NET Core Using advanced NLog features in ASP.NET Core How to handle errors in ASP.NET Web API How to implement global exception handling in ASP.NET Core MVC How to handle null values in ASP.NET Core MVC Advanced versioning in ASP.NET Core Web API How to work with worker services in ASP.NET Core How to use the Data Protection API in ASP.NET Core How to use conditional middleware in ASP.NET Core How to work with session state in ASP.NET Core How to write efficient controllers in ASP.NET Core Related content feature What is Rust? Safe, fast, and easy software development Unlike most programming languages, Rust doesn't make you choose between speed, safety, and ease of use. Find out how Rust delivers better code with fewer compromises, and a few downsides to consider before learning Rust. By Serdar Yegulalp Nov 20, 2024 11 mins Rust Programming Languages Software Development how-to Kotlin for Java developers: Classes and coroutines Kotlin was designed to bring more flexibility and flow to programming in the JVM. Here's an in-depth look at how Kotlin makes working with classes and objects easier and introduces coroutines to modernize concurrency. By Matthew Tyson Nov 20, 2024 9 mins Java Kotlin Programming Languages analysis Azure AI Foundry tools for changes in AI applications Microsoft’s launch of Azure AI Foundry at Ignite 2024 signals a welcome shift from chatbots to agents and to using AI for business process automation. By Simon Bisson Nov 20, 2024 7 mins Microsoft Azure Generative AI Development Tools news Microsoft unveils imaging APIs for Windows Copilot Runtime Generative AI-backed APIs will allow developers to build image super resolution, image segmentation, object erase, and OCR capabilities into Windows applications. By Paul Krill Nov 19, 2024 2 mins Generative AI APIs Development Libraries and Frameworks Resources Videos