--- title: Handle errors in ASP.NET Core web APIs author: pranavkm description: Learn about error handling with ASP.NET Core web APIs. monikerRange: '>= aspnetcore-2.1' ms.author: prkrishn ms.custom: mvc ms.date: 09/18/2019 uid: web-api/handle-errors --- # Handle errors in ASP.NET Core web APIs This article describes how to handle and customize error handling with ASP.NET Core web APIs. ## Developer Exception Page The [Developer Exception Page](xref:fundamentals/error-handling) is a useful tool to get detailed stack traces for server errors. ::: moniker range=">= aspnetcore-3.0" The Developer Exception Page displays a plain-text response if the client doesn't accept HTML-formatted output: ``` > curl https://localhost:5001/weatherforecast System.ArgumentException: count at errorhandling.Controllers.WeatherForecastController.Get(Int32 x) in D:\work\Samples\samples\aspnetcore\mvc\errorhandling\Controllers\WeatherForecastController.cs:line 35 at lambda_method(Closure , Object , Object[] ) at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters) ... ``` ::: moniker-end > [!WARNING] > Enable the Developer Exception Page **only when the app is running in the Development environment**. You don't want to share detailed exception information publicly when the app runs in production. For more information on configuring environments, see . ## Exception handler In non-development environments, [Exception Handling Middleware](xref:fundamentals/error-handling) can be used to produce an error payload: 1. In `Startup.Configure`, invoke to use the middleware: ```csharp public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/error"); } } ``` 1. Configure a controller action to respond to the `/error` route: ```csharp [ApiController] public class ErrorController : ControllerBase { [Route("/error")] public IActionResult Error() => Problem(); } ``` The preceding `Error` action sends an [RFC7807](https://tools.ietf.org/html/rfc7807)-compliant payload to the client. Exception Handling Middleware can also provide more detailed content-negotiated output in the local development environment. Use the following steps to produce a consistent payload format across development and production environments: 1. In `Startup.Configure`, register environment-specific Exception Handling Middleware instances: ```csharp public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseExceptionHandler("/error-local-development"); } else { app.UseExceptionHandler("/error"); } } ``` In the preceding code, the middleware is registered with: * A route of `/error-local-development` in the Development environment. * A route of `/error` in environments that aren't Development. 1. Apply attribute routing to controller actions: ```csharp [ApiController] public class ErrorController : ControllerBase { [Route("/error-local-development")] public IActionResult ErrorLocalDevelopment( [FromServices] IWebHostEnvironment webHostEnvironment) { if (!webHostEnvironment.IsDevelopment()) { throw new InvalidOperationException( "This shouldn't be invoked in non-development environments."); } var context = HttpContext.Features.Get(); return Problem( detail: context.Error.StackTrace, title: context.Error.Message); } [Route("/error")] public IActionResult Error() => Problem(); } ``` ## Use exceptions to modify the response The contents of the response can be modified from outside of the controller. In ASP.NET 4.x Web API, one way to do this was using the type. ASP.NET Core doesn't include an equivalent type. Support for `HttpResponseException` can be added with the following steps: 1. Create a well-known exception type named `HttpResponseException`: ```csharp public class HttpResponseException : Exception { public int Status { get; set; } = 500; public object Value { get; set; } } ``` 1. Create an action filter named `HttpResponseExceptionFilter`: ```csharp public class HttpResponseExceptionFilter : IActionFilter, IOrderedFilter { public int Order { get; set; } = int.MaxValue - 10; public void OnActionExecuting(ActionExecutingContext context) {} public void OnActionExecuted(ActionExecutedContext context) { if (context.Exception is HttpResponseException exception) { context.Result = new ObjectResult(exception.Value) { Status = exception.Status, }; context.ExceptionHandled = true; } } } ``` 1. In `Startup.ConfigureServices`, add the action filter to the filters collection: ```csharp public void ConfigureServices(IServiceCollection services) { services.AddControllers(options => options.Filters.Add(new HttpResponseExceptionFilter())); } ``` ## Validation failure error response For web API controllers, MVC responds with a response type when model validation fails. MVC uses the results of to construct the error response for a validation failure. The following example uses the factory to change the default response type to in `Startup.ConfigureServices`: ::: moniker range=">= aspnetcore-3.0" [!code-csharp[](index/samples/3.x/Startup.cs?name=snippet_DisableProblemDetailsInvalidModelStateResponseFactory&highlight=4-13)] ::: moniker-end ::: moniker range="= aspnetcore-2.2" [!code-csharp[](index/samples/2.x/Startup.cs?name=snippet_DisableProblemDetailsInvalidModelStateResponseFactory&highlight=5-14)] ::: moniker-end ::: moniker range="= aspnetcore-2.1" ```csharp services.AddMvc() .SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.Configure(options => { options.InvalidModelStateResponseFactory = context => { var result = new BadRequestObjectResult(context.ModelState); // TODO: add `using using System.Net.Mime;` to resolve MediaTypeNames result.ContentTypes.Add(MediaTypeNames.Application.Json); result.ContentTypes.Add(MediaTypeNames.Application.Xml); return result; }; }); ``` ::: moniker-end ## Client error response An *error result* is defined as a result with an HTTP status code of 400 or higher. For web API controllers, MVC transforms an error result to a result with . ::: moniker range=">= aspnetcore-3.0" The error response can be configured in one of the following ways: 1. [Implement ProblemDetailsFactory](#implement-problemdetailsfactory) 1. [Use ApiBehaviorOptions.ClientErrorMapping](#use-apibehavioroptionsclienterrormapping) ### Implement ProblemDetailsFactory MVC uses `Microsoft.AspNetCore.Mvc.ProblemDetailsFactory` to produce all instances of and . This includes client error responses, validation failure error responses, and the `Microsoft.AspNetCore.Mvc.ControllerBase.Problem` and helper methods. To customize the problem details response, register a custom implementation of `ProblemDetailsFactory` in `Startup.ConfigureServices`: ```csharp public void ConfigureServices(IServiceCollection serviceCollection) { services.AddControllers(); services.AddTransient(); } ``` ::: moniker-end ::: moniker range="<= aspnetcore-2.2" The error response can be configured as outlined in the [Use ApiBehaviorOptions.ClientErrorMapping](#use-apibehavioroptionsclienterrormapping) section. ::: moniker-end ### Use ApiBehaviorOptions.ClientErrorMapping Use the property to configure the contents of the `ProblemDetails` response. For example, the following code updates the `type` property for 404 responses: ::: moniker range=">= aspnetcore-3.0" [!code-csharp[](index/samples/3.x/Startup.cs?name=snippet_ConfigureApiBehaviorOptions&highlight=8-9)] ::: moniker-end ::: moniker range="<= aspnetcore-2.2" [!code-csharp[](index/samples/2.x/Startup.cs?name=snippet_ConfigureApiBehaviorOptions&highlight=9-10)] ::: moniker-end