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

.NET Core 6 Swagger支持XML输出时Dictionary引发FormatterNotFoundException

解决.NET Core 6 API中Swagger与XML格式化器兼容Dictionary的问题

问题背景

在.NET Core 6 API项目中,已配置Swagger及Swashbuckle.AspNetCore.Filters组件,同时为支持XML输出添加了以下序列化配置:

builder.Services.AddControllers(options =>
{
    options.InputFormatters.Add(new XmlSerializerInputFormatter(options));
    options.OutputFormatters.Add(new XmlSerializerOutputFormatter());
});

但当控制器方法添加[Produces("application/json", "application/xml")]特性,并返回包含Dictionary<string, string>属性的SeekApprovalResponse类型时,生成swagger.json时抛出错误:

Swashbuckle.AspNetCore.Filters.MvcOutputFormatter+FormatterNotFoundException: OutputFormatter not found for 'application/xml; charset=utf-8'

经排查,问题核心是ErrorResponse类中的Dictionary<string, string> Errors属性——默认的XmlSerializerOutputFormatter无法原生处理Dictionary类型的XML序列化,导致Swashbuckle在生成XML格式示例时找不到可用的格式化器。


解决方案

方案一:改用DataContractSerializer处理XML序列化

默认的XmlSerializer不支持Dictionary的原生序列化,而DataContractSerializer原生支持该类型。替换XML格式化器并配置类的序列化特性即可解决问题:

  1. 修改控制器配置,替换XML格式化器:
builder.Services.AddControllers(options =>
{
    // 移除原有的XmlSerializer格式化器
    var existingXmlOutput = options.OutputFormatters.OfType<XmlSerializerOutputFormatter>().FirstOrDefault();
    if (existingXmlOutput != null)
    {
        options.OutputFormatters.Remove(existingXmlOutput);
    }
    var existingXmlInput = options.InputFormatters.OfType<XmlSerializerInputFormatter>().FirstOrDefault();
    if (existingXmlInput != null)
    {
        options.InputFormatters.Remove(existingXmlInput);
    }

    // 添加DataContractSerializer的XML格式化器
    options.InputFormatters.Add(new XmlDataContractSerializerInputFormatter(options));
    options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
});
  1. 给所有需要序列化的类添加[DataContract]和[DataMember]特性:
using System.Runtime.Serialization;

[DataContract]
public class SeekApprovalResponse
{
    [DataMember]
    public ProcessedRequests[] AcceptedRequests { get; set; }
    [DataMember]
    public ErrorsInRequest[] ErroredData { get; set; }
    [DataMember]
    public string[] YetToBeProcessedRequestIds { get; set; }
}

[DataContract]
public class ProcessedRequests
{
    [DataMember]
    public string RequestId { get; set; }
    [DataMember]
    public long DataAcceptanceStamp { get; set; }
    [DataMember]
    public byte TotalDataFilesCount { get; set; }
    [DataMember]
    public uint TotalRecordCount { get; set; }
}

[DataContract]
public class ErrorsInRequest
{
    [DataMember]
    public string RequestId { get; set; }
    [DataMember]
    public byte TotalDataFilesCount { get; set; }
    [DataMember]
    public byte ReceivedFilesCount { get; set; }
    [DataMember]
    public byte ProcessedFilesCount { get; set; }
    [DataMember]
    public ErrorResponse Errors { get; set; }
}

[DataContract]
public class ErrorResponse
{
    [DataMember]
    public int StatusCode { get; set; }
    [DataMember]
    public string Message { get; set; }
    [DataMember]
    public Dictionary<string, string> Errors { get; set; }
}

此方案既能保留XML输出支持,又能让Swagger正常生成JSON和XML格式的示例。


方案二:通过中转属性适配XmlSerializer

如果不想替换序列化器,可以给ErrorResponse添加一个可被XmlSerializer处理的中转属性,同时忽略原Dictionary属性:

using System.Xml.Serialization;

public class ErrorResponse
{
    public int StatusCode { get; set; }
    public string Message { get; set; }

    // 供XmlSerializer序列化的中转属性
    [XmlArray("Errors")]
    [XmlArrayItem("Error")]
    public List<KeyValuePair<string, string>> ErrorsList
    {
        get => Errors?.ToList() ?? new List<KeyValuePair<string, string>>();
        set => Errors = value?.ToDictionary(kv => kv.Key, kv => kv.Value) ?? new Dictionary<string, string>();
    }

    // 忽略原Dictionary属性的XML序列化
    [XmlIgnore]
    public Dictionary<string, string> Errors { get; set; }
}

Swagger示例类无需修改,赋值Errors属性时会自动同步到ErrorsList,XmlSerializer会序列化ErrorsList为XML节点,同时API的JSON输出仍使用原Errors属性。


方案三:仅为JSON格式生成Swagger示例(备选)

如果XML格式的Swagger示例不是必需的,可以配置Swashbuckle只针对JSON生成示例:

builder.Services.AddSwaggerGen(c =>
{
    // 其他Swagger配置...

    // 指定仅为JSON格式生成示例
    c.ExampleFilters(() => new[] { "application/json" });
});

此方案会保留API的XML输出支持,但Swagger UI中XML格式不会显示示例。


内容的提问来源于stack exchange,提问作者Beli

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 07:45:07