asp.net core 自定義異常處理中間件

asp.net core 自定義異常處理中間件

Intro

在 asp.net core 中全局異常處理瞻赶,有時候可能不能滿足我們的需要嘴脾,可能就需要自己自定義一個中間件處理了稍途,最近遇到一個問題轩性,有一些異常棍辕,不希望記錄錯誤日志闰渔,目前主要是用戶請求取消導(dǎo)致的 TaskCanceledExceptionOperationCanceledException 異常席函。因為我的 ERROR 級別的日志會輸出到 Sentry,sentry的異常會自動發(fā)郵件提醒冈涧,如果是一些沒必要的錯誤茂附,自然不需要記錄錯誤日志,于是就想自定義一個異常處理中間件督弓,自己處理異常营曼,不將異常處理直接交給 asp.net core 的異常處理。

請求取消

請求取消導(dǎo)致的異常:

request aborted

asp.net core 引入了 HttpContext.RequestAborted 來監(jiān)聽用戶取消請求(實際測試下來愚隧,并不是每次都會觸發(fā)蒂阱,還沒搞清楚怎么100%的觸發(fā)),你可以使用 HttpContext.RequestAborted 來在用戶取消請求的時候中斷后臺邏輯的處理,避免處理一些不必要的業(yè)務(wù)录煤,下面給出一個使用示例鳄厌,示例源碼
,更多詳細(xì)信息可以參考 圣杰的這篇 中斷請求了解一下

[HttpGet]
public async Task<IActionResult> GetAsync(string keyword, int pageNumber = 1, int pageSize = 10)
{
    Expression<Func<Notice, bool>> predict = n => true;
    if (!string.IsNullOrWhiteSpace(keyword))
    {
        predict = predict.And(n => n.NoticeTitle.Contains(keyword));
    }
    var result = await _repository.GetPagedListResultAsync(x => new
    {
        x.NoticeTitle,
        x.NoticeVisitCount,
        x.NoticeCustomPath,
        x.NoticePublisher,
        x.NoticePublishTime,
        x.NoticeImagePath
    }, queryBuilder => queryBuilder
            .WithPredict(predict)
            .WithOrderBy(q => q.OrderByDescending(_ => _.NoticePublishTime))
        , pageNumber, pageSize, HttpContext.RequestAborted); // 直接使用 HttpContext.RequestAborted

    return Ok(result);
}

// 在 Action 方法中聲明 CancellationToken妈踊,asp.net core 會自動將 `HttpContext.RequestAborted` 綁定到 CancellationToken 對象
[HttpGet]
public async Task<IActionResult> GetAsync(CancellationToken cancellationToken)
{
    var result = await _repository.GetResultAsync(p => new
    {
        p.PlaceName,
        p.PlaceIndex,
        p.PlaceId,
        p.MaxReservationPeriodNum
    }, builder => builder
    .WithPredict(x => x.IsActive)
    .WithOrderBy(x => x.OrderBy(_ => _.PlaceIndex).ThenBy(_ => _.UpdateTime)), cancellationToken);
    return Ok(result);
}

異常處理中間件

異常處理中間件源碼:

public class CustomExceptionHandlerMiddleware
{
    private readonly RequestDelegate _next;
    private readonly CustomExceptionHandlerOptions _options;

    public CustomExceptionHandlerMiddleware(RequestDelegate next, IOptions<CustomExceptionHandlerOptions> options)
    {
        _next = next;
        _options = options.Value;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (System.Exception ex)
        {
            var logger = context.RequestServices.GetRequiredService<ILoggerFactory>()
                .CreateLogger<CustomExceptionHandlerMiddleware>();
            if (context.RequestAborted.IsCancellationRequested && (ex is TaskCanceledException || ex is OperationCanceledException))
            {
                _options.OnRequestAborted?.Invoke(context, logger);
            }
            else
            {
                _options.OnException?.Invoke(context, logger, ex);
            }
        }
    }
}

public class CustomExceptionHandlerOptions
{
    public Func<HttpContext, ILogger, Exception, Task> OnException { get; set; } =
        async (context, logger, exception) => logger.LogError(exception, $"Request exception, requestId: {context.TraceIdentifier}");

    public Func<HttpContext, ILogger, Task> OnRequestAborted { get; set; } =
        async (context, logger) => logger.LogInformation($"Request aborted, requestId: {context.TraceIdentifier}");
}

可以通過配置 CustomExceptionHandlerOptions 來實現(xiàn)自定義的異常處理邏輯了嚎,默認(rèn)請求取消會記錄一條 Information 級別的日志,其他異常則會記錄一條 Error 級別的錯誤日志

你可以通過下面的示例來配置遇到請求取消異常的時候什么都不做

service.Configure(options=>
{
    options.OnRequestAborted = (context, logger) => Task.CompletedTask;
});

Reference

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末廊营,一起剝皮案震驚了整個濱河市歪泳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌露筒,老刑警劉巖呐伞,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異慎式,居然都是意外死亡伶氢,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門瞬捕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鞍历,“玉大人,你說我怎么就攤上這事肪虎×涌常” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵扇救,是天一觀的道長刑枝。 經(jīng)常有香客問我,道長迅腔,這世上最難降的妖魔是什么装畅? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮沧烈,結(jié)果婚禮上掠兄,老公的妹妹穿的比我還像新娘。我一直安慰自己锌雀,他們只是感情好蚂夕,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著腋逆,像睡著了一般婿牍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上惩歉,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天等脂,我揣著相機(jī)與錄音俏蛮,去河邊找鬼。 笑死上遥,一個胖子當(dāng)著我的面吹牛搏屑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播粉楚,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼睬棚,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了解幼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤包警,失蹤者是張志新(化名)和其女友劉穎撵摆,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體害晦,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡特铝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了壹瘟。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鲫剿。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖稻轨,靈堂內(nèi)的尸體忽然破棺而出灵莲,到底是詐尸還是另有隱情,我是刑警寧澤殴俱,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布政冻,位于F島的核電站,受9級特大地震影響线欲,放射性物質(zhì)發(fā)生泄漏明场。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一李丰、第九天 我趴在偏房一處隱蔽的房頂上張望苦锨。 院中可真熱鬧,春花似錦趴泌、人聲如沸舟舒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽魏蔗。三九已至,卻和暖如春痹筛,著一層夾襖步出監(jiān)牢的瞬間莺治,已是汗流浹背廓鞠。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留谣旁,地道東北人床佳。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像榄审,于是被迫代替她去往敵國和親砌们。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354