WebAPI 2 JSON 序列化带有嵌套静态对象实例的对象数组失败
WebAPI 2 JSON serialization of object-arrays with nested static object instances fails
我需要一个 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 对象的数组("array" 在这个例子中只有一个),并且 Class1 对象有一个字符串 属性 (prop1 ),一组 Class2 对象 (prop2),和一组字符串 属性 (prop3),而 Class2 对象只有一个字符串 属性 (prop4).
WebAPI 控制器非常基础:
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<Class1> Get()
{
return FakeDatabase.AllData;
}
但是当我调用值控制器时,结果是:
<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 对象的数组。这种行为的解释是什么?
您的问题是您在初始化之前使用了 c2instance1
静态变量。来自 C# Language Specification §10.4.5.1 Static field initialization:
The static field variable initializers of a class correspond to a sequence of assignments that are executed in the textual order in which they appear in the class declaration.
因此,在您的 FateDatabase
class 中,c1instance1
被 c1instance1
的初始值设定项使用,同时它仍然为空:
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 };
}
我需要一个 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 对象的数组("array" 在这个例子中只有一个),并且 Class1 对象有一个字符串 属性 (prop1 ),一组 Class2 对象 (prop2),和一组字符串 属性 (prop3),而 Class2 对象只有一个字符串 属性 (prop4).
WebAPI 控制器非常基础:
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<Class1> Get()
{
return FakeDatabase.AllData;
}
但是当我调用值控制器时,结果是:
<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 对象的数组。这种行为的解释是什么?
您的问题是您在初始化之前使用了 c2instance1
静态变量。来自 C# Language Specification §10.4.5.1 Static field initialization:
The static field variable initializers of a class correspond to a sequence of assignments that are executed in the textual order in which they appear in the class declaration.
因此,在您的 FateDatabase
class 中,c1instance1
被 c1instance1
的初始值设定项使用,同时它仍然为空:
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 };
}