web-dev-qa-db-ja.com

非同期でMVC4コントローラーで待機

新しいAsyncおよびAwait演算子を使用してデータベースからオブジェクトのコレクションを返そうとするたびに、Invalid Operation例外が発生します。単一のアイテムのみを返すために使用すると、正常に機能します。

コントローラーコード:

public async Task<ActionResult> EnvironmentList()
{
    EfEnvironmentDataAccess dataAccess = new EfEnvironmentDataAccess();
    ICollection<Environment> environments = await dataAccess.GetAllEnvironmentsAsync();
    return PartialView(environments);
}

コードを表示:

<div class="ECURightCol">
<h3>Table Dumps</h3>
@Html.Action("EnvironmentList", "Environment")
@Html.Action("ComputerList", "Computer")
@Html.Action("ProductList", "Product")
@Html.Action("InstanceList", "Instance")
@Html.Action("ProfileList", "Profile")

データアクセスコード:

public ICollection<Environment> GetAllEnvironments()
{
    using (EcuWebDataContext db = new EcuWebDataContext())
    {
        return db.Environments.OrderBy(e => e.Name).ToList();
    }
}

public async Task<ICollection<Environment>> GetAllEnvironmentsAsync()
{
    return await Task.Run(() => GetAllEnvironments());
}

私が得るエラーは次のとおりです。

説明:現在のWebリクエストの実行中に未処理の例外が発生しました。エラーの詳細とコードの発生場所については、スタックトレースを確認してください。

例外の詳細:System.InvalidOperationException:HttpServerUtility.Executeは、非同期操作が完了するのを待っている間にブロックされました。

17
twreid

まず第一に、 子アクションで非同期処理を使用することはできません そして私はこれがあなたがやろうとしていることだと思います。

次に、別のスレッドを起動して次のコード行でコードを実行することにより、ここでは非同期処理を実行していません。

Task.Run(() => GetAllEnvironments());

1日の終わりにスレッドをブロックし、コンテキストスイッチのオーバーヘッドしかありません。 EF6は非同期処理をサポートします。純粋なADO.NETを使用した非同期クエリについては、以下を参照してください。

ASP.NET MVC 4のタスクベースの非同期プログラミングモデル(TAP)を使用した非同期データベース呼び出し

30
tugberk

これが回答されてからしばらく経ちましたが、別の方法は次のとおりです。

アクションからメソッドを呼び出す

@Html.Action("YourSyncMethod", "YourController")

通常の同期アクションとして定義します

public ActionResult YourSyncMethod()

次に、その中で非同期メソッドを呼び出します

var taskResponse = YourAsyncMethod(); 

必要なものが何でも含まれるモデルが返されます

private async Task<YourModel> YourAsyncMethod()

構成オプションを改ざんしたり、より複雑なコードを作成したりするよりも簡単なようです

0
JMVivas