0

Web API アクションを使用する非同期メソッドがあります。ループに陥っているようです。これは、catch ブロックの 1 行目にブレーク ポイントを設定してステップ インすると、実際には 2 行目に到達しないためです。

最初は 100,000 行以上 (~30 mb) のデータセットを返していましたが、リクエストのサイズが原因で遅くなる可能性があると考えていましたが、Web API アクションを変更して 1 行のみを返すように変更した後も、問題は解決しませんでした。Web API ソリューションの URI を参照すると、JSON がブラウザーに返されるため、データは確実に返されます。

public async Task<IEnumerable<Document>> GetAll()
{
    try
    {
        var response = await _client.GetAsync(
                       string.Format("{0}/api/document", _baseURI));

        // never hits line below
        return await response.Content.ReadAsAsync<Document>() 
                   as IEnumerable<Document>;
    }
    catch (Exception ex)
    {
        // handle exception
    }
}

ここで何か不足しているかどうかわかりませんか?いくつかの助けをいただければ幸いです。

編集1

いくつかの質問に答えて、MVC プロジェクトによって参照される Web API プロジェクトがあります。JSON デシリアライゼーションの元の質問からいくつかの変更を加える必要がありました。

リポジトリ:

public async Task<IEnumerable<Document>> GetAll()
{
    try
    {
        string json;
        var response = await _client.GetAsync(string.Format(
                       "{0}/api/document", _baseURI)).ConfigureAwait(false);

        var resource = await response.Content.ReadAsAsync<Document>();

        using(var reader = new StreamReader(resource.ToString()))
        {
            json = reader.ReadToEndAsync().ToString();
        }

        return JsonConvert.DeserializeObjectAsync<Document>(json) 
                       as IEnumerable<Document>;
        }
        catch (Exception)
        {
            throw;
        }
    }

コントローラ:

public async Task<ActionResult>  GetAll()
{
    return PartialView("_GetAllDocumentsPartial", await _docRepo.GetAll());
}

以下の回答で説明されている変更により、上記のデバッグ時に同じ問題が引き続き発生します。しかし、「タスクがキャンセルされました」と表示されます。リポジトリのメソッドの catch で例外が発生しました。

スタックトレース。

4

3 に答える 3

5

GetAll().ResultASP.NET アプリケーションから呼び出していますか? この質問に MVC のタグを付けたので、そう思います。もしそうなら、あなたは自分自身を行き詰まらせています。

このように Web API を呼び出すとします。

public ActionResult Index()
{
    var result = GetAll().Result;

    return View();
}

ここでの問題は、非同期呼び出しが完了したときです。ジャンプした元のスレッドで続行する必要がありますが、呼び出しによってそのスレッドをブロックしていますResult()。Call to Result はブロックされ、非同期呼び出しが返されるまで待機し、非同期継続は ASP.NET スレッドが続行できるようになるまで待機します。それはデッドロックです。

GetAll() を次のように変更します。

public async Task<IEnumerable<Document>> GetAll()
{
    try
    {
        var response = await _client.GetAsync(
                       string.Format("{0}/api/document", _baseURI))
                           .ConfigureAwait(false);

        // never hits line below
        return await response.Content.ReadAsAsync<Document>() 
                   as IEnumerable<Document>;
    }
    catch (Exception ex)
    {
        // handle exception
    }
}

これは、非同期呼び出しが完了したときにコンテキストを保持する必要がないことを示しているため、継続は (ASP.NET ではなく) スレッド プール スレッドで行われます。

アクション メソッドをpublic async Task<ActionResult> Index()and awaitに変更することをお勧めしGetAll()ます。

この回答が役に立ったと思われる場合は、 Stephen Clearyに感謝する必要があります。

于 2013-07-12T16:48:26.460 に答える
1

外部ライブラリで作業していますか? その場合は、ConfigureAwait(false); を追加してみてください。

var response = await _client.GetAsync(string.Format("{0}/api/document", _baseURI))
                            .ConfigureAwait(false);

これは、現在のコンテキストをキャプチャしないように await に指示することと関係があります。ConfigureAwait を呼び出すと、残りのメソッドが ThreadPool を使用して実行されるようになります。この件に関する良い読み物は、Stephen Cleary のブログにあります。

于 2013-07-12T16:48:49.103 に答える