C#Async / Await呼叫无法正常工作

时间:2018-01-12 19:19:22

标签: c# .net asynchronous async-await

我试图从同步方法调用异步方法,并且它一直在轰炸GetUsTraceApiHealth(),但没有错误。有什么问题?

通话方式:

public ActionResult TestSSN()
{
    try
    {
        var apiResponse = GetUsTraceApiHealth().GetAwaiter().GetResult();
        string responseBody = apiResponse.Content.ReadAsStringAsync().Result;
        return Json(responseBody, JsonRequestBehavior.AllowGet);
    }
    catch (Exception e)
    {                    
        throw new Exception(e.Message);
    }
}

正在调用的方法:

public async Task<HttpResponseMessage> GetUsTraceApiHealth()
{
    using (HttpClient httpClient = new HttpClient())
    {
        try
        {
            string uri = $"https://trace.{ConfigHelper.SterlingDomain}health?deep";

            HttpResponseMessage apiResponse = await httpClient.GetAsync(uri);
            return apiResponse;
        }
        catch (Exception e)
        {
            throw new Exception(e.Message);
        }
    }
}

3 个答案:

答案 0 :(得分:5)

按照&#34; async的async mantra一直向下&#34;。基本上,您应该几乎从不在任务上调用.Result。在大多数情况下,您的调用方法也应该是异步的。然后你可以简单地等待操作的结果:

public async Task<ActionResult> TestSSN()
{
    //...
    var apiResponse = await GetUsTraceApiHealth();
    string responseBody = await apiResponse.Content.ReadAsStringAsync();
    //...
}

应该由顶层的应用程序主机(在本例中为ASP.NET和Web服务器)来处理同步上下文。您不应该尝试将异步操作屏蔽为同步操作。

答案 1 :(得分:3)

您的代码的简化版本:

public async Task<ActionResult> TestSSN()
{
    var apiResponse = await GetUsTraceApiHealthAsync();
    return Json(apiResponse, JsonRequestBehavior.AllowGet);
}

public async Task<string> GetUsTraceApiHealthAsync()
{
    using (HttpClient httpClient = new HttpClient())
    {
        string uri = $"https://trace.{ConfigHelper.SterlingDomain}health?deep";

        return apiResponse = await httpClient.GetStringAsync(uri);
    }
}

我没有理由退回HttpResponseMessagestring的形式阅读其内容,只需使用GetStringAsync
此外,永远不要catch例外来重新抛出它。如果您需要这样做,请使用:

catch(Exception ex)
{
    //log or whatever
    throw;
}

答案 2 :(得分:0)

您不应该将asyncsync操作混合在一起。正确执行此操作的方法是将您的方法修改为async并简单地使用await;

public async Task<ActionResult> TestSSN()
{
    try
    {
        var apiResponse = await GetUsTraceApiHealth().GetAwaiter().GetResult();
        string responseBody = await apiResponse.Content.ReadAsStringAsync().Result;
        return Json(responseBody, JsonRequestBehavior.AllowGet);
    }
    catch (Exception e)
    {                    
        throw new Exception(e.Message);
    }
}

如果您无法在所有路径中应用async,则可以使用ConfigureAwait来防止死锁。

public async Task<HttpResponseMessage> GetUsTraceApiHealth()
{
    using (HttpClient httpClient = new HttpClient())
    {
        try
        {
            string uri = $"https://trace.{ConfigHelper.SterlingDomain}health?deep";

            HttpResponseMessage apiResponse = await httpClient.GetAsync(uri).ConfigureAwait(false);
            return apiResponse;
        }
        catch (Exception e)
        {
            throw new Exception(e.Message);
        }
    }
}