【问题标题】:ASP.NET MVC Null object returned from view从视图返回的 ASP.NET MVC Null 对象
【发布时间】:2023-03-07 12:18:02
【问题描述】:

我有一个非常简单的问题,可能有一个非常简单的答案,但是我无法解决。

我的视图模型如下:

namespace CommunicationsLog.ViewModels
{
    public class CommunicationViewModel
    {
        public Communication Communication { get; set; }
        public Feedback Feedback { get; set; }
        public IEnumerable<Resolution> Resolutions { get; set; }
    }
}

我正在尝试从我的 Add.cshtml 页面创建一个新的通信实例:

@model CommunicationsLog.ViewModels.CommunicationViewModel
@{
    ViewBag.Title = "Add";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
@using (Html.BeginForm("Add", "Communication"))
{
    <div class="form-horizontal" id="addForm">
        <div class="row">
            <div class="col-md-12">
                @Html.ValidationSummary(true, "", new { @class="text-danger"})
                <div class="form-group">
                    @Html.LabelFor(model => model.Communication.Customer.Name, htmlAttributes: new { @class = "control-label col-md-2" })
                    <div class="col-md-10">
                        @if (Model.Communication.Customer.Name == null)
                        {
                            <input id="btnCust" type="button" value="Select Customer" class="btn btn-default addCustomer" />
                        }
                        else
                        {
                            <span id="custSpan" style="font-size:16px; font:bold;">
                                @Html.DisplayFor(model => model.Communication.Customer.Name)
                                <input id="btnEditCust" type="button" value="Edit" class="btn btn-default addCustomer"/>
                            </span>
                        }
                     <div id="addCust"></div>
                 </div>
            </div>
        </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input id="btnSubmit" type="submit" value="Create" class="btn btn-default" />
        </div>
    </div>
}
<div>
    @Html.ActionLink("Back to Communications", "Index")
</div>

提交时调用以下控制器操作:

[HttpPost]
    public ActionResult Add(CommunicationViewModel viewModel)
    {
        callEnd = DateTime.Now;
        var totalCallTime = callEnd - callStart;
        Communication insertedComm = null;
        try
        {
            Communication comm = viewModel.Communication;
            comm.CallTime = totalCallTime.ToString(@"mm\:ss");
            var customer = _uow.CustomerRepository.Get()
                                                .Where(c => c.Name == comm.Customer.Name);
            comm.CustomerId = customer.FirstOrDefault().CustomerId;
            comm.Customer = customer.FirstOrDefault();
            comm.State = "Open";
            if (ModelState.IsValid)
            {
                insertedComm = _uow.CommunicationRepository.Insert(comm);
                _uow.Save();

            }

            Feedback feedback = viewModel.Feedback;
            if (feedback.Type != null && feedback.Notes != null)
            {
                feedback.Communication = insertedComm;
                feedback.CommunicationId = insertedComm.CommunicationId;
                var insertedFB = _uow.FeedbackRepository.Insert(feedback);
                _uow.Save();
            }

            return RedirectToAction("Index");
        }
        catch (Exception e)
        {
            if(viewModel.Communication == null)
            {
                viewModel.Communication = new Communication();
            }                
            return View(viewModel);
        }
    }

但是,当 viewModel 加载到控制器动作时,通信对象为空。反馈对象已成功实例化。

经过调试,我发现视图模型已正确实例化,并且在页面加载时不为空,并且预定义的数据显示正确。它似乎只是失去了 POST 请求的价值。

有人可以帮忙吗?

非常感谢,

编辑:

正如 cmets 中所指出的,我实际上已经从我的 sn-p 中删除了重要部分,所以这里是不包括 javascript 的完整视图,因为这与 POST 请求无关:

@model CommunicationsLog.ViewModels.CommunicationViewModel
@{
    ViewBag.Title = "Add";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Add</h2>
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
@using (Html.BeginForm("Add", "Communication"))
{
    <div class="form-horizontal" id="addForm">
        <h4>Communication</h4>
        <div id="countdown" class="countdownHolder"></div>
        <hr/>
        <div class="row">
            <div class="col-md-12">
                @Html.ValidationSummary(true, "", new { @class="text-danger"})
                <div class="form-group">
                    @Html.LabelFor(model => model.Communication.Customer.Name, htmlAttributes: new { @class = "control-label col-md-2" })
                    <div class="col-md-10">
                        @if (Model.Communication.Customer.Name == null)
                        {
                            <input id="btnCust" type="button" value="Select Customer" class="btn btn-default addCustomer" />
                        }
                        else
                        {
                            <span id="custSpan" style="font-size:16px; font:bold;">
                                @Html.DisplayFor(model => model.Communication.Customer.Name)
                                <input id="btnEditCust" type="button" value="Edit" class="btn btn-default addCustomer"/>
                            </span>
                        }
                        <div id="addCust"></div>
                    </div>
                </div>
                <div class="form-group">
                    @Html.LabelFor(model => model.Communication.Receiver, htmlAttributes: new { @class = "control-label col-md-2" })
                    <div class="col-md-10">
                        @Html.EditorFor(model => model.Communication.Receiver, new { htmlAttributes = new { @class = "form-control" } })
                        @Html.ValidationMessageFor(model => model.Communication.Receiver, "", new { @class = "text-danger" })
                    </div>
                </div>
                <div class="form-group">
                    @Html.LabelFor(model => model.Communication.Department, htmlAttributes: new { @class = "control-label col-md-2" })
                    <div class="col-md-10">
                        @Html.EditorFor(model => model.Communication.Department, new { htmlAttributes = new { @class = "form-control" } })
                        @Html.ValidationMessageFor(model => model.Communication.Department, "", new { @class = "text-danger" })
                    </div>
                </div>
                <div class="form-group">
                    @Html.LabelFor(model => model.Communication.CommDateTime, htmlAttributes: new { @class = "control-label col-md-2" })
                    <div class="col-md-10">
                        <span id="custSpan" style="font-size:14px;">
                            @Html.DisplayFor(model => model.Communication.CommDateTime)
                        </span>
                    </div>
                </div>
                <div class="form-group">
                    @Html.LabelFor(model => model.Communication.Method, htmlAttributes: new { @class = "control-label col-md-2" })
                    <div class="col-md-10">
                        @Html.EditorFor(model => model.Communication.Method, new { htmlAttributes = new { @class = "form-control" } })
                        @Html.ValidationMessageFor(model => model.Communication.Method, "", new { @class = "text-danger" })
                    </div>
                </div>
                <div class="form-group">
                    @Html.LabelFor(model => model.Communication.Product, htmlAttributes: new { @class = "control-label col-md-2" })
                    <div class="col-md-10">
                        @Html.EditorFor(model => model.Communication.Product, new { htmlAttributes = new { @class = "form-control" } })
                        @Html.ValidationMessageFor(model => model.Communication.Product, "", new { @class = "text-danger" })
                    </div>
                </div>
                <div class="form-group">
                    @Html.LabelFor(model => model.Communication.PartNo, htmlAttributes: new { @class = "control-label col-md-2" })
                    <div class="col-md-10">
                        @Html.EditorFor(model => model.Communication.PartNo, new { htmlAttributes = new { @class = "form-control" } })
                        @Html.ValidationMessageFor(model => model.Communication.PartNo, "", new { @class = "text-danger" })
                    </div>
                </div>
                <div class="form-group">
                    @Html.LabelFor(model => model.Communication.Description, htmlAttributes: new { @class = "control-label col-md-2" })
                    <div class="col-md-10">
                        @Html.EditorFor(model => model.Communication.Description, new { htmlAttributes = new { @class = "form-control" } })
                        @Html.ValidationMessageFor(model => model.Communication.Description, "", new { @class = "text-danger" })
                    </div>
                </div>
                <div class="form-group">
                    @Html.Label("Feedback?", htmlAttributes: new { @class = "control-label col-md-2" })
                    <div class="col-md-10">
                        <input type="checkbox" id="chkFeedback" name="chkFeedback" onclick="showFeedbackForm(this)"/>
                    </div>
                </div>
                <div id="feedbackForm" style="display:none">
                    <div class="form-group">
                        @Html.LabelFor(model => model.Feedback.Type, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.Feedback.Type, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.Feedback.Type, "", new { @class = "text-danger" })
                        </div>
                    </div>
                    <div class="form-group">
                        @Html.LabelFor(model => model.Feedback.Notes, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.EditorFor(model => model.Feedback.Notes, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.Feedback.Notes, "", new { @class = "text-danger" })
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input id="btnSubmit" type="submit" value="Create" class="btn btn-default" />
        </div>
    </div>
}
<div>
    @Html.ActionLink("Back to Communications", "Index")
</div>

我不知道它是否有帮助,但这是来自 VS 的完整堆栈跟踪:

Object reference not set to an instance of an object.       
   at ASP._Page_Views_Communication_Add_cshtml.Execute() in C:\Projects\CommunicationsLog\CommunicationsLog\Views\Communication\Add.cshtml:line 24
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
   at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
   at System.Web.WebPages.StartPage.RunPage()
   at System.Web.WebPages.StartPage.ExecutePageHierarchy()
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
   at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
   at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
   at System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)

【问题讨论】:

  • 您没有绑定任何东西,因为 MVC 找不到要绑定的东西。我看到了 displayfor 和标签,但你的输入在哪里?
  • 抱歉,我已经全面更新了这个问题
  • 如果删除 @Html.HiddenFor(model => model.Communication) 会发生什么?
  • 我尝试通过将通信存储在隐藏字段中来解决问题的尝试之一
  • 删除它,它没有任何好处:)

标签: c# asp.net asp.net-mvc post http-post


【解决方案1】:

由于您使用的是标记,任何&lt;input&gt; 标记都需要定义名称,输入的名称/值对将被发送回服务器:

<input name="@Html.NameFor(i => i.Communication.Customer.Name)" ... />

然后模型将被填充。你也可以使用:

@Html.TextBoxFor(i => i.Communication.Customer.Name)

您的所有输入都需要这个。我还看到您的值属性包含“选择客户”;这将发回服务器。如果你使用placeholder="Select Customer",那么这个值不会被发送到服务器,但是当文本框为空时仍然会显示。

【讨论】:

  • 工作方式是,如果没有客户进行通信,则只显示一个按钮,该按钮加载一个对话框供您选择客户,然后重新加载添加正确详细信息的视图(这一切都有效)一旦选择了客户,它就会在 displayfor 中显示名称并显示一个编辑按钮。那么您能否阐明我需要更改哪些输入以及当前如何在输入中显示未显示的客户名称。对不起,如果我错过了什么并且很天真
  • @DaRoGa 你不是天真;你在这里有一个复杂的设置。我真的不知道我理解的程度足以指导你。但是您必须了解 MVC 仅模型绑定其拥有的数据的规则。因此,它使用 Html.NameFor(i => i.Communication.Customer.Name) 帮助程序将输入名称映射到模型的约定,该帮助程序会为客户端生成类似 Communcation__Customer__Name 的内容(这不是 100% 正确... ) 所以 MVC 然后使用这个约定来重新绑定一个嵌套模型。 MVC 看不到任何这样的输入回传到服务器,因此您的模型为空。
  • 您的挑战是弄清楚您需要在何时/何地在表单中发送给服务器的内容....我注意到您的 标记都没有名称属性,所以当一个帖子发生时,不会在 POST 操作中向服务器发送任何内容....
  • 嗨@BrianMains。感谢那。抱歉回复晚了,我刚回到工作岗位。您能否解释一下关于没有名称属性的输入标签的最后一点?我唯一的 是除了提交按钮之外工作正常的按钮。是否应该以某种方式调整此按钮以正确发送表单?感谢您对此的帮助
  • 嗯,是的,我没有看到所有的标记,所以我输入错误。在上面的示例中,Feedback 将始终具有值,因为您有 @Html.EditorFor(m => m.Feedback.Notes),它正在呈现服务器看到值的输入,但对于 Communication 对象却没有。如果没有用于通信的输入/选择,则它不会将任何内容发送回服务器并且它将为空。至少将一些东西放在隐藏的字段中会有所帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-15
  • 2010-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多