我看到了这个,但是对我没有帮助。
Deserializing an object with a Dictionary<string, object> property (Newtonsoft.Json)
我正在研究WCF Restful服务。我有复杂的JSON。 我有以下数据合同
[DataContract]
public class TimestampPackageDC
{
[DataMember]
public string Timestamp { get; set; }
[DataMember]
public string Company { get; set; }
[DataMember]
public string ContactID { get; set; }
[DataMember]
public string Area { get; set; }
[DataMember]
public string PackageID { get; set; }
} // end of class TimestampPackageDC
[DataContract]
public class TimestampPackageExtraDC: TimestampPackageDC
{
[DataMember]
public IDictionary<string, string> ExtraInfo { get; set; }
} // end of class TimestampPackageExtraDC
[DataContract]
public class GetAllUnprintedItemsResponse: BaseResponse
{
[DataMember]
public TimestampPackageDC[] TimestampPackages { get; set; }
[DataMember]
public TimestampPackageExtraDC[] TimestampExtraInfoPackages { get; set; }
}
我正在像下面那样拨打REST服务电话
GetAllUnprintedItemsResponse upResponse = new GetAllUnprintedItemsResponse();
Request upRequest = new Request() { Name = "abc" };
string url = "http://localhost:2023/myservice/getdata";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "application/json";
byte[] data = Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(upRequest));
request.ContentLength = data.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(data, 0, data.Length);
requestStream.Close();
WebResponse response = request.GetResponse();
Stream respStream = response.GetResponseStream();
StreamReader reader = new StreamReader(respStream);
string responseData = reader.ReadToEnd();
//getting error below
Newtonsoft.Json.JsonConvert.PopulateObject(responseData, upResponse);
我正在获取如下所示的JSON字符串
{
"DocumentException": null,
"Success": true,
"TimestampExtraInfoPackages": [{
"Area ": "AA",
"Company": "XXX",
"ContactID": "123",
"PackageID": "P1",
"Timestamp": "20090501163433360001",
"ExtraInfo": [{
"Key": "Key1",
"Value": "value1"
},
{
"Key": "Key2",
"Value": "value2"
}
]
}],
"TimestampPackages": []
}
以下是我遇到的错误
无法将当前JSON数组(例如[1,2,3])反序列化为类型'System.Collections.Generic.IDictionary`2 [System.String,System.String]',因为该类型需要JSON对象(例如{“ name”:“ value”})正确反序列化。 要解决此错误,请将JSON更改为JSON对象(例如{“ name”:“ value”}),或将反序列化类型更改为数组或实现集合接口的类型(例如ICollection,IList) 例如可以从JSON数组反序列化的List。还可以将JsonArrayAttribute添加到类型中,以强制其从JSON数组反序列化。 路径“ TimestampExtraInfoPackages [0] .ExtraInfo”,第1行,位置194。
解决方案:
感谢湿婆,布莱恩和塔弗。我使用了taffer建议,并且有效。看来我们不能使用IDictionary。
我在下面用来解决我的问题。
public List<KeyValuePair<string, string>> ExtraInfo { get; set; }
我在下面尝试过,但没有工作,出现了相同的错误。
public IDictionary<string, string>[] ExtraInfo { get; set; }
答案 0 :(得分:4)
如错误消息所述,传入的ExtraInfo
应该是一个JSON对象,但在您的示例中,它是一个包含具有Key
和Value
属性的对象的JSON数组。
使用预期的JSON字符串来提供服务:
"ExtraInfo": {
"Key1": "value1",
"Key2": "value2"
}
或将合同修改为数组或列表,以便它可以接受JSON数组:
[DataMember]
public KeyValuePair<string, string>[] ExtraInfo { get; set; }
答案 1 :(得分:1)
您的ExtraInfo
声明应为数组。
public IDictionary<string, string>[] ExtraInfo { get; set; }
代替
public IDictionary<string, string> ExtraInfo { get; set; }
编辑
这是工作代码。我尝试将其放在dotNetFiddle上,但在dotnetfiddle.com上出现一些错误[包括System.Runtime.Serialization
,因此将下面的工作代码粘贴到了
请注意,您的ExtraInfo
如下所示。但这也是JSON的方式。如果要分别从Key
和Value
json键中获取值并构造一个字典或键值对条目,则可能必须编写一个https://github.com/Pyomo/PyomoGallery/wiki/Min-cost-flow。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using Newtonsoft.Json;
namespace SoDeserializeJson_53936668
{
[System.Runtime.Serialization.DataContract]
public class TimestampPackageDC
{
[DataMember]
public string Timestamp { get; set; }
[DataMember]
public string Company { get; set; }
[DataMember]
public string ContactID { get; set; }
[DataMember]
public string Area { get; set; }
[DataMember]
public string PackageID { get; set; }
} // end of class TimestampPackageDC
[DataContract]
public class TimestampPackageExtraDC : TimestampPackageDC
{
[DataMember]
public IDictionary<string, string>[] ExtraInfo { get; set; }
} // end of class TimestampPackageExtraDC
[DataContract]
public class GetAllUnprintedItemsResponse //: BaseResponse
{
[DataMember]
public TimestampPackageDC[] TimestampPackages { get; set; }
[DataMember]
public TimestampPackageExtraDC[] TimestampExtraInfoPackages { get; set; }
}
class Program
{
static void Main(string[] args)
{
var json = @"
{
'DocumentException': null,
'Success': true,
'TimestampExtraInfoPackages': [{
'Area ': 'AA',
'Company': 'XXX',
'ContactID': '123',
'PackageID': 'P1',
'Timestamp': '20090501163433360001',
'ExtraInfo': [{
'Key': 'Key1',
'Value': 'value1'
},
{
'Key': 'Key2',
'Value': 'value2'
}
]
}],
'TimestampPackages': []
}".Replace("'","\"");
GetAllUnprintedItemsResponse upResponse = new GetAllUnprintedItemsResponse();
string responseData = json;
var data = JsonConvert.DeserializeObject<GetAllUnprintedItemsResponse>(json);
Console.WriteLine(data.TimestampExtraInfoPackages.First().ExtraInfo.Count());
}
}
}
答案 2 :(得分:0)
您收到此错误,因为您的JSON具有一个键-值对对象数组,而一个字典被序列化为一个对象。
一种解决方案是按照@taffer的建议将ExtraInfo
属性更改为KeyValuePair<string, string>[]
以匹配JSON(或更改JSON以匹配您的类)。
但是,还有另一种方法。您可以将ExtraInfo
属性保持原样声明,并在反序列化期间使用自定义JsonConverter
创建和填充字典。
这是转换器所需的代码:
public class KvpArrayToDictionaryConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(IDictionary<string, string>).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var dict = new Dictionary<string, string>();
var array = JArray.Load(reader);
foreach (var obj in array.Children<JObject>())
{
dict.Add((string)obj["Key"], (string)obj["Value"]);
}
return dict;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
要使用转换器,只需将[JsonConverter]
属性添加到ExtraInfo
属性中,如下所示:
[DataMember]
[JsonConverter(typeof(KvpArrayToDictionaryConverter))]
public IDictionary<string, string> ExtraInfo { get; set; }
正在运行的演示:https://dotnetfiddle.net/1k7vNA
另一种可能的解决方案是使用ContractResolver
来更改字典的协定,以便Json.Net将其视为键值对对象的数组。有关此方法的更多信息,请参见Serialize dictionary as array (of key value pairs)。但是,如果采用这种方式,则需要将ExtraInfo
属性的声明从IDictionary
接口更改为具体的Dictionary
,否则Json.Net会给您一个错误的提示能够创建接口的实例。