Пустой возврат в запросе API - PullRequest
0 голосов
/ 06 июня 2019

Клиент и универсальный метод для запросов API создаются здесь:

public class Client : IDisposable
{
    private HttpClient _client;

    private void CreateClient()
    {
        _client = new HttpClient(); 
        _client.DefaultRequestHeaders.Accept.Clear();
        _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        _client.DefaultRequestHeaders.Add("KEY", token);
    }


    public void Dispose() => _client?.Dispose();

    public enum Method { GET, POST, PUT, DELETE }

    public HttpResponseMessage Request(string url, Method method, object data, HttpContent request)
    {
        if (data != null)
            request = new StringContent(Serialize(data), Encoding.UTF8, "application/json");

        switch (method)
        {
            case Method.POST: return _client.PostAsync(url, request).Result;
            case Method.PUT: return _client.PutAsync(url, request).Result;
            case Method.DELETE: return _client.DeleteAsync(url).Result;
            default: return _client.GetAsync(url).Result;
        }
    }

    public Task<HttpResponseMessage> RequestAsync(string url, Method method, object data, HttpContent request)
    {
        if (data != null)
            request = new StringContent(Serialize(data), Encoding.UTF8, "application/json");

        switch (method)
        {
            case Method.GET: return _client.GetAsync(url);
            case Method.POST: return _client.PostAsync(url, request);
            case Method.PUT: return _client.PutAsync(url, request);
            case Method.DELETE: return _client.DeleteAsync(url);
            default: return _client.GetAsync(url);
        }
    }

    public string Post(string url, object data) =>
        Request(url, Method.POST, data, null).Content.ReadAsStringAsync().Result;

    public Task<HttpResponseMessage> PostAsync(string url, object data) =>
        RequestAsync(url, Method.POST, data, null);

    //UTILS

    private static string Serialize(object data) =>
        data == null
            ? string.Empty
            : JsonConvert.SerializeObject(data, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
}

Я пытаюсь вызывать эти методы для определенных классов, чтобы упростить их использование для клиента.Например, чтобы создать новую проверку для транзакции по кредитной карте:

public class Checkout : SDK
{
    private static Client client;

    public Checkout() => client = new Client();

    public static async Task Credit(object data) => 
        await client.PostAsync(url, data);
}

Запрос должен быть смонтирован на основе нескольких моделей, которые могут иметь эту структуру, и я пытаюсь сгенерировать еепростым способом, например так:

    public async Task Test()
    {
        var transaction = new Transaction
        {
            PaymentMethod = new PaymentMethod { Code = "1" },
            Application = "Test",
            Vendor = "Name",
            Customer = new Customer
            {
                //Customer details...
            },
            Products = new List<TransactionProduct>
            {
                //Products...
            }
        };

        var teste = Checkout.Credit(transaction);
        Console.WriteLine(teste);
    }

И все, что я получаю в ответ:

System.Threading.Tasks.Task`1[System.Threading.Tasks.VoidTaskResult]
Id = 1, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}"

Я пытался добавить await для вызова Checkout.Credit,но я получаю:

CS0815  Test C# Cannot assign void to an implicitly-typed variable

Модульное тестирование с простыми запросами HttpClient работает как чудо, но я не могу определить проблему в структуре моего проекта, поэтому любая помощь будет очень признательна,

1 Ответ

1 голос
/ 06 июня 2019

Task - это тип возврата для async метода , который не имеет возвращаемого значения .

Или, иначе говоря, async упаковывает T значения в Task<T> (или void возвращает в Task), а await разворачивает эти значения. Поскольку Credit возвращает Task, тип выражения Checkout.Credit(transaction) равен Task, а тип выражения await Checkout.Credit(transaction) равен void. И вы не можете назначить void на var teste; это то, что говорит ошибка компилятора.

Чтобы исправить это, укажите тип возвращаемого вами метода async. В частности:

public static async Task<HttpResponseMessage> Credit(object data) => 
    await client.PostAsync(url, data);

Кстати, это довольно странно:

public string Post(string url, object data) => ...;
public Task<HttpResponseMessage> PostAsync(string url, object data) => ...;

Обычно, если у вас есть Method и MethodAsync, где Method имеет некоторый тип возврата TResult, тогда MethodAsync будет иметь тип возврата Task<TResult>, а не Task<SomeCompletelyDifferentType>. Более естественный API будет выглядеть примерно так:

public async Task<HttpResponseMessage> PostAsync(string url, object data)
{
  var result = await Request(url, Method.POST, data, null);
  return await result.Content.ReadAsStringAsync();
}
...