尝试调用 webApi 时出现标题错误。 这是我的类(class):
public class NotificationDTO
{
public long idCompanyService { get; set; }
public DocTypeEnum DocumentType { get; set; }
public List<Tuple<string, byte[], System.Net.Mime.ContentType>> Attachments { get; set; }
}
这在我的对象中:
NotificationDTO notifDto = new NotificationDTO()
{
idCompanyService = idCompServ,
DocumentType = DocType,
Attachments = listAttac
};
这是电话:
HttpContent content = new StringContent(JsonConvert.SerializeObject(notifDto), Encoding.UTF8, "application/json");
HttpResponseMessage response = client.PostAsync(uri, content).Result;
这是一个 Json:
{"idCompanyService":1234,"DocumentType":0,"Attachments":[{"Item1":"test.pdf","Item2":"ThisIsABase64Data","Item3":{"Boundary":null,"CharSet":null,"MediaType":"application/pdf","Name":null,"Parameters":[]}}}
附件有问题,因为是 List<Tuple<string, byte[], ContentType>> .
错误消息:
Exception: Newtonsoft.Json.JsonSerializationException: Cannot populate list type System.Net.TrackingStringDictionary. Path 'Attachments.$values[0].Item3.Parameters.$values', line 1, position 105257.
in Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
in Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadMetadataProperties(JsonReader reader, Type& objectType, JsonContract& contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue, Object& newValue, String& id)
in Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
in Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
in Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
in Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
尝试示例: 您可以使用简单的 Web API Controller 重现该错误:
[HttpPost]
[Route("api/TestNotification")]
public IHttpActionResult TestNotification(NotificationDTO dto)
{
return Ok();
}
在 Post Caller 中像这样的 Json:
{"idCompanyService":1234,"DocumentType":1,"Attachments":[{"Item1":"wqere.pdf","Item2":"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=","Item3":{"Boundary":null,"CharSet":null,"MediaType":"application/pdf","Name":null,"Parameters":[]}},{"Item1":"ewqeqwe.xml","Item2":"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=","Item3":{"Boundary":null,"CharSet":null,"MediaType":"text/xml","Name":null,"Parameters":[]}}]}
最后,一个 .Net fiddle 演示了将上述 JSON 字符串反序列化为 NotificationDTO 时失败的情况。直接通过:
var dto = JsonConvert.DeserializeObject<NotificationDTO>(json);
可以在这里找到:https://dotnetfiddle.net/EaPhm9 .
请您参考如下方法:
这里真正的问题是您的 DTO 引用 System.Net.Mime.ContentType 类型的对象其中又有一个成员 ContentType.Parameters其声明类型为 System.Collections.Specialized.StringDictionary (和实际类型 System.Net.TrackingStringDictionary )。 不幸的是,这种古老的类型(来自.Net 1.1)甚至没有实现IDictionary。由于它仅实现无类型枚举器 System.Collections.IEnumerable,Json.NET 无法知道如何反序列化它,并会在要求这样做时抛出您所看到的异常。
因此有必要写一个 custom JsonConverter反序列化该类型或派生自该类型的对象:
using System.Collections.Specialized;
public class StringDictionaryConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(StringDictionary).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var tokenType = reader.SkipComments().TokenType;
if (tokenType == JsonToken.Null)
return null;
var dictionary = existingValue as StringDictionary ?? (StringDictionary)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
switch (tokenType)
{
case JsonToken.StartArray:
{
// StringDictionary serialized without converter
var list = serializer.Deserialize<List<KeyValuePair<string, string>>>(reader);
foreach (var pair in list)
dictionary.Add(pair.Key, pair.Value);
}
break;
case JsonToken.StartObject:
{
// StringDictionary serialized with converter
var typedDictionary = serializer.Deserialize<Dictionary<string, string>>(reader);
foreach (var pair in typedDictionary)
dictionary.Add(pair.Key, pair.Value);
}
break;
default:
throw new JsonSerializationException(string.Format("Unknown token {0} at path {1}", tokenType, reader.Path));
}
return dictionary;
}
// Change to false if you want the dictionary written as an array of key/value objects.
public override bool CanWrite { get { return true; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var dictionary = (StringDictionary)value;
writer.WriteStartObject();
foreach (DictionaryEntry entry in dictionary)
{
writer.WritePropertyName((string)entry.Key);
writer.WriteValue((string)entry.Value);
}
writer.WriteEndObject();
}
}
public static partial class JsonExtensions
{
public static JsonReader SkipComments(this JsonReader reader)
{
while (reader.TokenType == JsonToken.Comment && reader.Read())
;
return reader;
}
}
编写完成后,您将需要使用服务器端的转换器来反序列化传入的 JSON。您没有指定您正在使用哪个版本的 Web API。要全局添加转换器,请参阅
ASP.NET Web API 2:请参阅 How to set custom JsonSerializerSettings for Json.NET in MVC 4 Web API? 以及 this answer 的第二部分至 Registering a custom JsonConverter globally in Json.Net 。在这种情况下,您的代码将类似于:
protected void Application_Start() { var config = GlobalConfiguration.Configuration; var settings = config.Formatters.JsonFormatter.SerializerSettings; settings.Converters.Add(new StringDictionaryConverter()); }ASP.NET Core MVC:请参阅 JsonSerializerSettings and Asp.Net Core 或 Setting JsonConvert.DefaultSettings asp net core 2.0 not working as expected 。在这里,您将再次访问全局
JsonSerializerSettings并添加一个StringDictionaryConverter,如上所示。
您可能还想在客户端使用转换器来序列化您的 JSON。如果这样做,您的内容参数将更紧凑地序列化为 JSON 对象,而不是键/值数组。 (转换器接受两种形式作为输入。)
fiddle 样本here .
