3

Есть сторонний сервер с 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 = &quot;N2U1OThkZDZkZDliZGFiM/lAfhoRNk0D+iJh2Z1h1fpYEUWXkzsbvGg1&quot;,
    date = dateTimeNow
};

try
{
    string jsonRequest = JsonSerializer.Serialize(requestMessage);
    string jsonResponseData = await PostRequesHttpAsync(url, jsonRequest);
    responseData = JsonSerializer.Deserialize&lt;ResponseMessageDataQRCode&gt;(jsonResponseData);
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}

if (responseData != null)
{
    if (responseData.status.Equals(&quot;200&quot;) || responseData.status.Equals(&quot;OK&quot;))
    {
        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);

}

aepot
  • 49,560

1 Answers1

3

Во-первых, запрос вы отправляете неверно. Надо как 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&lt;string, string&gt; requestMessage = new Dictionary&lt;string, string&gt;
{
    [&quot;token&quot;] = &quot;N2U1OThkZDZkZDliZGFiM/lAfhoRNk0D+iJh2Z1h1fpYEUWXkzsbvGg1&quot;,
    [&quot;date&quot;] = dateTimeNow
};

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

if (responseData != null)
{
    if (responseData.status.Equals(&quot;200&quot;) || responseData.status.Equals(&quot;OK&quot;))
    {
        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 тоже не нужен.

aepot
  • 49,560
  • Спасибо, это работает, он только в DateTime не смог серилиазовать - сделал строковый тип – Vlad-i-mir Sep 01 '21 at 13:31
  • А как вы поняли, что нужно не в формате JSON как я отправлял, а в форме отправлять? – Vlad-i-mir Sep 01 '21 at 13:32
  • 2
    @Vlad-i-mir --header 'Content-Type: application/x-www-form-urlencoded' – aepot Sep 01 '21 at 13:42
  • 2
    @Vlad-i-mir вам только нужно будет решить трюк с тем, что формат ответа при успехе и ошибке разный, например тип поля status но вы можете например это сделать с десереализацией прямо внутри PostFormAsync. Просто при ответе от сервера вам нужно проверить if (response.IsSuccessStatusCode) { десереализовать как успех } else { десереализовать как ошибку } - сделайте базовый класс ответа и от него 2 наследников, один для успеха, другой для ошибки. И возвращайте из метода уже десерализованный как тип базового класса. В методе RequestQRcodesReceiving: if (responseData is SuccessResponse)... – aepot Sep 01 '21 at 13:47
  • Понял, только вот пришлет ли он в ответе успешно/неуспешно? Судя по вот этому { "status": 0, "error": "Ошибочный токен пользователя", "region": "", "date": "2021-08-11 10:00:00", "items": [] } он всегда будет успешным, проверять наверное придется по полю "status" тела ответа – Vlad-i-mir Sep 01 '21 at 13:59
  • 2
    @Vlad-i-mir не путайте поле status в JSON и статус HTTP ответа. А пришлет ли - вы легко можете это проверить выдав серверу запрос с ошибкой. – aepot Sep 01 '21 at 14:12