15

ASP.NET MVC 2 のAsyncControllers に関するドキュメントを読んだ後、このシナリオで ajax プログレス バーを実装する最善の方法は何か疑問に思っています。チュートリアルでこれがまったくカバーされていないのは少し奇妙に思えます。

AJAX プログレス バーを実装するには、現在のタスクのステータスを返す追加のアクション メソッドが必要になると思います。ただし、ワーカー スレッドとそのアクション メソッドの間でタスクの状態に関する情報を交換する最善の方法についてはわかりません。

これまでの私の最善のアイデアは、現在の進行状況に関する情報を一意の ID と共にセッション ディクショナリに入れ、その ID をクライアントと共有してステータスをポーリングできるようにすることでした。しかし、私が気付かなかったもっと簡単な方法があるかもしれません。

これを行う最善の方法は何ですか?

ありがとう、

エイドリアン

4

1 に答える 1

16

とても興味深い質問です!実際には のタスクではないようですAsyncController。非同期コントローラーは、サーバー側で長時間実行される単一の HTTP クエリ操作用に設計されています。非同期アクションを使用している場合、これは、実行時間の長い操作中に ASP.Net ワーカー スレッドを解放し、操作の実行中に他の要求を処理できるようにするのに役立ちます。しかし、クライアント側の観点からは、この非同期コントローラーであるかどうかは問題ではありません。クライアントの場合、これは単一の HTTP 要求です。

アプリケーションで実行時間の長いクエリ サービスを使用して、これを再設計する必要があります。このようなワークフローを提供できるコントローラーの例を次に示します。

public class LongOperationsController : Controller
{
    public ActionResult StartOperation(OperationData data)
    { 
        Guid operationId = Guid.NewGuid(); // unique identifier for your operation
        OperationsService.DoStartOperation(operationId, data); // service starts to perform operation using separate thread
        return new JsonResult(operationId); // operation id should be sent to client to allow progress monitoring
    }

    public ActionResult GetOperationStatus(Guid operationId) 
    {
        var status = OperationsService.GetStatus(operationId); // this method returns some object, that describes status of operation (e.g. progress, current task etc.)
        return new JsonResult(status); // returning it to client
    }

    public ActionResult GetOperationResult(Guid operationId)
    {
        var result = OperationsService.GetOperationResult(operationId); // this should throw exception if operation is not yet completed
        return new JsonResult(result);
    }

    public ActionResult ClearOperation(Guid operationId)
    {
        OperationsService.ClearOperationResult(operationId); // we should delete operation result if it was handled by client
        return true;
    }
}

そして、このコントローラーとやり取りできるクライアント側のコードは次のとおりです。

var operationId;
function startOperation(data) {
    $.post('/LongOperations/StartOperation', data, function(response) {
        operationId = response; // store operationId
        startOperationMonitoring(); // start
    }, 'json');
}

function startOperationMonitoring() {
    // todo : periodically call updateOperationStatus() to check status at server-side
}

function updateOperationStatus() {
    // todo : get result of GetOperationStatus action from controller 
    // todo : if status is 'running', update progress bar with value from server, if 'completed' - stop operation monitoring and call finishOperation()
}

function finishOperation() {
    // todo : get result of GetOperationResult action from controller and update UI
    // todo : call ClearOperation action from controller to free resources
}

これは非常に基本的な概念であり、省略されている項目がいくつかありますが、主要なアイデアを理解していただければ幸いです。また、このシステムのコンポーネントをどのように設計するかはあなた次第です。例えば:

  • OperationsService にシングルトンを使用するかどうか。
  • 操作結果を保存する場所と期間 (DB? キャッシュ? セッション?);
  • 本当にリソースを手動で解放する必要があるのか​​、クライアントが操作を監視するために停止したとき (ユーザーがブラウザーを閉じたとき) はどうすればよいのかなど。

幸運!

于 2011-01-18T22:24:32.673 に答える