Lỗi error running app default activity not found

The Debug profile determines how to start debugging the application. You can right click on your Project Properties > navigate to “Debug” > create a debug profile by specifying various properties.

Show

About the error message, please launch your VS2019 as administrator and create a new project to check if it persists or not.

Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.

Handle errors in ASP.NET Core

  • Article
  • 07/25/2023

In this article

By Tom Dykstra

This article covers common approaches to handling errors in ASP.NET Core web apps. See also Handle errors in ASP.NET Core web APIs and Handle errors in Minimal API apps.

Developer exception page

The Developer Exception Page displays detailed information about unhandled request exceptions. ASP.NET Core apps enable the developer exception page by default when both:

  • Running in the Development environment.
  • App created with the current templates, that is, using WebApplication.CreateBuilder. Apps created using the must enable the developer exception page by calling var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler("/Error");  
    app.UseHsts();  
    
    } app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

    2 in

    var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler("/Error");  
    app.UseHsts();  
    
    } app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

    3.

The developer exception page runs early in the middleware pipeline, so that it can catch unhandled exceptions thrown in middleware that follows.

Detailed exception information shouldn't be displayed publicly when the app runs in the Production environment. For more information on configuring environments, see Use multiple environments in ASP.NET Core.

The Developer Exception Page can include the following information about the exception and the request:

  • Stack trace
  • Query string parameters, if any
  • Cookies, if any
  • Headers

The Developer Exception Page isn't guaranteed to provide any information. Use Logging for complete error information.

Exception handler page

To configure a custom error handling page for the Production environment, call UseExceptionHandler. This exception handling middleware:

  • Catches and logs unhandled exceptions.
  • Re-executes the request in an alternate pipeline using the path indicated. The request isn't re-executed if the response has started. The template-generated code re-executes the request using the var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler("/Error");  
    app.UseHsts();  
    
    } app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

    4 path.

Warning

If the alternate pipeline throws an exception of its own, Exception Handling Middleware rethrows the original exception.

Since this middleware can re-execute the request pipeline:

  • Middlewares need to handle reentrancy with the same request. This normally means either cleaning up their state after calling var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler("/Error");  
    app.UseHsts();  
    
    } app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

    5 or caching their processing on the

    var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler("/Error");  
    app.UseHsts();  
    
    } app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

    6 to avoid redoing it. When dealing with the request body, this either means buffering or caching the results like the Form reader.
  • For the overload that is used in templates, only the request path is modified, and the route data is cleared. Request data such as headers, method, and items are all reused as-is.
  • Scoped services remain the same.

In the following example, UseExceptionHandler adds the exception handling middleware in non-Development environments:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
}

The Razor Pages app template provides an Error page (

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

  1. and PageModel class (

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

  1. in the Pages folder. For an MVC app, the project template includes an

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

9 action method and an Error view for the Home controller.

The exception handling middleware re-executes the request using the original HTTP method. If an error handler endpoint is restricted to a specific set of HTTP methods, it runs only for those HTTP methods. For example, an MVC controller action that uses the

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

00 attribute runs only for GET requests. To ensure that all requests reach the custom error handling page, don't restrict them to a specific set of HTTP methods.

To handle exceptions differently based on the original HTTP method:

  • For Razor Pages, create multiple handler methods. For example, use [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    01 to handle GET exceptions and use

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    02 to handle POST exceptions.
  • For MVC, apply HTTP verb attributes to multiple actions. For example, use [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    00 to handle GET exceptions and use

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    04 to handle POST exceptions.

To allow unauthenticated users to view the custom error handling page, ensure that it supports anonymous access.

Access the exception

Use IExceptionHandlerPathFeature to access the exception and the original request path in an error handler. The following example uses

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

05 to get more information about the exception that was thrown:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

Warning

Do not serve sensitive error information to clients. Serving errors is a security risk.

Exception handler lambda

An alternative to a is to provide a lambda to UseExceptionHandler. Using a lambda allows access to the error before returning the response.

The following code uses a lambda for exception handling:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

Warning

Do not serve sensitive error information to clients. Serving errors is a security risk.

IExceptionHandler

is an interface that gives the developer a callback for handling known exceptions in a central location.

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

06 implementations are registered by calling . The lifetime of an

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

06 instance is singleton. Multiple implementations can be added, and they're called in the order registered.

If an exception handler handles a request, it can return

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

09 to stop processing. If an exception isn't handled by any exception handler, then control falls back to the default behavior and options from the middleware. Different metrics and logs are emitted for handled versus unhandled exceptions.

The following example shows an

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

06 implementation:

using Microsoft.AspNetCore.Diagnostics; namespace ErrorHandlingSample {

public class CustomExceptionHandler : IExceptionHandler
{
    private readonly ILogger logger;
    public CustomExceptionHandler(ILogger logger)
    {
        this.logger = logger;
    }
    public ValueTask TryHandleAsync(
        HttpContext httpContext,
        Exception exception,
        CancellationToken cancellationToken)
    {
        var exceptionMessage = exception.Message;
        logger.LogError(
            "Error Message: {exceptionMessage}, Time of occurrence {time}",
            exceptionMessage, DateTime.UtcNow);
        // Return false to continue with the default behavior
        // - or - return true to signal that this exception is handled
        return ValueTask.FromResult(false);
    }
}
}

The following example shows how to register an

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

06 implementation for dependency injection:

using ErrorHandlingSample; var builder = WebApplication.CreateBuilder(args); builder.Services.AddDatabaseDeveloperPageExceptionFilter(); builder.Services.AddRazorPages(); builder.Services.AddExceptionHandler(); var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} // Remaining Program.cs code omitted for brevity

When the preceding code runs in the Development environment:

  • The [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    12 is called first to handle an exception.
  • After logging the exception, the [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    13 method returns

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    14, so the is shown.

In other environments:

  • The [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    12 is called first to handle an exception.
  • After logging the exception, the [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    13 method returns

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    14, so the is shown.

UseStatusCodePages

By default, an ASP.NET Core app doesn't provide a status code page for HTTP error status codes, such as 404 - Not Found. When the app sets an HTTP 400-599 error status code that doesn't have a body, it returns the status code and an empty response body. To enable default text-only handlers for common error status codes, call UseStatusCodePages in

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

19:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePages();

Call

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 before request handling middleware. For example, call

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 before the Static File Middleware and the Endpoints Middleware.

When

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 isn't used, navigating to a URL without an endpoint returns a browser-dependent error message indicating the endpoint can't be found. When

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 is called, the browser returns the following response:

Status Code: 404; Not Found

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 isn't typically used in production because it returns a message that isn't useful to users.

Note

The status code pages middleware does not catch exceptions. To provide a custom error handling page, use the .

UseStatusCodePages with format string

To customize the response content type and text, use the overload of UseStatusCodePages that takes a content type and format string:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} // using static System.Net.Mime.MediaTypeNames; app.UseStatusCodePages(Text.Plain, "Status Code Page: {0}");

In the preceding code,

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

25 is a placeholder for the error code.

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 with a format string isn't typically used in production because it returns a message that isn't useful to users.

UseStatusCodePages with lambda

To specify custom error-handling and response-writing code, use the overload of UseStatusCodePages that takes a lambda expression:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePages(async statusCodeContext => {
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
    $"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 with a lambda isn't typically used in production because it returns a message that isn't useful to users.

UseStatusCodePagesWithRedirects

The UseStatusCodePagesWithRedirects extension method:

  • Sends a 302 - Found status code to the client.
  • Redirects the client to the error handling endpoint provided in the URL template. The error handling endpoint typically displays error information and returns HTTP 200.

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

The URL template can include a

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

25 placeholder for the status code, as shown in the preceding code. If the URL template starts with

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

29 (tilde), the

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

29 is replaced by the app's

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

31. When specifying an endpoint in the app, create an MVC view or Razor page for the endpoint.

This method is commonly used when the app:

  • Should redirect the client to a different endpoint, usually in cases where a different app processes the error. For web apps, the client's browser address bar reflects the redirected endpoint.
  • Shouldn't preserve and return the original status code with the initial redirect response.

UseStatusCodePagesWithReExecute

The UseStatusCodePagesWithReExecute extension method:

  • Generates the response body by re-executing the request pipeline using an alternate path.
  • Does not alter the status code before or after re-executing the pipeline.

The new pipeline execution may alter the response's status code, as the new pipeline has full control of the status code. If the new pipeline does not alter the status code, the original status code will be sent to the client.

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

0

If an endpoint within the app is specified, create an MVC view or Razor page for the endpoint.

This method is commonly used when the app should:

  • Process the request without redirecting to a different endpoint. For web apps, the client's browser address bar reflects the originally requested endpoint.
  • Preserve and return the original status code with the response.

The URL template must start with

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

32 and may include a placeholder

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

25 for the status code. To pass the status code as a query-string parameter, pass a second argument into

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

34. For example:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

1

The endpoint that processes the error can get the original URL that generated the error, as shown in the following example:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

2

Since this middleware can re-execute the request pipeline:

  • Middlewares need to handle reentrancy with the same request. This normally means either cleaning up their state after calling var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler("/Error");  
    app.UseHsts();  
    
    } app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

    5 or caching their processing on the

    var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler("/Error");  
    app.UseHsts();  
    
    } app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

    6 to avoid redoing it. When dealing with the request body, this either means buffering or caching the results like the Form reader.
  • Scoped services remain the same.

Disable status code pages

To disable status code pages for an MVC controller or action method, use the [SkipStatusCodePages] attribute.

To disable status code pages for specific requests in a Razor Pages handler method or in an MVC controller, use IStatusCodePagesFeature:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

3

Exception-handling code

Code in exception handling pages can also throw exceptions. Production error pages should be tested thoroughly and take extra care to avoid throwing exceptions of their own.

Response headers

Once the headers for a response are sent:

  • The app can't change the response's status code.
  • Any exception pages or handlers can't run. The response must be completed or the connection aborted.

Server exception handling

In addition to the exception handling logic in an app, the HTTP server implementation can handle some exceptions. If the server catches an exception before response headers are sent, the server sends a

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

37 response without a response body. If the server catches an exception after response headers are sent, the server closes the connection. Requests that aren't handled by the app are handled by the server. Any exception that occurs when the server is handling the request is handled by the server's exception handling. The app's custom error pages, exception handling middleware, and filters don't affect this behavior.

Startup exception handling

Only the hosting layer can handle exceptions that take place during app startup. The host can be configured to and .

The hosting layer can show an error page for a captured startup error only if the error occurs after host address/port binding. If binding fails:

  • The hosting layer logs a critical exception.
  • The dotnet process crashes.
  • No error page is displayed when the HTTP server is Kestrel.

When running on IIS (or Azure App Service) or IIS Express, a 502.5 - Process Failure is returned by the ASP.NET Core Module if the process can't start. For more information, see Troubleshoot ASP.NET Core on Azure App Service and IIS.

Database error page

The Database developer page exception filter AddDatabaseDeveloperPageExceptionFilter captures database-related exceptions that can be resolved by using Entity Framework Core migrations. When these exceptions occur, an HTML response is generated with details of possible actions to resolve the issue. This page is enabled only in the Development environment. The following code adds the Database developer page exception filter:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

4

Exception filters

In MVC apps, exception filters can be configured globally or on a per-controller or per-action basis. In Razor Pages apps, they can be configured globally or per page model. These filters handle any unhandled exceptions that occur during the execution of a controller action or another filter. For more information, see .

Exception filters are useful for trapping exceptions that occur within MVC actions, but they're not as flexible as the built-in exception handling middleware, UseExceptionHandler. We recommend using

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

38, unless you need to perform error handling differently based on which MVC action is chosen.

Model state errors

For information about how to handle model state errors, see Model binding and Model validation.

Problem details

Problem Details are not the only response format to describe an HTTP API error, however, they are commonly used to report errors for HTTP APIs.

The problem details service implements the IProblemDetailsService interface, which supports creating problem details in ASP.NET Core. The

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

39 extension method on IServiceCollection registers the default

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

40 implementation.

In ASP.NET Core apps, the following middleware generates problem details HTTP responses when

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

39 is called, except when the

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

42 request HTTP header doesn't include one of the content types supported by the registered IProblemDetailsWriter (default:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

43):

  • ExceptionHandlerMiddleware: Generates a problem details response when a custom handler is not defined.
  • StatusCodePagesMiddleware: Generates a problem details response by default.
  • DeveloperExceptionPageMiddleware: Generates a problem details response in development when the [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    42 request HTTP header does not include

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    45.

The following code configures the app to generate a problem details response for all HTTP client and server error responses that don't have a body content yet:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

5

The next section shows how to customize the problem details response body.

Customize problem details

The automatic creation of a

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

46 can be customized using any of the following options:

  1. Use
  2. Use a custom
  3. Call the

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

50 operation

The generated problem details can be customized using , and the customizations are applied to all auto-generated problem details.

The following code uses ProblemDetailsOptions to set :

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

6

For example, an

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

51 endpoint result produces the following problem details response body:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

7

Custom

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

48

An IProblemDetailsWriter implementation can be created for advanced customizations.

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

8

Note: When using a custom

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

48, the custom

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

48 must be registered before calling AddRazorPages, AddControllers, AddControllersWithViews, or AddMvc:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

9

Problem details from Middleware

An alternative approach to using ProblemDetailsOptions with is to set the in middleware. A problem details response can be written by calling

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

55:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

0

In the preceding code, the minimal API endpoints

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

56 and

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

57 return the expected custom problem response on error input.

The API controller endpoints return the default problem response on error input, not the custom problem response. The default problem response is returned because the API controller has written to the response stream, , before is called and the response is not written again.

The following

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

59 returns BadRequestResult, which writes to the response stream and therefore prevents the custom problem response from being returned.

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

1

The following

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

60 returns

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

61 so the expected custom problem result is returned:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

2

Produce a ProblemDetails payload for exceptions

Consider the following app:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

3

In non-development environments, when an exception occurs, the following is a standard ProblemDetails response that is returned to the client:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

4

For most apps, the preceding code is all that's needed for exceptions. However, the following section shows how to get more detailed problem responses.

An alternative to a is to provide a lambda to UseExceptionHandler. Using a lambda allows access to the error and writing a problem details response with

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

55:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

5

Warning

Do not serve sensitive error information to clients. Serving errors is a security risk.

An alternative approach to generate problem details is to use the third-party NuGet package Hellang.Middleware.ProblemDetails that can be used to map exceptions and client errors to problem details.

Additional resources

  • View or download sample code ()
  • Troubleshoot ASP.NET Core on Azure App Service and IIS
  • Common error troubleshooting for Azure App Service and IIS with ASP.NET Core
  • Handle errors in ASP.NET Core web APIs
  • Handle errors in Minimal API apps.

By Tom Dykstra

This article covers common approaches to handling errors in ASP.NET Core web apps. See also Handle errors in ASP.NET Core web APIs and Handle errors in Minimal API apps.

Developer exception page

The Developer Exception Page displays detailed information about unhandled request exceptions. ASP.NET Core apps enable the developer exception page by default when both:

  • Running in the Development environment.
  • App created with the current templates, that is, using WebApplication.CreateBuilder. Apps created using the must enable the developer exception page by calling var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler("/Error");  
    app.UseHsts();  
    
    } app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

    2 in

    var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler("/Error");  
    app.UseHsts();  
    
    } app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

    3.

The developer exception page runs early in the middleware pipeline, so that it can catch unhandled exceptions thrown in middleware that follows.

Detailed exception information shouldn't be displayed publicly when the app runs in the Production environment. For more information on configuring environments, see Use multiple environments in ASP.NET Core.

The Developer Exception Page can include the following information about the exception and the request:

  • Stack trace
  • Query string parameters, if any
  • Cookies, if any
  • Headers

The Developer Exception Page isn't guaranteed to provide any information. Use Logging for complete error information.

Exception handler page

To configure a custom error handling page for the Production environment, call UseExceptionHandler. This exception handling middleware:

  • Catches and logs unhandled exceptions.
  • Re-executes the request in an alternate pipeline using the path indicated. The request isn't re-executed if the response has started. The template-generated code re-executes the request using the var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler("/Error");  
    app.UseHsts();  
    
    } app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

    4 path.

Warning

If the alternate pipeline throws an exception of its own, Exception Handling Middleware rethrows the original exception.

Since this middleware can re-execute the request pipeline:

  • Middlewares need to handle reentrancy with the same request. This normally means either cleaning up their state after calling var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler("/Error");  
    app.UseHsts();  
    
    } app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

    5 or caching their processing on the

    var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler("/Error");  
    app.UseHsts();  
    
    } app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

    6 to avoid redoing it. When dealing with the request body, this either means buffering or caching the results like the Form reader.
  • For the overload that is used in templates, only the request path is modified, and the route data is cleared. Request data such as headers, method, and items are all reused as-is.
  • Scoped services remain the same.

In the following example, UseExceptionHandler adds the exception handling middleware in non-Development environments:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
}

The Razor Pages app template provides an Error page (

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

  1. and PageModel class (

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

  1. in the Pages folder. For an MVC app, the project template includes an

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

9 action method and an Error view for the Home controller.

The exception handling middleware re-executes the request using the original HTTP method. If an error handler endpoint is restricted to a specific set of HTTP methods, it runs only for those HTTP methods. For example, an MVC controller action that uses the

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

00 attribute runs only for GET requests. To ensure that all requests reach the custom error handling page, don't restrict them to a specific set of HTTP methods.

To handle exceptions differently based on the original HTTP method:

  • For Razor Pages, create multiple handler methods. For example, use [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    01 to handle GET exceptions and use

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    02 to handle POST exceptions.
  • For MVC, apply HTTP verb attributes to multiple actions. For example, use [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    00 to handle GET exceptions and use

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    04 to handle POST exceptions.

To allow unauthenticated users to view the custom error handling page, ensure that it supports anonymous access.

Access the exception

Use IExceptionHandlerPathFeature to access the exception and the original request path in an error handler. The following example uses

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

05 to get more information about the exception that was thrown:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

Warning

Do not serve sensitive error information to clients. Serving errors is a security risk.

Exception handler lambda

An alternative to a is to provide a lambda to UseExceptionHandler. Using a lambda allows access to the error before returning the response.

The following code uses a lambda for exception handling:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

Warning

Do not serve sensitive error information to clients. Serving errors is a security risk.

UseStatusCodePages

By default, an ASP.NET Core app doesn't provide a status code page for HTTP error status codes, such as 404 - Not Found. When the app sets an HTTP 400-599 error status code that doesn't have a body, it returns the status code and an empty response body. To enable default text-only handlers for common error status codes, call UseStatusCodePages in

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

19:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePages();

Call

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 before request handling middleware. For example, call

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 before the Static File Middleware and the Endpoints Middleware.

When

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 isn't used, navigating to a URL without an endpoint returns a browser-dependent error message indicating the endpoint can't be found. When

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 is called, the browser returns the following response:

Status Code: 404; Not Found

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 isn't typically used in production because it returns a message that isn't useful to users.

Note

The status code pages middleware does not catch exceptions. To provide a custom error handling page, use the .

UseStatusCodePages with format string

To customize the response content type and text, use the overload of UseStatusCodePages that takes a content type and format string:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} // using static System.Net.Mime.MediaTypeNames; app.UseStatusCodePages(Text.Plain, "Status Code Page: {0}");

In the preceding code,

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

25 is a placeholder for the error code.

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 with a format string isn't typically used in production because it returns a message that isn't useful to users.

UseStatusCodePages with lambda

To specify custom error-handling and response-writing code, use the overload of UseStatusCodePages that takes a lambda expression:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePages(async statusCodeContext => {
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
    $"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 with a lambda isn't typically used in production because it returns a message that isn't useful to users.

UseStatusCodePagesWithRedirects

The UseStatusCodePagesWithRedirects extension method:

  • Sends a 302 - Found status code to the client.
  • Redirects the client to the error handling endpoint provided in the URL template. The error handling endpoint typically displays error information and returns HTTP 200.

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

The URL template can include a

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

25 placeholder for the status code, as shown in the preceding code. If the URL template starts with

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

29 (tilde), the

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

29 is replaced by the app's

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

31. When specifying an endpoint in the app, create an MVC view or Razor page for the endpoint.

This method is commonly used when the app:

  • Should redirect the client to a different endpoint, usually in cases where a different app processes the error. For web apps, the client's browser address bar reflects the redirected endpoint.
  • Shouldn't preserve and return the original status code with the initial redirect response.

UseStatusCodePagesWithReExecute

The UseStatusCodePagesWithReExecute extension method:

  • Generates the response body by re-executing the request pipeline using an alternate path.
  • Does not alter the status code before or after re-executing the pipeline.

The new pipeline execution may alter the response's status code, as the new pipeline has full control of the status code. If the new pipeline does not alter the status code, the original status code will be sent to the client.

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

0

If an endpoint within the app is specified, create an MVC view or Razor page for the endpoint.

This method is commonly used when the app should:

  • Process the request without redirecting to a different endpoint. For web apps, the client's browser address bar reflects the originally requested endpoint.
  • Preserve and return the original status code with the response.

The URL template must start with

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

32 and may include a placeholder

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

25 for the status code. To pass the status code as a query-string parameter, pass a second argument into

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

34. For example:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

1

The endpoint that processes the error can get the original URL that generated the error, as shown in the following example:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

2

Since this middleware can re-execute the request pipeline:

  • Middlewares need to handle reentrancy with the same request. This normally means either cleaning up their state after calling var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler("/Error");  
    app.UseHsts();  
    
    } app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

    5 or caching their processing on the

    var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler("/Error");  
    app.UseHsts();  
    
    } app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

    6 to avoid redoing it. When dealing with the request body, this either means buffering or caching the results like the Form reader.
  • Scoped services remain the same.

Disable status code pages

To disable status code pages for an MVC controller or action method, use the [SkipStatusCodePages] attribute.

To disable status code pages for specific requests in a Razor Pages handler method or in an MVC controller, use IStatusCodePagesFeature:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

3

Exception-handling code

Code in exception handling pages can also throw exceptions. Production error pages should be tested thoroughly and take extra care to avoid throwing exceptions of their own.

Response headers

Once the headers for a response are sent:

  • The app can't change the response's status code.
  • Any exception pages or handlers can't run. The response must be completed or the connection aborted.

Server exception handling

In addition to the exception handling logic in an app, the HTTP server implementation can handle some exceptions. If the server catches an exception before response headers are sent, the server sends a

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

37 response without a response body. If the server catches an exception after response headers are sent, the server closes the connection. Requests that aren't handled by the app are handled by the server. Any exception that occurs when the server is handling the request is handled by the server's exception handling. The app's custom error pages, exception handling middleware, and filters don't affect this behavior.

Startup exception handling

Only the hosting layer can handle exceptions that take place during app startup. The host can be configured to and .

The hosting layer can show an error page for a captured startup error only if the error occurs after host address/port binding. If binding fails:

  • The hosting layer logs a critical exception.
  • The dotnet process crashes.
  • No error page is displayed when the HTTP server is Kestrel.

When running on IIS (or Azure App Service) or IIS Express, a 502.5 - Process Failure is returned by the ASP.NET Core Module if the process can't start. For more information, see Troubleshoot ASP.NET Core on Azure App Service and IIS.

Database error page

The Database developer page exception filter AddDatabaseDeveloperPageExceptionFilter captures database-related exceptions that can be resolved by using Entity Framework Core migrations. When these exceptions occur, an HTML response is generated with details of possible actions to resolve the issue. This page is enabled only in the Development environment. The following code adds the Database developer page exception filter:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

4

Exception filters

In MVC apps, exception filters can be configured globally or on a per-controller or per-action basis. In Razor Pages apps, they can be configured globally or per page model. These filters handle any unhandled exceptions that occur during the execution of a controller action or another filter. For more information, see .

Exception filters are useful for trapping exceptions that occur within MVC actions, but they're not as flexible as the built-in exception handling middleware, UseExceptionHandler. We recommend using

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

38, unless you need to perform error handling differently based on which MVC action is chosen.

Model state errors

For information about how to handle model state errors, see Model binding and Model validation.

Problem details

Problem Details are not the only response format to describe an HTTP API error, however, they are commonly used to report errors for HTTP APIs.

The problem details service implements the IProblemDetailsService interface, which supports creating problem details in ASP.NET Core. The

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

39 extension method on IServiceCollection registers the default

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

40 implementation.

In ASP.NET Core apps, the following middleware generates problem details HTTP responses when

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

39 is called, except when the

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

42 request HTTP header doesn't include one of the content types supported by the registered IProblemDetailsWriter (default:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

43):

  • ExceptionHandlerMiddleware: Generates a problem details response when a custom handler is not defined.
  • StatusCodePagesMiddleware: Generates a problem details response by default.
  • DeveloperExceptionPageMiddleware: Generates a problem details response in development when the [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    42 request HTTP header does not include

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    45.

The following code configures the app to generate a problem details response for all HTTP client and server error responses that don't have a body content yet:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

5

The next section shows how to customize the problem details response body.

Customize problem details

The automatic creation of a

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

46 can be customized using any of the following options:

  1. Use
  2. Use a custom
  3. Call the

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

50 operation

The generated problem details can be customized using , and the customizations are applied to all auto-generated problem details.

The following code uses ProblemDetailsOptions to set :

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

6

For example, an

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

51 endpoint result produces the following problem details response body:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

7

Custom

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

48

An IProblemDetailsWriter implementation can be created for advanced customizations.

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

8

Note: When using a custom

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

48, the custom

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

48 must be registered before calling AddRazorPages, AddControllers, AddControllersWithViews, or AddMvc:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

9

Problem details from Middleware

An alternative approach to using ProblemDetailsOptions with is to set the in middleware. A problem details response can be written by calling

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

55:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

0

In the preceding code, the minimal API endpoints

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

56 and

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

57 return the expected custom problem response on error input.

The API controller endpoints return the default problem response on error input, not the custom problem response. The default problem response is returned because the API controller has written to the response stream, , before is called and the response is not written again.

The following

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

59 returns BadRequestResult, which writes to the response stream and therefore prevents the custom problem response from being returned.

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

1

The following

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

60 returns

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

61 so the expected custom problem result is returned:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

2

Produce a ProblemDetails payload for exceptions

Consider the following app:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

3

In non-development environments, when an exception occurs, the following is a standard ProblemDetails response that is returned to the client:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

4

For most apps, the preceding code is all that's needed for exceptions. However, the following section shows how to get more detailed problem responses.

An alternative to a is to provide a lambda to UseExceptionHandler. Using a lambda allows access to the error and writing a problem details response with

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

55:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

5

Warning

Do not serve sensitive error information to clients. Serving errors is a security risk.

An alternative approach to generate problem details is to use the third-party NuGet package Hellang.Middleware.ProblemDetails that can be used to map exceptions and client errors to problem details.

Additional resources

  • View or download sample code ()
  • Troubleshoot ASP.NET Core on Azure App Service and IIS
  • Common error troubleshooting for Azure App Service and IIS with ASP.NET Core

By Tom Dykstra

This article covers common approaches to handling errors in ASP.NET Core web apps. See Handle errors in ASP.NET Core web APIs for web APIs.

Developer exception page

The Developer Exception Page displays detailed information about unhandled request exceptions. ASP.NET Core apps enable the developer exception page by default when both:

  • Running in the Development environment.
  • App created with the current templates, that is, using WebApplication.CreateBuilder. Apps created using the must enable the developer exception page by calling var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler("/Error");  
    app.UseHsts();  
    
    } app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

    2 in

    var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler("/Error");  
    app.UseHsts();  
    
    } app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

    3.

The developer exception page runs early in the middleware pipeline, so that it can catch unhandled exceptions thrown in middleware that follows.

Detailed exception information shouldn't be displayed publicly when the app runs in the Production environment. For more information on configuring environments, see Use multiple environments in ASP.NET Core.

The Developer Exception Page can include the following information about the exception and the request:

  • Stack trace
  • Query string parameters, if any
  • Cookies, if any
  • Headers

The Developer Exception Page isn't guaranteed to provide any information. Use Logging for complete error information.

Exception handler page

To configure a custom error handling page for the Production environment, call UseExceptionHandler. This exception handling middleware:

  • Catches and logs unhandled exceptions.
  • Re-executes the request in an alternate pipeline using the path indicated. The request isn't re-executed if the response has started. The template-generated code re-executes the request using the var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler("/Error");  
    app.UseHsts();  
    
    } app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

    4 path.

Warning

If the alternate pipeline throws an exception of its own, Exception Handling Middleware rethrows the original exception.

In the following example, UseExceptionHandler adds the exception handling middleware in non-Development environments:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
}

The Razor Pages app template provides an Error page (

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

  1. and PageModel class (

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

  1. in the Pages folder. For an MVC app, the project template includes an

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

9 action method and an Error view for the Home controller.

The exception handling middleware re-executes the request using the original HTTP method. If an error handler endpoint is restricted to a specific set of HTTP methods, it runs only for those HTTP methods. For example, an MVC controller action that uses the

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

00 attribute runs only for GET requests. To ensure that all requests reach the custom error handling page, don't restrict them to a specific set of HTTP methods.

To handle exceptions differently based on the original HTTP method:

  • For Razor Pages, create multiple handler methods. For example, use [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    01 to handle GET exceptions and use

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    02 to handle POST exceptions.
  • For MVC, apply HTTP verb attributes to multiple actions. For example, use [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    00 to handle GET exceptions and use

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    04 to handle POST exceptions.

To allow unauthenticated users to view the custom error handling page, ensure that it supports anonymous access.

Access the exception

Use IExceptionHandlerPathFeature to access the exception and the original request path in an error handler. The following example uses

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

05 to get more information about the exception that was thrown:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

Warning

Do not serve sensitive error information to clients. Serving errors is a security risk.

Exception handler lambda

An alternative to a is to provide a lambda to UseExceptionHandler. Using a lambda allows access to the error before returning the response.

The following code uses a lambda for exception handling:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

Warning

Do not serve sensitive error information to clients. Serving errors is a security risk.

UseStatusCodePages

By default, an ASP.NET Core app doesn't provide a status code page for HTTP error status codes, such as 404 - Not Found. When the app sets an HTTP 400-599 error status code that doesn't have a body, it returns the status code and an empty response body. To enable default text-only handlers for common error status codes, call UseStatusCodePages in

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

19:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePages();

Call

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 before request handling middleware. For example, call

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 before the Static File Middleware and the Endpoints Middleware.

When

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 isn't used, navigating to a URL without an endpoint returns a browser-dependent error message indicating the endpoint can't be found. When

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 is called, the browser returns the following response:

Status Code: 404; Not Found

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 isn't typically used in production because it returns a message that isn't useful to users.

Note

The status code pages middleware does not catch exceptions. To provide a custom error handling page, use the .

UseStatusCodePages with format string

To customize the response content type and text, use the overload of UseStatusCodePages that takes a content type and format string:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} // using static System.Net.Mime.MediaTypeNames; app.UseStatusCodePages(Text.Plain, "Status Code Page: {0}");

In the preceding code,

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

25 is a placeholder for the error code.

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 with a format string isn't typically used in production because it returns a message that isn't useful to users.

UseStatusCodePages with lambda

To specify custom error-handling and response-writing code, use the overload of UseStatusCodePages that takes a lambda expression:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePages(async statusCodeContext => {
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
    $"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 with a lambda isn't typically used in production because it returns a message that isn't useful to users.

UseStatusCodePagesWithRedirects

The UseStatusCodePagesWithRedirects extension method:

  • Sends a 302 - Found status code to the client.
  • Redirects the client to the error handling endpoint provided in the URL template. The error handling endpoint typically displays error information and returns HTTP 200.

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

The URL template can include a

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

25 placeholder for the status code, as shown in the preceding code. If the URL template starts with

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

29 (tilde), the

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

29 is replaced by the app's

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

31. When specifying an endpoint in the app, create an MVC view or Razor page for the endpoint.

This method is commonly used when the app:

  • Should redirect the client to a different endpoint, usually in cases where a different app processes the error. For web apps, the client's browser address bar reflects the redirected endpoint.
  • Shouldn't preserve and return the original status code with the initial redirect response.

UseStatusCodePagesWithReExecute

The UseStatusCodePagesWithReExecute extension method:

  • Returns the original status code to the client.
  • Generates the response body by re-executing the request pipeline using an alternate path.

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

0

If an endpoint within the app is specified, create an MVC view or Razor page for the endpoint.

This method is commonly used when the app should:

  • Process the request without redirecting to a different endpoint. For web apps, the client's browser address bar reflects the originally requested endpoint.
  • Preserve and return the original status code with the response.

The URL template must start with

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

32 and may include a placeholder

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

25 for the status code. To pass the status code as a query-string parameter, pass a second argument into

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

34. For example:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePages();

9

The endpoint that processes the error can get the original URL that generated the error, as shown in the following example:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

2

Disable status code pages

To disable status code pages for an MVC controller or action method, use the [SkipStatusCodePages] attribute.

To disable status code pages for specific requests in a Razor Pages handler method or in an MVC controller, use IStatusCodePagesFeature:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

3

Exception-handling code

Code in exception handling pages can also throw exceptions. Production error pages should be tested thoroughly and take extra care to avoid throwing exceptions of their own.

Response headers

Once the headers for a response are sent:

  • The app can't change the response's status code.
  • Any exception pages or handlers can't run. The response must be completed or the connection aborted.

Server exception handling

In addition to the exception handling logic in an app, the HTTP server implementation can handle some exceptions. If the server catches an exception before response headers are sent, the server sends a

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

37 response without a response body. If the server catches an exception after response headers are sent, the server closes the connection. Requests that aren't handled by the app are handled by the server. Any exception that occurs when the server is handling the request is handled by the server's exception handling. The app's custom error pages, exception handling middleware, and filters don't affect this behavior.

Startup exception handling

Only the hosting layer can handle exceptions that take place during app startup. The host can be configured to and .

The hosting layer can show an error page for a captured startup error only if the error occurs after host address/port binding. If binding fails:

  • The hosting layer logs a critical exception.
  • The dotnet process crashes.
  • No error page is displayed when the HTTP server is Kestrel.

When running on IIS (or Azure App Service) or IIS Express, a 502.5 - Process Failure is returned by the ASP.NET Core Module if the process can't start. For more information, see Troubleshoot ASP.NET Core on Azure App Service and IIS.

Database error page

The Database developer page exception filter AddDatabaseDeveloperPageExceptionFilter captures database-related exceptions that can be resolved by using Entity Framework Core migrations. When these exceptions occur, an HTML response is generated with details of possible actions to resolve the issue. This page is enabled only in the Development environment. The following code adds the Database developer page exception filter:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

4

Exception filters

In MVC apps, exception filters can be configured globally or on a per-controller or per-action basis. In Razor Pages apps, they can be configured globally or per page model. These filters handle any unhandled exceptions that occur during the execution of a controller action or another filter. For more information, see .

Exception filters are useful for trapping exceptions that occur within MVC actions, but they're not as flexible as the built-in exception handling middleware, UseExceptionHandler. We recommend using

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

38, unless you need to perform error handling differently based on which MVC action is chosen.

Model state errors

For information about how to handle model state errors, see Model binding and Model validation.

Additional resources

  • View or download sample code ()
  • Troubleshoot ASP.NET Core on Azure App Service and IIS
  • Common error troubleshooting for Azure App Service and IIS with ASP.NET Core

By Kirk Larkin, Tom Dykstra, and Steve Smith

This article covers common approaches to handling errors in ASP.NET Core web apps. See Handle errors in ASP.NET Core web APIs for web APIs.

View or download sample code. (.) The network tab on the F12 browser developer tools is useful when testing the sample app.

Developer Exception Page

The Developer Exception Page displays detailed information about unhandled request exceptions. The ASP.NET Core templates generate the following code:

Status Code: 404; Not Found

3

The preceding highlighted code enables the developer exception page when the app is running in the Development environment.

The templates place UseDeveloperExceptionPage early in the middleware pipeline so that it can catch unhandled exceptions thrown in middleware that follows.

The preceding code enables the Developer Exception Page only when the app runs in the Development environment. Detailed exception information shouldn't be displayed publicly when the app runs in the Production environment. For more information on configuring environments, see Use multiple environments in ASP.NET Core.

The Developer Exception Page can include the following information about the exception and the request:

  • Stack trace
  • Query string parameters if any
  • Cookies if any
  • Headers

The Developer Exception Page isn't guaranteed to provide any information. Use Logging for complete error information.

Exception handler page

To configure a custom error handling page for the Production environment, call UseExceptionHandler. This exception handling middleware:

  • Catches and logs unhandled exceptions.
  • Re-executes the request in an alternate pipeline using the path indicated. The request isn't re-executed if the response has started. The template-generated code re-executes the request using the var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler("/Error");  
    app.UseHsts();  
    
    } app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

    4 path.

Warning

If the alternate pipeline throws an exception of its own, Exception Handling Middleware rethrows the original exception.

In the following example, UseExceptionHandler adds the exception handling middleware in non-Development environments:

Status Code: 404; Not Found

4

The Razor Pages app template provides an Error page (

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

  1. and PageModel class (

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

  1. in the Pages folder. For an MVC app, the project template includes an

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

9 action method and an Error view for the Home controller.

The exception handling middleware re-executes the request using the original HTTP method. If an error handler endpoint is restricted to a specific set of HTTP methods, it runs only for those HTTP methods. For example, an MVC controller action that uses the

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

00 attribute runs only for GET requests. To ensure that all requests reach the custom error handling page, don't restrict them to a specific set of HTTP methods.

To handle exceptions differently based on the original HTTP method:

  • For Razor Pages, create multiple handler methods. For example, use [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    01 to handle GET exceptions and use

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    02 to handle POST exceptions.
  • For MVC, apply HTTP verb attributes to multiple actions. For example, use [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    00 to handle GET exceptions and use

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    04 to handle POST exceptions.

To allow unauthenticated users to view the custom error handling page, ensure that it supports anonymous access.

Access the exception

Use IExceptionHandlerPathFeature to access the exception and the original request path in an error handler. The following code adds

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

62 to the default

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

63 generated by the ASP.NET Core templates:

Status Code: 404; Not Found

5

Warning

Do not serve sensitive error information to clients. Serving errors is a security risk.

To test the exception in the sample app:

  • Set the environment to production.
  • Remove the comments from var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler(exceptionHandlerApp =>  
    {  
        exceptionHandlerApp.Run(async context =>  
        {  
            context.Response.StatusCode = StatusCodes.Status500InternalServerError;  
            // using static System.Net.Mime.MediaTypeNames;  
            context.Response.ContentType = Text.Plain;  
            await context.Response.WriteAsync("An exception was thrown.");  
            var exceptionHandlerPathFeature =  
                context.Features.Get();  
            if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
            {  
                await context.Response.WriteAsync(" The file was not found.");  
            }  
            if (exceptionHandlerPathFeature?.Path == "/")  
            {  
                await context.Response.WriteAsync(" Page: Home.");  
            }  
        });  
    });  
    app.UseHsts();  
    
    }

    64 in

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    19.
  • Select Trigger an exception on the home page.

Exception handler lambda

An alternative to a is to provide a lambda to UseExceptionHandler. Using a lambda allows access to the error before returning the response.

The following code uses a lambda for exception handling:

Status Code: 404; Not Found

6

To test the exception handling lambda in the sample app:

  • Set the environment to production.
  • Remove the comments from var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler(exceptionHandlerApp =>  
    {  
        exceptionHandlerApp.Run(async context =>  
        {  
            context.Response.StatusCode = StatusCodes.Status500InternalServerError;  
            // using static System.Net.Mime.MediaTypeNames;  
            context.Response.ContentType = Text.Plain;  
            await context.Response.WriteAsync("An exception was thrown.");  
            var exceptionHandlerPathFeature =  
                context.Features.Get();  
            if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
            {  
                await context.Response.WriteAsync(" The file was not found.");  
            }  
            if (exceptionHandlerPathFeature?.Path == "/")  
            {  
                await context.Response.WriteAsync(" Page: Home.");  
            }  
        });  
    });  
    app.UseHsts();  
    
    }

    66 in

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    19.
  • Select Trigger an exception on the home page.

UseStatusCodePages

By default, an ASP.NET Core app doesn't provide a status code page for HTTP error status codes, such as 404 - Not Found. When the app sets an HTTP 400-599 error status code that doesn't have a body, it returns the status code and an empty response body. To provide status code pages, use the status code pages middleware. To enable default text-only handlers for common error status codes, call UseStatusCodePages in the

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

68 method:

Status Code: 404; Not Found

7

Call

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 before request handling middleware. For example, call

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 before the Static File Middleware and the Endpoints Middleware.

When

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 isn't used, navigating to a URL without an endpoint returns a browser-dependent error message indicating the endpoint can't be found. For example, navigating to

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

72. When

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 is called, the browser returns:

Status Code: 404; Not Found

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 isn't typically used in production because it returns a message that isn't useful to users.

To test

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 in the sample app:

  • Set the environment to production.
  • Remove the comments from var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler(exceptionHandlerApp =>  
    {  
        exceptionHandlerApp.Run(async context =>  
        {  
            context.Response.StatusCode = StatusCodes.Status500InternalServerError;  
            // using static System.Net.Mime.MediaTypeNames;  
            context.Response.ContentType = Text.Plain;  
            await context.Response.WriteAsync("An exception was thrown.");  
            var exceptionHandlerPathFeature =  
                context.Features.Get();  
            if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
            {  
                await context.Response.WriteAsync(" The file was not found.");  
            }  
            if (exceptionHandlerPathFeature?.Path == "/")  
            {  
                await context.Response.WriteAsync(" Page: Home.");  
            }  
        });  
    });  
    app.UseHsts();  
    
    }

    76 in

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

    [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

    public string? RequestId { get; set; }  
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);  
    public string? ExceptionMessage { get; set; }  
    public void OnGet()  
    {  
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;  
        var exceptionHandlerPathFeature =  
            HttpContext.Features.Get();  
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)  
        {  
            ExceptionMessage = "The file was not found.";  
        }  
        if (exceptionHandlerPathFeature?.Path == "/")  
        {  
            ExceptionMessage ??= string.Empty;  
            ExceptionMessage += " Page: Home.";  
        }  
    }  
    
    }

    19.
  • Select the links on the home page on the home page.

Note

The status code pages middleware does not catch exceptions. To provide a custom error handling page, use the .

UseStatusCodePages with format string

To customize the response content type and text, use the overload of UseStatusCodePages that takes a content type and format string:

Status Code: 404; Not Found

9

In the preceding code,

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

25 is a placeholder for the error code.

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 with a format string isn't typically used in production because it returns a message that isn't useful to users.

To test

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 in the sample app, remove the comments from

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

81 in

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

19.

UseStatusCodePages with lambda

To specify custom error-handling and response-writing code, use the overload of UseStatusCodePages that takes a lambda expression:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} // using static System.Net.Mime.MediaTypeNames; app.UseStatusCodePages(Text.Plain, "Status Code Page: {0}");

0

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 with a lambda isn't typically used in production because it returns a message that isn't useful to users.

To test

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 in the sample app, remove the comments from

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

85 in

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

19.

UseStatusCodePagesWithRedirects

The UseStatusCodePagesWithRedirects extension method:

  • Sends a 302 - Found status code to the client.
  • Redirects the client to the error handling endpoint provided in the URL template. The error handling endpoint typically displays error information and returns HTTP 200.

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} // using static System.Net.Mime.MediaTypeNames; app.UseStatusCodePages(Text.Plain, "Status Code Page: {0}");

1

The URL template can include a

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

25 placeholder for the status code, as shown in the preceding code. If the URL template starts with

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

29 (tilde), the

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

29 is replaced by the app's

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

31. When specifying an endpoint in the app, create an MVC view or Razor page for the endpoint. For a Razor Pages example, see Pages/MyStatusCode.cshtml in the sample app.

This method is commonly used when the app:

  • Should redirect the client to a different endpoint, usually in cases where a different app processes the error. For web apps, the client's browser address bar reflects the redirected endpoint.
  • Shouldn't preserve and return the original status code with the initial redirect response.

To test

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 in the sample app, remove the comments from

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

92 in

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

19.

UseStatusCodePagesWithReExecute

The UseStatusCodePagesWithReExecute extension method:

  • Returns the original status code to the client.
  • Generates the response body by re-executing the request pipeline using an alternate path.

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} // using static System.Net.Mime.MediaTypeNames; app.UseStatusCodePages(Text.Plain, "Status Code Page: {0}");

2

If an endpoint within the app is specified, create an MVC view or Razor page for the endpoint. Ensure

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

34 is placed before

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

95 so the request can be rerouted to the status page. For a Razor Pages example, see Pages/MyStatusCode2.cshtml in the sample app.

This method is commonly used when the app should:

  • Process the request without redirecting to a different endpoint. For web apps, the client's browser address bar reflects the originally requested endpoint.
  • Preserve and return the original status code with the response.

The URL and query string templates may include a placeholder

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

25 for the status code. The URL template must start with

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

32.

The endpoint that processes the error can get the original URL that generated the error, as shown in the following example:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} // using static System.Net.Mime.MediaTypeNames; app.UseStatusCodePages(Text.Plain, "Status Code Page: {0}");

3

For a Razor Pages example, see Pages/MyStatusCode2.cshtml in the sample app.

To test

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 in the sample app, remove the comments from

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

99 in

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

19.

Disable status code pages

To disable status code pages for an MVC controller or action method, use the [SkipStatusCodePages] attribute.

To disable status code pages for specific requests in a Razor Pages handler method or in an MVC controller, use IStatusCodePagesFeature:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} // using static System.Net.Mime.MediaTypeNames; app.UseStatusCodePages(Text.Plain, "Status Code Page: {0}");

4

Exception-handling code

Code in exception handling pages can also throw exceptions. Production error pages should be tested thoroughly and take extra care to avoid throwing exceptions of their own.

Response headers

Once the headers for a response are sent:

  • The app can't change the response's status code.
  • Any exception pages or handlers can't run. The response must be completed or the connection aborted.

Server exception handling

In addition to the exception handling logic in an app, the HTTP server implementation can handle some exceptions. If the server catches an exception before response headers are sent, the server sends a

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

37 response without a response body. If the server catches an exception after response headers are sent, the server closes the connection. Requests that aren't handled by the app are handled by the server. Any exception that occurs when the server is handling the request is handled by the server's exception handling. The app's custom error pages, exception handling middleware, and filters don't affect this behavior.

Startup exception handling

Only the hosting layer can handle exceptions that take place during app startup. The host can be configured to and .

The hosting layer can show an error page for a captured startup error only if the error occurs after host address/port binding. If binding fails:

  • The hosting layer logs a critical exception.
  • The dotnet process crashes.
  • No error page is displayed when the HTTP server is Kestrel.

When running on IIS (or Azure App Service) or IIS Express, a 502.5 - Process Failure is returned by the ASP.NET Core Module if the process can't start. For more information, see Troubleshoot ASP.NET Core on Azure App Service and IIS.

Database error page

The Database developer page exception filter

using Microsoft.AspNetCore.Diagnostics; namespace ErrorHandlingSample {

public class CustomExceptionHandler : IExceptionHandler
{
    private readonly ILogger logger;
    public CustomExceptionHandler(ILogger logger)
    {
        this.logger = logger;
    }
    public ValueTask TryHandleAsync(
        HttpContext httpContext,
        Exception exception,
        CancellationToken cancellationToken)
    {
        var exceptionMessage = exception.Message;
        logger.LogError(
            "Error Message: {exceptionMessage}, Time of occurrence {time}",
            exceptionMessage, DateTime.UtcNow);
        // Return false to continue with the default behavior
        // - or - return true to signal that this exception is handled
        return ValueTask.FromResult(false);
    }
}
}

02 captures database-related exceptions that can be resolved by using Entity Framework Core migrations. When these exceptions occur, an HTML response is generated with details of possible actions to resolve the issue. This page is enabled only in the Development environment. The following code was generated by the ASP.NET Core Razor Pages templates when individual user accounts were specified:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} // using static System.Net.Mime.MediaTypeNames; app.UseStatusCodePages(Text.Plain, "Status Code Page: {0}");

5

Exception filters

In MVC apps, exception filters can be configured globally or on a per-controller or per-action basis. In Razor Pages apps, they can be configured globally or per page model. These filters handle any unhandled exceptions that occur during the execution of a controller action or another filter. For more information, see .

Exception filters are useful for trapping exceptions that occur within MVC actions, but they're not as flexible as the built-in exception handling middleware,

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

38. We recommend using

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

38, unless you need to perform error handling differently based on which MVC action is chosen.

Status Code: 404; Not Found

3

Model state errors

For information about how to handle model state errors, see Model binding and Model validation.

Additional resources

  • Troubleshoot ASP.NET Core on Azure App Service and IIS
  • Common error troubleshooting for Azure App Service and IIS with ASP.NET Core

By Tom Dykstra, and Steve Smith

This article covers common approaches to handling errors in ASP.NET Core web apps. See Handle errors in ASP.NET Core web APIs for web APIs.

View or download sample code. (.)

Developer Exception Page

The Developer Exception Page displays detailed information about request exceptions. The ASP.NET Core templates generate the following code:

Status Code: 404; Not Found

4

The preceding code enables the developer exception page when the app is running in the Development environment.

The templates place UseDeveloperExceptionPage before any middleware so exceptions are caught in the middleware that follows.

The preceding code enables the Developer Exception Page only when the app is running in the Development environment. Detailed exception information should not be displayed publicly when the app runs in production. For more information on configuring environments, see Use multiple environments in ASP.NET Core.

The Developer Exception Page includes the following information about the exception and the request:

  • Stack trace
  • Query string parameters if any
  • Cookies if any
  • Headers

Exception handler page

To configure a custom error handling page for the Production environment, use the Exception Handling Middleware. The middleware:

  • Catches and logs exceptions.
  • Re-executes the request in an alternate pipeline for the page or controller indicated. The request isn't re-executed if the response has started. The template generated code re-executes the request to var app = builder.Build();

    if (!app.Environment.IsDevelopment()) {

    app.UseExceptionHandler("/Error");  
    app.UseHsts();  
    
    } app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

    4.

In the following example, UseExceptionHandler adds the Exception Handling Middleware in non-Development environments:

Status Code: 404; Not Found

4

The Razor Pages app template provides an Error page (

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

  1. and PageModel class (

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

  1. in the Pages folder. For an MVC app, the project template includes an Error action method and an Error view in the Home controller.

Don't mark the error handler action method with HTTP method attributes, such as

using Microsoft.AspNetCore.Diagnostics; namespace ErrorHandlingSample {

public class CustomExceptionHandler : IExceptionHandler
{
    private readonly ILogger logger;
    public CustomExceptionHandler(ILogger logger)
    {
        this.logger = logger;
    }
    public ValueTask TryHandleAsync(
        HttpContext httpContext,
        Exception exception,
        CancellationToken cancellationToken)
    {
        var exceptionMessage = exception.Message;
        logger.LogError(
            "Error Message: {exceptionMessage}, Time of occurrence {time}",
            exceptionMessage, DateTime.UtcNow);
        // Return false to continue with the default behavior
        // - or - return true to signal that this exception is handled
        return ValueTask.FromResult(false);
    }
}
}

08. Explicit verbs prevent some requests from reaching the method. Allow anonymous access to the method if unauthenticated users should see the error view.

Access the exception

Use IExceptionHandlerPathFeature to access the exception and the original request path in an error handler controller or page:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} // using static System.Net.Mime.MediaTypeNames; app.UseStatusCodePages(Text.Plain, "Status Code Page: {0}");

9

Warning

Do not serve sensitive error information to clients. Serving errors is a security risk.

To trigger the preceding exception handling page, set the environment to productions and force an exception.

Exception handler lambda

An alternative to a is to provide a lambda to UseExceptionHandler. Using a lambda allows access to the error before returning the response.

Here's an example of using a lambda for exception handling:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePages(async statusCodeContext => {
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
    $"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});

0

In the preceding code,

using Microsoft.AspNetCore.Diagnostics; namespace ErrorHandlingSample {

public class CustomExceptionHandler : IExceptionHandler
{
    private readonly ILogger logger;
    public CustomExceptionHandler(ILogger logger)
    {
        this.logger = logger;
    }
    public ValueTask TryHandleAsync(
        HttpContext httpContext,
        Exception exception,
        CancellationToken cancellationToken)
    {
        var exceptionMessage = exception.Message;
        logger.LogError(
            "Error Message: {exceptionMessage}, Time of occurrence {time}",
            exceptionMessage, DateTime.UtcNow);
        // Return false to continue with the default behavior
        // - or - return true to signal that this exception is handled
        return ValueTask.FromResult(false);
    }
}
}

09 is added so the Internet Explorer browser displays the error message rather than an IE error message. For more information, see this GitHub issue.

To see the result of the exception handling lambda in the sample app, use the

using Microsoft.AspNetCore.Diagnostics; namespace ErrorHandlingSample {

public class CustomExceptionHandler : IExceptionHandler
{
    private readonly ILogger logger;
    public CustomExceptionHandler(ILogger logger)
    {
        this.logger = logger;
    }
    public ValueTask TryHandleAsync(
        HttpContext httpContext,
        Exception exception,
        CancellationToken cancellationToken)
    {
        var exceptionMessage = exception.Message;
        logger.LogError(
            "Error Message: {exceptionMessage}, Time of occurrence {time}",
            exceptionMessage, DateTime.UtcNow);
        // Return false to continue with the default behavior
        // - or - return true to signal that this exception is handled
        return ValueTask.FromResult(false);
    }
}
}

10 and

using Microsoft.AspNetCore.Diagnostics; namespace ErrorHandlingSample {

public class CustomExceptionHandler : IExceptionHandler
{
    private readonly ILogger logger;
    public CustomExceptionHandler(ILogger logger)
    {
        this.logger = logger;
    }
    public ValueTask TryHandleAsync(
        HttpContext httpContext,
        Exception exception,
        CancellationToken cancellationToken)
    {
        var exceptionMessage = exception.Message;
        logger.LogError(
            "Error Message: {exceptionMessage}, Time of occurrence {time}",
            exceptionMessage, DateTime.UtcNow);
        // Return false to continue with the default behavior
        // - or - return true to signal that this exception is handled
        return ValueTask.FromResult(false);
    }
}
}

11 preprocessor directives, and select Trigger an exception on the home page.

UseStatusCodePages

By default, an ASP.NET Core app doesn't provide a status code page for HTTP status codes, such as 404 - Not Found. The app returns a status code and an empty response body. To provide status code pages, use Status Code Pages middleware.

The middleware is made available by the Microsoft.AspNetCore.Diagnostics package.

To enable default text-only handlers for common error status codes, call UseStatusCodePages in the

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

68 method:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePages(async statusCodeContext => {
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
    $"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});

1

Call

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 before request handling middleware (for example, Static File Middleware and MVC Middleware).

When

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 isn't used, navigating to a URL without an endpoint returns a browser dependent error message indicating the endpoint can't be found. For example, navigating to

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

72. When

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

20 is called, the browser returns:

Status Code: 404; Not Found

UseStatusCodePages with format string

To customize the response content type and text, use the overload of UseStatusCodePages that takes a content type and format string:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePages(async statusCodeContext => {
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
    $"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});

3

UseStatusCodePages with lambda

To specify custom error-handling and response-writing code, use the overload of UseStatusCodePages that takes a lambda expression:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePages(async statusCodeContext => {
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
    $"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});

4

UseStatusCodePagesWithRedirects

The UseStatusCodePagesWithRedirects extension method:

  • Sends a 302 - Found status code to the client.
  • Redirects the client to the location provided in the URL template.

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePages(async statusCodeContext => {
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
    $"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});

5

The URL template can include a

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

25 placeholder for the status code, as shown in the example. If the URL template starts with

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

29 (tilde), the

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

29 is replaced by the app's

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

31. If you point to an endpoint within the app, create an MVC view or Razor page for the endpoint. For a Razor Pages example, see

using Microsoft.AspNetCore.Diagnostics; namespace ErrorHandlingSample {

public class CustomExceptionHandler : IExceptionHandler
{
    private readonly ILogger logger;
    public CustomExceptionHandler(ILogger logger)
    {
        this.logger = logger;
    }
    public ValueTask TryHandleAsync(
        HttpContext httpContext,
        Exception exception,
        CancellationToken cancellationToken)
    {
        var exceptionMessage = exception.Message;
        logger.LogError(
            "Error Message: {exceptionMessage}, Time of occurrence {time}",
            exceptionMessage, DateTime.UtcNow);
        // Return false to continue with the default behavior
        // - or - return true to signal that this exception is handled
        return ValueTask.FromResult(false);
    }
}
}

21 in the sample app.

This method is commonly used when the app:

  • Should redirect the client to a different endpoint, usually in cases where a different app processes the error. For web apps, the client's browser address bar reflects the redirected endpoint.
  • Shouldn't preserve and return the original status code with the initial redirect response.

UseStatusCodePagesWithReExecute

The UseStatusCodePagesWithReExecute extension method:

  • Returns the original status code to the client.
  • Generates the response body by re-executing the request pipeline using an alternate path.

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePages(async statusCodeContext => {
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
    $"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});

6

If you point to an endpoint within the app, create an MVC view or Razor page for the endpoint. Ensure

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

34 is placed before

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

95 so the request can be rerouted to the status page. For a Razor Pages example, see

using Microsoft.AspNetCore.Diagnostics; namespace ErrorHandlingSample {

public class CustomExceptionHandler : IExceptionHandler
{
    private readonly ILogger logger;
    public CustomExceptionHandler(ILogger logger)
    {
        this.logger = logger;
    }
    public ValueTask TryHandleAsync(
        HttpContext httpContext,
        Exception exception,
        CancellationToken cancellationToken)
    {
        var exceptionMessage = exception.Message;
        logger.LogError(
            "Error Message: {exceptionMessage}, Time of occurrence {time}",
            exceptionMessage, DateTime.UtcNow);
        // Return false to continue with the default behavior
        // - or - return true to signal that this exception is handled
        return ValueTask.FromResult(false);
    }
}
}

21 in the sample app.

This method is commonly used when the app should:

  • Process the request without redirecting to a different endpoint. For web apps, the client's browser address bar reflects the originally requested endpoint.
  • Preserve and return the original status code with the response.

The URL and query string templates may include a placeholder (

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

  1. for the status code. The URL template must start with a slash (

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] public class ErrorModel : PageModel {

public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
    RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    var exceptionHandlerPathFeature =
        HttpContext.Features.Get();
    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
    {
        ExceptionMessage = "The file was not found.";
    }
    if (exceptionHandlerPathFeature?.Path == "/")
    {
        ExceptionMessage ??= string.Empty;
        ExceptionMessage += " Page: Home.";
    }
}
}

32). When using a placeholder in the path, confirm that the endpoint (page or controller) can process the path segment. For example, a Razor Page for errors should accept the optional path segment value with the

using Microsoft.AspNetCore.Diagnostics; namespace ErrorHandlingSample {

public class CustomExceptionHandler : IExceptionHandler
{
    private readonly ILogger logger;
    public CustomExceptionHandler(ILogger logger)
    {
        this.logger = logger;
    }
    public ValueTask TryHandleAsync(
        HttpContext httpContext,
        Exception exception,
        CancellationToken cancellationToken)
    {
        var exceptionMessage = exception.Message;
        logger.LogError(
            "Error Message: {exceptionMessage}, Time of occurrence {time}",
            exceptionMessage, DateTime.UtcNow);
        // Return false to continue with the default behavior
        // - or - return true to signal that this exception is handled
        return ValueTask.FromResult(false);
    }
}
}

27 directive:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePages(async statusCodeContext => {
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
    $"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});

7

The endpoint that processes the error can get the original URL that generated the error, as shown in the following example:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePages(async statusCodeContext => {
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
    $"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});

8

Don't mark the error handler action method with HTTP method attributes, such as

using Microsoft.AspNetCore.Diagnostics; namespace ErrorHandlingSample {

public class CustomExceptionHandler : IExceptionHandler
{
    private readonly ILogger logger;
    public CustomExceptionHandler(ILogger logger)
    {
        this.logger = logger;
    }
    public ValueTask TryHandleAsync(
        HttpContext httpContext,
        Exception exception,
        CancellationToken cancellationToken)
    {
        var exceptionMessage = exception.Message;
        logger.LogError(
            "Error Message: {exceptionMessage}, Time of occurrence {time}",
            exceptionMessage, DateTime.UtcNow);
        // Return false to continue with the default behavior
        // - or - return true to signal that this exception is handled
        return ValueTask.FromResult(false);
    }
}
}

08. Explicit verbs prevent some requests from reaching the method. Allow anonymous access to the method if unauthenticated users should see the error view.

Disable status code pages

To disable status code pages for an MVC controller or action method, use the

using Microsoft.AspNetCore.Diagnostics; namespace ErrorHandlingSample {

public class CustomExceptionHandler : IExceptionHandler
{
    private readonly ILogger logger;
    public CustomExceptionHandler(ILogger logger)
    {
        this.logger = logger;
    }
    public ValueTask TryHandleAsync(
        HttpContext httpContext,
        Exception exception,
        CancellationToken cancellationToken)
    {
        var exceptionMessage = exception.Message;
        logger.LogError(
            "Error Message: {exceptionMessage}, Time of occurrence {time}",
            exceptionMessage, DateTime.UtcNow);
        // Return false to continue with the default behavior
        // - or - return true to signal that this exception is handled
        return ValueTask.FromResult(false);
    }
}
}

29 attribute.

To disable status code pages for specific requests in a Razor Pages handler method or in an MVC controller, use IStatusCodePagesFeature:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePages(async statusCodeContext => {
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
    $"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});

9

Exception-handling code

Code in exception handling pages can throw exceptions. It's often a good idea for production error pages to consist of purely static content.

Response headers

Once the headers for a response are sent:

  • The app can't change the response's status code.
  • Any exception pages or handlers can't run. The response must be completed or the connection aborted.

Server exception handling

In addition to the exception handling logic in your app, the HTTP server implementation can handle some exceptions. If the server catches an exception before response headers are sent, the server sends a 500 - Internal Server Error response without a response body. If the server catches an exception after response headers are sent, the server closes the connection. Requests that aren't handled by your app are handled by the server. Any exception that occurs when the server is handling the request is handled by the server's exception handling. The app's custom error pages, exception handling middleware, and filters don't affect this behavior.

Startup exception handling

Only the hosting layer can handle exceptions that take place during app startup. The host can be configured to and .

The hosting layer can show an error page for a captured startup error only if the error occurs after host address/port binding. If binding fails:

  • The hosting layer logs a critical exception.
  • The dotnet process crashes.
  • No error page is displayed when the HTTP server is Kestrel.

When running on IIS (or Azure App Service) or IIS Express, a 502.5 - Process Failure is returned by the ASP.NET Core Module if the process can't start. For more information, see Troubleshoot ASP.NET Core on Azure App Service and IIS.

Database error page

Database Error Page Middleware captures database-related exceptions that can be resolved by using Entity Framework migrations. When these exceptions occur, an HTML response with details of possible actions to resolve the issue is generated. This page should be enabled only in the Development environment. Enable the page by adding code to

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        // using static System.Net.Mime.MediaTypeNames;
        context.Response.ContentType = Text.Plain;
        await context.Response.WriteAsync("An exception was thrown.");
        var exceptionHandlerPathFeature =
            context.Features.Get();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            await context.Response.WriteAsync(" The file was not found.");
        }
        if (exceptionHandlerPathFeature?.Path == "/")
        {
            await context.Response.WriteAsync(" Page: Home.");
        }
    });
});
app.UseHsts();
}

68:

var app = builder.Build(); if (!app.Environment.IsDevelopment()) {

app.UseExceptionHandler("/Error");
app.UseHsts();
} app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

0

UseDatabaseErrorPage requires the Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore NuGet package.

Exception filters

In MVC apps, exception filters can be configured globally or on a per-controller or per-action basis. In Razor Pages apps, they can be configured globally or per page model. These filters handle any unhandled exception that occurs during the execution of a controller action or another filter. For more information, see .

Tip

Exception filters are useful for trapping exceptions that occur within MVC actions, but they're not as flexible as the Exception Handling Middleware. We recommend using the middleware. Use filters only where you need to perform error handling differently based on which MVC action is chosen.

Model state errors

For information about how to handle model state errors, see Model binding and Model validation.

Additional resources

  • Troubleshoot ASP.NET Core on Azure App Service and IIS
  • Common error troubleshooting for Azure App Service and IIS with ASP.NET Core

Collaborate with us on GitHub

The source for this content can be found on GitHub, where you can also create and review issues and pull requests. For more information, see our contributor guide.