HttpPost 方法未从视图中获取正确的模型,还获取其他对象的 Null/Reference 对象错误 - MVC 5 C#

HttpPost method doesn't get the correct model from view, also get Null/Reference object errors with other objects - MVC 5 C#

我会边解释边解释这个问题。

我这里有这个观点

查看:

@model Project.Models.CheckoutItem
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Checkout - Project</title>
    <link href="~/Content/bootstrap.min.css" rel="stylesheet" />
    <style type="text/css">
        body{ margin-top:20px; }
    </style>
</head>
<body>
    @using (Html.BeginForm( ))
    {
    <div class="container">
        <div class="row form-group">
            <div class="col-xs-12">
                <ul class="nav nav-pills nav-justified thumbnail setup-panel">
                    <li class="active">
                        <a href="#step-1">
                            <h4 class="list-group-item-heading">Step 1</h4>
                            <p class="list-group-item-text">Your Details</p>
                        </a>
                    </li>
                    <li class="disabled">
                        <a href="#step-2">
                            <h4 class="list-group-item-heading">Step 2</h4>
                            <p class="list-group-item-text">Delivery Method</p>
                        </a>
                    </li>
                    <li class="disabled">
                        <a href="#step-3">
                            <h4 class="list-group-item-heading">Step 3</h4>
                            <p class="list-group-item-text">Payment Information</p>
                        </a>
                    </li>
                </ul>
            </div>
        </div>
        <div class="panel panel-default">
            <div class="panel-body">
                Item: @Model.Item.ItemName
            </div>
        </div>
        <div class="row setup-content" id="step-1">
            <div class="col-xs-12">
                <div class="col-md-12 well text-center">
                    <div class="col-md-4 col-md-offset-4">

                        @Html.ValidationSummary()

                    <!-- STEP 1-->
                        @Html.LabelFor(m => m.FirstName) @Html.TextBoxFor(m => m.FirstName, new { @class = "form-control", @required = "required" }) <br/>

                        @Html.LabelFor(m => m.LastName) @Html.TextBoxFor(m => m.LastName, new { @class = "form-control", @required = "required" })<br />

                        @Html.LabelFor(m => m.Email) @Html.TextBoxFor(m => m.Email, new { @class = "form-control", @required = "required" })<br />

                        @Html.LabelFor(m => m.PhoneNumber) @Html.TextBoxFor(m => m.PhoneNumber, new { @class = "form-control", @required = "required" })<br />

                        @Html.LabelFor(m => m.MsgOnCard) @Html.TextAreaFor(m => m.MsgOnCard, new { @class = "form-control" })<br />

                            <button id="activate-step-2" class="btn btn-primary" type="button">Next</button>

                        </div>
                </div>
            </div>
        </div>
        <div class="row setup-content" id="step-2">
            <div class="col-xs-12">
                <div class="col-md-12 well text-center">
                    <div class="col-md-4 col-md-offset-4">
                    <!-- STEP 2 -->
                        @Html.LabelFor(m => m.ShippingMeth) @Html.EnumDropDownListFor(m => m.ShippingMeth) <br/> <br/>

                        <div id="shippingDetails" class="disabled">
                            @Html.LabelFor(m => m.deliveryDetails.Street)  @Html.TextBoxFor(m => m.deliveryDetails.Street, new { @class = "form-control" }) <br/>

                            @Html.LabelFor(m => m.deliveryDetails.City)  @Html.TextBoxFor(m => m.deliveryDetails.City, new { @class = "form-control" }) <br/>

                            @Html.LabelFor(m => m.deliveryDetails.State)  @Html.TextBoxFor(m => m.deliveryDetails.State, new { @class = "form-control" }) <br/>

                            @Html.LabelFor(m => m.deliveryDetails.Postcode)  @Html.TextBoxFor(m => m.deliveryDetails.Postcode, new { @class = "form-control" }) <br/>

                        </div>

                        <button id="activate-step-3" class="btn btn-primary" type="button">Next</button>

                    </div>
                </div>
            </div>
        </div>
        <div class="row setup-content" id="step-3">
            <div class="col-xs-12">
                <div class="col-md-12 well text-center">
                    <div class="col-md-4 col-md-offset-4">
                        <!-- STEP 3 -->
                        @Html.LabelFor(m => m.Card.CardHolder) @Html.TextBoxFor(m => m.Card.CardHolder, new { @class = "form-control" }) <br />

                        @Html.LabelFor(m => m.Card.CardNumber) @Html.TextBoxFor(m => m.Card.CardNumber, new { @class = "form-control" }) <br />

                        <b>Card Expiry</b> <br/> <br/> @Html.TextBoxFor(m => m.Card.ExpMonth, new { @class = "form-control" }) / @Html.TextBoxFor(m => m.Card.ExpYear, new { @class = "form-control" })  <br />

                        @Html.LabelFor(m => m.Card.Cvc) @Html.TextBoxFor(m => m.Card.Cvc, new { @class = "form-control" }) <br />

                        <input type="submit" value="Pay" class="btn btn-success btn-lg" name="Model" />

                    </div>

                </div>
            </div>
        </div>
    </div>

现在发生的事情是。该页面应该有一个用于付款处理的提交按钮。它会发送用户尝试购买的当前商品(型号)(包括其名称、描述、价格等)以及其他付款信息、运输信息和个人详细信息。

因此 CheckoutItem 包含实际出售的物品以及客户和购买的其他详细信息等。

问题是,视图提交,代码立即转到该模型的无参数构造函数。

还有

// I put in the constructor to initialize those variables in the class.
Item = new ItemModel();

有人告诉我这是必需的,因为当它抓取信息时,它需要一个空的模型实例来填充视图中的信息。

无论如何,发生的事情是,模型(对于正在出售的商品)曾经是空的,在如上所示初始化之后,它现在显示了它的默认值,但它仍然没有被视图真正返回到控制器。所以价格为 0,名称和描述本身为 null 等。所有其他付款信息、个人信息等都已在 CheckoutItem 中成功发送。

另一个问题是这个。信用卡信息只是从 CheckoutItem 的返回变量传输到控制器中的本地变量,但是我们得到一个 Reference Object not Instance(类似的东西)错误,您可能很熟悉。虽然在 Controller 中可以看到,本地信用卡详细信息对象的实例已经在 HttpPost 方法中进行了初始化。

对于为什么会出现这些问题,我们将不胜感激。我确信我在某个地方做过一些愚蠢的事情并不太复杂。

非常感谢你们,你们已经帮助我们解决了这个项目中的一个问题!

在您看来,您使用模型的 Item 属性 的唯一地方是这里:

<div class="panel-body">
    Item: @Model.Item.ItemName
</div>

显然这只是将其名称打印到 HTML。如果您不在 inside HTML 表单中包含这些数据,则您不可能期望在提交数据时取回任何值。

所以一种可能性是为它们设置隐藏字段:

@Html.HiddenFor(x => x.Item.ItemName)
@Html.HiddenFor(x => x.Item.ItemPrice)
@Html.HiddenFor(x => x.Item.ItemDescription)
...

现在,当您提交表单时,这些值将被发送到服务器。另一种可能性是使用项目 ID 从数据库中获取它们,就像您在 GET 操作中所做的一样。如果用户不应该修改他们的值,这是推荐的方法。

视图确实需要在与项目模型相关的 HTML 表单中隐藏字段,以便视图知道要提交给控制器的内容等,正如@Darin Dimitrov 所建议的:

@Html.HiddenFor(x => x.Item.ItemName)
@Html.HiddenFor(x => x.Item.ItemPrice)
@Html.HiddenFor(x => x.Item.ItemDescription)
...

eWay 支付 models/classes 返回空错误的另一个问题与它们在对象中包含对象这一事实有关。如果你说初始化对象 A,它也包含带有变量的对象 B,那么你需要在 A 中初始化对象 B 的实例,这样它就不是一个巨大的 NULL 值,而是一堆其他值。这听起来令人困惑,但如下所示:

CustomerPayment payment1 = new CustomerPayment();

现在 CustomerPayment 对象内部包含另一个对象,类型为 CreditCardDetails,名为 CardDetails。这还需要初始化,以便可以访问其变量并且整个对象不为空,如下所示:

payment1.CardDetails = new CreditCardDetails();

现在您实际上可以使用其中的东西并为它们赋值例如:

payment1.CardDetails.Number = 1234 1234 1234 1234;

没有返回空错误。

这是 eWay(我们的支付网关)的惰性编码,为我们提供了 类 具有无参数构造函数,这些构造函数不会初始化封装在其中的其他对象。