2016-11-21 10 views
0

UWP(フロントエンド)とREST-MVC-IIS(バックエンド)で開発されたプロジェクトに取り組んでいます。UWP + IIS +非同期動作

私は結果として起きる可能性が理論的なシナリオを考えていた:

私が知っているから、リクエストが処理され、IISによって提供される順序を保証する方法はありません。

だから、単純なシナリオでは、ちょうどこの仮定しよう:

UI:

SelectionChanged(商品コード= 1)。

SelectionChanged(productId = 2);

private async void SelectionChanged(int productId) 
{ 
    await GetProductDataAsync(productId); 
} 

IIS:あなたが見ることができるように

GetProductDataAsync(productId=1) scheduled on thread pool 

GetProductDataAsync(productId=2) scheduled on thread pool 

GetProductDataAsync(productId=2) finishes first => send response to client 

GetProductDataAsync(productId=1) finishes later => send response to client 

、何らかの理由productId=2の要求はproductId=1の最初の要求、その後速く終えました。

非同期で動作するため、両方の呼び出しでUIに2つの継続タスクが作成され、同じデータが含まれているため正しい順序で表示されない場合は、互いにオーバーライドされます。

ほとんどのマスター/ディテールのシナリオでは、マスターアイテムを選択して間違った情報を取得することがあります(IISからの応答が返されるため)。

私が知りたいのは、この種のシナリオを処理するベストプラクティスがある場合です。解決策がたくさん気になりますが、私が試してみる前に、銃を飛ばして1つの実装に行きたくありません。表にある他のオプションを確認してください。

+1

2つのUIを使用すると、表示さ呼び出します。彼らは文字通り他のコードに続いて2行のコードですか?その場合、2行目は最初の行が完了するまで実行されず、IISへの往復はすべて完了します。 – sellotape

+0

さて、2つの連続した呼び出しで使用されている非同期が欠落していました。非同期は、順次処理されずに並行処理されるため、すべてが変更されます。最初の呼び出しが最初に処理されることを意味します。つまり、2番目の要求が最初に終了した場合(何らかの理由で)、最初に呼び出された呼び出しが最初に処理されるため、上記の状況では、後の呼び出しが以前の呼び出しの結果をオーバーライドします。 –

+1

2つのUI行が連続していれば、並列では処理されません_。次の行に進む前に、呼び出しが終了するまで待ちます。実行は呼び出し元のメソッドではうまくいくかもしれませんが、待機しているタスクが完了するまで現在のメソッドでは処理を続行しません。 – sellotape

答えて

0

await GetProductDataAsync(productId=2);は、await GetProductDataAsync(productId=1);が完了した後に常に実行されます。したがって、競合状態はありません。

あなたのコードであった場合:

await Task.WhenAll(
    GetProductDataAsync(productId=1), 
    GetProductDataAsync(productId=2)) 

そして、競合状態があるかもしれません。それが問題であれば、async-awaitではなく、同時呼び出しを行っていることが原因です。

あなたが別の方法でそのコードをラップし、ConfigureAwait()を使用する場合は、UIスレッド上の唯一の続きがあります:

Task GetProductDataAsync() 
{ 
    await Task.WhenAll(
     GetProductDataAsync(productId=1).ConfigureAwait(), 
     GetProductDataAsync(productId=2).ConfigureAwait() 
    ).ConfigureAwait(); 
} 
+0

元の投稿を編集しましたが、状況をよく説明しました。それは競争条件ではなく、コールバックが処理された後にiisから戻って来るという魔女の命令です。 –

0

を私は私はあなたが言っているものを手に入れると思います。非同期voidイベントハンドラのため、UIの何も第2の呼び出しの前に最初の呼び出しを待っていません。私は値のドロップダウンを想像しています、そして、それが変化するとき、それは適切なデータをフェッチします。

理想的には、通話中にUIをロックアウトするか、cancellationtokenを実装することをお勧めします。

あなたは単に通話を測定する方法を探しているなら、読んでください...

私は、Webサービスまたはローカルにキャッシュされたコピーからデータをフェッチするかどうかを処理するUWPアプリケーションのシングルトンリポジトリレイヤを使用します。さらに、一度に1つを処理する要求を計測する場合は、SemaphoreSlimを使用します。これはロックのように機能しますが、非同期操作(単純化された直観)で動作します。ここで

は、それがどのように機能するかを説明しなければならない例です...

public class ProductRepository : IProductRepository 
{ 
    //initializing (1,1) will allow only 1 use of the object 
    static SemaphoreSlim semaphoreLock = new SemaphoreSlim(1, 1); 
    public async Task<IProductData> GetProductDataByIdAsync(int productId) 
    { 
     try 
     { 
      //if semaphore is in use, subsequent requests will wait here 
      await semaphoreLock.WaitAsync(); 
      try 
      { 
       using (var client = new HttpClient()) 
       { 
        client.BaseAddress = new Uri("yourbaseurl"); 
        client.DefaultRequestHeaders.Accept.Clear(); 
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 
        string url = "yourendpoint"; 
        HttpResponseMessage response = await client.GetAsync(url); 
        if (response.IsSuccessStatusCode) 
        { 
         var json = await response.Content.ReadAsStringAsync(); 
         ProductData prodData = JsonConvert.DeserializeObject<ProductData>(json); 
         return prodData; 
        } 
        else 
        { 
         //handle non-success 
        } 
       } 
      } 
      catch (Exception e) 
      { 
       //handle exception 
      } 
     } 
     finally 
     { 
      //if any requests queued up, the next one will fire here 
      semaphoreLock.Release(); 
     } 
    } 
} 
+0

ありがとう、あなたは問題を理解した唯一の人でした:)ちょうどこれにあなたに信用を与えたい! –

関連する問題