現在のプロジェクトで、クライアントは 2 つの方法でアンケートに回答する可能性を求めました。単一のフォームで (一度にWizard
1 つの質問) と(一度にすべての質問) を使用します。Listing
どちらの方法もすでに実装されています。
質問は、AJAX を使用してマニュアルの章ごとにデータベースからロードされます (これは非常に高速です)。現時点で最大の章には230
質問があります (それぞれに 4 つの HTML 入力フィールド (入力/テキスト、選択など) があります)。ユーザーがそのような章を選択してListing
フォーマットで回答すると、サーバーに投稿される<form>
at about フィールドが含まれます。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 秒) かかることです。
重要なことは、HTTP POST から ViewModel コレクション プロパティを具体化するときに、 Steve Sanderson の@Html.BeginCollectionItem ヘルパーを使用していることです。ViewModel (キー) でデータがどのように取得されるかを確認します。
これを最適化するために私ができることを知っていますか?
私は4つの回避策について考えました:
変更された質問のみを保存します。
<form>
これを行うには、リストをロードするときに各回答値を data-attribute に保存し、この男がここで提案しているように、送信時に実際の値と比較する必要があります。AnswerViewModel
クライアント側で JavaScript オブジェクトを作成し、アクション メソッドに渡します。これは Model Binder を軽減しますか?独自のモデル バインダーを展開しますが、ASP.NET MVC に付属する既定のバインダーよりも高速になるかどうかはわかりません。私が読んだことから、デフォルトのモデルバインダーは多くのリフレクションを行って値を設定したり、アクションのモデルパラメーターを水和したりしますが、これがボトルネックになる可能性があります。
ここに示すように、投稿されたデータを使用
FormCollection
して列挙し、キーごとに各値を取得し、手動で検証を実行します。
他に何を提案しますか?
更新 1
オプション 3 をAnswerModelBinder : IModelBinder
使用し、カスタムの Model Binder を実装しました。それを特定のアクション メソッドで使用しました。
public async Task<ActionResult> ListSaveAsync(
[ModelBinder(typeof(AnswerModelBinder))]List<AnswerViewModel> questions)
今10 seconds
、完了するのにかかったものは2 seconds
.
- デフォルトのモデル バインダーの検証チェック [
ModelState
] がパフォーマンスに大きな影響を与えているようです。
更新 2
もう一度経験しました。アクション パラメータとして a を持ち、呼び出しのみをList<Guid>
渡すと、アクション メソッドの 1 行目のブレークポイントに到達するのに約 3 秒かかりました。パラメータのタイプを変更して、すべてが一瞬で機能するようにしました。59 strings
$.getJson
List<string>
興味深い事実は、アクション メソッド内で次のようにしたことです。
List<Guid> userIds = resources.Select(Guid.Parse).ToList();
List<string>
そして、リソースをList<Guid>
瞬時に変換します。
確かに、ASP.NET モデル バインダーにはバグがあります。私はそれが何であるかを知りたいだけです... :)