相当于XmlChoiceIdentifier的Ne​​wtonsoft.json

时间:2019-05-17 17:11:16

标签: c# json.net asp.net-core-webapi

我目前正在研究第三方XML api的api包装。我希望将相同的对象和终结点与Web api一起使用以支持两者。 (几乎可以正常工作)

使用以下类型的对象时出现问题:


enum ItemsChoiceType
{
    Foo,
    Bar,
    Baz
}

...
        [XmlElement("Foo", typeof(string), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        [XmlElement("Bar", typeof(BarClass), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        [XmlElement("Baz", typeof(string), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        [XmlChoiceIdentifier("ItemsElementName")]
        public object[] Items
        {
            get => itemsField;
            set => itemsField = value;
        }

        /// <remarks/>
        [XmlElement("ItemsElementName")]
        [XmlIgnore()]
        public ItemsChoiceType[] ItemsElementName
        {
            get => itemsElementNameField;
            set => itemsElementNameField = value;
        }
...

使用对象时,数组如下所示:

obj.Items = new object[]{"This is Foo", "This is Baz", new BarClass()};
obj.ItemsElementName = new ItemsChoiceType[] {Foo, Baz, Bar};

xml看起来像这样:

<root>
    <Foo>This is Foo</Foo>
    <Baz>This is Baz</Baz>
    <Bar>/*BarClass xml*/</Bar>
</root>

当转换为json时,两个数组可以很好地序列化,但是BarClass的反序列化不能得到BarClass的正确类型,因为它反序列化为object []并且是JObject。阅读newtonsoft.json文档对解决这个问题没有多大帮助(尽管我已经学到了很多其他知识)。

TypeNameHandling由于其安全性问题而无法正常工作。之所以可以使用XML,是因为枚举确定了Items中XML元素的类型和名称。

1 个答案:

答案 0 :(得分:0)

它不是我想要的东西,但是我确实解决了这个问题。我偶然发现了
Serialization Callbacks,特别是OnDeserialized,在这里我可以询问ItemsElementName并查看是否存在枚举值,然后转换类型。

这与我所希望的通用名称相距甚远,但是它可以解决该特定类的当前问题。

...

        [OnDeserialized]
        internal void OnDeserializedMethod(StreamingContext context)
        {
            for (int i = 0; i < itemsElementNameField.Length; i++)
            {
                switch (itemsElementNameField[i])
                {
                    case ItemsChoiceType.Bar:
                        switch (Items[i])
                        {
                            case BarClass _:
                                return;
                            case JObject o:
                                Items[i] = new BarClass
                                               {
                                                   /*properties*/
                                               };
                                break;
                        }

                        break;
                        //All the other enum items we care about.
                }
            }
        }

...