web-dev-qa-db-ja.com

asp.netコアで例外を処理しますか?

Asp.netコアアプリケーションがあります。 configureメソッドの実装は、例外がある場合にユーザーを「エラー」ページにリダイレクトします(非開発環境で)

ただし、コントローラー内で例外が発生した場合にのみ機能します。コントローラーの外部、たとえばカスタムミドルウェアで例外が発生した場合、ユーザーはエラーページにリダイレクトされません。

ミドルウェアに例外がある場合、ユーザーを「エラー」ページにリダイレクトするにはどうすればよいですか。

_     public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        app.UseApplicationInsightsRequestTelemetry();

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

        app.UseApplicationInsightsExceptionTelemetry();

        app.UseStaticFiles();
        app.UseSession();
        app.UseMyMiddleware();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }
_

更新1
最初の投稿で欠落していた次の2行で上記のコードを更新しました。

_        app.UseSession();
        app.UseMyMiddleware();
_

また、_app.UseExceptionHandler_がエラーページにリダイレクトできなかった理由を見つけました。
ミドルウェアコードに例外がある場合、app.UseExceptionHandler("\Home\Error")は期待どおり_\Home\Error_にリダイレクトしています。しかし、それは新しいリクエストなので、私のミドルウェアは再び実行され、再び例外を投げていました。
それで問題を解決するために、ミドルウェアを_if context.Request.Path != "/Home/Error"_のみを実行するように変更しました

これがこの問題を解決する正しい方法であるかどうかはわかりませんが、機能します。

_public class MyMiddleWare
{
    private readonly RequestDelegate _next;
    private readonly IDomainService _domainService;

    public MyMiddleWare(RequestDelegate next, IDomainService domain)
    {
        _next = next;
        _domainService = domain;
    }

    public async Task Invoke(HttpContext context)
    {
        if (context.Request.Path != "/Home/Error")
        {
            if (context.User.Identity.IsAuthenticated && !context.Session.HasKey(SessionKeys.USERINFO))
            {           
                // this method may throw exception if domain service is down
                var userInfo = await _domainService.GetUserInformation(context.User.Name).ConfigureAwait(false);                    

                context.Session.SetUserInfo(userInfo);
            }
        }

        await _next(context);
    }
}

public static class MyMiddleWareExtensions
{
    public static IApplicationBuilder UseMyMiddleWare(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<MyMiddleWare>();
    }
 }
_
15
LP13

例外UseExceptionHandler()を処理するために使用でき、このコードを_Startup.cs_に入れます。

UseExceptionHandlerを使用して、例外をグローバルに処理できます。 Stack Trace、Inner exceptionなどの例外オブジェクトの詳細をすべて取得できます。そして、それらを画面に表示できます。 ここ

ここでは、この診断ミドルウェアの詳細を確認し、IExceptionFilterの使用方法と独自のカスタム例外ハンドラーを作成する方法を見つけることができます。

_   app.UseExceptionHandler(
                options =>
                {
                    options.Run(
                        async context =>
                        {
                            context.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
                            context.Response.ContentType = "text/html";
                            var ex = context.Features.Get<IExceptionHandlerFeature>();
                            if (ex != null)
                            {
                                var err = $"<h1>Error: {ex.Error.Message}</h1>{ex.Error.StackTrace}";
                                await context.Response.WriteAsync(err).ConfigureAwait(false);
                            }
                        });
                }
            );
_

UseDeveloperExceptionPage()などのデフォルト設定も削除する必要があります。使用すると、常にデフォルトのエラーページが表示されます。

_   if (env.IsDevelopment())
        {
            //This line should be deleted
            app.UseDeveloperExceptionPage();
            app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }
_
18
M. Wiśnicki

カスタムの例外処理を処理するには、独自のミドルウェアを作成する必要があります。また、ミドルウェアスタックの「早い」ミドルウェアで発生する例外は処理されないため、ミドルウェアスタックの先頭(可能な場合は最初)に追加してください。

例:

public class CustomExceptionMiddleware
{
    private readonly RequestDelegate _next;

    public CustomExceptionMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        try 
        {
            await _next.Invoke(context);
        } 
        catch (Exception e) 
        {
            // Handle exception
        }
    }
}
6
Andrius