【问题标题】:Exception handling using Hellang middleware in .Net Core MVC在 .Net Core MVC 中使用 Hellang 中间件进行异常处理
【发布时间】:2021-05-25 14:07:55
【问题描述】:

我使用Hellang 中间件作为我的 MVC 应用程序中的全局异常处理机制进行异常处理。 我在 Startup.cs 的 ConfigureServices 方法中添加了以下代码:

services.AddProblemDetails(opts =>
            {
                // Control when an exception is included
                opts.IncludeExceptionDetails = (ctx, ex) =>
                {
                    // Fetch services from HttpContext.RequestServices
                    var env = ctx.RequestServices.GetRequiredService<IHostEnvironment>();
                    return env.IsDevelopment() || env.IsStaging();
                };
                opts.ShouldLogUnhandledException = (ctx, e, d) =>
                {
                    return (d.Status.HasValue && d.Status.Value >= 500);
                };
            });

我还在 Configure 方法中添加了UseProblemDetails()

但是我知道如果我使用UseProblemDetails(),那么UseExceptionHandler() 将不起作用! 因此,我无法找出将用户导航到常见错误视图页面的方法。

在坚持使用 Hellang Middleware 进行异常处理和日志记录的同时,有什么方法可以将用户重定向到错误页面?

【问题讨论】:

    标签: exception asp.net-core-mvc middleware


    【解决方案1】:

    我遇到了类似的问题。我像下面这样解决了它。在此示例中记录自定义业务故障异常:

    services.AddProblemDetails(setup =>
    {
        setup.Map<FaultException<BusinessFault>>((context, exception) =>
        {
            // resolve logger
            var logger = context.RequestServices.GetRequiredService<ILogger<ProblemDetails>>();
    
            // log exception to Seq
            logger.LogError(exception, "{@Exception} occurred.", exception);
    
            // return the problem details map   
            return new ProblemDetails
            {
                Title = exception.Message,
                Detail = exception.Detail.FaultMessage,
                Status = exception.Detail.FaultType.ToHttpStatus(),
                Type = exception.Detail.FaultType.ToString(),
                Instance = exception.Detail.FaultReference
            };
        });
    });
    

    【讨论】:

      【解决方案2】:

      在此处查看答案: https://stackoverflow.com/a/40153711/90287

      您必须区分请求的类型,是 API 请求还是 UI 请求,以分别确定是否应返回问题+详细信息 JSON 或是否应返回网页。

      这是我在Startup.csConfigure方法顶部附近所做的:

      app.UseWhen(context => context.IsApiRequest(), branch =>
      {
          branch.UseProblemDetails();
      });
      
      app.UseWhen(context => !context.IsApiRequest(), branch =>
      {
          branch.UseExceptionHandler("/Home/Error");
      });
      

      您可以定义自己的自定义 HttpContext 扩展方法:

      public static class HttpContextExtensions
      {
          public static bool IsApiRequest(this HttpContext context)
          {
              return context.Request.Path.StartsWithSegments("/api", StringComparison.OrdinalIgnoreCase)
                  || (context.Request.Headers["X-Requested-With"] == "XMLHttpRequest"); // AJAX request
          }
      }
      

      【讨论】:

        【解决方案3】:

        这不完全是您问题的答案,但我在 Web API 应用程序中遇到了关于使用 ExceptionHandler 中间件和 Hellang ProblemDetails 中间件的类似问题,我也意识到我不能同时使用它们,因为它们都会改变响应以自己的方式并相互影响。

        根据文档here,您可以使用 ProblemDetails 包的配置选项之一在更改响应之前执行代码,您可以在那里记录您需要的所有信息。

        services.AddProblemDetails(options =>
                {
                    options.IncludeExceptionDetails = (context, ex) =>
                    {
                        var environment = context.RequestServices.GetRequiredService<IWebHostEnvironment>();
                        return environment.IsDevelopment();
                    };
        
                    options.Map<IdentityException>(exception => new ProblemDetails()
                    {
                        Title = exception.Title,
                        Detail = exception.Detail,
                        Status = StatusCodes.Status500InternalServerError,
                        Type = exception.Type,
                        Instance = exception.ToString()
                    });
        
                    options.OnBeforeWriteDetails = (ctx, pr) =>
                    {
                        //here you can do the logging
                        logger.LogError("Exception Occurred!!!!");
                        logger.LogError(pr.Detail);
                        logger.LogError(pr.Instance);
                    };
                });
        

        在这里,我使用了一个自定义异常,其中包含问题详细信息对象所需的额外字段作为响应,我使用 Instance 字段来保存异常并记录它。

        【讨论】:

        • 你是从哪里神奇地得到记录器的?
        • 您可以在此处访问 IServiceCollection,因此您可以构建 ServiceProvider 并从 DI 容器解析记录器。
        猜你喜欢
        • 2017-06-18
        • 1970-01-01
        • 1970-01-01
        • 2021-08-06
        • 2017-03-29
        • 2018-09-16
        • 1970-01-01
        • 1970-01-01
        • 2019-01-24
        相关资源
        最近更新 更多