简体   繁体   English

如何从C#中的同步调用异步方法?

[英]How to call async method from sync in C#?

I am adding a new web API call to existing functionality. 我正在向现有功能添加新的Web API调用。 I want to make this API call async but looks like it is causing deadlock. 我想使此API调用async但看起来它导致了死锁。 I have to make a lot more changes if I want to make entire code channel async which is not possible. 如果要使整个代码通道async ,则必须进行更多更改。

Questions I have are: 我的问题是:

  1. Is it possible to call async method from regular method? 是否可以从常规方法调用async方法?

  2. What am I missing here? 我在这里想念什么? OR What is the correct approach here? 或这里正确的方法是什么?

Code: 码:

// Exisitng Method
public Tuple<RestaurantDeliveryProvider, DeliveryHubResult, Task<DeliveryManagerQuoteResponse>> CreateDeliveryRequest(OrderContextDTO orderContextDto)
{
    var provider = RestaurantBl.GetDeliveryProviderInformationByRestaurantId(orderContextDto.RestaurantId ?? 0);

    var deliveryHubResult = RestaurantBl.GetDeliveryHubResult(orderContextDto.OrderId ?? 0);;

    // New Call which always comes back with "Not Yet Computed" result
    Task<DeliveryManagerQuoteResponse> deliveryManagerQuoteResponse = _deliveryManager.CreateQuoteRequestAsync(orderContextDto, orderInfo);

    return Tuple.Create(provider, deliveryHubResult, deliveryManagerQuoteResponse);
}

Async Methods: 异步方法:

public async Task<DeliveryManagerQuoteResponse> CreateQuoteRequestAsync(OrderContextDTO orderContextDto, OrderInfoDTO orderInfo)
{
    DeliveryManagerQuoteResponse deliveryManagerQuoteResponse = null;

    try
    {
        var restaurantInfo = RestaurantApi.GetRestaurant(orderInfo.RestaurantId);
        var quoteRequest = new DeliveryManagerQuoteRequest
        {
            DeliveryProvider = null, 
            Country = orderContextDto.DeliveryEstimateRequestDto.RequestedDeliveryAddress.Country,
            Concept = "BK", 
            StoreName = "BK-TEST-US-4", 
            OrderId = orderInfo.OrderId.ToString(),
            AllowCash = false, 
            PaymentType = OrderPaymentType.Prepaid_Credit,
            Note = orderInfo.DeliveryInstructions,
        };

        deliveryManagerQuoteResponse = await Quote(quoteRequest);
    }
    catch (Exception ex)
    {
        Log.ErrorFormat("Get Delivery Manager Quote failed: Error: {0}, OrderId: {1}", ex.Message, orderContextDto.OrderId);
    }

    return deliveryManagerQuoteResponse;
}


public async Task<DeliveryManagerQuoteResponse> Quote(DeliveryManagerQuoteRequest quoteRequest)
{
    DeliveryManagerQuoteResponse deliveryManagerQuoteResponse;

    var client = HttpClientFactory.GetClient();
    var content = HttpClientFactory.JsonContentFactory.CreateJsonContent(quoteRequest);
    var response = await client.PostAsync("https://myUrl", content);

    if (response.IsSuccessStatusCode)
    {
        var data = await response.Content.ReadAsStringAsync();
        deliveryManagerQuoteResponse = JsonConvert.DeserializeObject<DeliveryManagerQuoteResponse>(data);
    }
    else
    {
        throw new Exception((int)response.StatusCode + "-" + response.StatusCode);
    }

    return deliveryManagerQuoteResponse;
}

I tried following as well but same result: 我也尝试了以下方法,但结果相同:

public async Task<DeliveryManagerQuoteResponse> Quote(DeliveryManagerQuoteRequest quoteRequest)
{
    DeliveryManagerQuoteResponse deliveryManagerQuoteResponse;

    using (var client = new HttpClient())
    {
        var content = HttpClientFactory.JsonContentFactory.CreateJsonContent(quoteRequest);
        var response = await client.PostAsync("https://myUrl", content);

        if (response.IsSuccessStatusCode)
        {
            var data = await response.Content.ReadAsStringAsync();
            deliveryManagerQuoteResponse = JsonConvert.DeserializeObject<DeliveryManagerQuoteResponse>(data);
        }
        else
        {
            throw new Exception((int)response.StatusCode + "-" + response.StatusCode);
        }
    }

    return deliveryManagerQuoteResponse;
}

Output (sorry for the blurry output, if you click on it, you will see clear result): 输出(对模糊输出感到抱歉,如果单击它,您将看到清晰的结果):

在此处输入图片说明

  1. don't
  2. don't

Basically, there is no good or workable way to call an async method from a sync method and wait for the answer. 基本上,没有一种好的方法或可行的方法来从同步方法中调用异步方法并等待答案。 There's "sync over async", but that's an anti-pattern and should be aggressively avoided. 存在“异步同步”,但这是一种反模式,应积极避免。

So either: 所以:

  1. rewrite the caller to be async 重写调用方使其async
  2. implement a synchronous version of the API 实现API的同步版本

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM