【ASP.NET Core】處理異常(下篇)

来源:https://www.cnblogs.com/tcjiaan/archive/2018/02/26/8468901.html
-Advertisement-
Play Games

上一篇中,老周給大伙伴們扯了有關 ASP.NET Core 中異常處理的簡單方法。按照老周的優良作風,我們應該順著這個思路繼續挖掘。 本文老周就不自量力地介紹一下如何使用 MVC Filter 來處理異常。MVC 模型(當然適用於 Razor Page 、Web API 模型)可以用一系列的 Fil ...


上一篇中,老周給大伙伴們扯了有關 ASP.NET Core 中異常處理的簡單方法。按照老周的優良作風,我們應該順著這個思路繼續挖掘。

本文老周就不自量力地介紹一下如何使用 MVC Filter 來處理異常。MVC 模型(當然適用於 Razor Page 、Web API 模型)可以用一系列的 Filter 來對請求與回應消息進行過濾處理。其中,在 Microsoft.AspNetCore.Mvc.Filters 命名空間下,你會發現有兩個介面,它們跟異常處理有關:

IExceptionFilter:實現 OnException 方法,可以自定義回傳給客戶端的異常信息。

IAsyncExceptionFilter:跟上面的一樣的,只不過這廝支持非同步等待而已。

 

在實現處理異常的 Filter 時,傳給 OnException / OnExceptionAsync 方法的有一個 ExceptionContext 類型參數,我們可以通過它來設置自定義的返回結果。

訪問 Exception 屬性,你可以得到相關的異常實例,當然這個屬性是可寫的,所以你可以獲取異常實例後,將它改為其他異常實例,再重新賦給這個屬性,比如,你用你自己編寫的異常類來重新封裝。通過 Result 屬性設置返回結果,這個與 MVC Action 方法的返回方法一樣,不同的是,在 Action 方法中,你可以調用 Controller 基類的方法來返回對應的 Result ,而對於 Result 屬性,你必須顯式地去創建實現了 IActionResult 介面的類型實例。

另外,值得註意的是,ExceptionContext 類還有一個 ExceptionHandled 屬性,該屬性值可讀可寫,主要是用於標識當前發生的異常是否已經過處理。這主要是應對 Filter 的執行順序的,一種情況是你可能使用了多個 Filter 來處理異常,在處理過程中你就可以將這個屬性值設為 true 以表示這個錯誤已處理過了,後面的就不必處理了;另一種情況是,以 Attribute 方式使用的 Filter 的優先順序會比全局使用的 Filter 高,也許在 Attribute 上我沒有對異常進行處理,那麼到了全局 Filter 執行的時候,我就可以檢查一下這個屬性,如果沒有處理就進行一下處理。關於 Attribute 方式使用 Filter 老周隨後會說的,這裡先提一下。

 

好了,咱們先說說如何實現自己的異常處理 Filter,其實很簡單,看下麵代碼。

    public class MyExceptionFilter : IExceptionFilter, IFilterMetadata
    {
        public void OnException(ExceptionContext context)
        {
            if(context.ExceptionHandled == false)
            {
                string msg = context.Exception.Message;
                context.Result = new ContentResult
                {
                    Content = msg,
                    StatusCode = StatusCodes.Status200OK,
                    ContentType = "text/html;charset=utf-8"
                };
            }
            context.ExceptionHandled = true; //異常已處理了
        }

在 OnException 方法中,我直接獲取異常信息,然後用一個 ContentResult 對象來返回,這個是類似於 MVC 中 Controller . Action 方法返回結果,我這裡簡單地以 HTML 文本形式返回,一旦處理到異常,應用程式會自動把這個 Result 返回給客戶端。

你可能發現了,我除了實現 IExceptionFilter 介面外,還實現了一個 IFilterMetadata 介面,這個介面是必須的,不然待會兒我們無法應用這個 Filter 了,為什麼呢,等一下你就會明白了。

這裡實現的這個是同步調用的,如果你希望有一個可非同步等待的版本,那麼,你就順便實現一下 IAsyncExceptionFilter 介面。把上面的代碼改為:

    public class MyExceptionFilter : IExceptionFilter, IAsyncExceptionFilter, IFilterMetadata
    {
        public void OnException(ExceptionContext context)
        {
            if(context.ExceptionHandled == false)
            {
                string msg = context.Exception.Message;
                context.Result = new ContentResult
                {
                    Content = msg,
                    StatusCode = StatusCodes.Status200OK,
                    ContentType = "text/html;charset=utf-8"
                };
            }
            context.ExceptionHandled = true; //異常已處理了
        }

        public Task OnExceptionAsync(ExceptionContext context)
        {
            OnException(context);
            return Task.CompletedTask;
        }
    }

 

好了,接下來咱們得考慮怎麼用它了。在 Startup.ConfigureServices 方法中,添加 MVC 功能後可以把咱們自己寫的 Filter 添加進去。

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc(opt =>
            {
                opt.Filters.Add<MyExceptionFilter>();
            });
        }

上面代碼添加 Filter 後,是用於全局的,說白了,當應用程式內不管哪個 Controller 裡面發生的異常,都會經過咱們添加的 Filter 處理。

 

現在我們測試一下這個異常處理的 Filter 起到什麼作用。為了不影響測試,請把 Configure 方法中這段代碼刪除。

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseMvc();
        }

變成這樣

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseMvc();
        }

 

然後,隨便弄段代碼來測試。

        [HttpPost("/code")]
        public IActionResult SubmitSome(int val)
        {
            if(val <= 0)
            {
                throw new ArgumentException("號碼不能小於或等於 0。");
            }
            return Content($"恭喜你,中獎了。\n中獎號碼為:{val}", "text/html;charset=utf-8");
        }

這個邏輯很簡單,就是在前臺頁面輸入一個數值,然後 POST 上來,如果數值不是大於 0 的值就拋異常。

 

然後我故意輸入一個 -10。

 

 POST 後在伺服器上引發異常。

繼續執行,讓 Filter 對異常進行處理。

最後,異常信息就返回給瀏覽器了。

 

 這樣說明咱們寫的 Filter 起作用了。

剛剛說過,在 ConfigureServices 方法中添加的 Filter 是用於全局的,如果我們的項目中有個別的 Controller 或者 Controller 中的個別方法,希望使用專門的 Filter 去處理異常,這時候就可以考慮以 Attribute 的方式去處理。

要用 Attribute 方式處理異常,需要實現 ExceptionFilterAttribute 抽象類。該抽象類已實現了咱們上面提到過的幾個介面。

這個類還實現了 IOrderedFilter 介面,可以用來安排多個 Attribute 實例在處理異常上的順序(假設你用了多個實例來處理)。

 

下麵咱們自己實現一個 Attribute ,用來處理異常。

    public class MyExceptionFilterAttribute : ExceptionFilterAttribute
    {
        public override void OnException(ExceptionContext context)
        {
            var ex = context.Exception;
            // 構建錯誤信息對象
            var dic = new Dictionary<string, object>
            {
                ["err_code"] = 80250,
                ["err_msg"] = ex.Message,
                ["err_sol"] = "建議攜帶你的數據到醫院做檢查。"
            };
            // 設置結果
            context.Result = new JsonResult(dic);
            context.ExceptionHandled = true;
        }

        public override Task OnExceptionAsync(ExceptionContext context)
        {
            OnException(context);
            return Task.CompletedTask;
        }
    }

上面代碼中,我以 JSON 格式返回錯誤數據。

 

這個 Attribute 可以用於類與方法,然後咱們用 Web API 來測試。

    [Route("api/[controller]")]
    public class DemoController : Controller
    {
        [HttpGet]
        [MyExceptionFilter]
        public IActionResult Compute(int m, int n)
        {
            if (m < 0 || n < 0)
            {
                throw new Exception("數值不能小於 0。");
            }
            return Json(new { num1 = m, num2 = n, result = m + n });
        }
    }

此處把 attrbute 用到方法上。

 

運行應用程式,然後請出 Postman 大叔來幫我們測試 Web API。為參數 m 和 n 賦值,然後以 GET 方式發送請求。

獲得正確的結果,現在咱們提交小於 0 的參數。就會返回剛剛自定義的錯誤。

 

 好了,今天的內容就說到這裡,下次有空繼續扯。

示例源代碼下載地址

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 原文章地址:http://www.cnblogs.com/fish-li/archive/2013/05/05/3061816.html 首先做個大概的總結,XML包括的元素有XmlElement,XmlAttribute ,InnerText。 閱讀目錄 開始 最簡單的使用XML的方法 類型定義與 ...
  • "跨平臺"後的ASP.Net Core是如何接收並處理請求的呢? 它的運行和處理機制和之前有什麼不同? 本章從"巨集觀"到"微觀"地看一下它的結構以及不同時期都幹了些什麼. 本章主要內容如下: ASP.NET Core 的運行機制: "巨集觀"的看一下Http請求的處理流程. ASP.NET Core ...
  • 相信做asp.net web開發的碼友們,對ASP.NET_SessionId一定不陌生。ASP.NET_SessionId保存在瀏覽器cookie中。那麼它是來源於哪裡?何時生成?何時失效?有何作用呢? 帶著這些疑問,我們開始探尋它。廢話不多說,實踐才是檢驗真理的最好方法,直接上代碼。 打開VS建 ...
  • 1. 下載安裝VS支持Mysql的包 1.1 Connector/Net : https://dev.mysql.com/downloads/connector/net/6.9.html 1.2 MySQL for Visual Studio: https://dev.mysql.com/downl ...
  • 文件套印,目前比較常用的有三種形式:office組件套印、NPOI套印、Asponse.words套印。 針對這三種套印各有優勢: office套印:基於office組件,需要使用者電腦安裝office功能。 優勢:能完全滿足頁面所使用的office特性功能,包含頁眉、頁腳類及支持其他特殊樣式,根據 ...
  • 兩步:1.註冊GridView的CustomDrawFooterCell事件2.在事件響應中,根據條件修改e.Appearance.ForeColor例子如下: 效果: 不知道為什麼設置e.Appearance.BackColor無效(而在非統計行中有效),知道的大俠麻煩告知。 ...
  • 一.單一職責原則 就一個類而言,應該僅有一個引起它變化的原因.如果你能想到多於一個的動機去改變一個類,那麼這個類就具有多於一個的職責. 二.開放-封閉原則 對於更改是封閉的,對於擴展是開放的.面對需求,對程式的改動是通過增加代碼來實現的,而不是更改現有代碼,從而保持相對的穩定.如何做到呢?預測最有可 ...
  • Debug版本:通常稱為調試版本,它包含調試信息,並且不作任何優化,便於程式員調試程式。 Release版本:稱為發佈版本,它往往是進行了各種優化,使得程式在代碼大小和運行速度上都是最優的,以便用戶很好地使用。 實際上,Debug版本和 Release 並沒有本質的界限,他們只是一組編譯選項的集合, ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...