0

私が構築している MVC アプリケーションには、ViewData からロードされた ViewModel を使用するページの一部 (部分的に実装) があります。すべてのコントローラーが継承する抽象コントローラーを作成しました (使用している IoC システムでは、ベース コントローラーが最適なオプションになります)。現時点では、OnActionExecuting オーバーライドでデータを設定しています。

protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
    ViewData["OperationStatusVM"] = OperationsStatusBuilder.Get(Operations);
    base.OnActionExecuting(filterContext);
}

問題は、OperationsStatusBuilder メソッドの実行時間がかなり長いことです。残りのリクエストをブロックせずに ViewModel にデータを入力する方法をまとめようとしています。

私が最初に考えたのは、OnActionExecuting の Task を介して操作を開始し、OnActionExecuted で実際の値を設定することです。

protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
    filterContext.RequestContext.HttpContext.Items["OperationTask"]
        = Task<OperationsStatusVM>.Factory.StartNew(() => OperationsStatusBuilder.Get(Operations));
    base.OnActionExecuting(filterContext);
}

protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
    var task = filterContext.RequestContext.HttpContext.Items["OperationTask"] as Task<OperationsStatusVM>;
    ViewData["OperationStatusVM"] = task.Result;
    base.OnActionExecuted(filterContext);
}

私はまだねじれを解決していますが、MVC に組み込まれているものを使用する機会を逃しているようです。私の主な要件は、ページがレンダリングされるときに ViewData を設定する必要があることです。

このアプローチは理にかなっていますか?これはこの問題を解決する良い方法ですか、それともより良いアプローチがありますか?

ありがとう、エリック

4

2 に答える 2

1

MVC で非同期コントローラーについて説明しているようですね。これにより、長時間実行されるリクエストの処理中に IIS が解放されて他のリクエストに応答できるようになりますが、OperationsStatusBuilder の実行中に同じアクション内の他のメソッドを実行したい場合は、いくつかの非同期コードを使用してそれらすべてをキューに入れ、待機する必要があります。レンダリングされるビューに結果を返す前に、それらすべてが結果を返すようにします。このサイトをホストしているサーバーに複数のコアがある場合、最良の結果が得られます。これは、データベースからドキュメントを非同期的にプルするためにアプリで使用した例です。

GetFileResultメソッド (コントローラーの他の場所で非アクションとしてフラグが付けられている) は、実際にロジックを実行したものです。タスクを結果に戻す理由は、Async メソッドで発生したエラーが結果メソッドに到達しなかったためです。タスクをパラメーターとして渡し、結果メソッドの最初の行として呼び出すtask.Wait()ことで、例外を再スローさせ、黙って無視するのではなく、サイトに処理/表示させることができました。

複数のタスクを同時に実行するために実行時間の長い複数のタスクがある場合は、複数のタスクを作成し、それぞれに対して OutstandingOperations を 1 回インクリメントできることに注意してください。結果は、未処理の操作の数が 0 に達し、それらがすべて完了した場合にのみ結果を取得する必要があります。

public void FileAsync(Guid id)
{
    AsyncManager.OutstandingOperations.Increment();
    Action getFileAsync = () =>
        {
            FileResult fileResult = GetFileResult(id, false);
            AsyncManager.Parameters["result"] = fileResult;
            AsyncManager.OutstandingOperations.Decrement();
        };
    var task = Task.Factory.StartNew(getFileAsync);
    AsyncManager.Parameters["task"] = task;
}
public ActionResult FileCompleted(FileResult result, Task task)
{
    task.Wait(); 
    if (result == null)
        return HttpNotFound();
    return result;
}
于 2012-06-27T00:36:07.243 に答える
0

「問題は、OperationsStatusBuilder メソッドの実行時間がかなり長いことです。私は > リクエストの残りをブロックすることなく、ViewModel にデータを入力する方法をまとめようとしています。」

ひとつのお願いです。クライアントと同様に、ビューと部分ビューのマージ結果を 1 つのドキュメントとして取得しています。あなたが説明していることは、ソケットのように聞こえます。とにかく、これを行う唯一の方法は、ページを送信し、事後に AJAX を使用して部分ビューを要求し、ページを更新することだと思います。

それとも私は混乱していますか?

さらに:

ViewData ディクショナリ内に部分ビュー モデルを格納する必要はありません。メインモデル内に保存してから、次のようにパーシャルを呼び出すことができます:@Html.Partial(Model.MyPartialViewModel)

于 2012-06-26T23:48:33.750 に答える