包含数组的嵌套类的JSON到C#转换
摘要 将CICS(=大型机)Web服务生成为使用JSON进行通信的COBOL程序,并生成相关的C#接口,将这些服务作为属性和方法公开给客户端程序。程序JSPG2以一条员工记录作为响应,JSPG2A是一个可以返回最多10条员工记录的版本。JSPG2可以完美地工作(),但JSPG2A不能 细节 为了将层次化COBOL记录结构映射到C#类,一组嵌套的C#类定义如下包含数组的嵌套类的JSON到C#转换,c#,json,json.net,C#,Json,Json.net,摘要 将CICS(=大型机)Web服务生成为使用JSON进行通信的COBOL程序,并生成相关的C#接口,将这些服务作为属性和方法公开给客户端程序。程序JSPG2以一条员工记录作为响应,JSPG2A是一个可以返回最多10条员工记录的版本。JSPG2可以完美地工作(),但JSPG2A不能 细节 为了将层次化COBOL记录结构映射到C#类,一组嵌套的C#类定义如下 namespace MyJSv { public class ResponseJSPG2A { publi
namespace MyJSv
{
public class ResponseJSPG2A
{
public class JSPG2AResponse_
{
public class OJSPG2A_
{
//...
public int JZ_Employee_BrowseCount { get; set; }
// and more scalar classes,
public class JZ_Employee_
{
public string JZ_Employee_NthReturnCode { get; set; }
public string EMPNO { get; set; }
// and more classes within the Employee record
}
public JZ_Employee_[] JZ_Employee { get; } = new JZ_Employee_[10];
}
public OJSPG2A_ OJSPG2A { get; } = new OJSPG2A_ ();
}
public JSPG2AResponse_ JSPG2AResponse { get; } = new JSPG2AResponse_ ();
}
}
对于JZ Employee的单个事件,其定义为
public JZ_Employee_ JZ_Employee { get; } = new JZ_Employee_ ();
否则,ResponseJSPG2和ResponseJSPG2A的定义相同
JSON将传入的JSON转换为C#,并使用
将来自ResponseJSPG2的数据分配给JSPG2Client希望公开的属性
这一切都适用于ResponseJSPG2
,其中只有一个员工记录。与
等效的,其中有10条记录的数组返回10条空记录,等效的AssignResponseToProperties
在尝试引用员工字段时失败:-
_EMPNO = Response.JSPG2AResponse.OJSPG2A.JZ_Employee[EmployeeSub].EMPNO;
然而,VisualStudio调试以及使用测试实用程序ReadyAPI对web服务程序JSPG2A进行的相同测试表明,返回的JSON包含10条员工记录,所有记录都包含预期的数据
以下是返回到测试的JSON,经过编辑以删除大多数字段和仅2条员工记录,以便与上面嵌套的C#类匹配:-
{
“JSPG2A响应”:{
“OJSPG2A”:{
“JZ_员工_BrowseCount”:16,
“JZ_员工”:[
{
“JZ_员工返回代码”:“F”,
“EMPNO”:“000060”
},
{
“JZ_员工返回代码”:“N”,
“EMPNO”:“000090”
}
]
}
}
}
问题
有没有办法让反序列化对象自动处理数组类,或者我必须使用Newtonsoft.Json.Linq和写逻辑来解析Json并显式处理数组?或者通过其他方式实现我的目标?您的问题是
JZ_Employee
属性是一个数组值属性,而缺少setter:
public JZ_Employee_[] JZ_Employee { get; } = new JZ_Employee_[10];
由于.Net数组无法调整大小,Json.Net将其视为只读集合,其内容需要累积到临时列表中,然后用于构造数组并将其设置回其父级。但是,您的数组属性没有setter,因此Json.NET将其视为完全只读,并完全跳过它
要解决此问题,可以添加setter。如果您使用以下标记属性,则它可能受到保护
或私有
:
演示小提琴#1
或者,您可以将属性保留为get only,但将数组替换为可调整大小的集合,如List
:
转换器将自动将单个
JZ_Employee
对象的大小写转换为一个包含一项的列表。您的问题是JZ_Employee
属性是一个数组值属性,缺少setter:
public JZ_Employee_[] JZ_Employee { get; } = new JZ_Employee_[10];
由于.Net数组无法调整大小,Json.Net将其视为只读集合,其内容需要累积到临时列表中,然后用于构造数组并将其设置回其父级。但是,您的数组属性没有setter,因此Json.NET将其视为完全只读,并完全跳过它
要解决此问题,可以添加setter。如果您使用以下标记属性,则它可能受到保护
或私有
:
演示小提琴#1
或者,您可以将属性保留为get only,但将数组替换为可调整大小的集合,如List
:
转换器将自动将单个
JZ_员工
对象的大小写转换为包含一个项目的列表。这是否回答了您的问题?我添加了一个实际JSON的编辑版本(只有2条记录,大部分字段被省略),以便它与我给出的C#类结构(数据模型)匹配。反序列化代码也已给出。您不需要完整的请求/响应代码,因为这也需要任何人复制我的实际程序来设置CICS Web服务器和DB2数据库。谢谢Martin,我会检查这些代码,然后我会回来说“一切正常”或提出进一步的问题“@RobertB_NZ-对于未来,这个问题有很多不需要的额外细节。真正需要的是——刚好足够的代码和JSON来演示这个问题。我在这里创建了一个:。这是否回答了您的问题?我添加了一个实际JSON的编辑版本(只有2条记录,大部分字段被省略),以便它与我给出的C#类结构(数据模型)匹配。反序列化代码也已给出。您不需要完整的请求/响应代码,因为这也需要任何人复制我的实际程序来设置CICS Web服务器和DB2数据库。谢谢Martin,我会检查这些代码,然后我会回来说“一切正常”或提出进一步的问题“@RobertB_NZ-对于未来,这个问题有很多不需要的额外细节。真正需要的是——刚好足够的代码和JSON来演示这个问题。我在这里创建了一个:。非常好,这为我的问题提供了一个非常简单的解决方案。我同意第二种选择。谢谢你,罗伯特。太好了,这为我的问题提供了一个非常简单的解决方法。我同意第二种选择。谢谢你,罗伯特。
public JZ_Employee_[] JZ_Employee { get; } = new JZ_Employee_[10];
[JsonProperty]
public JZ_Employee_[] JZ_Employee { get; private set; } = new JZ_Employee_[10];
public List<JZ_Employee_> JZ_Employee { get; } = new List<JZ_Employee_>();
[JsonConverter(typeof(SingleOrArrayConverter<JZ_Employee_>))]
public List<JZ_Employee_> JZ_Employee { get; } = new List<JZ_Employee_>();