0

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

代码更新:

using (HttpClient hc = new HttpClient())
{
    hc.BaseAddress = new Uri(CatalogUri);
    hc.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/jsonp"));
    // request for standard options
    HttpResponseMessage stdResponse = hc.PostAsJsonAsync(CatalogSearchOptionPath, searchmeta).Result;
    List<string> keynames = {"Key3", "Key2","Key1"};
    ConcurrentDictionary<string, List<string>> customOptions = new ConcurrentDictionary<string, List<string>>();

    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);
        //options = response.Content.ReadAsAsync<SearchOption[]>().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
4

2 回答 2

1

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

编辑:当心使用.Result,尽管它可能不是您的问题的原因。

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

资源

最后,如果在一切正常的情况下你最终只实现了 2 倍的加速,请考虑调整这个 web.config 标签:

System.NET MaxConnection 属性

于 2013-10-15T21:37:12.467 回答
0

这就是我让它工作的方式,所以我所有的下拉菜单都有正确的值。感觉就像我做错了什么,但它有效,而且我在截止日期前,所以现在必须这样做。也许以后我能得到更好的解决方案。也许 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

用于执行单个自定义搜索的异步方法:

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
于 2013-10-17T14:10:18.783 回答