Моя программа вызывает API, который реагирует по-разному, в зависимости от результата операции.
Как я могу справиться с этим в коде?
Ответ на успех
{
"status": "OK",
"message": {
"name": "HELLO NAME",
"id": "3171024302821001",
"pob": "GARESSI SUPPA",
"dob": "01-01-1961",
"gender": "LAKI-LAKI",
"address": "BTN UNHALU BLOK C NO. 28",
"rt": "006",
"rw": "003",
"village": "KAMBU",
"district": "KAMBU",
"religion": "ISLAM",
"marital_status": "KAWIN",
"work": "PEGAWAI NEGERI SIPIL (PNS)",
"nationnality": "WNI",
"city": "KOTA KENDARI",
"province": "SULAWESI TENGGARA"
}
}
Ответ на неудачу
{
"status": "FAIL",
"message": "check input image and retry"
}
я использую модель linq в С#
моя модель С#
public class IziDataKtpOcrResponseMessage
{
public string Status { get; set; }
public IziDataKtpOcrResponseMessageData message;
}
тогда это мой код для сбора сообщений
iziDataKtpOcrResponseMessage = JsonConvert.DeserializeObject<IziDataResponseMessage>(iziDataKtpOcrResponse);
Я использую модель linq и Newtonsoft.Json для этого ответа, но когда я получаю ответ «не удалось», моя модель не поддерживает этот результат.
Используйте дискриминируемый союз, например OneOf<>
https://github.com/mcintyre321/OneOf
Вот так:
sealed class GotPersonalDetailsResult
{
public GotPersonalDetailsResult( String name, String id, String pob, etc... )
{
this.Name = name;
this.Id = id;
}
public String Name { get; }
public String Id { get; }
// etc
}
sealed class FailureResult
{
public FailureResult( String status, String message )
{
this.Status = status;
this.Message = message ;
}
public String Status { get; }
public String Message { get; }
}
С вашим методом обслуживания, например:
using OneOf;
public class RandomPeopleSearchClient
{
public async Task< OneOf<GotPersonalDetails,FailureResult> > FindRandomPersonAsync( CancellationToken cancellationToken = default )
{
using( HttpClient hc = this.hcf.CreateClient() )
{
// etc
if ( httpResponse.Status == 200 && isJsonResponse )
{
if ( TryParseGotPersonalDetailsResult( out GotPersonalDetailsResult ok ) )
{
return ok; // <-- This is allowed due to implicit conversion from X or Y in OneOf<X,Y>
}
else if ( TryParseFailureResult( out FailureResult whoops ) )
{
return whoops;
}
}
// Otherwise, this is exceptional, so throwing is fine:
throw new RandomPeopleSearchClientException( "Expected either a GotPersonalDetailsResult or a FailureResult but encountered an unexpected result", /* details-from-response-go-here */ );
}
}
}
И потребляется так:
RandomPeopleSearchClient client = ...
OneOf<GotPersonalDetails,FailureResult> result = await client.FindRandomPersonAsync();
if ( result.TryPickT0( out GotPersonalDetailsResult ok, out FailureResult failed )
{
// Use only `ok` here
}
else
{
// Use only `failed` here
}
Обратите внимание, что вы не ограничены двумя взаимоисключающими типами результатов: тип OneOf<>
поддерживает до 8 различных типов.
Когда вы используете OneOf<X,Y,Z>
3-го типа (или более), метод TryPickT0()
возвращает остаток n-1
в качестве второго параметра out
, что позволяет вам безопасно использовать else if
C#, не опасаясь случайного разыменования невозможного значения результата, например:
OneOf<X,Y,Z> choiceOf3 = ...
if ( choiceOf3.TryPickT0( out X x, out OneOf<Y,Z> yz )
{
// Use only `x` here
}
else if ( if ( yz.TryPickT0( out Y y, out Z z ) )
{
// Use only `y` here
}
else
{
// Use only `z` here
}
В нем также есть другие методы Match
и Switch
в стиле FP, которые вы можете использовать, чтобы не беспокоиться об исчерпывающих блоках if
.
Вы можете проверить значение поля JSON (статус) перед десериализацией в определенный класс.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
var jsonString = @"
{
""status"": ""FAIL"",
""message"": ""check input image and retry""
}
";
var jobj = JsonConvert.DeserializeObject<JObject>(jsonString);
var status = jobj["status"].ToString();
if (status == "FAIL")
{
var errorResponse = JsonConvert.DeserializeObject<ErrorResponse>(jsonString);
}
else if (status == "OK")
{
var successResponse = JsonConvert.DeserializeObject<SuccessResponse>(jsonString);
}
public class Message
{
public string name { get; set; }
public string id { get; set; }
public string pob { get; set; }
public string dob { get; set; }
public string gender { get; set; }
public string address { get; set; }
public string rt { get; set; }
public string rw { get; set; }
public string village { get; set; }
public string district { get; set; }
public string religion { get; set; }
public string marital_status { get; set; }
public string work { get; set; }
public string nationnality { get; set; }
public string city { get; set; }
public string province { get; set; }
}
public class SuccessResponse
{
public string status { get; set; }
public Message message { get; set; }
}
public class ErrorResponse
{
public string status { get; set; }
public string message { get; set; }
}
хо, если я приму сообщение об успешном ответе вот так? var status = jobj["status"].ToString();
Возвращаются ли разные ответы с разными кодами состояния HTTP? Если это так, вы можете использовать это, чтобы определить, содержит ли ответ сообщение об ошибке или может ли быть десериализован в соответствующий объект.