#asp.net #asp.net-mvc #asp.net-mvc-3
#asp.net #asp.net-mvc #asp.net-mvc-3
Вопрос:
У меня есть страница контактов, и на этой странице должна отображаться либо форма, либо сообщение об успешном завершении, либо сообщение об ошибке, так что в основном что-то вроде этого:
@model MyApp.Models.ContactData
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div>
...Some static content...
If page was opened the first time
-> Render a form here
Else If form was posted and data successfully processed
-> Render a success message here
Else If form was posted but error occurred during processing
-> Render a failure message here
...Some static content...
</div>
Я не знаю, каков наилучший способ добиться этого с помощью MVC 3. Должен ли я создавать три полностью отдельных представления (чего я хотел бы избежать из-за статического содержимого, которое было бы одинаковым для всех трех представлений)? Или я мог бы создать три частичных представления, а затем решить на основе дополнительного флага, который я мог бы поместить в класс модели, какое частичное представление отображать? Или я могу каким-то образом динамически вводить частичные представления из контроллера в представление?
Контроллер, который у меня есть до сих пор, выглядит следующим образом:
public class ContactController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(ContactData contactData)
{
if (ModelState.IsValid)
{
ContactService service = new ContactService();
bool result = service.Process(contactData);
return ?; // What do I return now? It must somehow depend on result.
}
else
return View(contactData));
}
}
У меня была похожая страница и поведение с ASP.NET Веб-формы и решение заключались в том, чтобы поместить три переменных блока разметки в asp:Panel
элементы управления, а затем включить или выключить Visible
флаг этих панелей из code-behind. Я думаю, мне нужен совсем другой подход с ASP.NET MVC для достижения той же цели.
Каков наилучший способ?
Заранее благодарим вас за предложения!
Ответ №1:
Вы можете попробовать этот способ:
[HttpPost]
public ActionResult Index(Contact contactData)
{
if (ModelState.IsValid)
{
ContactService service = new ContactService();
if (service.Process(contactData))
{
TempData["Success"] = "Your success message.";
return RedirectToAction("Index");
}
else
{
TempData["Error"] = "Your fail message.";
}
}
return View(contact);
}
Комментарии:
1. Ваше решение, похоже, имеет преимущество перед решением П.Кэмпбелла (см. Мой комментарий к его ответу). Как долго
TempData
сохраняется в отличие от ViewBag? Кажется, что она сохраняетсяRedirectToAction
, что, по-видимому, не относится к ViewBag.2. Временные данные существуют для подобных сценариев. Данные доступны только для еще одного запроса. Однако, если вам нужны данные для еще нескольких последующих запросов (скажем, для какого-нибудь мастера), вы можете «продлить» это, вызвав методы Keep(). Смотрите более подробную информацию в MSDN: goo.gl/rEQ03
3. Это действительно выглядит как идеальный способ. Тем временем я узнал, что у этого шаблона даже есть название: «Шаблон Post / Redirect / Get (PRG)», и TempData создан для поддержки этого шаблона. Еще раз спасибо!
Ответ №2:
Возможно, используйте ViewBag, чтобы помочь достичь всего этого. Конечно, она динамическая, поэтому вы можете добавлять и проверять любую поддержку, которую вы хотите / нуждаетесь / ожидаете.
[HttpPost]
public ActionResult Index(ContactData contactData)
{
if (ModelState.IsValid)
{
ContactService service = new ContactService();
bool result = service.Process(contactData);
ViewBag.ContactSuccess = true;
}
else
{
ViewBag.ModelStateErr= "some err";
}
return View(contactData));
}
Тогда, по вашему мнению:
if (ViewBag.ContactSuccess !=null amp;amp; ((bool)ViewBag.ContactSuccess))
{
//thanks for posting!
}
else
{
if (ViewBag.ModelStateErr !=null)
{
//show that we have an err
}
else
{
//we have no err nor a 'true' contact success yet
//write out the form
}
}
Комментарии:
1. Мне не нравится это решение. Это работает, но после отправки она отобразит файл from с входными данными.
2. это приводит к большому уродливому блоку if в вашей разметке представления. Не идеально подходит для оптимизации и обслуживания.
3. @frennky: Почему это должно отображать форму после отправки? Вы никогда не доходите до второго блока else в разметке после публикации, не так ли?
4. Логика, которую я хочу, больше похожа на:
if (result) ViewBag.ContactSuccess = true; else ViewBag.ContactFailure = true;
И если ModelState неверен, я хочу повторно отобразить форму с обычными уведомлениями о проверке. Но это второстепенный момент, ясно, как я могу достичь этой логики. Для меня было важно увидеть, что возможно решение с использованием ViewBag и каким образом. Спасибо за это простое решение!5. @Slauma вы правы, я не уделял достаточного внимания представлению. Лично я стараюсь иметь минимальную логику внутри представлений. В решении, которое я предоставил, был бы один блок if для проверки сообщений. И поскольку у вас, вероятно, будет больше форм в вашем веб-приложении, вы можете преобразовать эту логику сообщения в частичную или вспомогательную, удалив ее из представления контактов и сделав доступной для повторного использования в другом месте.
Ответ №3:
Похоже, что вы можете выполнить вызов ajax на стороне клиента, и на основе результата Json вы можете отображать другой контент на стороне клиента.
Ответ №4:
Я бы предложил закодировать три разных представления
- index.cshtml
- contactSuccess.cshtml
- contactFail.cshtml
Тогда в вашем контроллере у вас будет аналогичный код, как и раньше
public class ContactController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(ContactData contactData)
{
if (ModelState.IsValid)
{
ContactService service = new ContactService();
bool result = service.Process(contactData);
return View("contactSuccess.cshtml");
}
else
return View("contactFail.cshtml", contactData);
}
}
Таким образом, каждое представление становится независимым, и у вас нет большого встроенного блока IF в середине вашей разметки.
В качестве альтернативы (и именно так я бы это сделал) вы можете сделать так, чтобы index.cshtml содержал три части…
- _ContactForm.cshtml
- _ContactSuccess.cshtml
- _ContactFail.cshtml
а затем вы можете загружать частичные представления в индексное представление и даже динамически менять их местами с помощью AJAX.
Комментарии:
1. «… вы можете загрузить частичные представления в индексное представление …»: Это звучит как хорошее решение, но я не знаю, как это сделать. Если я вас правильно понял, ваш фрагмент кода предоставляет три совершенно разных представления, что не идеально, потому что все три представления имеют общие части разметки, которые мне нужно было бы скопировать затем. Возможно ли динамически вводить разные частичные представления БЕЗ использования Ajax?