Использование 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" (серверная сторона, то есть контракт на обслуживание).