我有这种解析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);
}
}
答案 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; }
}
通过这种方式,您无需更改通用实现,该类将按照您希望的方式进行序列化/反序列化。