Asp.net mvc 4 通过邮递传递模型

Asp.net mvc 4 通过邮递传递模型,asp.net-mvc-4,Asp.net Mvc 4,我的ASP.NET网站的一个特定部分出现了一些问题。此页面基本上是用户编辑发票然后发布更改的页面 在这一点上,我正在重新编写一个现有的页面,这是可行的。我不知道有什么区别,除了另一个是旧的MVC3 当我第一次转到EditInvoice操作时: public ActionResult EditInvoice() { SalesDocument invoice = null; try { invoice = SomeService.GetTheInvoice

我的ASP.NET网站的一个特定部分出现了一些问题。此页面基本上是用户编辑发票然后发布更改的页面

在这一点上,我正在重新编写一个现有的页面,这是可行的。我不知道有什么区别,除了另一个是旧的MVC3

当我第一次转到EditInvoice操作时:

public ActionResult EditInvoice()
{
    SalesDocument invoice = null;

    try
    {
        invoice = SomeService.GetTheInvoice();
    }
    catch (Exception ex)
    {
        return HandleControllerException(ex);
    }

    return View("InvoiceEdit", invoice.LineItems);
}
“InvoiceEdit”视图的模型是列表

现在,视图可以正常加载,并以一种形式显示所有文档行项目:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<List<MyApp.SalesDocumentLineItem>>" %>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <% using (Html.BeginForm()) {%>

    <fieldset>
        <legend>Line Items</legend>
            <div id="lineItems" class="table">
                <div class="row">
                    <div class="colHButton">X</div>
                    <div class="colH">Item</div>
                    <div class="colHPrice">Price</div>
                    <div class="colHQty">Qty</div>
                </div>
              <% foreach (var item in Model.Where(m => m.LineItemType.Id == NexTow.Client.Framework.UnitsService.LineItemTypes.SaleItem || m.LineItemType.Id == NexTow.Client.Framework.UnitsService.LineItemTypes.NonSaleItem))
              { %>    
                <div class="row">
                    <%=Html.Hidden("Model.LineItemNameId", item.LineItemNameId)%>
                    <div class="cellButton"><button onclick="DeleteContainer(event);">X</button></div>
                    <div class="cell"><span class="formData"><%=item.LineItemDescription %></span></div>                
                    <div class="cellPrice">
                        <span class="formData">$</span>
                        <%= Html.TextBox("Model.Price", item.Price, new { style="width:75px;" })%>
                    </div>
                    <div class="cellQty">
                        <%= Html.TextBox("Model.Quantity", item.Quantity, new { style = "width:60px;" })%>
                    </div>
                </div>  
            <%} %>
        </div>
    </fieldset>
    <p>
        <input type="submit" value="Update Invoice" onclick="SequenceFormElementsNames('salesItems');" />
    </p>

    <% } %>
</asp:Content>

行项目
X
项目
价格
数量
m、 LineItemType.Id==NexTow.Client.Framework.UnitsService.LineItemTypes.SaleItem | | m.LineItemType.Id==NexTow.Client.Framework.UnitsService.LineItemTypes.NonSaleItem))
{ %>    
X
$

然后,用户可以编辑条目,然后单击“更新发票”提交按钮。这将使用POST发布到相同的视图和操作:

[HttpPost]
public ActionResult EditInvoice(List<SalesDocumentLineItem> salesItems)
{
    if (salesItems == null || salesItems.Count == 0)
    {
        return View("ClientError", new ErrorModel() { Description = "Line items required." });
    }

    SalesDocument invoice = null;

    try
    {
        invoice = SomeService.UpdateInvoice();
    }
    catch (Exception ex)
    {
        return HandleControllerException(ex);
    }

    InvoiceModel model = new InvoiceModel();
    model.Document = invoice;

    return View("InvoicePreview", model);
}
[HttpPost]
公共操作结果编辑发票(列出销售项目)
{
如果(salesItems==null | | salesItems.Count==0)
{
返回视图(“ClientError”,new ErrorModel(){Description=“Line items required.”});
}
SalesDocument发票=空;
尝试
{
发票=SomeService.UpdateInvoice();
}
捕获(例外情况除外)
{
返回HandleController异常(ex);
}
InvoiceModel模型=新的InvoiceModel();
模型.单据=发票;
返回视图(“发票预览”,模型);
}

然而,尽管这在旧应用程序中起作用。在新应用程序中,这不起作用。当我们在最终EditInvoice POST操作方法处设置断点时,salesItems集合为空。发生了什么事!?

当您使用
Html.TextBox(字符串,对象)时
,第一个参数用作表单字段的名称。当您将此表单发布回服务器时,MVC会查看操作方法的参数列表,并使用表单字段的名称尝试构建这些参数。在您的情况下,MVC会尝试构建一个
列表

看起来您正在使用“Model.Something”作为表单字段的名称。这可能在过去是有效的,但我猜MVC4中发生了一些变化,以至于框架不再知道您在说什么。幸运的是,有更好的方法

不要使用字符串设置表单字段的名称,而是使用以下强类型HTML帮助程序:

<% for (var i = 0; i < Model.Count; i++) { %>
  <div class="row">
    <%= Html.HiddenFor(model => model[i].LineItemNameId) %>
    <!-- etc... -->
  </div>
<% } %>

模型[i]。LineItemNameId)%>
这些版本的HTML帮助程序使用lambda表达式指向模型中的属性,并说“看到该属性了吗?就在那里?为它生成一个适当的表单字段名。”(好处:因为表达式无论如何都指向属性,所以您不必再指定值——MVC将只使用表达式所表示的属性的值)

由于lambda表达式是C#代码,如果输入错误,将出现编译时错误,如果更改属性名称,Visual Studio的“重命名”功能等工具将起作用


(更详细地介绍了这是如何工作的。)

看看在HTML中生成的表单元素的
name
属性。看起来它们会有点不对劲。我一直看到MVC表单帖子使用
for
循环而不是
foreach
,以及
HTML.TextBoxFor(x=>x[I].Price)
用于输入字段。这为字段提供了唯一的名称,并正确发布了集合。我不知道是否有办法让您的示例工作。这立即解决了我的问题。当我将HTML帮助程序更改为“for”等效项时,它就工作了。MVC4中一定有我忽略的内容,我感谢您的帮助!