使用数组根解析JSON

时间:2019-06-24 16:30:19

标签: c# json

我有这种解析JSON的通用方法

 public async Task<T> ProcessAsync<T>(HttpRequestMessage request, NamingStrategy namingStrategy)
    {
        if (!string.IsNullOrEmpty(_authToken))
        {
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _authToken);
        }

        HttpResponseMessage response = await _client.SendAsync(request);
        if (response.IsSuccessStatusCode)
        {
            _logger.LogSuccess(response.StatusCode.ToString(), request.Method.ToString(), request.RequestUri.ToString());

            var dezerializerSettings = new JsonSerializerSettings
            {
                ContractResolver = new DefaultContractResolver
                {
                    NamingStrategy = namingStrategy
                }
            };
            try
            {
                T responseModel = JsonConvert.DeserializeObject<T>(await response.Content.ReadAsStringAsync(), dezerializerSettings);
                return responseModel;

            }
            catch (Exception ex)
            {
                _logger.LogError(request.Method.ToString(), request.RequestUri.ToString(), ex);
                throw;
            }
        }
        else
        {
            throw await GetFailureResponseModel(response);

        }
    }

这很好,但是现在我遇到了一个极端的情况,我的API响应之一在根目录中包含Array。像这样

[
{
    "productId": "100013",
    "lastUpdate": "2018-02-07 15:07:09.0"
},
{
    "productId": "643927",
    "lastUpdate": "2018-07-05 15:25:48.0"
},
{
    "productId": "699292",
    "lastUpdate": "2018-07-05 15:22:24.0"
},
{
    "productId": "722579",
    "lastUpdate": "2018-07-05 15:20:52.0"
},
{
    "productId": "722580",
    "lastUpdate": "2018-07-05 15:20:53.0"
}

]

我在解析JSON时遇到了问题。这就是我试图解析的方式

 var response = await _client.GetAsync<FavoriteProductResponseModel>($"v2/member/favourites?total={WebUtility.UrlEncode(total)}&offset={WebUtility.UrlEncode(offset)}");

这是我要解析的模型,

 public class FavoriteProductResponseModel : BaseResponse
{
    public List<FavoriteProduct> favoriteProducts { get; set; }
}

我可以通过我的Generic方法解析这种类型的JSON吗? 仅供参考:您可以看到我的模型是从BaseResponse扩展而来的,这是针对通用方法中的类型约束的。即

 public async Task<T> GetAsync<T>(string uri, NamingStrategy namingStrategy) where T : BaseResponse
    {
        using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri))
        {
            return await ProcessAsync<T>(requestMessage, namingStrategy);
        }
    }

2 个答案:

答案 0 :(得分:2)

我将您的代码简化为:

public async Task<T> ProcessAsync<T>(HttpRequestMessage request)
{
    HttpResponseMessage response = await new HttpClient().SendAsync(request);
    T responseModel = JsonConvert.DeserializeObject<T>(await response.Content.ReadAsStringAsync());
    return responseModel;
}

public async Task<T> GetAsync<T>(string uri)
{
    return await ProcessAsync<T>(new HttpRequestMessage(HttpMethod.Get, uri));
}

然后您的问题现在看起来很清楚:您想将数组反序列化为包含该数组的对象。

所以您的请求应该是:

var favorites = await _client.GetAsync<List<FavoriteProduct>>(....)
var response = new FavoriteProductResponseModel { favoriteProducts = favorites };

,并且您的FavoriteProduct应该配置了JsonPropertyAttribute

public class FavoriteProduct
{
    [JsonProperty("productId")]
    public int ProductId { get; set; }

    [JsonProperty("lastUpdate")]
    public DateTime LastUpdate { get; set; }
}

如果您想使用类型限制,则必须编写以下代码:

public class BaseResponse<T>
{
    public T Data { get; set; }
}

public class FavoriteProductResponseModel : BaseResponse<List<FavoriteProduct>>
{
}

那么您的GetAsync将是:

public async Task<Toutput> GetAsync<Tdata, Toutput>(string uri) where Toutput : BaseResponse<Tdata>, new()
{
    var data = await ProcessAsync<Tdata>(new HttpRequestMessage(HttpMethod.Get, uri));

    return new Toutput { Data = data };
}

您的呼叫将会是:

public async Task<FavoriteProductResponseModel> GetFavorites()
{
    return await GetAsync<List<FavoriteProduct>, FavoriteProductResponseModel>("your uri.....");
}

答案 1 :(得分:0)

在不丢失BaseResponse类型约束的情况下,最简单的选择可能就是创建自定义JsonConverter

public class FavoriveProductConverter : JsonConverter<FavoriteProductResponseModel>
{
    public override FavoriteProductResponseModel ReadJson(
        JsonReader reader,
        Type objectType,
        FavoriteProductResponseModel existingValue,
        bool hasExistingValue,
        JsonSerializer serializer)
    {
        var model = existingValue;
        if (model == null)
        {
            model = new FavoriteProductResponseModel();
        }

        // Here we deserialize the list under the hood
        // And assign it to the FavoriteProducts property.
        model.FavoriteProducts = serializer.Deserialize<List<FavoriteProduct>>(reader);
        return model;
    }

    public override void WriteJson(JsonWriter writer, FavoriteProductResponseModel value, JsonSerializer serializer)
    {
        if (value == null) return;

        // On serialization, we serialize the favorite products list instead
        serializer.Serialize(writer, value.FavoriteProducts);
    }
}

然后使用FavoriteProductResponseModel将转换器添加到JsonConverterAttribute

[JsonConverter(typeof(FavoriveProductConverter))]
public class FavoriteProductResponseModel : BaseResponse
{
    public List<FavoriteProduct> FavoriteProducts { get; set; }
}

通过这种方式,您无需更改通用实现,该类将按照您希望的方式进行序列化/反序列化。