Использование ReadAsAsync <T>() для десериализации сложного объекта Json
Я хочу использовать ReadAsAsync() в моем проекте mvc с .net 4.0. Результат получается нулевым.
Если я вхожу в uri в адресную строку, результат в chrome как (имена тегов изменяются):
<ns2:MyListResponse xmlns:ns2="blablabla">
<customerSessionId>xxcustomerSessionIdxx</customerSessionId>
<numberOfRecordsRequested>0</numberOfRecordsRequested>
<moreResultsAvailable>false</moreResultsAvailable>
<MyList size="1" activePropertyCount="1">
<MySummary order="0">
<id>1234</id>
<name>...</name>
.
.
</MySummary>
</MyList>
</ns2:MyListResponse>
Если я использую оператор в коде:
using (var client = new HttpClient())
{
var response = client.GetAsync(apiUri).Result;
var message = response.Content.ReadAsStringAsync().Result;
var result1 = JsonConvert.DeserializeObject<MyListResponse>(message);
var result2 = response.Content.ReadAsAsync<MyListResponse>().Result;
}
сообщение приходит в формате строки как "{\"MyListResponse\":{\"customerSessionId\"...}"
, которое соответствует объекту json как:
{"MyListResponse":
{"customerSessionId":"xxcustomerSessionIdxx",
"numberOfRecordsRequested":0,
"moreResultsAvailable":false,
"MyList":
{"@size":"1",
"@activePropertyCount":"1",
"MySummary":
{"@order":"0",
"id":1234,
"name":"...",
.
.
}
}
}
}
, а свойства result1 и result2 равны нулю или значениям по умолчанию. Ниже приведены определения классов. Я хочу читать контент как объект, но не мог. Что вы советуете для решения этой проблемы? Что я делаю не так? Спасибо заранее.
public class MySummary
{
public int @Order { get; set; }
public string Id { get; set; }
public string Name { get; set; }
.
.
}
public class MyList
{
public int @Size { get; set; }
public int @ActivePropertyCount { get; set; }
public MySummary MySummary{ get; set; }
}
public class MyListResponse
{
public string CustomerSessionId { get; set; }
public int NumberOfRecordsRequested { get; set; }
public bool MoreResultsAvailable { get; set; }
public MyList MyList { get; set; }
}
Ответы
Ответ 1
Я определил новый класс как:
public class ResponseWrapper
{
public MyListResponse MyListResponse { get; set; }
}
то я использовал эту оболочку с помощью
var result1 = JsonConvert.DeserializeObject<ResponseWrapper>(message);
var result2 = response.Content.ReadAsAsync<ResponseWrapper>().Result;
тогда это сработало. Мне нужен только объект MySummary, но я должен написать больше классов, чтобы он работал.
Ответ 2
После прочтения вашего решения я придумал тот, который не нуждается в дополнительном классе:
private static async Task<U> Execute<U>(HttpClient client, string path)
{
U output = default(U);
HttpResponseMessage response = await client.GetAsync(path);
if (response.IsSuccessStatusCode)
{
var jsonAsString = await response.Content.ReadAsStringAsync();
output = JsonConvert.DeserializeObject<U>(jsonAsString);
}
else
{
throw new ApplicationException(string.Format("Response message is not OK. Issues in action: {0}", path));
}
return output;
}
Ответ 3
Для будущих читателей я считаю, что правильный подход использует перегрузку ReadAsAsync
, которая принимает IEnumerable<MediaTypeFormatter>
и предоставляет форматтер с теми же настройками, которые используются на сервере для сериализации. Это должно исправить это.
Ответ 4
Можно использовать на клиенте ReadAsAsync напрямую с MyListResponse (в результате без ResponseWrapper). Для этого вы можете определить "BodyStyle = WebMessageBodyStyle.Bare" в операционном контракте "apiuri" вместо "BodyStyle = WebMessageBodyStyle.Wrapped" (серверная сторона, то есть контракт на обслуживание).