C# 同时使用HttpClient PostAsJsonAsync扩展名填充字典

C# 同时使用HttpClient PostAsJsonAsync扩展名填充字典,c#,asp.net,dotnet-httpclient,parallel.foreach,C#,Asp.net,Dotnet Httpclient,Parallel.foreach,我有一个.net站点,在其中我试图获得几个web服务调用的结果,以并行方式在几个dropdownlist元素之间共享。我的问题是所有下拉列表最终都具有相同的值,或者有些下拉列表具有相同的值,而另一些下拉列表具有不同的值(可能不是正确的值)。我如何解决这个问题,使这些事情并行 代码更新: 使用(HttpClient hc=new HttpClient()) { hc.BaseAddress=新Uri(目录RI); hc.DefaultRequestHeaders.Accept.Add(新的Syst

我有一个.net站点,在其中我试图获得几个web服务调用的结果,以并行方式在几个dropdownlist元素之间共享。我的问题是所有下拉列表最终都具有相同的值,或者有些下拉列表具有相同的值,而另一些下拉列表具有不同的值(可能不是正确的值)。我如何解决这个问题,使这些事情并行

代码更新:

使用(HttpClient hc=new HttpClient())
{
hc.BaseAddress=新Uri(目录RI);
hc.DefaultRequestHeaders.Accept.Add(新的System.Net.Http.Headers.MediaTypeWithQualityHeaderValue(“应用程序/jsonp”);
//要求提供标准选项
HttpResponseMessage stdResponse=hc.postsjsonasync(CatalogSearchOptionPath,searchmeta).Result;
列表键名={“Key3”、“Key2”、“Key1”};
ConcurrentDictionary customOptions=新建ConcurrentDictionary();
IEnumerable tasks=从关键字输入中选择GetCustomOptionList(关键字、hc、searchmeta);
customOptions=new ConcurrentDictionary(wait Task.WhenAll(tasks));
if(stdResponse.IsSuccessStatusCode)
{
字符串g=stdResponse.Content.ReadAsStringAsync().Result;
stdOptions=Newtonsoft.Json.JsonConvert.DeserializeObject(g);
//选项=response.Content.ReadAsAsync().Result.ToList();
}
}
执行请求的异步方法:

private async Task<KeyValuePair<string, List<string>>> GetCustomOptionList(string key, HttpClient client, SearchMetadata sm)
{
    sm.OptionFieldName = key;
    var response = await client.PostAsJsonAsync(CatalogSpecificOptionPath, sm);
    var result = await response.Content.ReadAsStringAsync();
    return new KeyValuePair<string, List<string>>(key, Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>>(result));
}// end task
专用异步任务GetCustomOptionList(字符串键、HttpClient客户端、SearchMetadata sm)
{
sm.OptionFieldName=密钥;
var response=wait client.postsjsonasync(CatalogSpecificOptionPath,sm);
var result=await response.Content.ReadAsStringAsync();
返回新的KeyValuePair(key,Newtonsoft.Json.JsonConvert.DeserializeObject(result));
}//结束任务

发生这种情况的一个原因是,在循环的外部实例化了一个
HttpClient
。由于循环随后使用
HttpClientExtensions.PostAsJsonAsync
,它接受
hc
变量,然后,
ConcurrentDictionary
中键的重复值可能是在所有循环迭代中从
HttpClient
返回的第一个调用被覆盖的结果。这将取决于
PostAsJsonAsync
的实现,但一种简单的测试方法是在循环中实例化一个新的
HttpClient
,看看是否可以修复它

编辑:小心使用
.Result
,尽管这可能不是问题的原因

“始终异步”意味着您不应该在不仔细考虑后果的情况下混合使用同步和异步代码。特别是,通过调用Task.Wait或Task.Result来阻止异步代码通常是个坏主意。对于那些“埋头于”异步编程的程序员来说,这是一个特别常见的问题,他们只转换应用程序的一小部分,并将其包装在同步API中,以便将应用程序的其余部分与更改隔离开来

最后,如果你在完成这项工作时只得到2X的加速,考虑调整Web.CONFIG标签:


这是我让它工作的方式,因此我的所有下拉列表都有正确的值。感觉好像我做了什么错事,但它是有效的,我在一个最后期限,所以它将不得不做现在。也许以后我能找到更好的解决办法。也许StackOverflow上的某个人会提供更好的解决方案-我们拭目以待

/// Do Stuff in Async method
using (HttpClient hc = new HttpClient())
{
    hc.BaseAddress = CatalogUri;
    hc.DefaultRequestHeaders.Accept.Add(HttpJsonHeader);

    if (Session["StandardSearchOptions"] == null || rebindStandardOptions)
    {
        // request for standard options
        HttpResponseMessage stdResponse = hc.PostAsJsonAsync(CatalogSearchOptionPath,
                                                 searchmeta).Result;

        IEnumerable<Task<KeyValuePair<string, List<string>>>> tasks = 
                               from key in keynames 
                               select GetCustomOptionList(key, hc, searchmeta);

        customOptions = new ConcurrentDictionary<string, List<string>>(await
                                                    Task.WhenAll(tasks));

        if (stdResponse.IsSuccessStatusCode)
        {
            string g = stdResponse.Content.ReadAsStringAsync().Result;
            stdOptions = Newtonsoft.Json
                          .JsonConvert.DeserializeObject<List<SearchOption>>(g);
        }
        Session["StandardSearchOptions"] = stdOptions;
    }
    else // only rebinding the custom options
    {

        IEnumerable<Task<KeyValuePair<string, List<string>>>> tasks = 
                                                  from key in keynames 
                                                  select GetCustomOptionList(key, hc,
                                                                         searchmeta);

        customOptions = new ConcurrentDictionary<string, List<string>>(await 
                                                              Task.WhenAll(tasks));
    }
}
/// Do other stuff in Async Method
///在异步方法中执行操作
使用(HttpClient hc=new HttpClient())
{
hc.BaseAddress=ri;
hc.DefaultRequestHeaders.Accept.Add(HttpJsonHeader);
如果(会话[“StandardSearchOptions”]==null | |重新绑定StandardOptions)
{
//要求提供标准选项
HttpResponseMessage stdResponse=hc.postsjsonasync(CatalogSearchOptionPath,
搜索结果;
IEnumerable任务=
从输入关键字名称开始
选择GetCustomOptionList(键、hc、searchmeta);
customOptions=新建ConcurrentDictionary(等待
任务。当所有(任务));
if(stdResponse.IsSuccessStatusCode)
{
字符串g=stdResponse.Content.ReadAsStringAsync().Result;
stdOptions=Newtonsoft.Json
.JsonConvert.DeserializeObject(g);
}
会话[“StandardSearchOptions”]=标准选项;
}
else//仅重新绑定自定义选项
{
IEnumerable任务=
从输入关键字名称开始
选择GetCustomOptionList(键,hc,
搜索元);
customOptions=新建ConcurrentDictionary(等待
任务。当所有(任务));
}
}
///在异步方法中执行其他操作
用于执行单个自定义搜索的异步方法:

private async Task<KeyValuePair<string, List<string>>> GetCustomOptionList(string key,
                                    HttpClient client, SearchMetadata sm)
{
    sm.OptionFieldName = key;
    var response = await HttpClientExtensions
                      .PostAsJsonAsync(client, CatalogSpecificOptionPath, sm)
                      .Result.Content.ReadAsStringAsync();
    return new KeyValuePair<string, List<string>>(key,
                Newtonsoft.Json.JsonConvert
                            .DeserializeObject<List<string>>(response));
}// end task
专用异步任务GetCustomOptionList(字符串键,
HttpClient客户端,搜索元数据(sm)
{
sm.OptionFieldName=密钥;
var响应=等待HttpClientExtensions
.PostAsJsonAsync(客户端,目录指定选项路径,sm)
.Result.Content.ReadAsStringAsync();
返回新的KeyValuePair(键,
Newtonsoft.Json.JsonConvert
.反序列化对象(响应);
}//结束任务

您是否尝试在
并行中创建
HttpClient(hc)
。ForEach
循环?目前还没有,但这不会破坏使用()的目的吗?Matt,将其也移动到循环中:)您尝试调试代码了吗?你确定结果是错的吗?如果是,在哪种情况下
private async Task<KeyValuePair<string, List<string>>> GetCustomOptionList(string key,
                                    HttpClient client, SearchMetadata sm)
{
    sm.OptionFieldName = key;
    var response = await HttpClientExtensions
                      .PostAsJsonAsync(client, CatalogSpecificOptionPath, sm)
                      .Result.Content.ReadAsStringAsync();
    return new KeyValuePair<string, List<string>>(key,
                Newtonsoft.Json.JsonConvert
                            .DeserializeObject<List<string>>(response));
}// end task