将Json反序列化为对象和子对象以返回 [英] Deserialize Json into object and child object for return

查看:141
本文介绍了将Json反序列化为对象和子对象以返回的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对JSON不太熟悉,遇到了一个对我来说并不明显的问题.

Not too familiar with JSON yet and have come across a an issue that not obvious to me.

我正在查询的api返回一个标准响应对象,并将处理后的命令/api请求的结果嵌入json的数据对象中.

The api I'm querying returns a standard response object with the result of the processed command/api request embedded within a data object within the json.

因此,对于API上的所有请求,响应如下所示返回,数据组件根据请求的内容而变化.

So the response comes back like the following for all requests on the API the data component changes dependent on whats been requested.

ObjectType1响应

ObjectType1 response

{
    "data": { 
        "person" : { 
            "id" : 21, 
            "name" : "Json can be annoying at times"
        }
    },
    "message" : "",
    "result" : "success"
}

或对api的另一个请求将返回以下

or another request on api will return the following List of

ObjectType2响应

ObjectType2 response

{
    "data": { 
        "1234" : {
            "id": 1234,
            "title" : "Terminator"

        },
        "3245" : { 
            "id" : 3245, 
            "name" : "Terminator 2"
        }
    },
    "message" : "",
    "result" : "success"
}

我想要一个自定义的JsonConverter,将响应拉入这样的对象

I would like to have a custom JsonConverter that pulls out the response into an object as such

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字符串可以根据请求正确处理.

And then from there i can act on the Status / message within a generic method then return a json string back to the calling method in my library. From which the json string returned can be processed properly according to the request.

任何想法如何将数据的子对象反序列化为字符串,或者如果我通过通用类型T的方法将其反序列化甚至更好,那么如何将json反序列化为两个对象.

Any ideas how to deserialize data's child object back into a string or even better if i passed the method a generic type T how could i deserialize the json into both objects.

编辑

在下面为希望做类似事情的人发布答案

Posted answer below for those looking to do something similar

欢呼

推荐答案

谢谢那些提供了帮助的人,但是我最终想出了我想要的答案,它将我的对象反序列化为通过泛型提供的适当类型

Thank you to those that offered some help, but I eventually came up with the answer I was looking for that would deserialize my object into a proper type offered via generics.

这是我的MyCustomResponse对象

Here is my MyCustomResponse object

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类型的对象

The custom JsonConverter ended up like so, I look for the property in the json string "data" then convert it to an object of type 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();
    }
}

要使用上述方法,我创建了一个通用方法,该方法类似于以下内容,并允许我传递命令运行,额外的查询字符串以及将数据"对象转换为的类型:

To use the above I created a Generic method that looks like the following and allows me to pass the command to run, extra query string and also the Type to convert 'Data' object to:

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方法,我只需向其传递命令,查询和键入要转换为Data对象的数据对象,无论它可能是什么.

Then to use the actual GenericApiRequestAsync method i simply pass it the command, query and type for the Data object to be converted into, whatever it maybe.

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));
}

最终得到了一个简单的解决方案,但到达那里却很复杂.同时也消除了将数据对象第二次处理到最终对象中的需要.

Ended up a simple solution but complex in getting there. It removes the need to process the data object a second time into in the final object as well.

希望该解决方案可以帮助遇到类似JSON结构的其他人,如果有人看到实现转换器的更简单方法,我很乐意接受任何输入.

Hope this solution can help others out there that come across similar JSON structures, if anyone sees a simpler way to implement the converter, i'm happy to accept any input.

欢呼

这篇关于将Json反序列化为对象和子对象以返回的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆