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

.NET Core 6 Web API中如何序列化继承自Dictionary的类?

解决继承Dictionary的类同时支持JSON和XML根节点序列化的问题

问题场景

你定义了如下继承自Dictionary<string, string>的类:

[DataContract(Name = "Item", Namespace = "")]
public class Item : Dictionary<string, string>
{

}

控制器方法返回该类的异步枚举:

public async IAsyncEnumerable<Item> Query()
{
 ...
}

JSON请求响应符合预期,字典键值对直接作为对象根属性输出;但XML请求时抛出异常:

An error occurred while trying to create a DataContractSerializer for the type 'Item'.
      System.Runtime.Serialization.InvalidDataContractException: Type 'Item' cannot be ISerializable and have DataContractAttribute attribute.

需求是让任意属性直接序列化到对象根节点,而非字典作为子节点。

问题原因

Dictionary<string, string>本身实现了ISerializable接口,而DataContractSerializer不允许同一类型同时标记DataContractAttribute和实现ISerializable(默认Dictionary的序列化逻辑与数据契约不兼容),导致XML序列化失败。

解决方案

方法1:移除DataContractAttribute,自定义XML序列化逻辑

JSON序列化(无论是System.Text.Json还是Newtonsoft.Json)默认会将Dictionary的键值对解析为对象属性,无需额外配置。针对XML序列化,我们可以通过实现IXmlSerializable手动控制输出格式,同时切换ASP.NET Core的XML格式化器为XmlSerializer。

  1. 修改Item类:
public class Item : Dictionary<string, string>, IXmlSerializable
{
    public XmlSchema GetSchema() => null;

    public void ReadXml(XmlReader reader)
    {
        // 实现反序列化逻辑(按需添加)
        reader.ReadStartElement();
        while (reader.NodeType != XmlNodeType.EndElement)
        {
            var key = reader.LocalName;
            var value = reader.ReadElementContentAsString();
            Add(key, value);
        }
        reader.ReadEndElement();
    }

    public void WriteXml(XmlWriter writer)
    {
        // 将字典键值对直接输出为根节点的子元素
        foreach (var kvp in this)
        {
            writer.WriteElementString(kvp.Key, kvp.Value);
        }
    }
}
  1. 配置ASP.NET Core使用XmlSerializer格式化器:
    在Program.cs中添加XML序列化配置:
builder.Services.AddControllers()
    .AddXmlSerializerFormatters();

配置后,XML序列化会使用XmlSerializer而非DataContractSerializer,配合IXmlSerializable的实现,就能让字典键值对以根属性的形式输出,和JSON格式一致。

方法2:使用DynamicObject实现动态属性(更灵活)

如果需要保留DataContractAttribute或更灵活的动态属性支持,可以改用DynamicObject,同时实现IXmlSerializable控制XML输出:

[DataContract(Name = "Item", Namespace = "")]
public class Item : DynamicObject, IXmlSerializable
{
    private readonly Dictionary<string, string> _properties = new();

    // 支持动态属性读取
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        return _properties.TryGetValue(binder.Name, out result);
    }

    // 支持动态属性赋值
    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        if (value is string strValue)
        {
            _properties[binder.Name] = strValue;
            return true;
        }
        return false;
    }

    // 供JSON序列化自动识别属性(System.Text.Json需额外配置,Newtonsoft.Json默认支持)
    public IEnumerable<KeyValuePair<string, string>> Properties => _properties;

    public XmlSchema GetSchema() => null;

    public void ReadXml(XmlReader reader)
    {
        reader.ReadStartElement();
        while (reader.NodeType != XmlNodeType.EndElement)
        {
            var key = reader.LocalName;
            var value = reader.ReadElementContentAsString();
            _properties.Add(key, value);
        }
        reader.ReadEndElement();
    }

    public void WriteXml(XmlWriter writer)
    {
        foreach (var kvp in _properties)
        {
            writer.WriteElementString(kvp.Key, kvp.Value);
        }
    }
}

这种方式既支持动态添加属性,又能让JSON和XML序列化都将属性输出到根节点,同时避开了Dictionary与DataContractAttribute的冲突问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 22:15:52