Каков наилучший способ правильно использовать один из двух «успешных» ответов с одной и той же конечной точки на веб-API? - PullRequest
1 голос
/ 08 июля 2019

У меня есть клиент C #, который отправляет запросы другому веб-API.

Веб-API, который я использую, может ответить двумя "успешными" ответами, оба 200.

Мне нужно перехватитьответ до того, как я сопоставлю его с соответствующим объектом и ищу наилучшую практику.

У меня есть клиент и сервер, поэтому любой из них можно настроить в соответствии с рекомендациями.

IЯ много не пробовал, но я рассмотрел следующее

  1. Имея понятную карту невостребованных кодов состояния для каждой ошибки.
  2. Попытка отловить попытку сопоставить JSON слибо один из двух бизнес-объектов, либо другой анализ и сравнение JSON с ожидаемым форматом, который ожидает каждый объект перед отображением.
response = await PostAsync(
    $"{BaseUrl}/endpoint/{identifier}",
    new StringContent(jsonBody, Encoding.UTF8, "application/json")
);

var responseJson = await response.Content.ReadAsStringAsync();
var responseObject = json.Deserialize<ResponseObject>(responseJson);
businessObject = new BusinessObject(responseObject);```

//These are two example responses
{
 "StartDate": "01/01/01",
 "EndDate": "01/01/01"
 "Object": {
  "Property1": 1,
  "Property2": "someStr"
 }
}
//OR
{
 "message": "Valid reason you are not receiving the JSON above, status 200 btw"
}

Ответы [ 2 ]

0 голосов
/ 08 июля 2019

Низкобюджетным решением может быть просто оценить тело ответа перед десериализацией.

var response = await PostAsync(
    $"{BaseUrl}/endpoint/{identifier}",
    new StringContent(jsonBody, Encoding.UTF8, "application/json")
);

var responseJson = await response.Content.ReadAsStringAsync();
var responseObject = responseJson.Contains("[special string or property name]")
    ? json.Deserialize<ResponseObjectA>(responseJson)
    : json.Deserialize<ResponseObjectB>(responseJson);
0 голосов
/ 08 июля 2019

У меня недавно была похожая проблема, но моя была, когда я принимал сообщения из очереди.Я решил это, сказав Newtonsoft добавить тип при сериализации моего объекта.Вы можете сделать это следующим образом:

JsonConvert.SerializeObject(response, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });

С помощью SerializeObject и DeserializeObject вы можете передать некоторые дополнительные параметры сериализации.Здесь мы передаем новый экземпляр JsonSerializerSettings этому параметру и устанавливаем для него TypeNameHandling значение enum TypeNameHandling.All.Это говорит Newtonsoft о включении типов всех сериализаций в сам JSON.Например, если у вас был класс, который выглядел так (на основе вашего примера JSON):

public class SuccessOne
{
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
    public SuccessOneChild Object { get; set; }
}

public class SuccessOneChild
{
    public int Property1 { get; set; }
    public string Property2 { get; set; }
}

Тогда полученный вами JSON будет выглядеть так:

{  
   "$type":"Functions.Tests.SuccessOne, Functions.Tests",
   "StartDate":"2019-07-09T09:32:11.0090507+01:00",
   "EndDate":"2019-07-16T09:32:11.0091048+01:00",
   "Object":{  
      "$type":"Functions.Tests.SuccessOneChild, Functions.Tests",
      "Property1":1,
      "Property2":"someStr"
   }
}

Обратите внимание надополнительные $type свойства, которые были добавлены?Они были автоматически добавлены Newtonsoft, потому что вы указали это в настройках сериализации.

Затем, когда вы приступите к десериализации, вы также можете указать ему использовать обработку типов.Он будет смотреть на дополнительное свойство типа в вашем JSON и десериализовать в любой тип.При этом вам не нужно указывать DeserializeObject аргумент типа:

var response = JsonConvert.DeserializeObject(response, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });

Обратите внимание, что везде, где вы десериализуете, нужно знать о классах.Поэтому может быть полезно иметь эти классы в общей библиотеке, на которую могут ссылаться как ваш API, так и потребитель, чтобы избежать дублирования вашего кода.

Затем вы можете обрабатывать ответ в зависимости от его типа.Я сделал это с помощью оператора switch:

switch (response.GetType().Name)
{
    case nameof(SuccessOne):
        var successOneResponse = (SuccessOne)response;
        handleSuccessOne(successOneResponse);
        break;
    case nameof(SuccessTwo):
        var successTwoResponse = (SuccessTwo)response;
        handleSuccessTwo(successTwoResponse);
        break;
    default:
        // Throw exception or whatever you want to do
        break;
}

Я также создал скрипку, показывающую сериализацию и десериализацию здесь: https://dotnetfiddle.net/UcugGg

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...