C# .NET HttpClient在使用wait关键字时挂起?

C# .NET HttpClient在使用wait关键字时挂起?,c#,asynchronous,asp.net-mvc-5,async-await,task-parallel-library,C#,Asynchronous,Asp.net Mvc 5,Async Await,Task Parallel Library,在考虑了这个有趣的答案之后,我仍然有一种情况,即当我使用wait(下面的示例代码)时,我的HttpClient没有返回。此外我从asp.net MVC5控制器(UI驱动)和WebApi中使用此帮助程序例程。我能做些什么来: 使用wait而不是(可怕的)。结果是否仍然有此函数返回 从MVC控制器和WebApi重用相同的例程 显然,我应该将.Result替换为.ConfigureAwait(false),但这似乎与上面引用的文章中的“Task4”与await httpClient.GetAsync配

在考虑了这个有趣的答案之后,我仍然有一种情况,即当我使用wait(下面的示例代码)时,我的HttpClient没有返回。此外我从asp.net MVC5控制器(UI驱动)和WebApi中使用此帮助程序例程。我能做些什么来:

  • 使用wait而不是(可怕的)。结果是否仍然有此函数返回
  • 从MVC控制器和WebApi重用相同的例程 显然,我应该将.Result替换为.ConfigureAwait(false),但这似乎与上面引用的文章中的“Task4”与await httpClient.GetAsync配合使用的情况相矛盾。或者对于控制器和WebApi案例,我需要单独的例程吗

    public static async Task<IEnumerable<TcMarketUserFullV1>> TcSearchMultiUsersAsync(string elasticQuery)
    {
        if (string.IsNullOrEmpty(elasticQuery)) return null;
    
        IEnumerable<TcMarketUserFullV1> res = null;
        using (var hclient = new HttpClient())
        {
            hclient.BaseAddress = new Uri("https://addr.servicex.com");
            hclient.DefaultRequestHeaders.Accept.Clear();
            hclient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    
            hclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",
                CloudConfigurationManager.GetSetting("jwt-bearer-token"));
    
            // Why does this never return when await is used?
            HttpResponseMessage response =  hclient.GetAsync("api/v2/users?q=" + elasticQuery + "&search_engine=v2").Result; 
            if (response.IsSuccessStatusCode)
            {
                var content = await response.Content.ReadAsStringAsync();
                res = JsonConvert.DeserializeObject<TcMarketUserFullV1[]>(content).AsEnumerable();
            }
            else{log.Warn("...");}
        } 
        return res;
    } 
    
    公共静态异步任务TcSearchMultiUsersAsync(字符串elasticQuery)
    {
    if(string.IsNullOrEmpty(elasticQuery))返回null;
    IEnumerable res=null;
    使用(var hclient=new HttpClient())
    {
    hclient.BaseAddress=新Uri(“https://addr.servicex.com");
    hclient.DefaultRequestHeaders.Accept.Clear();
    hclient.DefaultRequestHeaders.Accept.Add(新的MediaTypeWithQualityHeaderValue(“应用程序/json”);
    hclient.DefaultRequestHeaders.Authorization=新的AuthenticationHeaderValue(“承载人”,
    GetSetting(“jwt承载令牌”);
    //为什么在使用wait时,此选项永远不会返回?
    HttpResponseMessage response=hclient.GetAsync(“api/v2/users?q=“+elasticQuery+”&search_engine=v2”)。结果;
    if(响应。IsSuccessStatusCode)
    {
    var content=await response.content.ReadAsStringAsync();
    res=JsonConvert.DeserializeObject(content.AsEnumerable();
    }
    else{log.Warn(“…”);}
    } 
    返回res;
    } 
    
    更新:我的呼叫链,以Telerik Kendo Mvc开头。网格数据绑定呼叫如下:

    [HttpPost]
    public async Task<ActionResult> TopLicenseGrid_Read([DataSourceRequest]DataSourceRequest request)
    {
        var res = await GetLicenseInfo();
        return Json(res.ToDataSourceResult(request)); // Kendo.Mvc.Extensions.DataSourceRequest
    }
    
    [HttpPost]
    公共异步任务TopLicenseGrid_读取([DataSourceRequest]DataSourceRequest请求)
    {
    var res=等待GetLicenseInfo();
    返回Json(res.ToDataSourceResult(request));//Kendo.Mvc.Extensions.DataSourceRequest
    }
    
    然后:

    private异步任务GetLicenseInfo()
    {
    ...
    //永不回头
    var qry=@“app_metadata.tc_app_user.country:“DE”;
    返回等待TcSearchMultiUsersAsync(qry);
    }
    
    然后,上面完整显示的例程,但现在没有。结果:

    public static async Task<IEnumerable<TcMarketUserFullV1>> TcSearchMultiUsersAsync(string elasticQuery)
    {
        if (string.IsNullOrEmpty(elasticQuery)) return null;
    
        IEnumerable<TcMarketUserFullV1> res = null;
        using (var hclient = new HttpClient())
        {
            hclient.BaseAddress = new Uri("https://addr.servicex.com");
            hclient.DefaultRequestHeaders.Accept.Clear();
            hclient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    
            hclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",
                CloudConfigurationManager.GetSetting("jwt-bearer-token"));
    
            // This now returns fine
            HttpResponseMessage response =  hclient.GetAsync("api/v2/users?search_engine=v2&q=" + elasticQuery"); 
            if (response.IsSuccessStatusCode)
            {
                // This returns my results fine too
                var content = await response.Content.ReadAsStringAsync();
                // The following line never returns results. When debugging, everything flows perfectly until I reach the following line, which never 
                // returns and the debugger returns me immediately to the top level HttpPost with a result of null. 
                res = JsonConvert.DeserializeObject<TcMarketUserFullV1[]>(content).AsEnumerable();
            }
            else{log.Warn("...");}
        } 
        return res;
    } 
    
    公共静态异步任务TcSearchMultiUsersAsync(字符串elasticQuery)
    {
    if(string.IsNullOrEmpty(elasticQuery))返回null;
    IEnumerable res=空;
    使用(var hclient=new HttpClient())
    {
    hclient.BaseAddress=新Uri(“https://addr.servicex.com");
    hclient.DefaultRequestHeaders.Accept.Clear();
    hclient.DefaultRequestHeaders.Accept.Add(新的MediaTypeWithQualityHeaderValue(“应用程序/json”);
    hclient.DefaultRequestHeaders.Authorization=新的AuthenticationHeaderValue(“承载人”,
    GetSetting(“jwt承载令牌”);
    //现在恢复正常了
    HttpResponseMessage response=hclient.GetAsync(“api/v2/users?search_engine=v2&q=“+elasticQuery”);
    if(响应。IsSuccessStatusCode)
    {
    //这也很好地返回了我的结果
    var content=await response.content.ReadAsStringAsync();
    //下一行永远不会返回结果。调试时,一切都会完美地进行,直到我到达下一行,这一行永远不会返回结果
    //返回,调试器立即将我返回到顶层HttpPost,结果为null。
    res=JsonConvert.DeserializeObject(content.AsEnumerable();
    }
    else{log.Warn(“…”);}
    } 
    返回res;
    } 
    
    你需要
    等待
    一切。你对其中一个
    等待
    是不够的,你需要对所有这些
    等待

    这:

    应该是:

    HttpResponseMessage response = await hclient.GetAsync(
                                    "api/v2/users?q=" + elasticQuery + "&search_engine=v2");
    

    .Result
    进行一次阻塞调用就足够了,这样就可以死锁。您需要。

    您需要等待
    一切。仅对其中一个进行
    等待
    是不够的,您需要对所有这些进行
    等待

    这:

    应该是:

    HttpResponseMessage response = await hclient.GetAsync(
                                    "api/v2/users?q=" + elasticQuery + "&search_engine=v2");
    

    只要对
    .Result
    进行一次阻塞调用就足够了。您需要。

    谢谢。但这正是我面临的问题,而不是答案。您知道,当我删除.Result和use wait时,它会挂起线程,当我使用.Result时,我至少会从httpClient调用中获得结果。@GGleGrand这听起来特别iar.显示
    TcSearchMultiUsersAsync的整个调用链顶级操作仍然是ActionResult TopGrid\u Read。更改为公共异步任务TopGrid\u Read似乎已解决。谢谢!我说得太早了。它曾经起作用似乎是侥幸的。我将尝试在原始问题中添加我的调用流和观察结果。可能只是一个计时的东西——即运气=定时炸弹——我们会看到……测试继续。谢谢。但这正是我的问题,而不是答案。你看,当我删除.Result并使用wait时,它挂起线程,当我使用.Result时,我至少会从httpClient调用中得到结果。@GGleGrand这听起来很奇怪。显示整个调用链对于
    TcSearchMultiUsersAsync
    来说,顶级操作仍然是ActionResult TopGrid\u Read。更改为公共异步任务TopGrid\u Read似乎已解决。谢谢!我说得太早了。它曾经起作用似乎是一种侥幸。我将尝试在原始问题中添加我的调用流和观察结果。可能只是时间问题——即运气=定时炸弹--我们将看到…测试继续。您在
    hclient.SendAsync
    中缺少了一个
    wait
    。我知道。这是因为当我将wait放在那里时它会“挂起”。请注意代码行上方的注释。它向我提供返回数据的唯一方法是当我使用(可怕的)时.结果。这就是我不明白的……您缺少一个
    waitHttpResponseMessage response = await hclient.GetAsync(
                                    "api/v2/users?q=" + elasticQuery + "&search_engine=v2");