.NETコア戦闘開発(レッスン22:例外処理ミドルウェア:論理真の異常を区別し、異常にする) - 研究ノート(下)

次は、ロジックと、ここでロジックを処理するために、匿名デリゲートを使用して、のErrorControllerは全体のロジックは、登録の代わりに直接定義されていることを意味プロキシ方式を使用しての方法来る前と同じです

app.UseExceptionHandler(errApp =>
{
    errApp.Run(async context =>
    {
        // 在 Features 里面获取异常
        var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
        // 识别异常是否为 IKnownException
        IKnownException knownException = exceptionHandlerPathFeature.Error as IKnownException;
        if (knownException == null)
        {
            // 如果不是则记录并且把错误的响应码响应成 Http 500
            var logger = context.RequestServices.GetService<ILogger<MyExceptionFilterAttribute>>();
            logger.LogError(exceptionHandlerPathFeature.Error, exceptionHandlerPathFeature.Error.Message);
            knownException = KnownException.Unknown;
            context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        }
        else
        {
            // 如果捕获到的是一个业务逻辑的异常,Http 响应码应该给是 200
            knownException = KnownException.FromKnownException(knownException);
            context.Response.StatusCode = StatusCodes.Status200OK;
        }
        // 然后再把响应信息通过 json 的方式输出出去
        var jsonOptions = context.RequestServices.GetService<IOptions<JsonOptions>>();
        context.Response.ContentType = "application/json; charset=utf-8";
        await context.Response.WriteAsync(System.Text.Json.JsonSerializer.Serialize(knownException, jsonOptions.Value.JsonSerializerOptions));
    });
});

不明の場合は、なぜ例外が出力HTTP 500、およびビジネスロジックの例外のため、提案された出力HTTP 200をするのですか?

監視システムは、実際にHTTP応答コードを識別するので、監視システム500の割合を特定するときに応答が比較的高いHTTP、システムの可用性が問題があると思いますが、このときの警告システムは警告します

この通常の場合、通常200あなたには、いくつかの未知のシステムエラーメッセージを識別し、システムの作業がより良いモニターにし、正しいことができるようにHTTPは、正常な動作ですに対処するために、そして、ビジネスロジックを知ら識別誤警報、警報システムとなるよう、より敏感でなく、ビジネスロジックの例外干渉警告システムを回避するために、

次に、例外フィルタを経由して、第三を見て

これは、システム全体が、次の枠組みの中でのミドルウェアの役割のMVC最古の発生を行われている、それはないが、実際にアクションの方法ですそれが唯一で働くことができることを意味MVCライフサイクル全体、内部リクエストサイクルMVCのWeb API内部

まず、カスタムMyExceptionFilter

namespace ExceptionDemo.Exceptions
{
    public class MyExceptionFilter : IExceptionFilter
    {
        public void OnException(ExceptionContext context)
        {
            IKnownException knownException = context.Exception as IKnownException;
            if (knownException == null)
            {
                var logger = context.HttpContext.RequestServices.GetService<ILogger<MyExceptionFilterAttribute>>();
                logger.LogError(context.Exception, context.Exception.Message);
                knownException = KnownException.Unknown;
                context.HttpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
            }
            else
            {
                knownException = KnownException.FromKnownException(knownException);
                context.HttpContext.Response.StatusCode = StatusCodes.Status200OK;
            }
            context.Result = new JsonResult(knownException)
            {
                ContentType = "application/json; charset=utf-8"
            };
        }
    }
}

前と同じロジックを処理

そして、登録フィルタ

services.AddMvc(mvcOptions =>
{
    mvcOptions.Filters.Add<MyExceptionFilter>();
}).AddJsonOptions(jsonoptions =>
{
    jsonoptions.JsonSerializerOptions.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
});

次のようにプログラムを起動し、出力は次のようになります。

{"message":"未知错误","errorCode":9999,"errorData":null}

前の出力と一致し、それはコントローラの出力誤差内にあるので、

MVCミドルウェアの前に出力エラーがあれば、それはに対処する方法はありません

通常の状況下では、このシナリオには、コントローラを扱う特別な例外の必要性を意味し、別の特定のロジックで再度処理全体の中間の点で、あなたはマナーExceptionFilterを処理することができます

この方法であなたは属性の仕方によってもできます

MyExceptionFilterAttributeのカスタマイズ

namespace ExceptionDemo.Exceptions
{
    public class MyExceptionFilterAttribute : ExceptionFilterAttribute
    {
        public override void OnException(ExceptionContext context)
        {
            IKnownException knownException = context.Exception as IKnownException;
            if (knownException == null)
            {
                var logger = context.HttpContext.RequestServices.GetService<ILogger<MyExceptionFilterAttribute>>();
                logger.LogError(context.Exception, context.Exception.Message);
                knownException = KnownException.Unknown;
                context.HttpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
            }
            else
            {
                knownException = KnownException.FromKnownException(knownException);
                context.HttpContext.Response.StatusCode = StatusCodes.Status200OK;
            }
            context.Result = new JsonResult(knownException)
            {
                ContentType = "application/json; charset=utf-8"
            };
        }
    }
}

コントローラーでMyExceptionFilterの上にマーク

[MyExceptionFilter]
public class WeatherForecastController : ControllerBase

あなたは同じ効果の実行を開始した後

あなたは例外処理のよりきめ細かい制御を言うことができることを、コントローラまたは例外の指定部分は、私たちの例外処理を決定する、またはグローバルExceptionFilterに登録することを除き、これらの2つの方法の効果は、等価です

それはまた、グローバルにサインアップすることができるようにExceptionFilterAttributeも、IExceptionFilterを達成しましたので、もちろん、あなたはまた、使用するグローバル例外ハンドラのフィルタとして使用することができ、上記の必要はありませんラベルのコントローラー

登録フィルタ

services.AddMvc(mvcOptions =>
{
    //mvcOptions.Filters.Add<MyExceptionFilter>();
    mvcOptions.Filters.Add<MyExceptionFilterAttribute>();
}).AddJsonOptions(jsonoptions =>
{
    jsonoptions.JsonSerializerOptions.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
});

コントローラで上記のラベルMyExceptionFilterをキャンセル

//[MyExceptionFilter]
public class WeatherForecastController : ControllerBase

プログラムを起動し、一貫性のある出力

このシナリオでは、我々は、APIのいくつかを定義し、私たちの慣例を扱うAPI定義された例外は便利です

要約します

まず、我々は、特定の例外クラスやインタフェースを定義する必要があり、我々は抽象クラスを定義することができ、インタフェース手段は、例外ビジネス・ロジック・インターフェースを経由して、例えば、ショーを使用することができます

ビジネスロジックの例外の場合は、実際には、我々は世界的なエラーコードを定義する必要があります

未知の異常の場合は、出力が特定の出力およびエラーコードで、その後、完全なログを記録する必要があり、私たちは、このようなユーザへの例外スタック情報出力として内部システムの一部を取るべきではありません

より良い仕事に監視システムを可能にする方法HTTP 200、異常不明のため、道によるHTTP 500、との既知のビジネスロジックの例外のための

もう一つの提案は、その後の分析のためにログに例外のすべての詳細を記録しようとすることですが、また、監視システムのためのいくつかの具体的な監視、警告を行うために

クリエイティブコモンズライセンス

この作品は、ある非営利- -同一条件許諾4.0の国際ライセンス契約クリエイティブ・コモンズのライセンスのために。

転載、使用、再投稿へようこそ、しかし鄭Ziming(リンクを含む:http://www.cnblogs.com/MingsonZheng/)によって署名された記事を保つようにしてください、商業目的のために使用してはならない、紙のライセンス変更に基づいて、同じ作業を公開するようにしてください。

ご質問があれば、私に連絡してください([email protected])。

おすすめ

転載: www.cnblogs.com/MingsonZheng/p/12483923.html