2017-05-17 10 views
1

私はAPIを持つ.NET Core Webアプリケーションを持っています。例外がコードでスローされたときにのみ、エラー処理が扱う不正な.NET Core APIルートに404を投げる方法?

public class ErrorHandlingMiddleware 
{ 
    private readonly RequestDelegate next; 
    private readonly ILogger logger; 

    public ErrorHandlingMiddleware(RequestDelegate next, 
     ILoggerFactory loggerFactory) 
    { 
     this.next = next; 
     logger = loggerFactory.CreateLogger<ErrorHandlingMiddleware>(); 
    } 

    public async Task Invoke(HttpContext context) 
    { 
     try 
     { 
      await next(context); 
     } 
     catch (Exception ex) 
     { 
      logger.LogError(0, ex, "An unhandled exception has occurred: " + ex.StackTrace); 
      await HandleExceptionAsync(context, ex); 
     } 
    } 

    private static Task HandleExceptionAsync(HttpContext context, Exception exception) 
    { 
     var code = HttpStatusCode.InternalServerError; 
     var message = exception.Message; 
     if (exception is BadRequestException) 
     { 
      code = HttpStatusCode.BadRequest; 
     } 
     else if (exception is NotFoundException) 
     { 
      code = HttpStatusCode.NotFound; 
     } 
     else if (exception is NotAuthorizedException) 
     { 
      code = HttpStatusCode.Forbidden; 
     } 
     else if (exception is NotAuthenticatedException) 
     { 
      code = HttpStatusCode.Unauthorized; 
     } 
     else 
     { 
      message = "An unexpected error occurred."; 
     } 

     var result = JsonConvert.SerializeObject(new { error = message }); 
     context.Response.ContentType = "application/json"; 
     context.Response.StatusCode = (int)code; 
     return context.Response.WriteAsync(result); 
    } 
} 

:私はそうのようなthis回答に基づいてミドルウェアクラスを定義しました。悪いルートは例外をスローしません。問題は、存在しないAPIルートにアクセスしようとすると、つまり、APIルート規則に従って "/ api/adfasdf"で始まるAPIにアクセスしようとすると、APIがHTML(またはエラーページまたはホームページ、私は忘れる)。

await next(context);の実行後にcontext.Response.StatusCodeを確認するための提案がありましたが、それは200です。

ウェブアプリケーションが悪いAPIルートを認識して404を返すように設定するにはどうすればよいですか?

UPDATE私は私のスタートアップクラスでミドルウェアを読み込む際にここで が/さ:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationLifetime appLifetime, IOptions<OidcConfig> oidcConfigOptions) 
{ 
    loggerFactory.AddConsole(Configuration.GetSection("Logging")); 
    loggerFactory.AddDebug(); 

    // Add Serilog to the logging pipeline 
    loggerFactory.AddSerilog(); 

    app.UseMiddleware<ErrorHandlingMiddleware>(); 

    if (env.IsLocal()) 
    { 
     app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions 
     { 
      HotModuleReplacement = true 
     }); 
    } 

    var oidcConfig = oidcConfigOptions.Value; 

    // Configure the app to use Jwt Bearer Authentication 
    app.UseJwtBearerAuthentication(new JwtBearerOptions 
    { 
     AutomaticAuthenticate = true, 
     AutomaticChallenge = true, 
     Authority = oidcConfig.GetAuthority(), 
     Audience = oidcConfig.ResourceAppId, 
     TokenValidationParameters = new TokenValidationParameters 
     { 
      RequireExpirationTime = true, 
      RequireSignedTokens = true, 
      ValidateAudience = true, 
      ValidIssuer = oidcConfig.GetIssuer(), 
      ValidateIssuer = true, 
      ValidateActor = false, 
      ValidateLifetime = true, 
      ValidateIssuerSigningKey = true 
     }, 
    }); 

    app.UseSiteIdClaimInjection(); 

    app.UseStaticFiles(); 

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

     routes.MapSpaFallbackRoute(
      name: "spa-fallback", 
      defaults: new { controller = "Home", action = "Index" }); 
    }); 

    appLifetime.ApplicationStopped.Register(() => this.ApplicationContainer.Dispose()); 
} 
+0

あなたが右隣(コンテキスト)を待つ ''を呼び出した後context.Response.StatusCode'を検査しようとすることができ; ' – Nkosi

+0

@Nkosiものですその答えのコメントに示唆された。 '200'を返します。 – im1dermike

+0

その/ flowコントロールの例外を乱用しないでください。これらは予期した結果ではない例外のためのものです。 – Tseng

答えて

1

ASP.NET Core Middleware Fundamentals - Ordering

ミドルウェアコンポーネントを構成する方法で追加される順序を参照 定義それらが要求に対して呼び出される順序、および応答の逆の順序が含まれます。この順序付けは、セキュリティ、パフォーマンス、および機能性の面では、 にとって重要です。

設定方法(以下に示す)は、以下のミドルウェア コンポーネント追加:

  • 静的ファイルサーバ
  • 認証
  • 取り扱い

    • 例外/エラーをMVC

    C#

    上記のコードでは
    public void Configure(IApplicationBuilder app) 
    { 
        app.UseExceptionHandler("/Home/Error"); // Call first to catch exceptions 
                  // thrown in the following middleware. 
    
        app.UseStaticFiles();     // Return static files and end pipeline. 
    
        app.UseIdentity();      // Authenticate before you access 
                  // secure resources. 
    
        app.UseMvcWithDefaultRoute();   // Add MVC to the request pipeline. 
    } 
    

    UseExceptionHandlerはパイプライン従ってに追加最初のミドルウェア 成分であり、それは後の呼び出しで発生する例外をキャッチ 。

  • OPおよび引用されたドキュメントで提供されているコードに基づいて、あなたの例外を先に、または最初にパイプラインに追加することをお勧めします。

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationLifetime appLifetime) { 
        loggerFactory.AddConsole(Configuration.GetSection("Logging")); 
        loggerFactory.AddDebug(); 
        loggerFactory.AddSerilog(); 
    
        app.UseMiddleware<ErrorHandlingMiddleware>(); // Call first to catch exceptions 
                    // thrown in the following middleware.  
        if (env.IsLocal()) { 
         app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions { HotModuleReplacement = true }); 
        } 
    
        //Bunch of other stuff 
    } 
    

    UPDATEコメントに基づいています。

    ミドルウェアの1つがさらにパイプラインを通過してこの問題が発生している可能性があります。それを一つずつ取り除き、どちらが犯人かを絞り込むために同じ行動を取るかどうかを調べてみてください。

    +0

    'context.Response.StatusCode'から' await next(context);の後に '200'が得られます。 – im1dermike

    +0

    ミドルウェアの1つがパイプラインを経由してこの問題を引き起こしていると思われます。それを一つずつ取り除き、どちらが犯人かを絞り込むために同じ行動を取るかどうかを調べてみてください。 – Nkosi

    +1

    ビンゴ! https://github.com/aspnet/JavaScriptServicesで追加された 'MapSpaFallbackRoute'のようです。 – im1dermike

    1

    後継のために、@ NkosiがStartupクラスのMVCルート定義と関係があることを助けたように、私は200を得ていたのです。これはhttps://github.com/aspnet/JavaScriptServicesから自動的に入力されました。ソリューションは、以下に私のルートの設定を変更することでした

    app.UseMvc(routes => 
    { 
        routes.MapRoute(
         name: "default", 
         template: "{controller=Home}/{action=Index}/{id?}"); 
    }); 
    
    app.MapWhen(x => !x.Request.Path.Value.StartsWith("/api"), builder => 
    { 
        builder.UseMvc(routes => 
        { 
         routes.MapSpaFallbackRoute(
          name: "spa-fallback", 
          defaults: new { controller = "Home", action = "Index" }); 
        }); 
    }); 
    
    関連する問題