2013-02-19 21 views
16

現在のプロジェクトでは、クライアントはWizard(一度に1つの質問)とListing(一度にすべての質問)を1つの方法で使用するという2つの方法でアンケートに回答する可能性を求めました形。どちらの方法も既に実装されています。なぜASP.NET MVCのデフォルトモデルバインダーが遅いのですか?

質問はAJAXを使用してマニュアルの章ごとにデータベースから読み込まれます(これは超高速です)。現時点で最大の章は230(4つのHTML入力フィールド - 入力/テキスト、選択など)の質問があります。ユーザーがListing形式で回答する章を選択した場合、<form>には、約920のフィールドがサーバーに送信されます。

私はjQueryのserialize方法でデータを渡すAJAX POSTリクエストをやってる:

data: $("#questions :input").serialize() 

この連載が完了する207.143msかかります。私はFirefoxでFirebugのでは、この値のデバッグを得た:

console.profile(); 
$("#questions :input").serialize(); 
console.profileEnd(); 

ここでも、これは、超高速です...データを水和すると、次のアクションメソッドで受信したときに

問題が来る:

public async Task<ActionResult> ListSaveAsync(IEnumerable<AnswerViewModel> questions) 

ご覧のとおり、投稿されたデータはIEnumerable<AnswerViewModel> questionsにバインドされたデータです。 AnswerViewModelには、各回答を格納するフィールドが4つしかありません。

このアクションメソッドでブレークポイントをヒットするには、[保存]ボタンをクリックした後、おそらく10秒間がモデルバインダーに費やされていると考えられます。

重要なことは、Steve Sandersonの@Html.BeginCollectionItem helperを使用して、HTTP POSTからViewModelコレクションプロパティを作成する際に役立つことです。データはViewModelに(キー)で取得する方法を参照してください:

enter image description here

あなたは、私がこれを最適化するためにやろうとすることができるものを知っていますか?

  1. 保存バックのみ変更質問:

    は、私は約4回避策を考えました。これを行うには、リストをロードするときにデータ属性に各回答値を格納し、<form>を提出するときに実際の値と比較する必要があります。hereです。

  2. クライアント側でAnswerViewModel JavaScriptオブジェクトを作成し、アクションメソッドに渡します。モデルバインダーを緩和しますか?

  3. 私のモデルバインダーをロールバックしますが、ASP.NET MVCに付属するデフォルトのバインダーよりも高速であるかどうかはわかりません。私が読んだことから、デフォルトのモデルバインダーは、値を設定するための多くの反省を行い、アクションのモデルパラメータを水和させ、これがボトルネックになる可能性があります。

  4. FormCollectionを使用し、各値をキーで取得し、hereのように手動で検証を実行して投稿データを列挙します。

他に何をお勧めしますか?


アップデート1

私はオプション3と一緒に行って、カスタムモデルバインダーを実装:AnswerModelBinder : IModelBinderとその具体的なアクションメソッドでそれを使用:

public async Task<ActionResult> ListSaveAsync(
      [ModelBinder(typeof(AnswerModelBinder))]List<AnswerViewModel> questions) 

今完了すること10 secondsを取ったものをただ2 secondsがかかります。

  • デフォルトのモデルバインダー検証チェック[ModelState]のように見えますが、パフォーマンスに大きな影響を与えます。

アップデート2

私は再びそれを経験した:アクションパラメータとしてList<Guid>を有し、かつ$.getJson呼び出しを通じてのみ59 stringsを渡すの1行目にブレークポイントをヒットする〜3秒を取っていましたアクションメソッド。パラメータタイプをList<string>に変更すると、目の瞬きの中で全体が機能します。

興味深い事実は、アクションメソッドの内部で、私はこれをしなかったということです。

List<Guid> userIds = resources.Select(Guid.Parse).ToList(); 

、それが瞬時にList<Guid>にリソースList<string>を変換します。

確かに、ASP.NETモデルバインダーにはバグがあります。私はちょうどそれが何であるか知りたいと思います... :)

+1

です。いくつの質問をサーバーに送信していますか?モデルバインダーは、要求からの入力を解析することについて非常に汎用的であるようにするために、多くのコードを使用します。私はあなたのケースでは解決する最善の方法は、あなたが取った道だったと思います。 – OdeToCode

+0

@OdeToCode見ていただきありがとうございましたScott ...ありがとうございます。あなたはカスタムモデルバインダーのアプローチに同意します。この特定のケースでは、230の質問をサーバーに送信しています。私もオプション#1を行うと、もっと速くなると思う...;)JavaScriptはかなり速いので2秒ではなく1秒かもしれない。これをテストしなければなりません。 –

+0

@OdeToCodeコードを補完して回避策を実装しました#1質問をロードするときに上記のように言及しました。データ属性に現在の値を入力/選択し、保存するときには、属性。私はjQueryのフィルタ関数を使ってこれを助けます。今すぐ保存は瞬間的です。 :-) jQueryコードは非常に高速です! –

答えて

1

これはあなたが探している答えではありませんが、役立つかもしれません。 FormCollectionを使用する代わりに、コントローラメソッドがシグネチャ内のモデルを受け入れ、Ajax.BeginForm()を使用するようにしてください。これにより、シリアライゼーションの必要性がなくなり、MVCがその作業を行えるようになります。また、質問タイプのリストを持つモデルを調べる価値があるかもしれません。このアプローチでは、すでにモデルに入っているように、ポストの値を繰り返し処理する必要性が排除されるようです。

+0

アンソニーの入力をありがとう。ほんとうにありがとう。私はこれを試してみる必要があります... –

0

私はこれを試しませんでしたが、整数インデックスを使用する場合、バインダーはIEnumerableへのバインディングに問題ありませんでした。あなたが実際にこれらのガイドを使用していないので、私はそれらを整数で置き換えます。 (0,1,2 ...)

私は、フォームをレンダリングするページやJSを使って簡単にこれを行うことができると思います。

関連する問題