尝试调用webApi时,标题中出现错误。 这是我的课程:
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;
这是一个杰森:
{"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控制器重现该错误:
[HttpPost]
[Route("api/TestNotification")]
public IHttpActionResult TestNotification(NotificationDTO dto)
{
return Ok();
}
还有一个在帖子调用者中的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小提琴通过以下方式演示了将上述JSON字符串直接反序列化为NotificationDTO
时失败的情况:
var dto = JsonConvert.DeserializeObject<NotificationDTO>(json);
可以在这里找到:https://dotnetfiddle.net/EaPhm9。
答案 0 :(得分:0)
这里的真正问题是您的DTO引用类型为System.Net.Mime.ContentType
的对象,而对象又具有声明的类型为ContentType.Parameters
(而实际类型为{{3})的成员System.Collections.Specialized.StringDictionary
}。
不幸的是,这种古老的类型(来自.Net 1.1)甚至没有实现IDictionary
。由于Json.NET仅实现无类型的枚举器System.Collections.IEnumerable
,因此Json.NET无法知道如何对其进行反序列化,并且会抛出要求时看到的异常。
因此,有必要编写一个System.Net.TrackingStringDictionary
来反序列化此类型的对象或从该类型派生的对象:
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:另请参见 custom JsonConverter
和How to set custom JsonSerializerSettings for Json.NET in MVC 4 Web API?到 this answer 的第二部分。在这种情况下,您的代码将类似于:
protected void Application_Start()
{
var config = GlobalConfiguration.Configuration;
var settings = config.Formatters.JsonFormatter.SerializerSettings;
settings.Converters.Add(new StringDictionaryConverter());
}
ASP.NET Core MVC:请参见 Registering a custom JsonConverter globally in Json.Net 或 JsonSerializerSettings and Asp.Net Core 。再次在这里,您将访问全局JsonSerializerSettings
并添加一个StringDictionaryConverter
,如上所示。
您可能还希望在客户端使用转换器来序列化JSON。如果这样做,您的内容参数将更紧凑地序列化为JSON对象,而不是键/值数组。 (转换器接受两种形式的输入。)
提琴Setting JsonConvert.DefaultSettings asp net core 2.0 not working as expected。