На нашем сайте есть несколько «мастеров», где различные данные собираются на нескольких страницах и не могут быть сохранены в базе данных до последнего шага.
Каков наилучший / правильный способ сделать такого мастера с помощью ASP.Net MVC
edit: Мой босс теперь говорит «без javascript» - есть мысли о том, как обойти это ограничение?
Я надеюсь, что ваш босс больше не ваш босс ... из-за того, что он сказал ...;)
Спросите его, почему «нет Javascript».





Сделайте все разные панели клиентскими ... все в одной форме ... и когда будет нажата последняя кнопка отправки, вы можете опубликовать все значения одновременно.
Я не верю, что есть лучший / правильный способ, но я бы сделал это ...
У каждого мастера есть своя страница. Каждый шаг получает свой собственный div. Все шаги в одинаковой форме.
Кнопки «предыдущий / следующий» будут по существу скрывать / отображать div на каждом этапе процесса. Кнопка отправки на последнем шаге отправляет всю форму. Было бы довольно тривиально реализовать это с помощью jQuery, и его было бы легко поддерживать, поскольку все шаги мастера находятся на одной странице ViewPage.
На стороне контроллера у вас будет два метода контроллера: версия HttpVerbs.Get, которая подготовит форму для просмотра, и версия HttpVerbs.Post, которая будет принимать FormsResult и анализировать ее, чтобы получить информацию, необходимую для отправки ответов пользователя. хранилищу / другим процессам.
Вау, от твоего босса воняет.
Этот ответ почти изящно работает для тех ******, у которых отключен javascript (да, оба). Вы можете настроить его, чтобы скрыть кнопки «следующий-предыдущий» с помощью CSS и отобразить их в коде javascript. Таким образом, люди с javascript будут видеть мастера, а люди без javascript будут видеть всю форму (без кнопок «следующий / предыдущий»).
Другой вариант - создать представление для каждого шага мастера. Вы можете сохранить промежуточные результаты формы в сеансе. Этот способ потребует много времени и усилий для реализации, а это означает, что вы, вероятно, сможете выжать из своего босса немного сверхурочной работы, когда продемонстрируете примерно за двадцать минут усилий, которые вы потратите во время обеда, насколько легко реализовать маршрут javascript.
Чтобы добавить что-то еще, вы можете поместить каждый шаг мастера в частичное представление и выполнить Render.Partial для каждого DIV.
Существует проблема с использованием единого представления и javascript для скрытия / отображения, как вы упомянули - ваша страница станет абсолютно огромной по мере роста мастера. Конечно, может подойти мастер с 2-3 шагами, но даже больше, и вы просто напрашиваетесь на проблемы.
@charles Какое число становится хуже преждевременной оптимизации?
@Will Нет установленного числа, и я не знаю, верно ли то, что вы здесь подразумеваете. «Преждевременная оптимизация»? Вы пытаетесь спровоцировать что-то, говоря это. Это не значит, что мы говорим об огромном объеме работы, просто сохраняя этот сериализованный объект на сервере, вместо того, чтобы передавать его туда и обратно для каждого отдельного запроса страницы.
@charles Вы говорили, что более трех шагов заставят страницу стать «абсолютно огромной». Итак, вас беспокоит то, что страница будет увеличиваться в размерах, замедляя запросы. Другими словами, прежде чем вы действительно узнаете, что вам нужно, вы пытаетесь оптимизировать время отклика. Это действительно так просто. Не пытайтесь подстрекать, просто отвечая на ваши опасения. Конечно, они действительны, но только в том случае, если ваша страница мастера вызывает проблему. Или вы просто пытались «спровоцировать что-то», говоря, что более трех шагов = проблема?
И не забывайте, что данные, сохраненные в Session, могут быть потеряны в любой момент, когда .NET решит, что памяти недостаточно.
Как насчет мастеров, в которых выбор на раннем этапе определяет данные, которые будут извлечены или заполнены на более поздних этапах? Этот сценарий не будет работать с одностраничной формой ...
@RicoSuave: Очевидно, это здесь не подходит. Вместо 10-страничного мастера у вас есть одностраничная форма, в которой обратная передача превращается в 9-страничный мастер.
Проблема с дизайном, основанным на загрузке всего HTML сразу, заключается в том, что он не масштабируется. Если ваша страница станет слишком большой, вы не будете оптимизировать, вы будете перестраивать.
Сохраненный сеанс также плохо влияет на то, что если вы перешли в другой раздел приложения и вернулись в этот раздел мастера, параметры сеанса, которые не были очищены, могут иметь неблагоприятные последствия для вашего приложения. Сессия = Проблемы. Мне нравится представление хминой о частичном взгляде. Таким образом, вид не будет слишком большим. У меня был бы div, а затем логика partialViewRender, а затем sub div. Если внешний div скрыт, он ничего не отобразит.
Если вы не можете использовать JavaScript, сделайте каждый шаг представлением с помощью метода в контроллере и храните данные в сеансе до тех пор, пока они не будут готовы к отправке в базу данных.
Вы можете создать кнопки «Далее» и «Назад» с помощью метода ActionLink HtmlHelper.
Я бы сделал это, но просто использовал бы TempData. Да, он тоже хранится в сеансе, но нет необходимости управлять им, поскольку он удаляется для вас.
Для мастера вам нужна информация на нескольких страницах, поэтому вы не хотите, чтобы она удалялась до тех пор, пока вы не отправите ее. Сохранение его в сеансе позволяет вам перемещаться вперед, назад или перезапускать и сохранять данные, которые уже были введены.
Что произойдет, если пользователь внезапно решит перейти в другую область приложения? Информацию о сеансе следует очищать каждый раз, когда пользователь решает перейти в другое место.
Если вы не можете использовать Javascript и не хотите тратить ресурсы сервера на переменные сеанса, вы также можете сериализовать и десериализовать значения, вводимые на разных этапах, и передавать их туда и обратно, используя скрытое поле ввода. Немного похоже на ViewState в веб-формах ASP.NET.
Проблема с этим решением заключается в количестве данных, которые вы в конечном итоге сохраняете в своем скрытом поле ввода, что увеличивает размер как HTTP-запроса, так и соответствующего ответа. Оба они повлияют на производительность вашего сайта для пользователя и других пользователей (поскольку это повлияет на вашу пропускную способность). Последнее может быть незначительным, в зависимости от того, как часто осуществляется доступ к мастеру, но это может вызвать проблему. Если вы собираетесь сериализовать данные, вам лучше временно сохранить их в таблице БД или в сеансе.
@charles, если вы ожидаете такого огромного трафика в мастере, то объект сеанса будет переполняться намного быстрее, чем у вас возникнут проблемы с производительностью при сериализации / десериализации предыдущих шагов (или даже проблемах с пропускной способностью). Вышеупомянутое решение определенно более масштабируемое и безопасное ( по производительности). Помните, что мы говорим об asp.net mvc, поэтому я на 99% уверен, что сеанс не распределяется, или, по крайней мере, на сервере состояний .. Остерегайтесь микрооптимализации не в том месте ..
@jhexp, я понятия не имею, как можно сказать, что использование скрытого поля ввода более масштабируемо и безопаснее для производительности, чем использование временной таблицы базы данных. Нет абсолютно никакого способа повысить производительность, передавая огромную строку вперед и назад при каждом запросе, чем если бы вы каждый раз извлекали ее из базы данных. Да, а что касается сеанса, почему вы думаете, что сеанс не распределяется? Это полностью зависит от разработчика, MVC не имеет ограничений на это.
@charles Вы хотите сказать нам, что полный запрос к базе данных на каждом шаге быстрее и масштабируемее, чем наличие скрытого поля в форме ?? И я не говорю, что MVC ограничивает реализацию распределенных сессий, но это очень-очень редкий случай. В любом случае многие сильно загруженные приложения не имеют состояния на сервере.
@jhexp вы, очевидно, не представляете, насколько медленен HTTP-запрос по сравнению с простым вызовом базы данных. Увеличение размера этого запроса и ответа определенно происходит медленнее, чем один вызов базы данных. И это с высокоскоростным соединением, даже не начинайте с коммутируемой линии (да, люди все еще используют коммутируемую связь).
Вы правы, но это неправильная мера. Более важным является использование ресурсов, а не в том случае, если браузер загружает ответ на несколько миллисекунд быстрее. Допустим, у вас будет мастер из трех шагов, каждый шаг будет добавлять 5 КБ к сериализованной строке (что действительно достаточно для одностраничной формы), вы переместили назад и вперед еще 30 КБ за все три шага. В отличие от трех вставок и одного выбора в db.
@jhexp - Вам явно никогда не приходилось создавать или оптимизировать веб-сайт для повышения производительности. Ключевым фактором повышения производительности веб-сайта почти всегда является минимизация объема трафика, передаваемого между браузером и сервером. Как вы думаете, почему так популярны Ajax и частичное обновление страниц? И да, я бы сказал, что у вас определенно улучшится общая производительность системы, выполняя вставку / выбор БД по дополнительному переданному КБ.
@jhexp - «Я не говорю, что MVC ограничивает реализацию распределенных сессий, но это очень-очень редкий случай» ????? Что именно в нем редкость? Невероятно просто И невероятно распространено, чтобы ваш сеанс распределялся по серверам в ЛЮБОЙ версии Asp.Net, MVC или нет. Что в нем редкости? И что вы имеете в виду, говоря, что «многие высоконагруженные приложения в любом случае не имеют состояния на сервере»? Вы думаете, что Facebook не имеет гражданства? Твиттер? Да правильно. Найти подсказку.
@charles .. Во-первых, было бы неплохо исключить личные оскорбления из обсуждения некоторых технических подходов. И да, у меня довольно хороший опыт работы с очень большими приложениями баз данных.
@charles Суть этой проблемы заключается в том, что масштабировать веб-сервер намного проще (независимо от того, как вы решаете состояние сеанса на стороне сервера, будете ли вы иметь распределенные сеансы или использовать какую-либо форму «липких сеансов» на стороне балансировщика нагрузки. ), чем горизонтальное масштабирование баз данных sql, что требует больших затрат на лицензии и технических проблем. Поэтому лучше сохранять запросы sql server.
@jhexp - Я когда-либо говорил что-нибудь об "очень больших приложениях баз данных". Я сказал об оптимизации веб-сайтов для повышения производительности. Очень разные вещи. И вы так и не ответили на мой другой вопрос - что именно является редкостью в распределенном сеансе в приложении Asp.Net MVC? Масштабирование веб-сервера по сравнению с сервером базы данных здесь не проблема. Проблема в том, где узкие места в производительности веб-сайта, управляемого данными. Узким местом почти всегда оказывается связь между клиентом и веб-сервером. Единственный способ минимизировать эту проблему - минимизировать размер и количество HTTP-запросов.
Я считаю, что именно так работают некоторые элементы управления веб-форм ASP.net. Они отображают HTML всех шагов на странице и все данные шага в состоянии просмотра. Работает очень медленно, потому что страницы становятся огромными.
Обычно пропускная способность на стороне клиента является более серьезной проблемой, чем потребление памяти на стороне сервера в сеансе.
Другой способ - сохранить незавершенный объект, который вы создаете с помощью мастера, в базу данных и просто передать первичный ключ следующему шагу мастера. Я знаю, что это означает, что вам нужно сделать некоторые поля базы данных обнуляемыми, но у этого есть дополнительное преимущество, заключающееся в том, что вы можете сохранить первичный ключ в файле cookie и позволить пользователю вернуться к мастеру позже. Эта опция не требует javascript или состояния сеанса.
Для повышения безопасности вы должны хешировать первичный ключ, иначе хакер может забрать чужой объект.
Вам не нужны значения NULL, если на каждом шаге есть собственная таблица в базе данных.
Что, если пользователь выберет отмену или мастер будет прерван каким-либо другим способом? Тогда вы получите неполные записи мусора в базе данных.
Отмена может позволить системе очистить данные. Но если пользователь щелкает другую ссылку в приложении, это также требует вызова метода очистки. Итак, вы хотите заставить пользователя следовать строгому рабочему процессу, иначе ваше приложение начнет ломаться.
Я собрал мастер входа в систему и задокументировал его идеи в своем блоге, если это поможет: текст ссылки
Вы можете использовать простой компонент MVCWizard.Wizard, доступный в NuGet. WizardController позволяет создавать мастера, используя частичное представление. Существует также AutoWizardController, который отображает весь мастер в одном представлении. Все эти компоненты работают с сеансом для сохранения состояния модели.
Есть ли образец кода? Ваш контроллер находится в классе, код не виден.
@rob есть пример проекта на NuGet, и если вы хотите, я могу предоставить вам исходный код примера.
Было бы здорово, вы можете связаться со мной через мой сайт.
В этом вопросе есть очень простой, гибкий и расширяемый метод: Как упростить мои чередующиеся модальные диалоги с сохранением состояния в ASP.NET MVC
Почему «без javascript»? Вместо этого я бы использовал Flash или Silverlight :)