使用HttpClient进行http调用的异步方法永远不会回来

时间:2017-04-20 20:15:00

标签: c# multithreading async-await

我在域名服务中有以下代码:

HttpClient client = new HttpClient();
client.GetAsync("http://somewebsite.com").Result;

哪个工作正常,我可以在跟随的线上设置一个断点,它们确实击中了,一切都很好。但是,我在同一个项目中安装的nuget包中有相同的代码行。那里有完全相同的http电话:

public class Client : Base
{
    public Task<List<Stuff>> GetAsync()
    {
        return SendMessageAsync(HttpMethod.Get, "http://getstuff.com")
            .ContinueWith(x => JsonConvert.DeserializeObject<List<StuffView>>(x.Result.Content.ReasAsStringAsync().Result);
    }
}
public class Base
{
    HttpClient client:

    public Base(HttpClient client)
    {
        this.client = client:
    }
    protected async Task<HttpResponseMessage> GetMessageAsync(BttpMethod method, string url)
    {
        var request = CreateRequestAsync(method, url);
        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        var response = await client.SendAsync(request); //line 1
        return response; // Line 2
    }
    protected HttpRequestMessage CreateRequestAsync(HttpMethod method, string url) 
    {
        var request = new HttpRequestMessage(method, url);
        request.SetBearerToken(myAccessTokenProvider);
        return request;
    }
}

这是我的域名服务使用nuget包代码的方式:

var client = factory.Create();
client.GetAsync().Result;

调试此代码显示内部基类行1被命中,但第2行永远不会。在互联网上搜索似乎是一个线程死锁问题。所以我的问题是,假设它是一个死锁,为什么域服务中的第一个http调用工作,但不是第二个使用nuget包代码?#/ p>

HttpClient死锁问题: HttpClient.GetAsync(...) never returns when using await/async

2 个答案:

答案 0 :(得分:2)

第一个示例有效,因为任务在您调用.Completed == true之前处于.Result状态,或者该行代码具有SyncronisationContext.Current == null

如果任务未处于已完成状态,则在您调用.Result或{.Wait()时,如果SyncronisationContext.Current != null调用.Result.Wait(),则可能会导致死锁{1}}。最好的办法是将整个调用堆栈标记为async并开始返回Task而不是voidTask<T>,然后返回T,然后调用{{} 1}}在您使用await.Result的所有地方。

如果您不愿意更改这些代码,则必须切换到使用非异步方法,这将要求从.Wait()切换到HttpClient并使用非异步方法调用来执行您的请求。

答案 1 :(得分:1)

请勿使用.Result。使用.Result,I / O启动(异步),调用线程(同步)阻止等待它完成。

只需使用await

var stuff = await client.GetAsync();