Десериализация объекта полученного со стороннего сервера

Есть сторонний сервер с API, которое описывается следующим образом:

Структура запроса
Для получения данных об отсканированных талонах необходимо выполнить POST запрос со следующими параметрами (пример cURL):

curl --location --request POST 'https://xxxxx/app/api/barcodes/get.php' \
     --header 'Application: remoteData' \
     --header 'Content-Type: application/x-www-form-urlencoded' \
     --data-urlencode 'token=ваш_токен' \
     --data-urlencode 'date=2021-08-18 10:00:00'
  • Адрес обращения: https://xxxxxx/app/api/barcodes/get.php
  • Обязательный заголовок: Application: remoteData
  • Поля запроса:
    • token – ваш уникальный идентификатор
    • date – дата и время, после которого будут собраны данные в формате YYYY-MM-DD HH:II:SS

Структура ответа сервера
При успешной обработке ответ сервера будет представлен в следующем виде:

{
  "status": "OK",
  "error": "",
  "region": 76,
  "date": "2021-08-11 10:00:00",
  "items": {
    "2": "2021-08-17 16:26:32",
    "3": "2021-08-17 16:28:48",
    "12": "2021-08-17 19:30:19"
  }
}

Пример ответа сервера при возникновении ошибки. Например, указан неправильный токен пользователя:

{
  "status": 0,
  "error": "Ошибочный токен пользователя",
  "region": "",
  "date": "2021-08-11 10:00:00",
  "items": []
}

В итоге строка ответа при ошибке выглядит следующим образом:

"{\"status\":103,\"error\":\"Не найден токен\",\"region\":\"\",\"date\":\"\",\"items\":[]}"

Для сериализации запроса и десериализации ответа создал следующие классы:

public class RequestMessageData
{
    public string token { get; set; }
    public string date { get; set; }
}
    
public class ResponseMessageDataQRCode
{
    public string status { get; set; }
    public string error { get; set; }
    public int region { get; set; }
    public string date { get; set; }
    public Items [] items { get; set; }
}
    
public class Items
{
    public string name { get; set; }
    public string dateTime { get; set; }
}    

Отправляю запрос и обрабатываю ответ следующим образом:

string jsonRequest = JsonSerializer.Serialize(requestMessage);
string jsonResponseData = await PostRequesHttpAsync(url, jsonRequest);
responseData = JsonSerializer.Deserialize<ResponseMessageDataQRCode>(jsonResponseData);

На строке responseData = JsonSerializer.Deserialize<ResponseMessageDataQRCode> получаю ошибку десериализации.

Полный текст метода:

[HttpPost]
[Route("requestqrcodesreceiving")]
public async Task<IActionResult> RequestQRcodesReceiving([FromBody] string dateTimeStr)
{
    string url = "https://хххххх/app/api/barcodes/get.php";
    ReportQrCodeExchange reportQrCodeExchange = new ReportQrCodeExchange();
    ResponseMessageDataQRCode responseData = null;
    string dateTimeNow = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");

    RequestMessageData requestMessage = new RequestMessageData
    {
        token = "N2U1OThkZDZkZDliZGFiM/lAfhoRNk0D+iJh2Z1h1fpYEUWXkzsbvGg1",
        date = dateTimeNow
    };
    
    try
    {
        string jsonRequest = JsonSerializer.Serialize(requestMessage);
        string jsonResponseData = await PostRequesHttpAsync(url, jsonRequest);
        responseData = JsonSerializer.Deserialize<ResponseMessageDataQRCode>(jsonResponseData);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
    
    if (responseData != null)
    {
        if (responseData.status.Equals("200") || responseData.status.Equals("OK"))
        {
            reportQrCodeExchange = CheckQrCodes(responseData);
        }
        else
        {
            reportQrCodeExchange.error = responseData.error;
            reportQrCodeExchange.status = responseData.status;
            return Ok(reportQrCodeExchange);
        }
    }
    
    return Ok(reportQrCodeExchange);
}

Метод формирования запроса:

public async Task<string> PostRequesHttpAsync(string url, string json)
{
    using HttpContent content = new StringContent(json, Encoding.UTF8, "application/x-www-form-urlencoded");
    httpClient.DefaultRequestHeaders.Add("Application", "remoteData");
    //httpClient.DefaultRequestHeaders.Add("Content-Type", "application/x-www-form-urlencoded");
    using HttpResponseMessage response = await httpClient.PostAsync(url, content).ConfigureAwait(false);
    
    return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}

Ответы (1 шт):

Автор решения: aepot

Во-первых, запрос вы отправляете неверно. Надо как form-urlencoded, а вы как json.

private async Task<string> PostFormAsync(string url, IEnumerable<KeyValuePair<string, string>> data)
{
    using var request = new HttpRequestMessage(HttpMethod.Post, url)
    {
        Content = new FormUrlEncodedContent(data)
    };
    request.Headers.Add("Application", "remoteData");
    using var response = await httpClient.SendAsync(request).ConfigureAwait(false);
    return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}

Ну и чтобы это использовать, я не много изменил код

[HttpPost]
[Route("requestqrcodesreceiving")]
public async Task<IActionResult> RequestQRcodesReceiving([FromBody] string dateTimeStr)
{
    string url = "https://хххххх/app/api/barcodes/get.php";
    ReportQrCodeExchange reportQrCodeExchange = new ReportQrCodeExchange();
    ResponseMessageDataQRCode responseData = null;
    string dateTimeNow = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");

    Dictionary<string, string> requestMessage = new Dictionary<string, string>
    {
        ["token"] = "N2U1OThkZDZkZDliZGFiM/lAfhoRNk0D+iJh2Z1h1fpYEUWXkzsbvGg1",
        ["date"] = dateTimeNow
    };

    try
    {
        string jsonResponseData = await PostFormAsync(url, requestMessage);
        responseData = JsonSerializer.Deserialize<ResponseMessageDataQRCode>(jsonResponseData);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }

    if (responseData != null)
    {
        if (responseData.status.Equals("200") || responseData.status.Equals("OK"))
        {
            reportQrCodeExchange = CheckQrCodes(responseData);
        }
        else
        {
            reportQrCodeExchange.error = responseData.error;
            reportQrCodeExchange.status = responseData.status;
            return Ok(reportQrCodeExchange);
        }
    }

    return Ok(reportQrCodeExchange);
}

Во-вторых, Items не нужен, принятые данные можно десереализовать в словать.

public class ResponseMessageDataQRCode
{
    public string status { get; set; }
    public string error { get; set; }
    public int region { get; set; }
    public DateTime date { get; set; }
    public Dictionary<string, DateTime> items { get; set; }
}

Кстати, получается что класс RequestMessageData тоже не нужен.

→ Ссылка