Asp.net Core 2.1 HttpClientFactory: второй вызов API не ожидает возврата результата первого вызова API

Я столкнулся с проблемой при использовании HttpClientFactory. Мне нужно вызвать два веб-метода из одного стороннего веб-API.

  1. получитьНомерЗаказа.
  2. получитьShippingLabelFile.

Вызов № 2 зависит от результата № 1, поскольку ему необходимо передать ему orderNumber, например:

await _client.getAsync("http://xxx/api/getLabel?orderNumber=[returnedOrderNumber]&fileType=1")

Когда я устанавливаю точку останова и отлаживаю, все работает как положено. Без режима отладки веб-метод №2 всегда терпел неудачу. Я провел расследование. Если я передам статический параметр запроса, например:

http://xxx/api/getLabel?orderNumber=123&fileType=1

это работает нормально. Кажется, № 2 оценивает строку запроса и выполняет вызов API до того, как ему будет передан orderNumber. Это очень расстраивает, не могли бы вы пролить свет на этот вопрос?

На контроллере:

private readonly ISite1AuthHttpClient _site1HttpClient;

public OrderShippingOrdersController(site1AuthHttpClient)
{
    _site1HttpClient=site1AuthHttpClient
}

[HttpGet("{id}")]
public async Task<IActionResult> GetShippingLabel(int id)
{
    string token=await _site1HttpClient.GetToken(username.ToString(),password);
    string orderNumber=await _site1HttpClient.CreateOrder(Order,token);

    if (orderNumber!=null && orderNumber!="")
    {
        //this API call always failed during runtime. It works on debugging mode.
        var streamFile=(MemoryStream)(await _site1HttpClient.getShippingLabel(orderNumber,token));

    }
}

Класс типа HttpClient:

public interface ISite1HttpClient
{
    Task<string> CreateOrder(AueCreateOrder order,string token);
    Task<Stream> GetShippingLabel(string orderNumber,string token);
}

public class Site1HttpClient:ISite1HttpClient
{
    private readonly HttpClient _client;

    public Site1HttpClient(HttpClient httpClient)
    {
        httpClient.BaseAddress = new Uri("http://abcapi.Site1.com/");
        httpClient.DefaultRequestHeaders.Accept.Clear();
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));

        _client = httpClient;
    }

    public async Task<string> CreateOrder(AbcCreateOrder order,string token)
    {
        var jsonInString=JsonConvert.SerializeObject(order);
        jsonInString="[ " + jsonInString + " ]";

        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",token);
        HttpResponseMessage response = await _client.PostAsync(
            "api/AgentShipmentOrder/Create", new StringContent(jsonInString, Encoding.UTF8, "application/json"));

        if (response.IsSuccessStatusCode)
        {
            var contents = await response.Content.ReadAsStringAsync();
            AbcOrderCreateResponse abcRes = JsonConvert.DeserializeObject<AbcOrderCreateResponse>(contents);
            return abcRes.Message;
        }
        else
        {
            var errorResponse = await response.Content.ReadAsStringAsync();
            throw new Exception(errorResponse);
        }
    }

    public async Task<Stream> GetShippingLabel(string orderNumber,string token)
    {
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",token);
        HttpResponseMessage response = await _client.GetAsync("api/GetOrderLabel?orderId="+orderNumber+"&fileType=1");

        if (response.IsSuccessStatusCode)
        {
            Stream streamFile= await response.Content.ReadAsStreamAsync();
            return streamFile;
        }
        else
        {
            throw new Exception("failed to get label.");
        }
    }
}

person Edison    schedule 15.12.2018    source источник
comment
Прежде всего, я бы добавил ведение журнала. Гораздо проще, если вы видите, что происходит, чем гадать… docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/   -  person Christoph Lütjen    schedule 15.12.2018
comment
Скорее всего, номер вашего заказа не такой, как вы ожидаете, и я бы использовал string.IsNullOrWhiteSpace(), который будет покрывать нулевое, пустое и белое пространство   -  person Kos    schedule 16.12.2018
comment
Для вашего кода orderNumber имеет возвращаемое значение. Я предполагаю, что даже через сторонний возврат orderNumber он еще не сохранился в базе данных в третьей стороне. Я бы посоветовал вам попробовать запросить заказ по номеру заказа до _site1HttpClient.getShippingLabel, чтобы проверить, существует ли заказ. Чтобы проверить эту проблему, попробуйте Thread.Sleep до _site1HttpClient.getShippingLabel, чтобы сузить круг этой проблемы. Вам также необходимо подтвердить стороннюю поддержку.   -  person Edward    schedule 17.12.2018


Ответы (1)


string token = _site1HttpClient.GetToken(username.ToString(),password);
string orderNumber = await _site1HttpClient.CreateOrder(Order,token);

Я предполагаю, что проблема возникает из-за ключевого слова first await. Когда вы используете await для первого вызова функции (вызов асинхронной функции), вы объявляете, что вашей программе не нужно ждать ответа. Таким образом, переменная token используется во второй функции, когда она не установлена. Как вы можете видеть выше, вы должны обойтись без первого ожидания для переменной токена.

person Hasan    schedule 16.12.2018