将Json反序列化为对象和返回的子对象
本文关键字:对象 返回 反序列化 Json | 更新日期: 2023-09-27 17:50:33
还不太熟悉JSON,遇到了一个对我来说不太明显的问题。
我正在查询的api返回一个标准响应对象,其中包含json中的数据对象中嵌入的处理命令/api请求的结果。
因此,对于API上的所有请求,响应返回如下:数据组件的变化取决于请求的内容。
ObjectType1反应
{
"data": {
"person" : {
"id" : 21,
"name" : "Json can be annoying at times"
}
},
"message" : "",
"result" : "success"
}
或api上的其他请求将返回以下
列表ObjectType2反应
{
"data": {
"1234" : {
"id": 1234,
"title" : "Terminator"
},
"3245" : {
"id" : 3245,
"name" : "Terminator 2"
}
},
"message" : "",
"result" : "success"
}
我想有一个自定义的JsonConverter拔出响应到一个对象,如
public class MyResponse {
[JsonProperty(PropertyName = "data")]
public string Data { get; set; }
[JsonProperty(PropertyName = "message")]
public string Message { get; set; }
[JsonProperty(PropertyName = "status")]
public string Status { get; set; }
}
或
public class MyResponse<T> : class T {
public T Data { get; set; }
public string Message { get; set; }
public string Status { get; set; }
}
然后从那里我可以在一个通用方法中的状态/消息,然后返回一个json字符串返回到我的库中的调用方法。可以根据请求正确处理返回的json字符串。
有什么想法如何反序列化数据的子对象返回到一个字符串,甚至更好,如果我传递一个泛型类型T的方法,我怎么能反序列化json到两个对象。
编辑
为那些想做类似事情的人贴出答案
欢呼
感谢那些提供帮助的人,但我最终找到了我一直在寻找的答案,它将把我的对象反序列化为通过泛型提供的适当类型。
这是我的MyCustomResponse对象
public class MyCustomResponse
{
[JsonProperty(PropertyName = "data")]
public object Data { get; set; }
[JsonProperty(PropertyName = "message")]
public string Message { get; set; }
[JsonProperty(PropertyName = "result")]
public string Result { get; set; }
}
自定义JsonConverter最终是这样的,我在json字符串"data"中查找属性,然后将其转换为T类型的对象
public class MyCustomResponseConverter<T> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(MyCustomResponse));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
object instance = objectType.GetConstructor(Type.EmptyTypes).Invoke(null);
PropertyInfo[] props = objectType.GetProperties();
JObject jo = JObject.Load(reader);
foreach ( JProperty jp in jo.Properties() )
{
PropertyInfo prop = props.FirstOrDefault(pi =>
pi.CanWrite && string.Equals(pi.Name, jp.Name, StringComparison.OrdinalIgnoreCase));
if ( prop != null )
{
// Convert data object to what was passed in at T
if ( jp.Name == "data" )
prop.SetValue(instance, jo.SelectToken("data").ToObject(typeof(T)));
else
prop.SetValue(instance, jp.Value.ToObject(prop.PropertyType, serializer));
}
}
return instance;
}
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
为了使用上面的内容,我创建了一个泛型方法,看起来像下面这样,允许我传递命令来运行,额外的查询字符串和类型来转换'Data'对象:
private async Task<T> GenericApiRequestAsync<T>(string command, string query)
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Uri uri = new Uri(string.Format("{0}/api/{1}/?cmd={2}{3}", apiUrl, apiKey, command, query));
try {
HttpResponseMessage response = await client.GetAsync(uri);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
// Convert responseContent via MyCustomResponseConverter
var myCustomResponse =
await Task.Factory.StartNew(() =>
JsonConvert.DeserializeObject<MyCustomResponse(
responseContent,
new MyCustomResponseConverter<T>()
));
return (T)myCustomResponse.Data;
}
catch(Exception ex)
{
...
}
}
然后使用实际的GenericApiRequestAsync方法,我只是简单地传递命令,查询和类型的数据对象转换成,无论它是什么。
public async Task<Person> GetPersonAsync(int id)
{
return await GenericApiRequestAsync<Person>("person.byid", string.Format("&id={0}", id));
}
public async Task<IDictionary<string, ObjectType2>> GetObjectType2ListAsync(string name)
{
return await GenericApiRequestAsync<IDictionary<string, ObjectType2>>("show.byname", string.Format("&name={0}", name));
}
最终得到了一个简单的解决方案,但实现起来很复杂。它也消除了在最终对象中对数据对象进行第二次处理的需要。
希望这个解决方案可以帮助其他人在那里遇到类似的JSON结构,如果有人看到一个更简单的方法来实现转换器,我很高兴接受任何输入。
欢呼
要了解JSON对象的序列化/反序列化,请查看Json.NET。您可以将其作为Nuget包包含,并使用内置的方法,如JsonConvert.SerializeObject(Object object)
和JsonConvert.DeserializeObject(string value, Type type)
。
你可以通过用JsonProperty
属性装饰你的模型来控制JSON属性的名称。例如:
public class MyResponse {
[JsonProperty(PropertyName = "data")]
public string Data { get; set; }
[JsonProperty(PropertyName = "message")]
public string Message { get; set; }
[JsonProperty(PropertyName = "status")]
public string Status { get; set; }
}
两个实体:
public class Response
{
public Dictionary<string, Data> data { get; set; }
public string message { get; set; }
public string result { get; set; }
}
public class Data
{
public int id { get; set; }
public string title { get; set; }
}
响应码为:
JavaScriptSerializer serializer = new JavaScriptSerializer();
Response response = (Response) serializer.Deserialize<Response>(jsonString);
可以看到没有附加的包