【问题标题】:How can I catch ASP.NET Core (3.1) URL parsing error with my custom exception middleware?如何使用自定义异常中间件捕获 ASP.NET Core (3.1) URL 解析错误?
【发布时间】:2020-04-17 21:34:11
【问题描述】:

我在 ASP.NET Core 3.1 (WebAPI) 项目中添加了一个自定义异常中间件。中间件非常简单,它捕获特定类型的异常并将适当的消息传递给消费者,同时为其他所有内容发送通用错误消息。

这是中间件类:

    /// <summary>
    /// Middleware which catches controller exceptions and extracts exceptions which are specifically intended for the 
    /// client and sends them as a regular response (and not 500 server error).
    /// </summary>
    public class ExceptionMiddleware
    {
        private readonly RequestDelegate _next;
        private ILogger<ExceptionMiddleware> _logger;

        public ExceptionMiddleware(RequestDelegate next, ILogger<ExceptionMiddleware> logger)
        {
            _next = next;
            _logger = logger;
        }

        public async Task Invoke(HttpContext context)
        {
            try
            {
                await _next(context);
            }
            catch (MDEException ex) // we only care about this particular exception
            {
                // Send exception message as plain message
                _logger.Log(LogLevel.Error, ex.Message);
                context.Response.ContentType = "text/plain";
                context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
                await context.Response.WriteAsync(ex.Message);
            }
            catch (Exception ex)
            {
                // Send generic error as plain message
                _logger.Log(LogLevel.Error, ex, ex.Message);
                context.Response.ContentType = "text/plain";
                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                await context.Response.WriteAsync("Es trat ein unvorhergesehenes Problem auf - bitte kontaktieren Sie Ihren Administrator!");
            }
        }
    }

这一切都很好,除非我向应用程序发送无效的 URL。在这种情况下,我的中间件甚至没有被触及。例如,如果我使用此 URL:api/vm/ziel-standort/stellplatzId=2,则会收到类似以下的错误:

{"errors":{"stellplatzId":["The value 'stellplatzId=2' is not valid."]},"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1","title":"One or more validation errors occurred.","status":400,"traceId":"|d7456c7b-469208468c4ac571."}

我的 Configure 方法如下所示:

/// <summary>
/// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
/// </summary>
/// <param name="app">Application builder (injected by framework)</param>
/// <param name="log">Logger (injected by framework)</param>
/// <param name="actionProvider">Action provider for listing routes (injected by framework)</param>
public void Configure(IApplicationBuilder app, ILogger<Startup> log, Microsoft.AspNetCore.Mvc.Infrastructure.IActionDescriptorCollectionProvider actionProvider)
{
    log.Log(LogLevel.Information, "Configuring application ...");

    log.Log(LogLevel.Debug, "Using CorsPolicy");
    app.UseCors("CorsPolicy");

    log.Log(LogLevel.Debug, "Using Exception middleware (MDEException message pass-through to client)");
    app.UseMiddleware<ExceptionMiddleware>();

    log.Log(LogLevel.Debug, "Enabling routing");
    app.UseRouting();

    log.Log(LogLevel.Debug, "Enabling authentication and authorization");
    app.UseAuthentication();
    app.UseAuthorization();

    log.Log(LogLevel.Debug, "Setting up routing for controllers");
    app.UseEndpoints(opt =>
    {
        opt.MapControllers();
    });

    // .....
}

如何让我的中间件捕捉到这个错误?

【问题讨论】:

    标签: asp.net-core .net-core url-routing asp.net-core-webapi


    【解决方案1】:

    您收到模型验证错误,而不是异常。要覆盖它,您可以在 Startup 类的 ConfigureServices 方法中使用以下代码:

            services.AddControllers()
                .ConfigureApiBehaviorOptions(o =>
                {
                    o.InvalidModelStateResponseFactory = context =>
                    {
                        var _logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<Startup>>();
                        var ex = new Exception(context.ModelState.Values.First().Errors.First().ErrorMessage);
                        _logger.Log(LogLevel.Error, ex, ex.Message);
                        context.HttpContext.Response.ContentType = "text/plain";
                        context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                        context.HttpContext.Response.WriteAsync("Es trat ein unvorhergesehenes Problem auf - bitte kontaktieren Sie Ihren Administrator!");
                        return new EmptyResult();
                    };
                });
    

    而且,这就是应该根据 Microsoft 文档进行异常处理的方式:

            app.UseExceptionHandler(errorApp =>
            {
                errorApp.Run(async context =>
                {
                    var ex = context.Features.Get<IExceptionHandlerPathFeature>()?.Error;                    
                    if (ex is MDEException) // we only care about this particular exception
                    {
                        // Send exception message as plain message
                        _logger.Log(LogLevel.Error, ex.Message);
                        context.Response.ContentType = "text/plain";
                        context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
                        await context.Response.WriteAsync(ex.Message);
                    }
                    else
                    {
                        // Send generic error as plain message
                        _logger.Log(LogLevel.Error, ex, ex.Message);
                        context.Response.ContentType = "text/plain";
                        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                        await context.Response.WriteAsync("Es trat ein unvorhergesehenes Problem auf - bitte kontaktieren Sie Ihren Administrator!");
                    }
                });
            });
    

    【讨论】:

      猜你喜欢
      • 2020-09-23
      • 2019-06-30
      • 1970-01-01
      • 2019-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-24
      • 2019-01-24
      相关资源
      最近更新 更多