3

System.Web.Http.IActionFilter現在、現在のリクエストを続行できるかどうかを判断するために内部サービスを呼び出す を実装しています。私が抱えている問題は、Task<T1>によってカプセル化されたロジックに基づいて を返すことですTask<T2>

例が役立つ場合があります。

内部サービス API は、タスクを使用して実装されます。ロジックは、.NET 4.5の async/await を使用すると簡単です。

public async Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
    UserAuthenticationResult authResult = await HitInternalServiceAsync();

    if (!authResult.IsAuthenticated)
    {
        throw new HttpResponseException("User is not authenticated", HttpStatusCode.Unauthorized);
    }

    return await continuation();
}

ただし、 .NET 4.0の古い Task API ではより困難です。

public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
    return HitInternalServiceAsync()
            .ContinueWith(t1 => {
                UserAuthenticationResult authResult = t1.Result;

                if (!authResult.IsAuthenticated)
                {
                    throw new HttpResponseException("User is not authenticated", HttpStatusCode.Unauthorized);
                }

                //Hack hack - this blocks the thread until the task retuned by continuation() completes
                return continuation().Result;
            });
}

難しいのは、認証チェックが成功したときです。その後、継続関数によって返されるタスクを待ちたいと思います。

continuation().NET 4.0 を使用すると、タスクの完了時に Tasks API にタスクを自動的に続行するように指示するのではなく、タスクの完了を待つときに明示的にブロックしたように見えcontinuation()ます。

質問: これが .NET 4.0 でこの動作を実装する唯一の方法ですか?

十分に複雑な内部サービス API を考えると、他のタスクを待機しているタスクの数が急速に増加していることを簡単に確認できます。

編集: HttpContext.Current のような ASP.NET スレッド コンテキスト サービスで継続ラムダが実行されないため、上記の4.0コードも実行可能ではないようです。より良い実装は...

public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
    Task<UserAuthenticationResult> authResultTask = HitInternalServiceAsync();

    var authResult = authResultTask.Result;

    if (!authResult.IsAuthenticated)
    {
        throw new HttpResponseException("User is not authenticated", HttpStatusCode.Unauthorized);
    }

    return continuation();
}
4

3 に答える 3

5

あなたの問題は、あなたが使用しない場合Result、あなたが必要とするものではなく、ContinueWith()戻ってくるということです。Task<Task<HttpResponseMessage>>Task<HttpResponseMessage>

Task<Task<T>>幸いなことに、anyをTask<T>:に変換するメソッドはすでにありますUnwrap()。したがってreturn continuation();、ラムダからだけで、結果ContinueWith()を呼び出します。Unwrap()

継続をASP.NETコンテキストで実行する場合は、を使用できますTaskScheduler.FromCurrentSynchronizationContext()

于 2012-05-03T11:09:22.070 に答える
3

質問: これが .NET 4.0 でこの動作を実装する唯一の方法ですか?

async/awaitは C# 5.0 の機能であり、.NET 4.5 の機能ではありません。.NET 4.5 で導入されたいくつかの型を使用しますが、新しいランタイムが必要になる他の理由はありません。

VS2010 (C# 4.0) を使用している場合は、svick の回答が最適です。

ただし、VS11 Beta (C# 5.0) を使用している場合は、別のオプションがあります。非同期ターゲティング パックを使用して、.NET 4.0 で実行されるコードを記述できasyncます。awaitターゲット パックには、.NET 4.0 用のこれらの新しい型があります。

于 2012-05-03T12:59:07.213 に答える
1

continuation().Result の代わりに continuation().Wait() を使用します

task.wait は、タスクをブロックする適切な方法です。

MSDN のドキュメントによると、Task.Wait メソッド: タスクの実行が完了するまで待機します。

http://msdn.microsoft.com/en-us/library/dd235635.aspx

以下は、関連する質問のようです。その答え は、新しい C# 5.0 の「async」および「await」キーワードは複数のコアを使用しますか?

于 2012-05-03T03:20:04.440 に答える