我跟随json:
{"EventMessageUId":"ef51b5a3-32b2-e611-baf9-fc3fdb446bd2","Message":
"{\"StoryId\":20500,\"StoryDesc\":\"Test Story
data\"}","ProjectId":"1"}
以下是我正在尝试映射它的类:
public class Requirments
{
public int FileID { get; set; }
public string EventMessageUId { get; set; }
public string ProjectId { get; set; }
public List<Message> Message { get; set; }
//public object[] Message { get; set; }
public string error { get; set; }
}
将消息标记作为字符串
"Message": "{\"StoryId\":20500,\"StoryDesc\":\"Test Story data\"}"
我想将其映射到List<Message>
public class Message
{
public string StoryID { get; set; }
public string StoryDesc { get; set; }
}
如果不改变json,我该怎么做?
在当前情况下,当我使用List<Message>
答案 0 :(得分:3)
这可能会为你做到这一点
string jsonstr = File.ReadAllText(YourJSONFile);
jsonstr = jsonstr.Replace("\"{", "{");
jsonstr = jsonstr.Replace("}\"", "}");
jsonstr = jsonstr.Replace("\\", "");
var ser = JsonConvert.DeserializeObject<MyMessages>(jsonstr);
这些类看起来像
public class Message
{
[JsonProperty("StoryId")]
public int StoryId { get; set; }
[JsonProperty("StoryDesc")]
public string StoryDesc { get; set; }
}
public class MyMessages
{
[JsonProperty("Message")]
public Message Message { get; set; }
}
JSON的问题是
"Message": "{\"StoryId\":20500,\"StoryDesc\":\"Test Story data\"}"
^ ^
是这些"
,它使它成为字符串而不是JSON的两个不同属性。我们已将"{
和}"
与
jsonstr = jsonstr.Replace("\"{", "{");
jsonstr = jsonstr.Replace("}\"", "}");
现在剩下的JSON字符串将是
"Message": {\"StoryId\":20500,\"StoryDesc\":\"Test Story data\"}
^ ^ ^ ^ ^ ^
我们在JSON字符串中有\
反斜杠,这会在解除JSON字符串的同时再次产生问题。所以
jsonstr = jsonstr.Replace("\\", "");
答案 1 :(得分:2)
将JSON反序列化到Requirments
类时有两个不同的问题:
Message
属性包含嵌套的双序列化数据。即发送系统将原始Message
对象序列化为JSON字符串,然后将其包含在随后自行序列化的外部容器对象中,从而导致内部JSON数据被转义。
嵌套的JSON表示单个对象 - 由大括号括起的名称/值对的集合。但是您希望反序列化为List<Message>
,并且所有JSON序列化程序都会将List<T>
映射到JSON数组而不是JSON对象。
使用json.net结合custom JsonConverter
Message
属性可以克服这两个问题。但是,转换需要两个独立的步骤:
您需要将嵌套的双序列化JSON解包为字符串。
然后映射JSON对象,从而使用How to handle both a single item and an array for the same property using JSON.net中与SingleOrArrayConverter<T>
类似的转换器展开。
以下转换器集执行此链式转换:
public class SingleOrArrayConverter<TCollection, TItem> : SingleOrArrayConverter where TCollection : ICollection<TItem>
{
public override bool CanConvert(Type objectType)
{
if (!base.CanConvert(objectType))
return false;
return typeof(TCollection).IsAssignableFrom(objectType);
}
}
public class SingleOrArrayConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
if (objectType.IsArray || objectType == typeof(string) || objectType.IsPrimitive)
return false;
Type elementType = null;
foreach (var type in objectType.GetCollectItemTypes())
{
if (elementType == null)
elementType = type;
else
return false;
}
return elementType != null;
}
object ReadJsonGeneric<TItem>(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var collection = (ICollection<TItem>)(existingValue ?? serializer.ContractResolver.ResolveContract(objectType).DefaultCreator());
if (reader.TokenType == JsonToken.StartArray)
serializer.Populate(reader, collection);
else
collection.Add(serializer.Deserialize<TItem>(reader));
return collection;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
if (objectType.IsArray)
throw new JsonSerializationException("Read-only collections such as arrays are not supported");
try
{
var elementType = objectType.GetCollectItemTypes().SingleOrDefault();
if (elementType == null)
throw new JsonSerializationException(string.Format("{0} is not an ICollection<T> for some T", objectType));
var method = typeof(SingleOrArrayConverter).GetMethod("ReadJsonGeneric", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
return method.MakeGenericMethod(new[] { elementType }).Invoke(this, new object[] { reader, objectType, existingValue, serializer });
}
catch (Exception ex)
{
// Wrap the TargetInvocationException in a JsonSerializerException
throw new JsonSerializationException("Failed to deserialize " + objectType, ex);
}
}
void WriteJsonGeneric<TItem>(JsonWriter writer, object value, JsonSerializer serializer)
{
var list = (ICollection<TItem>)value;
if (list.Count == 1)
{
foreach (object item in list)
{
serializer.Serialize(writer, item);
break;
}
}
else
{
writer.WriteStartArray();
foreach (var item in list)
{
serializer.Serialize(writer, item);
}
writer.WriteEndArray();
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var objectType = value.GetType();
try
{
var elementType = objectType.GetCollectItemTypes().SingleOrDefault();
if (elementType == null)
throw new JsonSerializationException(string.Format("{0} is not an ICollection<T> for some T", objectType));
var method = typeof(SingleOrArrayConverter).GetMethod("WriteJsonGeneric", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
method.MakeGenericMethod(new[] { elementType }).Invoke(this, new object[] { writer, value, serializer });
}
catch (Exception ex)
{
// Wrap the TargetInvocationException in a JsonSerializerException
throw new JsonSerializationException("Failed to serialize " + objectType, ex);
}
}
}
public static class TypeExtensions
{
public static IEnumerable<Type> GetInterfacesAndSelf(this Type type)
{
if (type == null)
throw new ArgumentNullException();
if (type.IsInterface)
return new[] { type }.Concat(type.GetInterfaces());
else
return type.GetInterfaces();
}
public static IEnumerable<Type> GetCollectItemTypes(this Type type)
{
foreach (Type intType in type.GetInterfacesAndSelf())
{
if (intType.IsGenericType
&& intType.GetGenericTypeDefinition() == typeof(ICollection<>))
{
yield return intType.GetGenericArguments()[0];
}
}
}
}
public class StringConverterDecorator : JsonConverterDecorator
{
public StringConverterDecorator(Type jsonConverterType) : base(jsonConverterType) { }
public StringConverterDecorator(JsonConverter converter) : base(converter) { }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
// Unwrap the double-serialized string.
var s = JToken.Load(reader).ToString();
var token = JToken.Parse(s);
// Then convert the revealed JSON to its final form.
using (var subReader = token.CreateReader())
{
while (subReader.TokenType == JsonToken.None)
subReader.Read();
return base.ReadJson(subReader, objectType, existingValue, serializer);
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
string s;
// Serialize the value to an intermediate JSON string.
using (var textWriter = new StringWriter())
{
using (var subWriter = new JsonTextWriter(textWriter))
{
base.WriteJson(subWriter, value, serializer);
}
s = textWriter.ToString();
}
// Then double-serialize the value by writing the JSON as a string literal to the output stream.
writer.WriteValue(s);
}
}
public abstract class JsonConverterDecorator : JsonConverter
{
readonly JsonConverter converter;
public JsonConverterDecorator(Type jsonConverterType) : this((JsonConverter)Activator.CreateInstance(jsonConverterType)) { }
public JsonConverterDecorator(JsonConverter converter)
{
if (converter == null)
throw new ArgumentNullException();
this.converter = converter;
}
public override bool CanConvert(Type objectType)
{
return converter.CanConvert(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return converter.ReadJson(reader, objectType, existingValue, serializer);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
converter.WriteJson(writer, value, serializer);
}
public override bool CanRead { get { return converter.CanRead; } }
public override bool CanWrite { get { return converter.CanWrite; } }
}
然后使用[JsonConverter(typeof(TConverter), ...)]
属性将链式转换器应用于Message
属性,如下所示:
public class Requirments
{
public int FileID { get; set; }
public string EventMessageUId { get; set; }
public string ProjectId { get; set; }
[JsonConverter(typeof(StringConverterDecorator), typeof(SingleOrArrayConverter))]
public List<Message> Message { get; set; }
public string error { get; set; }
}
然后使用JsonConvert.DeserializeObject<T>
反序列化:
var requirement = JsonConvert.DeserializeObject<Requirments>(jsonString);
或者,如果您不想将转换器直接应用于您的类型,可以将其添加到JsonSerializerSettings.Converters
并反序列化,如下所示:
var settings = new JsonSerializerSettings
{
Converters = { new StringConverterDecorator(new SingleOrArrayConverter<List<Message>, Message>()) },
};
var requirement = JsonConvert.DeserializeObject<Requirments>(json, settings);
请注意,此处需要通用SingleOrArrayConverter<List<Message>, Message>
以防止转换器应用于所有类型的集合。
示例fiddle。
答案 2 :(得分:0)
Message
类的定义是对的。但是message
属性的Json主体不是数组。所以课程应该是
public class Requirments
{
public int FileID { get; set; }
public string EventMessageUId { get; set; }
public string ProjectId { get; set; }
public Message Message { get; set; }
//public object[] Message { get; set; }
public string error { get; set; }
}
答案 3 :(得分:0)
主要问题在于你的JSON,它应该是这样的
{"EventMessageUId":"ef51b5a3-32b2-e611-baf9-fc3fdb446bd2","Message":
[{"StoryId":20500,"StoryDesc":"Test Story
data"}],"ProjectId":"1"}
之后,您将获得“消息”列表,并且您可以轻松地将其映射到班级。
public class Message
{
public int StoryId { get; set; }
public string StoryDesc { get; set; }
}
public class Requirments
{
public string EventMessageUId { get; set; }
public List<Message> Message { get; set; }
public string ProjectId { get; set; }
}
答案 4 :(得分:0)
我已经成功地从您的Json中解析了班级类型消息的列表,但为此您需要更改您的班级要求:
public class Requirments
{
public int FileID { get; set; }
public string EventMessageUId { get; set; }
public string ProjectId { get; set; }
public string Message { get; set; }
//public List<Message> Message { get; set; } // **need to change property type to "string"**
//public object[] Message { get; set; }
public string error { get; set; }
}
您可以尝试以下代码:
Requirments mainResult = JsonConvert.DeserializeObject<Requirments>("YOUR JSON STING");
List<Message> MessageList = JsonConvert.DeserializeObject<List<Message>>(mainResult.Message.ToString());
注意:您需要在班级中使用使用Newtonsoft.Json; 。
这将为您提供消息列表
中的课程类型列表消息希望,这会有所帮助!