【问题标题】:A Contact page with ASP.NET MVC 3带有 ASP.NET MVC 3 的联系人页面
【发布时间】:2011-05-07 19:11:45
【问题描述】:

我有一个联系页面,这个页面应该显示一个表单或一个成功消息或一个失败消息,所以基本上是这样的:

@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 WebForms 类似的页面和行为,解决方案是将三个可变标记块放入 asp:Panel 控件,然后从代码打开或关闭这些面板的 Visible 标志-在后面。我想我需要使用 ASP.NET MVC 的另一种方法来达到相同的目标。

最好的方法是什么?

提前感谢您的建议!

【问题讨论】:

    标签: asp.net asp.net-mvc asp.net-mvc-3


    【解决方案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);
        }
    

    【讨论】:

    • 您的解决方案似乎比 p.campbell 的解决方案更有优势(请参阅我对他的回答的评论)。 TempData 与 ViewBag 相比能活多久?它似乎在 RedirectToAction 中幸存下来,而 ViewBag 显然不是这样。
    • TempData 存在于此类场景中。数据仅适用于另外一个请求。但是,如果您需要更多后续请求的数据(例如某些向导),您可以通过调用 Keep() 方法来“延长”它。在 MSDN 上查看更多详细信息:goo.gl/rEQ03
    • 这看起来确实是完美的方式。与此同时,我了解到这种模式甚至有一个名称:“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 && ((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
        }
    }
    

    【讨论】:

    • 我不喜欢这个解决方案。它可以工作,但它会在提交后使用输入数据呈现一个。
    • 这会在您的视图标记中导致一个非常难看的 if 块。不适合优化和维护。
    • @frennky:为什么会在提交后呈现表单?发帖后,您永远不会到达标记中的第二个 else 块,是吗?
    • 我想要的逻辑更像是:if (result) ViewBag.ContactSuccess = true; else ViewBag.ContactFailure = true; 如果 ModelState 无效,我想用通常的验证通知重新呈现表单。但这是次要的一点,很清楚我如何实现这个逻辑。对我来说重要的是看到使用 ViewBag 的解决方案是可能的以及如何。感谢这个简单的解决方案!
    • @Slauma 你是对的,我没有对视图给予足够的关注。就个人而言,我尝试在视图中使用最少的逻辑。我提供的解决方案将有一个 if 块来检查消息。由于您的 Web 应用程序中可能会有更多表单,因此您可以将该消息逻辑包装到部分或帮助程序中,将其从联系人视图中移除并使其可在其他地方重用。
    【解决方案3】:

    看起来你可以在客户端发出一个ajax调用,并根据Json结果,你可以从客户端渲染不同的内容。

    【讨论】:

      【解决方案4】:

      我建议编写三个不同的视图

      • index.cshtml
      • contactSuccess.cshtml
      • contactFail.cshtml

      然后在您的 Controller 中,您将拥有与之前类似的代码

      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 动态交换它们。

      【讨论】:

      • "...您可以将部分视图加载到索引视图中...":这听起来是个不错的解决方案,但我不知道该怎么做。如果我对您的理解正确,您的代码 sn-p 提供了三个完全不同的视图,这并不理想,因为所有三个视图都有标记的公共部分,然后我需要复制这些部分。是否可以在不使用 Ajax 的情况下动态注入不同的局部视图?
      猜你喜欢
      • 1970-01-01
      • 2012-03-31
      • 1970-01-01
      • 2012-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-25
      相关资源
      最近更新 更多