處理 ASP.NET Core 中的錯誤Handle errors in ASP.NET Core

作者:Tom DykstraLuke LathamSteve SmithBy Tom Dykstra, Luke Latham, and Steve Smith

本文說明處理 ASP.NET Core 應用程式錯誤的常見方法。This article covers common approaches to handling errors in ASP.NET Core apps.

檢視或下載範例程式碼View or download sample code. (如何下載。)該文章包含在範例應用程式中設定前置處理器指示詞 (#if#endif#define) 以啟用不同案例的指示。(How to download.) The article includes instructions about how to set preprocessor directives (#if, #endif, #define) in the sample app to enable different scenarios.

開發人員例外狀況頁面Developer Exception Page

「開發人員例外狀況頁面」會顯示要求例外狀況的詳細資訊。The Developer Exception Page displays detailed information about request exceptions. 該頁面是由 Microsoft.AspNetCore.Diagnostics (英文) 套件所提供,其位於 Microsoft.AspNetCore.App 中繼套件中。The page is made available by the Microsoft.AspNetCore.Diagnostics package, which is in the Microsoft.AspNetCore.App metapackage. 當應用程式在開發環境中執行時,新增程式碼到 Startup.Configure 方法以啟用頁面:Add code to the Startup.Configure method to enable the page when the app is running in the Development environment:

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

將對 UseDeveloperExceptionPage 的呼叫放置於任何您想要攔截例外狀況的中介軟體之前。Place the call to UseDeveloperExceptionPage before any middleware that you want to catch exceptions.

警告

僅有當應用程式是在開發環境中執行時,才啟用開發人員例外狀況頁面。Enable the Developer Exception Page only when the app is running in the Development environment. 當應用程式在生產環境中執行時,您不會想要公開共用例外狀況的詳細資訊。You don't want to share detailed exception information publicly when the app runs in production. 如需設定環境的詳細資訊,請參閱在 ASP.NET Core 中使用多個環境For more information on configuring environments, see 在 ASP.NET Core 中使用多個環境.

此頁面包含下列和例外狀況與要求有關的資訊:The page includes the following information about the exception and the request:

  • 堆疊追蹤Stack trace
  • 查詢字串參數 (如果有的話)Query string parameters (if any)
  • Cookie (如果有的話)Cookies (if any)
  • 頁首Headers

若要在範例應用程式 (英文) 中查看開發人員例外狀況頁面,請使用 DevEnvironment 前置處理器指示詞,並選取首頁上的 [觸發例外狀況]。To see the Developer Exception Page in the sample app, use the DevEnvironment preprocessor directive and select Trigger an exception on the home page.

例外處理常式頁面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.

在下列範例中,UseExceptionHandler 會在非開發環境中加入例外狀況處理中介軟體:In the following example, UseExceptionHandler adds the Exception Handling Middleware in non-Development environments:

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

Razor Pages 應用程式範本會在 Pages 資料夾中提供錯誤頁面 ( .cshtml) 與 PageModel 類別 (ErrorModel)。The Razor Pages app template provides an Error page (.cshtml) and PageModel class (ErrorModel) in the Pages folder. 針對 MVC 應用程式,專案範本會包含 Error 動作方法和 Error 檢視。For an MVC app, the project template includes an Error action method and an Error view. 以下為動作方法:Here's the action method:

[AllowAnonymous]
public IActionResult Error()
{
    return View(new ErrorViewModel 
        { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}

請勿使用 HTTP 方法屬性 (如 HttpGet) 裝飾錯誤處理常式動作方法。Don't decorate the error handler action method with HTTP method attributes, such as HttpGet. 明確的動詞命令可防止某些要求取得方法。Explicit verbs prevent some requests from reaching the method. 允許匿名存取方法,以便未經驗證的使用者能夠收到錯誤檢視。Allow anonymous access to the method so that unauthenticated users are able to receive the error view.

存取例外狀況Access the exception

使用 IExceptionHandlerPathFeature 來存取例外狀況或和錯誤處理常式控制器或頁面中的原始要求路徑:Use IExceptionHandlerPathFeature to access the exception and the original request path in an error handler controller or page:

var exceptionHandlerPathFeature =
    HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
    ExceptionMessage = "File error thrown";
}
if (exceptionHandlerPathFeature?.Path == "/index")
{
    ExceptionMessage += " from home page";
}

警告

提供敏感性的錯誤資訊給用戶端。Do not serve sensitive error information to clients. 提供錯誤有安全性風險。Serving errors is a security risk.

若要在範例應用程式 (英文) 中查看例外狀況處理頁面,請使用 ProdEnvironmentErrorHandlerPage 前置處理器指示詞,並選取首頁上的 [觸發例外狀況]。To see the exception handling page in the sample app, use the ProdEnvironment and ErrorHandlerPage preprocessor directives, and select Trigger an exception on the home page.

例外處理常式 LambdaException handler lambda

自訂例外處理常式頁面的替代方法,便是將 Lambda 提供給 UseExceptionHandlerAn alternative to a custom exception handler page is to provide a lambda to UseExceptionHandler. 使用 lambda 可讓您在傳回回應之前存取錯誤。Using a lambda allows access to the error before returning the response.

以下是將 Lambda 用於例外狀況處理的範例:Here's an example of using a 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>();

            // Use exceptionHandlerPathFeature to process the exception (for example, 
            // logging), but do NOT expose sensitive error information directly to 
            // the client.

            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();
}

警告

IExceptionHandlerFeatureIExceptionHandlerPathFeature 提供錯誤資訊給用戶端。Do not serve sensitive error information from IExceptionHandlerFeature or IExceptionHandlerPathFeature to clients. 提供錯誤有安全性風險。Serving errors is a security risk.

若要在範例應用程式 (英文) 中查看例外狀況處理 Lambda 的結果,請使用 ProdEnvironmentErrorHandlerLambda 前置處理器指示詞,並選取首頁上的 [觸發例外狀況]。To see the result of the exception handling lambda in the sample app, use the ProdEnvironment and ErrorHandlerLambda preprocessor directives, and select Trigger an exception on the home page.

UseStatusCodePagesUseStatusCodePages

根據預設,ASP.NET Core 應用程式不會提供 HTTP 狀態碼 (例如「404 - 找不到」) 等狀態碼頁面。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.

該中介軟體是由 Microsoft.AspNetCore.Diagnostics (英文) 套件所提供,其位於 Microsoft.AspNetCore.App 中繼套件中。The middleware is made available by the Microsoft.AspNetCore.Diagnostics package, which is in the Microsoft.AspNetCore.App metapackage.

若要針對常見的錯誤狀態碼啟用預設的純文字處理常式,請呼叫 Startup.Configure 方法中的 UseStatusCodePagesTo enable default text-only handlers for common error status codes, call UseStatusCodePages in the Startup.Configure method:

app.UseStatusCodePages();

要求處理中介軟體 (例如靜態檔案中介軟體和 MVC 中介軟體) 之前,應該先呼叫 UseStatusCodePagesCall UseStatusCodePages before request handling middleware (for example, Static File Middleware and MVC Middleware).

以下是預設處理常式所有顯示文字的範例:Here's an example of text displayed by the default handlers:

Status Code: 404; Not Found

若要在範例應用程式 (英文) 中查看其中一種狀態碼頁面格式,請使用其中一個以 StatusCodePages 為前置處理器指示詞,並選取首頁上的 [觸發 404]。To see one of the various status code page formats in the sample app, use one of the preprocessor directives that begin with StatusCodePages, and select Trigger a 404 on the home page.

具格式字串的 UseStatusCodePagesUseStatusCodePages with format string

若要自訂回應內容類型和文字,請使用 UseStatusCodePages 的多載,其會採用內容類型和格式字串:To customize the response content type and text, use the overload of UseStatusCodePages that takes a content type and format string:

app.UseStatusCodePages(
    "text/plain", "Status code page, status code: {0}");            

具 Lambda 的 UseStatusCodePagesUseStatusCodePages with lambda

若要指定自訂錯誤處理和回應撰寫程式碼,請使用 UseStatusCodePages 的多載,其會採用 Lambda 運算式:To specify custom error-handling and response-writing code, use the overload of UseStatusCodePages that takes a lambda expression:


app.UseStatusCodePages(async context =>
{
    context.HttpContext.Response.ContentType = "text/plain";

    await context.HttpContext.Response.WriteAsync(
        "Status code page, status code: " + 
        context.HttpContext.Response.StatusCode);
});

UseStatusCodePagesWithRedirectUseStatusCodePagesWithRedirect

UseStatusCodePagesWithRedirects 擴充方法:The UseStatusCodePagesWithRedirects extension method:

  • 傳送「302 - 已找到」狀態碼傳送給用戶端。Sends a 302 - Found status code to the client.
  • 將用戶端重新導向到 URL 範本中提供的位置。Redirects the client to the location provided in the URL template.
app.UseStatusCodePagesWithRedirects("/StatusCode?code={0}");

URL 範本可以針對狀態碼包含 {0} 預留位置,如範例所示。The URL template can include a {0} placeholder for the status code, as shown in the example. 如果 URL 範本是以波狀符號 (~) 為開頭,該波狀符號會被應用程式的 PathBase取代。If the URL template starts with a tilde (~), the tilde is replaced by the app's PathBase. 如果您指向應用程式內的端點,請針對該端點建立 MVC 檢視或 Razor 頁面。If you point to an endpoint within the app, create an MVC view or Razor page for the endpoint. 如需 Razor Pages 範例,請參閱範例應用程式中的 Pages/StatusCode.cshtmlFor a Razor Pages example, see Pages/StatusCode.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. 針對 Web 應用程式,用戶端的瀏覽器網址列會反映重新導向後的端點。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.

UseStatusCodePagesWithReExecuteUseStatusCodePagesWithReExecute

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.
app.UseStatusCodePagesWithReExecute("/StatusCode","?code={0}");

如果您指向應用程式內的端點,請針對該端點建立 MVC 檢視或 Razor 頁面。If you point to an endpoint within the app, create an MVC view or Razor page for the endpoint. 如需 Razor Pages 範例,請參閱範例應用程式中的 Pages/StatusCode.cshtmlFor a Razor Pages example, see Pages/StatusCode.cshtml in the sample app.

此方法通常是在下列應用程式相關情況下使用:This method is commonly used when the app should:

  • 在不重新導向至其他端點的情況下處理要求。Process the request without redirecting to a different endpoint. 針對 Web 應用程式,用戶端的瀏覽器網址列會反映原始要求的端點。For web apps, the client's browser address bar reflects the originally requested endpoint.
  • 保留並傳回原始狀態碼與回應時。Preserve and return the original status code with the response.

URL 和查詢字串範本可能會包含該狀態碼的預留位置 ({0})。The URL and query string templates may include a placeholder ({0}) for the status code. URL 範本的開頭必須是斜線 (/)。The URL template must start with a slash (/). 在路徑中使用預留位置時,請確認端點 (頁面或控制器) 可以處理路徑線段。When using a placeholder in the path, confirm that the endpoint (page or controller) can process the path segment. 例如適用於錯誤的 Razor Page 應接受具備 @page 指示詞的選擇性路徑區段值:For example, a Razor Page for errors should accept the optional path segment value with the @page directive:

@page "{code?}"

處理錯誤的端點可以取得產生該錯誤的原始 URL,如下列範例所示:The endpoint that processes the error 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 pages

若要停用 MVC 控制器或動作方法的狀態碼頁面,請使用 [SkipStatusCodePages] 屬性。To disable status code pages for an MVC controller or action method, use the [SkipStatusCodePages] attribute.

若要停用 Razor 頁面處理常式方法或 MVC 控制器中的特定要求狀態碼頁面,請使用 IStatusCodePagesFeatureTo disable status code pages for specific requests in a Razor Pages handler method or in an MVC controller, use IStatusCodePagesFeature:

var statusCodePagesFeature = HttpContext.Features.Get<IStatusCodePagesFeature>();

if (statusCodePagesFeature != null)
{
    statusCodePagesFeature.Enabled = false;
}

例外狀況處理程式碼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

除了應用程式中的例外狀況處理邏輯之外,HTTP 伺服器實作也可以處理一些例外狀況。In addition to the exception handling logic in your app, the HTTP server implementation can handle some exceptions. 如果伺服器在回應標頭傳送之前攔截到例外狀況,伺服器會傳送「500 - 內部伺服器錯誤」回應,且沒有回應本文。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 capture startup errors and capture detailed errors.

只有在錯誤是於主機位址/連接埠繫結之後發生的情況下,裝載層才能顯示已擷取之啟動錯誤的錯誤頁面。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.
  • Dotnet 會處理損毀狀況。The dotnet process crashes.
  • 當 HTTP 伺服器是 Kestrel 時,不會顯示任何錯誤頁面。No error page is displayed when the HTTP server is Kestrel.

IIS (或 Azure App Service) 或 IIS Express 上執行時,如果無法啟動處理序,模組會傳回 502.5 - 處理序失敗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. 如需詳細資訊,請參閱 疑難排解 Azure App Service 和 IIS 上的 ASP.NET CoreFor more information, see 疑難排解 Azure App Service 和 IIS 上的 ASP.NET Core.

資料庫錯誤頁面Database error page

資料庫錯誤頁面中介軟體能擷取資料庫相關的例外狀況,其可透過使用 Entity Framework 移轉來解決。The Database Error Page middleware captures database-related exceptions that can be resolved by using Entity Framework migrations. 發生這些例外狀況時,系統會產生具解決該問題之可能動作詳細資料的 HTML 回應。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. 將程式碼加入 Startup.Configure 來啟用該頁面:Enable the page by adding code to Startup.Configure:

if (env.IsDevelopment())
{
    app.UseDatabaseErrorPage();
}

例外狀況篩選條件Exception filters

在 MVC 應用程式中,您能以全域設定例外狀況篩選條件,或是以每個控制器或每個動作為基礎的方式設定。In MVC apps, exception filters can be configured globally or on a per-controller or per-action basis. 在 Razor Pages 應用程式中,您能以全域或每個頁面模型的方式設定它們。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. 如需詳細資訊,請參閱 ASP.NET Core 中的篩選條件For more information, see ASP.NET Core 中的篩選條件.

提示

例外狀況篩選條件適合用來截獲 MVC 動作中發生的例外狀況,但是它們並不像例外狀況處理中介軟體那麼有彈性。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. 請只在需要根據已選擇的 MVC 動作執行不同的錯誤處理時,才使用篩選條件。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