2013-10-15 44 views
0

我有一個.net網站,我試圖得到幾個web服務調用的結果,在幾個dropdownlist元素之間共享,並行方式。我的問題是所有的下拉菜單都有相同的值,或者有一些值與具有不同值的值相同(可能不是正確的值)。我該如何解決這個問題並行獲取這些東西?同時填寫字典與HttpClient PostAsJsonAsync擴展

代碼更新時間:

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 
+0

您是否嘗試過創建''中環Parallel.ForEach' HttpClient的'(HC)? –

+0

不是現在,但不會打敗使用()的目的? – Matt

+0

馬特,移動它也進入循環:) –

回答

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 
1

原因之一,這可能發生的是,有一個HttpClient的實例化的事實在循環之外。由於循環使用了HttpClientExtensions.PostAsJsonAsync,其中包含hc變量,因此ConcurrentDictionary中密鑰的重複值可能是response被覆蓋的結果,因爲在所有循環迭代中第一次調用HttpClient返回。這將取決於PostAsJsonAsync的實現,但是一個簡單的測試方法是在循環中實例化一個新的HttpClient並查看是否修復了它。

編輯:當心使用.Result,雖然它可能不是你的問題的原因。

「一路異步」意味着您不應混淆同步代碼和異步代碼,而不會仔細考慮後果。特別是,通過調用Task.Wait或Task.Result阻止異步代碼通常是一個壞主意。對於那些正在將腳趾頭浸入異步編程的程序員來說,這是一個特別常見的問題,它只轉換一小部分應用程序並將其封裝在同步API中,這樣應用程序的其餘部分就與變化隔離開來。

source

最後,如果你最終實現,只有當這一切工作了2倍的加速,可以考慮調整這個web.config文件標籤:

Sytem.NET MaxConnection property

+0

在'Parallel.ForEach()'裏面使用'await'是個壞主意,並且不能按預期工作。使用'SomethingAsync()。Result'往往是一個不錯的選擇,但我認爲這是合理的,因爲沒有同步版本的方法(我認爲)。無論如何,我看不出如何解決這個問題。 – svick

+0

關於在Parallel.ForEach()中等待的好處,我想我沒有仔細閱讀這個問題。 '.Result'的使用只是錯誤的一個常見原因,所以我認爲它可能是這樣的。 – welegan

+0

你現在可能是對的。 'HttpClient'不是線程安全的,所以像這樣從多個線程使用它肯定是錯誤的。 – svick