0

我的 ASP.NET 站点的一个特定部分存在一些问题。此页面本质上是用户编辑发票然后发布更改的地方。

在这一点上,我正在重新编写现有页面,这很有效。除了另一个是旧的 MVC 3 之外,我无法弄清楚有什么区别。

当我第一次进入 EditInvoice 操作时:

public ActionResult EditInvoice()
{
    SalesDocument invoice = null;

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

    return View("InvoiceEdit", invoice.LineItems);
}

“InvoiceEdit”视图的模型是 List

现在视图加载正常,并在一个表单中显示所有文档行项目:

<%@ 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>

然后,这为用户提供了编辑条目的能力,然后用户单击“更新发票”提交按钮。这使用 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);
}

但是,尽管这在旧应用程序中有效。在新版本中,这不起作用。当我们在最终的 EditInvoice POST 操作方法处断点时,salesItems 的集合为 NULL。怎么了!?

4

1 回答 1

2

When you use Html.TextBox(string, object), the first argument is used as the name of the form field. When you post this form back to the server, MVC looks at your action method's argument list and uses the names of the form fields to try and build those arguments. In your case, it tries to build a List<SalesDocumentLineItem>.

It looks like you're using "Model.Something" as the names of your form fields. This probably worked in the past, but I'm guessing something changed in MVC4 such that the framework doesn't know what you're talking about anymore. Fortunately, there's a better way.

Instead of setting the name of the form field using a string, use the strongly-typed HTML helpers like this:

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

These versions of the HTML helpers use a lambda expression to point to a property in your model and say "See that property? That one right there? Generate an appropriate form field name for it." (Bonus: Since the expression is pointing at the property anyway, you don't have to specify a value anymore -- MVC will just use the value of the property the expression represents)

Since lambda expressions are C# code, you will get a compile-time error if you make a typo, and tools like Visual Studio's "Rename" feature will work if you ever change the property's name.

(This answer goes into more detail on exactly how this works.)

于 2013-07-08T21:48:54.390 回答