【问题标题】:ASP.NET MVC: Using multiple viewModels and how to pass the data correct to the model?ASP.NET MVC:使用多个视图模型以及如何将数据正确传递给模型?
【发布时间】:2016-09-28 07:25:47
【问题描述】:

根据我上次的question 和我得到的答案,我在思考它们以及我的应用程序的真正问题是什么。而且我认为你们帮助我弄清楚了你们在那里写的所有内容,非常感谢。所以我做了一个小而有效的例子来演示我的问题:

我的模特:

public class Order
    {
        public int OrderID { get; set; }
        public string NameOfCustomer { get; set; }
        public string Address { get; set; }
    }

包含我需要的另外 2 个 ViewModel 的 ViewModel:

public class ViewModelOrder
    {
        public ViewModelSendItNow viewModelSenditNow { get; set; }
        public ViewModelSafeForLater viewModelSafeForLater { get; set; }
    }

ViewModel SendItNow:

public class ViewModelSendItNow
    {
        [Required]
        public string NameOfCustomer { get; set; }
        [Required]
        public string Address { get; set; }
    }

ViewModel SafeForLater:

public class ViewModelSafeForLater
    {
        public string NameOfCustomer { get; set; }
        public string Address { get; set; }
    }

观点:

@model ProblemExample.Models.ViewModelOrder

@{
    ViewBag.Title = "CreateOrder";
}

<h2>CreateOrder</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

        @if (Request.Form["SafeForLater"] != null)
        {
            @Html.TextBoxFor(m => m.viewModelSafeForLater.NameOfCustomer)
            @Html.TextBoxFor(m => m.viewModelSafeForLater.Address)
        }

        else
        {
            @Html.TextBoxFor(m => m.viewModelSenditNow.NameOfCustomer)
            @Html.TextBoxFor(m => m.viewModelSenditNow.Address)
        }
        <hr />
        <button class="formular-button-submit" type="submit" name="SenditNow">Send it now!</button>
        <button class="formular-button-submit" type="submit" name="SafeForLater">Safe it for later!</button>
    </div>
}

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

控制器:

public ActionResult CreateOrder()
        {
            ViewModelOrder viewModel = new ViewModelOrder();
            return View(viewModel);
        }

        [HttpPost]
        public ActionResult CreateOrder(ViewModelOrder viewModel)
        {
            if (Request.Form["SafeForLater"] != null)
            {
                Order myOrder = new Order()
                {
                    NameOfCustomer = viewModel.viewModelSafeForLater.NameOfCustomer,
                    Address = viewModel.viewModelSafeForLater.Address
                };
                db.Orders.Add(myOrder);
                db.SaveChanges();
            }

            else
            {
                Order myOrder = new Order()
                {
                    NameOfCustomer = viewModel.viewModelSenditNow.NameOfCustomer,
                    Address = viewModel.viewModelSenditNow.Address
                };
                db.Orders.Add(myOrder);
                db.SaveChanges();
            }
            return View(viewModel);
        }

所以,用户应该看到一个表单,当他决定现在发送它时,应该进行验证,如果他想保存它以供以后使用,则不应进行验证。这就是为什么我尝试使用视图中的 2 个按钮来做到这一点。问题是,该示例现在可以发送它,它会像应该的那样保存在数据库中,但是当我稍后点击安全按钮时,我得到一个空引用异常,我真的不知道为什么。所以也许你们看到了我的代码中的错误,并给我一个提示,我可以如何解决这个问题或者我可以尝试什么。

问候,

【问题讨论】:

  • 你的代码没有意义。首次渲染视图时,您总是点击else 块并为viewModelSenditNow 生成表单控件(因此验证将始终启动)。然后在 POST 方法中,Request.Form["SafeForLater"] 将始终为null,因为您的提交按钮没有value 属性,因此不回发值。那你为什么还要返回视图呢?
  • @StephenMuecke 感谢您的回答。我能用语言问你一件事,你会如何解决这个问题?从概念的角度来看,有什么我完全错过了做类似的事情吗?
  • 您没有提供足够的信息来解释您想要做什么,但最好的猜测是使用包含 bool SaveAsDraft 属性的单一视图模型,并将 foolproof [RequiredIfFalse("SaveAsDraft")] 应用于其他属性(并且可能将$.validator 重新配置为仅在提交时验证)。然后如果用户想要保存可能无效的“草稿”,他们可以选中@Html.CheckBoxFor(m =&gt; m.SaveAsDraft)生成的复选框。
  • 您只需要一个提交按钮,然后在POST方法中,您还可以检查SaveAsDraft的值,如果是true,您应该将其保存到数据库中的另一个表这样主表就可以应用约束(尽管这一点实际上取决于您 - 如果您确实只有一个表,那么您的所有字段都需要允许 NULL
  • 再次感谢您的努力,我将尝试解释整个想法是什么。所以用户有一个像上面这样的表格,他应该能够做两件事,1)发送一个完整的订单(验证应该跳进去)2)如果他决定稍后发送完整的订单(此时没有验证),他应该能够将其保存以备后用并再次编辑。但我想将所有这些都保存在一个视图中,以便稍后他能够轻松地在真实订单和他想要稍后保存的内容之间切换。我希望现在这个想法很清楚,如果没有,请随时询问有什么不清楚的地方,我会尽力回答。

标签: c# asp.net asp.net-mvc razor model-view-controller


【解决方案1】:

答案很简单,因为您在页面加载时只渲染了 2 个文本框,所以一次只会渲染两个文本框,现在发送它,因为看起来 Request.Form["SafeForLater"] 是空的,所以代码移动了到 else 块并仅呈现 send it now 文本框。

您应该同时渲染它们,并且只使用 css 隐藏/显示它们。 所以你的代码应该是这样的:

@model ProblemExample.Models.ViewModelOrder

@{
    ViewBag.Title = "CreateOrder";
}

<h2>CreateOrder</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

        @if (Request.Form["SafeForLater"] != null)
        {
            @Html.TextBoxFor(m => m.viewModelSafeForLater.NameOfCustomer)
            @Html.TextBoxFor(m => m.viewModelSafeForLater.Address)
            <div style="display:none">
               @Html.TextBoxFor(m => m.viewModelSenditNow.NameOfCustomer)
               @Html.TextBoxFor(m => m.viewModelSenditNow.Address)
            </div>
        }

        else
        {
            <div style="display:none">
               @Html.TextBoxFor(m => m.viewModelSafeForLater.NameOfCustomer)
               @Html.TextBoxFor(m => m.viewModelSafeForLater.Address)
            </div>

            @Html.TextBoxFor(m => m.viewModelSenditNow.NameOfCustomer)
            @Html.TextBoxFor(m => m.viewModelSenditNow.Address)
        }
        <hr />
        <button class="formular-button-submit" type="submit" name="SenditNow">Send it now!</button>
        <button class="formular-button-submit" type="submit" name="SafeForLater">Safe it for later!</button>
    </div>
}

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

【讨论】:

  • 嗨@Haitham Shaddad,感谢您的回答,我确实尝试了您的解决方案,它解决了 Nullreference 的错误,但是 Safe It for Later 的值并未保存到数据库中,它只是显示空
  • 您是否调试并检查了操作中的值?您能否确认这些值已绑定到控制器操作中的模型?只是想知道这是数据绑定问题还是保存到数据库问题
  • 我做了一步一步的调试,值似乎没有绑定到模型,在模型中两个值都是空的。
  • 您能否通过在浏览器中单击 F12 检查发布的值,检查网络选项卡并单击提交按钮,然后检查请求并查看请求正文包含的内容?你能在浏览器中向我们展示生成的 HTML 吗?
  • 所以另一个奇怪的事情是,如果我尝试保存它以供以后使用,然后单击两个文本框中的按钮,文本就消失了。如果我现在发送它,文本仍然存在,所以它必须是绑定到模型的问题......
猜你喜欢
  • 1970-01-01
  • 2014-09-14
  • 1970-01-01
  • 2012-02-02
  • 2023-04-05
  • 1970-01-01
  • 2020-10-24
  • 2011-12-21
  • 1970-01-01
相关资源
最近更新 更多