This article introduces some ways to deal with common errors in ASP.NET Core Web applications. Related Web API, see Handling ASP.NET Core Web API
errors.
Developer exception page
The developer exception page displays the detailed information of the request exception. The ASP.NET Core template generates the following code:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
When the app 开发环境
is running in, the previously highlighted code enables the developer exception page.
The template is placed in the front part of the middleware pipeline UseDeveloperExceptionPage
so that it can catch exceptions raised in the middleware later.
The preceding code enables the developer exception page only when the application is running in the development environment. When the application is running in a production environment, detailed exception information should not be displayed publicly. For details on configuring environments, see Using multiple environments in ASP.NET Core.
The developer exception page includes the following information about exceptions and requests:
- Stack trace
- Query string parameters (if any)
- Cookie (if any)
- Header
Exception handler page
To configure a custom error handling page for the production environment, use exception handling middleware. Middleware:
- Catch and log the exception.
- Re-execute the request in the alternate pipeline using the indicated path. If the response has been initiated, the request will not be re-executed. Template generated code
/Error
path re-execution request.
In the following example, UseExceptionHandler
add exception handling middleware in a non-development environment:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
The Razor Pages application template provides an "error" page (.cshtml) and PageModel class (ErrorModel) in the Pages folder. For MVC applications, the project template includes the error operation method and the error view of the main controller.
Do not use HTTP method attributes (such as HttpGet) to mark error handler operation methods. Explicit predicates can prevent certain request access methods. If unauthenticated users should see the error view, allow anonymous access to the method.
The exception is handled in different ways according to the original HTTP method:
- For Razor Pages, create multiple handler methods. For example, using the
OnGet
process GET exceptions,OnPost
handling POST exception. - For MVC, apply HTTP verb attributes to multiple operations. For example, using the
[HttpGet]
process GET exceptions,[HttpPost]
handling POST exception.
To allow unauthenticated users to view the custom error handling page, make sure it supports anonymous access.
Access exception
Use IExceptionHandlerPathFeature to access the exception and original request path in the error handler controller or page:
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
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<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
ExceptionMessage = "File error thrown";
}
if (exceptionHandlerPathFeature?.Path == "/index")
{
ExceptionMessage += " from home page";
}
}
}
[!WARNING]
Do not provide sensitive error information to the client. Errors in providing services are a security risk.
To test for exceptions in the sample app:
- Set the environment to the production environment.
- Program.cs from the
webBuilder.UseStartup<Startup>();
comments removed. - Select "Trigger Exception" on the homepage.
To trigger the previous exception handling page, please set the environment to the production environment and force an exception to be thrown.
Exception handler lambda
An alternative to a custom exception handler page is to provide a lambda to UseExceptionHandler. Using lambda, you can access the error before returning the response.
The following example shows how to use lambda for exception handling:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
context.Response.StatusCode = 500;
context.Response.ContentType = "text/html";
await context.Response.WriteAsync("<html lang=\"en\"><body>\r\n");
await context.Response.WriteAsync("ERROR!<br><br>\r\n");
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
await context.Response.WriteAsync("File error thrown!<br><br>\r\n");
}
await context.Response.WriteAsync("<a href=\"/\">Home</a><br>\r\n");
await context.Response.WriteAsync("</body></html>\r\n");
await context.Response.WriteAsync(new string(' ', 512)); // IE padding
});
});
app.UseHsts();
}
In the preceding code, await context.Response.WriteAsync(new string('', 512)); is added so that the Internet Explorer browser displays the corresponding error message instead of displaying the IE error message. For more information, see this GitHub issue.
caveat
Do not offer to the client from
IExceptionHandlerFeature
orIExceptionHandlerPathFeature
sensitive error messages. Errors in providing services are a security risk.
To view the results of the exception handling lambda in the sample application, please use the ProdEnvironment and ErrorHandlerLambda preprocessor directives, and select "Trigger Exception" on the homepage.
UseStatusCodePages
By default, ASP.NET Core apps will not provide a status code page for HTTP status codes (such as "404-Not Found"). The application returns a status code and an empty response body. To provide a status code page, use status code page middleware.
This middleware is provided through the Microsoft.AspNetCore.Diagnostics package.
To enable the default plain text handler for common error status codes, call UseStatusCodePages in the Startup.Configure method:
app.UseStatusCodePages();
Called before request processing middleware UseStatusCodePages
. For example, it is called before static file middleware and endpoint middleware UseStatusCodePages
.
Not used UseStatusCodePages
when there is no endpoint to navigate to the URL will return an error message associated with the browser, indicating not find the endpoint. For example, navigate to Home/Privacy2
. Call UseStatusCodePages
, the browser returns:
Status Code: 404; Not Found
UseStatusCodePages
It is usually not used in production because it returns messages that are not useful to the user.
The status code page middleware does not catch exceptions. To provide a custom error handling page, please use
异常处理程序页
.
Contains the format string UseStatusCodePages
To customize the response content type and text, use the UseStatusCodePages overload that requires the content type and format string:
app.UseStatusCodePages(
"text/plain", "Status code page, status code: {0}");
In the preceding code, it {0}
is a placeholder for the error code.
Containing lambda UseStatusCodePages
To specify custom error handling and response writing codes, use the UseStatusCodePages overload that requires lambda expressions:
app.UseStatusCodePages(async context =>
{
context.HttpContext.Response.ContentType = "text/plain";
await context.HttpContext.Response.WriteAsync(
"Status code page, status code: " +
context.HttpContext.Response.StatusCode);
});
UseStatusCodePagesWithRedirects
UseStatusCodePagesWithRedirects
Extension method:
- Send a "302-Found" status code to the client.
- Redirect the client to the error handling endpoint provided in the URL template. The error handling endpoint usually displays an error message and returns HTTP 200.
app.UseStatusCodePagesWithRedirects("/StatusCode?code={0}");
URL template may include a state code {0}
placeholders, as shown in the previous code. If the URL template with a tilde ~
(tilde) at the beginning, it ~
will be replaced with the application PathBase
. When specifying the endpoint in the app, create an MVC view or Razor page for the endpoint. For Razor Pages samples, see Pages/StatusCode.cshtml in the sample application.
This method is usually used when the application:
- The client should be redirected to a different endpoint (usually when different applications handle errors). For web applications, the client's browser address bar reflects the redirection endpoint.
- The original status code should not be retained and returned through the initial redirect response.
UseStatusCodePagesWithReExecute
UseStatusCodePagesWithReExecute
Extension method:
- Return the original status code to the client.
- Re-execute the request pipeline by using the alternate path to generate the response body.
app.UseStatusCodePagesWithReExecute("/StatusCode","?code={0}");
If you point to an endpoint in the app, create an MVC view or Razor page for the endpoint. Ensure UseStatusCodePagesWithReExecute
placed UseRouting
before, so that the request can be re-routed to the status page. For Razor Pages samples, see Pages/StatusCode.cshtml in the sample application.
This method is usually used when the application should:
- Process the request, but do not redirect to a different endpoint. For web applications, the client's browser address bar reflects the endpoint of the original request.
- Keep the original status code and return it with the response.
URL templates and query string templates may include placeholders for status codes {0}
. URL template must /
begin with.
@page "{code?}"
The error handling endpoint can get the original URL that generated the error, as shown in the following example:
var statusCodeReExecuteFeature = HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature != null)
{
OriginalURL =
statusCodeReExecuteFeature.OriginalPathBase
+ statusCodeReExecuteFeature.OriginalPath
+ statusCodeReExecuteFeature.OriginalQueryString;
}
Disable status code page
To disable MVC controller or method of operation status code page, use the [SkipStatusCodePages]
feature.
To disable the Razor Pages handler method or the specific request status code page in the MVC controller, use IStatusCodePagesFeature
:
var statusCodePagesFeature = HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature != null)
{
statusCodePagesFeature.Enabled = false;
}
Exception handling code
The code in the exception handling page may also raise an exception. You should thoroughly test the production error page and take extra care to avoid throwing its own exceptions.
Response header
After the response header is sent:
- The app cannot change the status code of the response.
- No exception page or handler can be run. The response must be completed or the connection must be aborted.
Server exception handling
In addition to the exception handling logic in the application, it HTTP 服务器实现
can also handle some exceptions. If the server before sending the captured response header to abnormal, the server sends a response that does not contain the body of 500 - Internal Server Error
the response. If the server catches an exception after sending the response header, the server will close the connection. Requests that cannot be processed by the application will be processed by the server. When the server processes the request, any exceptions that occur will be handled by the server's exception handling. The applied custom error pages, exception handling middleware, and filters will not affect this behavior.
Start exception handling
Exceptions that occur during application startup can only be handled at the bearer layer. The host can be configured as, 捕获启动错误
and 捕获详细错误
.
Only when the error occurs after the host address/port binding, the hosting layer can display the error page of the captured startup error. If the binding fails:
- The hosting layer will log critical exceptions.
- The dotnet process crashed.
- In the HTTP server will not
Kestrel
display any error page.
When running the application on IIS (or Azure Application Service) or IIS Express, if the process cannot be started, the ASP.NET Core module will return "502.5-Process failed". For more information, see Troubleshooting ASP.NET Core on Azure App Service and IIS.
Database error page
The database error page middleware captures database-related exceptions, and Entity Framework migration can be used to resolve these exceptions. When these exceptions occur, an HTML response is generated that contains detailed information about possible actions to solve the problem. This page should only be enabled in a development environment. Enable this page by adding code to Startup.Configure:
if (env.IsDevelopment())
{
app.UseDatabaseErrorPage();
}
UseDatabaseErrorPage
Requires Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
NuGet package.
Exception filter
In MVC applications, exception filters can be configured globally or individually for each controller or each operation. In the Razor Pages application, exception filters can be configured globally or individually for each page model. These filters handle any unhandled exceptions that occur while performing controller actions or other filters. For more information, see ASP.NET Core 中的筛选器
.
Exception filters are suitable for catching exceptions that occur within MVC operations, but they are not as 异常处理中间件
UseExceptionHandler
flexible as built-in . We recommend using UseExceptionHandler
it unless you need to perform error handling in different ways based on the selected MVC operation.
Model status error
To learn how to handle model status errors, see 模型绑定
and 模型验证
.
Error handling
Add error handling page
In Startup.cs
setting middleware:
app.UseStatusCodePagesWithReExecute("/error/{0}");
Recommended UseStatusCodePagesWithReExecute
instead of UseStatusCodePagesWithRedirects
the former execution in the pipeline error jump url, which will be redirected to the url, leading to http error status code becomes normal execution of a new page 200 yards.
Then write the error controller:
public class ErrorController : Controller
{
[Route("Error/{statusCode}")]
public IActionResult Index(int statusCode)
{
var statusCodeResult = HttpContext.Features.
Get<IStatusCodeReExecuteFeature>();
var viewModel = new ErrorViewModel
{
Path = statusCodeResult.OriginalPath,
QueryString = statusCodeResult.
OriginalQueryString,
};
switch (statusCode)
{
case 404:
viewModel.Message = "页面未找到";
break;
}
return View("Error", viewModel);
}
}
By the way, I also defined ViewModel:
public class ErrorViewModel
{
public int Code { get; set; }
public string Message { get; set; }
public string Path { get; set; }
public string QueryString { get; set; }
}
The view code will not be posted, it is nothing more than displaying these error messages in the ViewModel~
Set global exception jump
Add middleware
app.UseExceptionHandler("/exception");
To write the processing controller, you need to add AllowAnonymous
annotations here to allow users to access this exception page when they are not logged in to ensure that the exception page can be displayed anyway.
[AllowAnonymous]
[Route("exception")]
public IActionResult ExceptionHandler()
{
var exception = HttpContext.Features.
Get<IExceptionHandlerPathFeature>();
var viewModel = new ExceptionViewModel
{
Path = exception.Path,
Message = exception.Error.Message,
StackTrace = exception.Error.StackTrace,
};
return View("Exception", viewModel);
}
In addition, ViewModel is defined as follows:
public class ExceptionViewModel
{
public string Path { get; set; }
public string Message { get; set; }
public string StackTrace { get; set; }
}