You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 8 Web API自定义异常处理器在Swagger与Postman中表现不一致的问题求助

.NET 8 Web API自定义异常处理器在Swagger与Postman中表现不一致的问题求助

大家好,我最近在搞.NET 8 Web API的错误管理,想找个优雅的方案确保出错时始终返回ProblemDetails格式的响应。我用的是默认的WeatherForecast API模板,已经实现了自定义异常处理器,但发现它的表现不太稳定:

  • 用Postman调用触发错误时,能正常返回正确的ProblemDetails、状态码和头部信息;
  • 但用Swagger的“Try it out”功能调用时,却返回500内部错误,还带了异常详情而非ProblemDetails,头部信息也不对。

排查后发现,我的GlobalExceptionHandler类(实现了IExceptionHandler接口)里,ProblemDetailsService.TryWriteAsync(...)方法在Swagger调用时返回false,但Postman调用时返回true。于是我加了失败分支,尝试直接把ProblemDetailsContext写入httpContext.Response,结果遇到了这个仅在Swagger调用时出现的异常:

Serialization and deserialization of 'System.Type' instances is not supported. Path: $.HttpContext.Features.Key."

我完全搞不懂为什么会这样,想请教各位怎么才能让错误管理在不同调用方式下表现一致?

以下是我的相关代码:

GlobalExceptionHandler 实现

public class GlobalExceptionHandler : IExceptionHandler
{
      private readonly IProblemDetailsService _problemDetailsService;

      public GlobalExceptionHandler(IProblemDetailsService problemDetailsService)
      {
          if (problemDetailsService == null) throw new ArgumentException(nameof(problemDetailsService));
          _problemDetailsService = problemDetailsService;
      }

      public async ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
      {
          var message = exception switch
          {
              ArgumentException => ((ArgumentException)exception).Message,
              ValidationException => ((ValidationException)exception).Message,
              _ => $"Internal Server Error ({exception.GetType().Name})"
          };

          int status = exception switch
          {
              ArgumentException => (int)HttpStatusCode.BadRequest,
              ValidationException => (int)HttpStatusCode.BadRequest,
              _ => (int)HttpStatusCode.InternalServerError
          };

          ProblemDetails problemDetails = new()
          {
              Title = $"Bad Request: {exception.GetType().Name}", // human-readable summary of the problem type
              Detail = message, //detailed explanation specific to the problem
              Status = status,
              Instance = httpContext.Request.GetEncodedUrl(),
              Type = exception.HelpLink
          };

          var errorcontext = new ProblemDetailsContext()
          {
              HttpContext = httpContext,
              ProblemDetails = problemDetails,
              //Exception = exception,
              AdditionalMetadata = null
          };

          httpContext.Response.Clear();
          httpContext.Response.StatusCode = status;

          var written = await _problemDetailsService.TryWriteAsync(errorcontext);

          if (!written)
          {
              try
              {
                  await httpContext.Response.WriteAsJsonAsync<ProblemDetailsContext>(errorcontext);
                  written = true;
              }
              catch (Exception ex)
              {
                  Console.WriteLine(ex.ToString());
                  written = false;
              }
          }

          return written;
      }
}

Program.cs 配置

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Net;
using System;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System.Net.Http;
using Microsoft.AspNetCore.Diagnostics;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();

// Add services to the container.
builder.Services.AddExceptionHandler<ProblemDetailsScratchPad.GlobalExceptionHandler>();   // Using a custom exception handler that converts the exception into a Problem Details
builder.Services.AddProblemDetails();  // required for using the exception handler with the custom problem details exception handler code because it adds the services required for Problem Details

// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseExceptionHandler(opt => { }); //adding the custom GlobalExceptionHandler to the app's pipeline
app.UseAuthorization();

app.MapControllers();

app.Run();

WeatherForecastController 测试代码

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    

    private readonly ILogger<WeatherForecastController> _logger;

    public WeatherForecastController(ILogger<WeatherForecastController> logger)
    {
        _logger = logger;
    }

    [HttpGet("GetWeatherForecast")]
    public ActionResult<IEnumerable<object>> GetWeatherForecast()
    {
        
            throw new ArgumentException("Please provide a valid value for a week day: between 0 and 6");

    }

    [HttpPost("PostWeatherForecastDTO")]
    public ActionResult<IEnumerable<object>> PostWeatherForecastDTO()
    {
         throw new Exception("Please provide a valid value for a week day: between 0 and 6");

    }
}

备注:内容来源于stack exchange,提问作者Frinavale

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 03:18:26