提问人:exploring.cheerily.impresses 提问时间:11/16/2023 最后编辑:Ruikai Fengexploring.cheerily.impresses 更新时间:11/21/2023 访问量:57
防止 Swashbuckle 设置“Accept”标头
Prevent Swashbuckle from setting "Accept" header
问:
我有一个 .NET 7 Web API 项目,我使用该项目来生成 Swagger UI。Swashbuckle.AspNetCore
我的一个端点可以根据响应状态代码返回不同的值; 对于 200 和 404。Content-Type
application/xml
application/json
我设法让 Swagger UI 通过使用属性装饰控制器方法来传达这一点,以便 200 的示例响应显示为 XML,而 404 的示例响应显示为 JSON。目前为止,一切都好。SwaggerResponse
当我实际从 Swagger UI 调用端点时,问题就来了。响应始终是 XML,即使对于 404 也是如此。我在 Postman 中调用了相同的端点,令我惊讶的是,看到了不同的行为 - JSON 用于 404 而不是 XML。然后我意识到发生了什么:Swagger UI 正在传递内容类型为 的标头,因此它基本上是在进行内容协商。Accept
application/xml
更仔细地观察 Swagger,在第一个示例响应旁边显示“Controls Accept header”的位置很清楚:
我的问题是:是否可以更改此行为,以便 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; }
}
}
答:
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 个结果”选项
它将允许所有内容类型
对于 404:
对于 200:
评论
0赞
exploring.cheerily.impresses
11/20/2023
您好,感谢您抽出宝贵时间查看此内容。你是对的,这是由 .我根据要求为问题添加了一个最小的示例。XmlSerializerOutputFormatter
0赞
exploring.cheerily.impresses
11/20/2023
理想情况下,我仍然想知道是否可以将 Swashbuckle 配置为不根据与第一个示例响应关联的媒体类型自动传递 Accept 请求标头。
0赞
Ruikai Feng
11/21/2023
我明白你的意思,很难阻止它设置标题(这将在 js 中完成),但我们可以添加一个选项,我们可以接受所有内容类型,我已经更新了我的答案,希望对您有所帮助
评论