ASP.NET Core 2.2 基礎知識(九)【處理錯誤】

風靈使發表於2019-02-19

本文介紹了處理 ASP.NET Core 應用中常見錯誤的一些方法。

開發人員異常頁

要將應用配置為顯示有關異常的詳細資訊的頁面,請使用開發人員異常頁。 該頁面通過 Microsoft.AspNetCore.App 元包中的 Microsoft.AspNetCore.Diagnostics 包提供。 向 Startup.Configure 方法新增程式碼行:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    env.EnvironmentName = EnvironmentName.Production;

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

將對 UseDeveloperExceptionPage 的呼叫放在要對其捕獲異常的任何中介軟體(例如,app.UseMvc)前面。

警告
僅當應用程式在開發環境中執行時才啟用開發人員異常頁。 否則當應用程式在生產環境中執行時,詳細的異常資訊會向公眾洩露 瞭解環境配置

要檢視開發人員異常頁,請將環境設定為 Development,執行示例應用,並嚮應用的基 URL 新增 ?throw=true。 該頁面包括幾個選項卡,這些選項卡中包含關於異常和請求的資訊。 第一個選項卡包括堆疊跟蹤:
在這裡插入圖片描述
下一個選項卡顯示查詢字串引數(如有):
在這裡插入圖片描述

如果請求具有 cookie,它們在“Cookie”選項卡上顯示。標頭出現在最後一個選項卡中:
在這裡插入圖片描述

配置自定義異常處理頁

配置當應用未在 Development 環境中執行時要使用的異常處理程式頁:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    env.EnvironmentName = EnvironmentName.Production;

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

在 Razor Pages 應用中,dotnet new Razor Pages 模板在 Pages 資料夾中提供“錯誤”頁面和錯誤 PageModel 類。

在 MVC 應用中,不要使用 HTTP 方法特性(如 HttpGet)修飾錯誤處理程式操作方法。 顯式謂詞可阻止某些請求訪問方法。 允許匿名訪問方法,以便未經身份驗證的使用者能夠接收錯誤檢視。

例如,以下錯誤處理程式方法由dotnet new MVC 模板提供並在主控制器中顯示:

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

配置狀態內碼表

預設情況下,應用不會為 HTTP 狀態程式碼提供豐富狀態內碼表,例如 404 未找到。 要提供狀態內碼表,請使用狀態內碼表中介軟體。

該中介軟體通過Microsoft.AspNetCore.App 元包中的 Microsoft.AspNetCore.Diagnostics 包提供。

Startup.Configure 方法新增程式碼行:

app.UseStatusCodePages();

應在管道中的請求處理中介軟體之前呼叫 UseStatusCodePages(例如,靜態檔案中介軟體和 MVC 中介軟體)。

預設情況下,狀態內碼表中介軟體為常見狀態程式碼(如 404)新增純文字處理程式:
在這裡插入圖片描述
該中介軟體支援多種擴充套件方法。 一種方法採用 Lambda 表示式:

// Expose the members of the 'Microsoft.AspNetCore.Http' namespace 
// at the top of the file:
// using Microsoft.AspNetCore.Http;
app.UseStatusCodePages(async context =>
{
    context.HttpContext.Response.ContentType = "text/plain";

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

UseStatusCodePages 過載需要使用內容型別和格式字串:

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

重定向重新執行擴充套件方法

UseStatusCodePagesWithRedirects

  • 向客戶端傳送“302 - 已找到”狀態程式碼。
  • 將客戶端重定向到 URL 模板中的位置。

該模板可能包括狀態程式碼的 {0} 佔位符。 模板必須以正斜槓 (/) 開頭。

app.UseStatusCodePagesWithRedirects("/error/{0}");

UseStatusCodePagesWithReExecute

  • 向客戶端返回原始狀態程式碼。
  • 指定應使用備用路徑重新執行請求管道,從而生成響應正文。

該模板可能包括狀態程式碼的 {0} 佔位符。 模板必須以正斜槓 (/) 開頭。

app.UseStatusCodePagesWithReExecute("/error/{0}");

可禁用 Razor 頁處理程式方法或 MVC 控制器中的特定請求的狀態內碼表。 要禁用狀態內碼表,請嘗試從請求的 HttpContext.Features集合中檢索 IStatusCodePagesFeature,並在功能可用時禁用該功能:

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

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

若要在應用中使用指向終結點的 UseStatusCodePages* 過載,請為終結點建立 MVC 檢視或 Razor Page。 例如,Razor Pages 應用的dotnet new模板將生成以下頁面和頁面模型類:

Error.cshtml:

@page
@model ErrorModel
@{
    ViewData["Title"] = "Error";
}

<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>

@if (Model.ShowRequestId)
{
    <p>
        <strong>Request ID:</strong> <code>@Model.RequestId</code>
    </p>
}

<h3>Development Mode</h3>
<p>
    Swapping to <strong>Development</strong> environment will display more detailed 
    information about the error that occurred.
</p>
<p>
    <strong>Development environment should not be enabled in deployed applications
    </strong>, as it can result in sensitive information from exceptions being 
    displayed to end users. For local debugging, development environment can be 
    enabled by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment 
    variable to <strong>Development</strong>, and restarting the application.
</p>

Error.cshtml.cs:

public class ErrorModel : PageModel
{
    public string RequestId { get; set; }

    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, 
        NoStore = true)]
    public void OnGet()
    {
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
    }
}

異常處理程式碼

異常處理頁中的程式碼可能會引發異常。 建議在生產錯誤頁面中包含純靜態內容。

此外還要注意,一旦傳送響應的標頭,則無法更改響應的狀態程式碼,也不能執行任何異常頁或處理程式。 必須完成響應或中止連線。

伺服器異常處理

除應用程式中的異常處理邏輯外,託管應用程式的伺服器也會執行一些異常處理。 如果伺服器在傳送標頭之前捕獲異常,伺服器將傳送沒有正文的 500 內部伺服器錯誤響應。 如果伺服器在已傳送標頭後捕獲異常,伺服器會關閉連線。 應用程式無法處理的請求將由伺服器進行處理。 發生的任何異常都將由伺服器進行處理。 任何配置的自定義錯誤頁面或異常處理中介軟體或篩選器都不會影響此行為。

啟動異常處理

應用程式啟動期間發生的異常僅可在承載層進行處理。 利用Web主機,你可以使用 captureStartupErrorsdetailedErrors配置主機在響應啟動期間出現錯誤時的行為方式

僅當捕獲的啟動錯誤發生在主機地址/埠繫結之後,承載層才會為該錯誤顯示錯誤頁。 如果繫結因任何原因而失敗,則承載層會記錄關鍵異常,dotnet 程式崩潰,且在Kestrel伺服器上執行應用時,不會顯示任何錯誤頁。

IISIIS Express上執行應用時,如果無法啟動程式,ASP.NET Core 模組將返回 502.5 程式失敗。 要了解在通過 IIS 託管時如何排查啟動問題,請參閱 對 IIS 上的 ASP.NET Core 進行故障排除。 要了解如何排查 Azure 應用服務的啟動問題,請參閱 對 Azure 應用服務上的 ASP.NET Core 進行故障排除

ASP.NET Core MVC 錯誤處理

MVC應用還有一些其他的錯誤處理選項,例如配置異常篩選器和執行模型驗證。

異常篩選器

在 MVC 應用中,異常篩選器可以進行全域性配置,也可以為每個控制器或每個操作單獨配置。 這些篩選器處理在執行控制器操作或其他篩選器時出現的任何未處理的異常。 不會以其他方式呼叫這些篩選器。 要了解詳細資訊,請參閱篩選器

[!TIP]
異常篩選器非常適用於捕獲 MVC 操作內出現的異常,但靈活性不如錯誤處理中介軟體。 一般情況下最好使用中介軟體;僅在需要根據所選 MVC 操作以不同方式執行錯誤處理時,才使用篩選器。

處理模型狀態錯誤

模型驗證在每個控制器操作被呼叫之前發生,操作方法負責檢查 ModelState.IsValid 並相應地作出反應。

某些應用使用標準約定處理模型驗證錯誤,在這種情況下,使用篩選器可以更好地實施這種策略。 你需要使用無效模型狀態測試操作的行為。 檢視測試控制器邏輯瞭解詳情。

相關文章