防止 Swashbuckle 设置“Accept”标头

Prevent Swashbuckle from setting "Accept" header

提问人:exploring.cheerily.impresses 提问时间:11/16/2023 最后编辑:Ruikai Fengexploring.cheerily.impresses 更新时间:11/21/2023 访问量:57

问:

我有一个 .NET 7 Web API 项目,我使用该项目来生成 Swagger UI。Swashbuckle.AspNetCore

我的一个端点可以根据响应状态代码返回不同的值; 对于 200 和 404。Content-Typeapplication/xmlapplication/json

我设法让 Swagger UI 通过使用属性装饰控制器方法来传达这一点,以便 200 的示例响应显示为 XML,而 404 的示例响应显示为 JSON。目前为止,一切都好。SwaggerResponse

当我实际从 Swagger UI 调用端点时,问题就来了。响应始终是 XML,即使对于 404 也是如此。我在 Postman 中调用了相同的端点,令我惊讶的是,看到了不同的行为 - JSON 用于 404 而不是 XML。然后我意识到发生了什么:Swagger UI 正在传递内容类型为 的标头,因此它基本上是在进行内容协商。Acceptapplication/xml

更仔细地观察 Swagger,在第一个示例响应旁边显示“Controls Accept header”的位置很清楚:

enter image description here

我的问题是:是否可以更改此行为,以便 Swashbuckle 不会自动传递 Accept 标头?

重现问题的最小代码示例

程序.cs:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();

builder.Services
    .AddMvc()
    .AddXmlSerializerFormatters();

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

var app = builder.Build();

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

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

天气预报控制器.cs:

using System.Runtime.Serialization;
using System.Xml.Linq;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;

namespace WebApplication1.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        private readonly ILogger<WeatherForecastController> _logger;

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

        [HttpGet(Name = "GetWeatherForecast")]
        [Produces("application/xml", "application/json")]
        [SwaggerResponse(200, Type = typeof(XDocument), ContentTypes = new[] { "application/xml" })]
        [SwaggerResponse(404, Type = typeof(ProblemDetails), ContentTypes = new[] { "application/json" })]
        public ActionResult<WeatherForecast> Get(string region)
        {
            if (region is not "Yorkshire")
            {
                return this.NotFound();
            }

            var forecast = Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();

            var doc = new XDocument();
            using (var writer = doc.CreateWriter())
            {
                // write xml into the writer
                var serializer = new DataContractSerializer(forecast.GetType());
                serializer.WriteObject(writer, forecast);
            }

            return this.Content(doc.ToString(), "application/xml");
        }
    }
}

天气预报.cs:

namespace WebApplication1
{
    public class WeatherForecast
    {
        public DateOnly Date { get; set; }

        public int TemperatureC { get; set; }

        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);

        public string? Summary { get; set; }
    }
}
swagger asp.net-core-webapi swashbuckle

评论


答:

0赞 Ruikai Feng 11/17/2023 #1

从您的评论中了解您的观点

您可以尝试使用过滤器:

public class AddContentTypeFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        var responses= operation.Responses;
        foreach(var response in responses)
        {
            response.Value.Content.Add("*/*", new OpenApiMediaType() );
        }
    }
}

应用它:

builder.Services.AddSwaggerGen(c => c.OperationFilter<AddContentTypeFilter>());

现在,您可以选择“200 个结果”选项

enter image description here

它将允许所有内容类型

对于 404:

enter image description here

对于 200:

enter image description here

评论

0赞 exploring.cheerily.impresses 11/20/2023
您好,感谢您抽出宝贵时间查看此内容。你是对的,这是由 .我根据要求为问题添加了一个最小的示例。XmlSerializerOutputFormatter
0赞 exploring.cheerily.impresses 11/20/2023
理想情况下,我仍然想知道是否可以将 Swashbuckle 配置为不根据与第一个示例响应关联的媒体类型自动传递 Accept 请求标头。
0赞 Ruikai Feng 11/21/2023
我明白你的意思,很难阻止它设置标题(这将在 js 中完成),但我们可以添加一个选项,我们可以接受所有内容类型,我已经更新了我的答案,希望对您有所帮助