5

私は async / await に1週間苦労しています。背景: 以下のコードは、MVC4 ウェブサイト プロジェクトの一部です。Web サイトで多数の API 呼び出しが発生しています。目標は、これらの API 呼び出しを同期ではなく並行して実行して、サイトの応答性を向上させることです。現在、すべての API 呼び出しが相互にブロックされています。したがって、1 つのページで 4 つの呼び出しが必要な場合は、読み込み時間が長くなります。

すべての API 呼び出しの同期バージョンと非同期バージョンの両方に個別のメソッドを作成しました。私が抱えている問題は、待機が応答しないことです。この質問に関連していると思います。しかし、私はそれを解決する方法が本当にわかりません。ConfigureAwait(false) を試しましたが、役に立ちませんでした。

コードは次のとおりです。

コントローラーでの最初の呼び出しは次のようになります。

BaseData bdata = API.GetBaseData().Result;

ここで await を使用したいのですが、リクエスト/レスポンス アクセスが必要なため使用できない AsyncController がなければ、それはオプションではありません。その他のメソッドは API クラスにあります。

internal static async Task<BaseData> GetBaseData() {
    var catTask = GetParentCategoriesAsync();
    var yearTask = GetYearsAsync();

    await Task.WhenAll(new Task[] { catTask, yearTask });

    var bdata = new BaseData {
        years = await yearTask,
        cats = await catTask
    };
    return bdata;
}

internal static async Task<List<APICategory>> GetParentCategoriesAsync() {
    try {
        WebClient wc = new WebClient();
        wc.Proxy = null;

        string url = getAPIPath();
        url += "GetFullParentCategories";
        url += "?dataType=JSON";

        Uri targeturi = new Uri(url);
        List<APICategory> cats = new List<APICategory>();

        var cat_json = await wc.DownloadStringTaskAsync(targeturi);
        cats = JsonConvert.DeserializeObject<List<APICategory>>(cat_json);

        return cats;
    } catch (Exception) {
        return new List<APICategory>();
    }
}

internal static async Task<List<double>> GetYearsAsync() {
    WebClient wc = new WebClient();
    wc.Proxy = null;
    Uri targeturi = new Uri(getAPIPath() + "getyear?dataType=JSON");
    var year_json = await wc.DownloadStringTaskAsync(targeturi);
    List<double> years = JsonConvert.DeserializeObject<List<double>>(year_json);
    return years;
}

これらのメソッドが呼び出されると、GetYearsAsync() と GetParentCategoriesAsync() にブレークポイントを設定できます。await wc.DownloadStringTaskAsync(targeturi) コマンドまですべてが起動します。そこで止まります。

すべてのタスクに ConfigureAwait(continueOnCapturedContext: false) を追加しましたが、役に立ちませんでした。問題は、スレッドが同じコンテキストにないことだと思います。しかし、確かではありません。しかし、私は何か間違ったことをしていると確信しています。よくわかりません。それか、.NET MVC4 ではできないことをしようとしているだけです。どんな考えでも非常に高く評価されます。

4

2 に答える 2

2

この問題は、実際には が原因でWebClientあり、これは常に要求コンテキスト (Result呼び出しのためにブロックされている) に同期されます。

HttpClient代わりに、次と組み合わせて使用​​できますConfigureAwait(false)

internal static async Task<BaseData> GetBaseDataAsync() {
  var catTask = GetParentCategoriesAsync();
  var yearTask = GetYearsAsync();

  await Task.WhenAll(catTask, yearTask).ConfigureAwait(false);

  var bdata = new BaseData {
    years = await yearTask,
    cats = await catTask
  };
  return bdata;
}

internal static async Task<List<APICategory>> GetParentCategoriesAsync() {
  try {
    var client = new HttpClient();

    string url = getAPIPath();
    url += "GetFullParentCategories";
    url += "?dataType=JSON";

    Uri targeturi = new Uri(url);
    List<APICategory> cats = new List<APICategory>();

    var cat_json = await client.GetStringAsync(targeturi).ConfigureAwait(false);
    cats = JsonConvert.DeserializeObject<List<APICategory>>(cat_json);

    return cats;
  } catch (Exception) {
    return new List<APICategory>();
  }
}

internal static async Task<List<double>> GetYearsAsync() {
  var client = new HttpClient();
  Uri targeturi = new Uri(getAPIPath() + "getyear?dataType=JSON");
  var year_json = await client.GetStringAsync(targeturi).ConfigureAwait(false);
  List<double> years = JsonConvert.DeserializeObject<List<double>>(year_json);
  return years;
}

これにより、次のように呼び出すことができます。

BaseData bdata = API.GetBaseDataAsync().Result;

ただし、次のように呼び出すことを強くお勧めします。

BaseData bdata = await API.GetBaseDataAsync();

の前後のコードでawait、リクエストとレスポンスのコンテキストに問題なくアクセスできることがわかります。

于 2013-08-02T12:26:25.397 に答える