【问题标题】:WebAPI 2 JSON serialization of object-arrays with nested static object instances fails具有嵌套静态对象实例的对象数组的 WebAPI 2 JSON 序列化失败
【发布时间】:2015-07-03 00:13:00
【问题描述】:

我需要一个 Web API 服务,其中包含一些用于新 PoC 的虚假数据。这个对象模型非常简单,有 2 个类,其中 class1 有一个嵌套数组 class2。 所以我开始构建一个 FakeDataService,我只是在其中硬编码了一些数据。 为简洁起见,我省略了很多属性,因此代码重点关注问题的本质:

public class Class1
{
    public string Prop1 { get; set; }
    public IEnumerable<Class2> Prop2 { get; set; }
    public IEnumerable<string> Prop3 { get; set; }
}    

public class Class2
{
    public string Prop4 { get; set; }
}

public static class FakeDatabase
{
    public static Class1 c1instance1 = new Class1 { Prop1 = "value1", 
                          Prop2 = new Class2[] { c2instance1 }, 
                          Prop3 = new string[] { "value3" } };

    public static Class2 c2instance1 = new Class2 { Prop4 = "Value4" };

    public static Class1[] AllData = new Class1[] { c1instance1 };

}

所以,我的假数据库的“AllData”是一个 Class1 对象数组(本例中只有一个“数组”),Class1 对象有一个字符串属性(prop1),一个 Class2 对象数组(prop2) , 和一组字符串属性 (prop3),而 Class2 对象只有一个字符串属性 (prop4)。

WebAPI 控制器是最基本的:

public class ValuesController : ApiController
{

    // GET api/values
    public IEnumerable<Class1> Get()
    {
        return FakeDatabase.AllData;                                                                                                                                                                                       
    }

但是当我调用 Values 控制器时,结果是:

<ArrayOfClass1 xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/FakeDataService.Models">
<Class1>
<Prop1>value1</Prop1>
<Prop2>
<Class2 i:nil="true"/>
</Prop2>
<Prop3 xmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d3p1:string>value3</d3p1:string>
</Prop3>
</Class1>
</ArrayOfClass1>

注意 Class2 对象的序列化如何产生 i:nil=true

经过几个小时的搜索(我的示例数据比这里的这个简单示例大很多),我发现问题的根源在于嵌套对象数组被定义为静态实例这一事实。例如。将 FakeDatabase 的初始代码更改为:

public static class FakeDatabase
    {
        public static Class1 c1instance1 = new Class1 { Prop1 = "value1", 
                Prop2 = new Class2[] { new Class2 { Prop4 = "Value4" }},
                Prop3 = new string[] { "value3" } };


        public static Class1[] AllData = new Class1[] { c1instance1 };

}

现在调用 WebAPI 控制器给了我(正确):

<ArrayOfClass1 xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/FakeDataService.Models">
<Class1>
<Prop1>value1</Prop1>
<Prop2>
<Class2>
<Prop4>Value4</Prop4>
</Class2>
</Prop2>
<Prop3 xmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d3p1:string>value3</d3p1:string>
</Prop3>
</Class1>
</ArrayOfClass1>

所以唯一的区别是 Class2 对象的数组。这种行为的解释是什么?

【问题讨论】:

  • 您的输出是 XML,因此您在这里没有使用 Json.NET,您可能使用的是 DataContractSerializer。但实际上这个问题与特定的序列化程序无关。我更新了标签以反映这一点。

标签: c# serialization asp.net-web-api static-initializer


【解决方案1】:

您的问题是您在初始化之前使用了c2instance1 静态变量。来自C# Language Specification §10.4.5.1 Static field initialization

类的静态字段变量初始值设定项对应于以它们出现在类声明中的文本顺序执行的一系列赋值。

因此,在您的 FateDatabase 类中,c1instance1c1instance1 的初始化程序使用,而它仍然为空:

public static class FakeDatabase
{
    public static Class1 c1instance1 = new Class1
    {
        Prop1 = "value1",
        Prop2 = new Class2[] { c2instance1 }, // NOT INITIALIZED YET, THUS NULL
        Prop3 = new string[] { "value3" }
    };

    public static Class2 c2instance1 = new Class2 { Prop4 = "Value4" };

    public static Class1[] AllData = new Class1[] { c1instance1 };
}

翻转静态变量的文本顺序以修复错误:

public static class FakeDatabase
{
    public static Class2 c2instance1 = new Class2 { Prop4 = "Value4" };

    public static Class1 c1instance1 = new Class1
    {
        Prop1 = "value1",
        Prop2 = new Class2[] { c2instance1 },
        Prop3 = new string[] { "value3" }
    };

    public static Class1[] AllData = new Class1[] { c1instance1 };
}

【讨论】:

  • 谢谢!确实是这个原因。 Ps,服务确实返回了 JSOn,但是我还没有更改默认的 Content-Type,所以 Chrome 显示为 XML。
猜你喜欢
  • 2015-11-29
  • 1970-01-01
  • 1970-01-01
  • 2011-07-08
  • 2011-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-15
相关资源
最近更新 更多