W bieżącym projekcie klient poprosił o możliwość udzielenia odpowiedzi na kwestionariusz na dwa sposoby: za pomocą pytania: Wizard
(jedno pytanie za jednym razem) i Listing
(wszystkie pytania naraz) w jednym Formularz. Oba sposoby są już wdrożone.Dlaczego domyślny spinacz modelu ASP.NET MVC jest wolny? Wykonanie tego zajmuje dużo czasu.
Pytania są ładowane z bazy danych w rozdziale podręcznika przy użyciu technologii AJAX (jest to bardzo szybkie). Największy rozdział w tej chwili ma pytania 230
(każdy z 4 polami wprowadzania HTML - input/text, select, etc). Jeśli użytkownik wybierze taki rozdział do odpowiedzi w formacie Listing
, <form>
będzie zawierał około 920
pól do wysłania na serwer.
robię żądanie AJAX POST przekazując dane z serialize
metody jQuery:
data: $("#questions :input").serialize()
Ten serializacji zaczyna 207.143ms
aby zakończyć. Dostałem tę wartość debugowania Firebug Firefox:
console.profile();
$("#questions :input").serialize();
console.profileEnd();
znowu jest super szybki ...
Problem pojawia się, gdy Hydrating dane otrzymane w następujący sposób działanie:
public async Task<ActionResult> ListSaveAsync(IEnumerable<AnswerViewModel> questions)
Jak widzisz, opublikowane dane są danymi związanymi z IEnumerable<AnswerViewModel> questions
. AnswerViewModel
ma tylko 4 pola do przechowywania każdej odpowiedzi.
Chodzi o to, że zajmuje dużo czasu (dokładnie 10 sekund) po kliknięciu przycisku Zapisz, aby trafić punkt przerwania w tej metodzie akcji, czyli te 10 sekund są prawdopodobnie wydawane w segregatorze modelu.
Należy wspomnieć, że używam narzędzia Steve Sandersona @Html.BeginCollectionItem helper, aby pomóc w zmaterializowaniu właściwości kolekcji ViewModel z testu HTTP POST. Zobacz, w jaki sposób dane dostaje w ViewModel (klawisze):
Czy wiesz, co mogę spróbować zrobić, aby zoptymalizować to?
myślałem o 4 obejścia:
Zapisz powrotem tylko zmodyfikowane pytania. Aby to zrobić, muszę zapisać każdą wartość odpowiedzi w atrybucie danych podczas ładowania listy i porównać ją z rzeczywistą wartością podczas przesyłania
<form>
, ponieważ ten facet sugeruje here.Utwórz
AnswerViewModel
obiektów JavaScript po stronie klienta i przekaż je do metody działania. Czy to złagodzi model Binder?Rzuć mój własny segregator ... ale naprawdę nie wiem, czy byłby szybszy niż domyślny, który jest dostarczany z ASP.NET MVC. Z tego, co przeczytałem, domyślny model spoiwa robi wiele refleksji, aby ustawić wartości/nawodnić parametr modelu działania, a to może być wąskie gardło.
Użyj
FormCollection
i wylicz na podstawie opublikowanych danych, uzyskując każdą wartość kluczem i wykonując sprawdzanie ręcznie, jak pokazano here.
Co jeszcze sugerujesz?
Update 1
poszedłem z opcji 3 i wdrożony model niestandardowy Binder: AnswerModelBinder : IModelBinder
i stosować go w tej konkretnej metody działania:
public async Task<ActionResult> ListSaveAsync(
[ModelBinder(typeof(AnswerModelBinder))]List<AnswerViewModel> questions)
Teraz co miało 10 seconds
zakończenia zajmuje tylko 2 seconds
.
- Wygląda jak domyślne sprawdzanie poprawności bindownicy modelu [
ModelState
] ma duży wpływ na wydajność.
Aktualizacja 2
właśnie doświadczył go jeszcze raz: o List<Guid>
jako parametr działania i przechodząc tylko 59 strings
przez $.getJson
rozmowy brał ~ 3 sekundy uderzy punkt przerwania w 1. linii metoda działania. Zmiana typu parametru na List<string>
sprawiła, że cała sprawa działała w mgnieniu oka.
Ciekawostką jest fakt, że wewnątrz metody działania zrobiłem to:
List<Guid> userIds = resources.Select(Guid.Parse).ToList();
i przekształca zasoby List<string>
do List<Guid>
natychmiast.
Na pewno jest coś buggy z segregatora ASP.NET modelu. Chciałbym tylko wiedzieć, co to jest ... :)
żal powolnej odpowiedzi, Leniel. Ile pytań wysyłasz na serwer? Segregator modelu używa dużej ilości kodu, aby uzyskać bardzo ogólne informacje o analizie danych wejściowych z żądania.Myślę, że w twoim przypadku najlepszym sposobem na rozwiązanie była ścieżka, którą podjąłeś. – OdeToCode
@OdeToCode Dzięki Scott za spojrzenie ... Miło, że zgadzasz się z niestandardowym podejściem Binder Model. W tym konkretnym przypadku wysyłam 230 pytań na serwer. Jeśli zrobię też opcję nr 1, myślę, że będzie jeszcze szybciej ...;) Może 1s zamiast 2s, ponieważ JavaScript jest dość szybki. Musisz to przetestować. –
@OdeToCode Po prostu uzupełniłem kod i zaimplementowałem obejście # 1 Wspominam powyżej => przy ładowaniu pytań Wkładam każde wejście/wybieram bieżącą wartość w atrybucie danych i podczas zapisu porównuję bieżącą wartość z tą poprzednią wartością w danych atrybut. Następnie używam funkcji filtrowania jQuery, aby pomóc w tym. Teraz Oszczędzanie jest natychmiastowe. :-) Kod jQuery jest imponująco szybki! –