【问题标题】:View Model posting null properties back to controller查看模型将空属性发布回控制器
【发布时间】:2013-10-09 09:38:47
【问题描述】:

在我的索引页面上,我有一个搜索表单,允许用户根据 3 个搜索条件提取信息。当搜索结果从控制器返回时,它们将作为 List 对象返回,该对象是视图模型的属性,并显示在搜索表单下方的表格中。

然后用户可以选择他们想要更改的记录。他们将通过选中指定记录旁边的复选框来执行此操作。然后,使用搜索框下方显示的表单,输入新值并点击“更新”按钮以保存更改。 (我们这样做是为了让用户无需逐行更改表格即可进行大规模更新)

这是一个屏幕截图来说明我的意思。这是用户点击“搜索”按钮后页面的外观:

当用户点击“搜索”时,表单被指示回发到控制器的 Index 方法。当用户点击“克隆选定项目”时,表单被指示回发到同一控制器中的“更新”方法。但是,问题是返回到“更新”方法的视图模型对象完全为空,除了放在New TerritoryNew DescriptionNew Effective Date 文本框中的值。

我对 ASP MVC 比较陌生,因此我们将不胜感激任何帮助/建议。不知道为什么视图模型会使用“搜索”按钮从控制器发回相同的值,但不会使用“克隆选定项目”按钮。

视图模型(这是返回给控制器的内容)

public class ZipCodeIndex
{
    public List<ZipCodeTerritory> zipCodeTerritory { get; set; }
    [DisplayName("Zip Code")]
    public string searchZip { get; set; }
    [DisplayName("Effective on this date")]
    public string searchDate { get; set; }
    [DisplayName("State")]
    public string searchState { get; set; }
    [DisplayName("New Territory")]
    public string newTerritory { get; set; }
    [DisplayName("New Description")]
    public string newDescription { get; set; }
    [DisplayName("New Effective Date")]
    public string newEffectiveDate { get; set; }

    public ZipCodeIndex() 
    {
        zipCodeTerritory = new List<ZipCodeTerritory>();
    }
}

模型(这会填充视图模型中的列表对象)

[MetadataType(typeof(ZipCodeTerritoryMetaData))]
public partial class ZipCodeTerritory
{
    public bool Update { get; set; }
}

public partial class ZipCodeTerritory
{
    public string ChannelCode { get; set; }
    public string DrmTerrDesc { get; set; }
    public string IndDistrnId { get; set; }
    public string StateCode { get; set; }
    public string ZipCode { get; set; }
    public System.DateTime EndDate { get; set; }
    public System.DateTime EffectiveDate { get; set; }
    public string LastUpdateId { get; set; }
    public Nullable<System.DateTime> LastUpdateDate { get; set; }
    public int Id { get; set; }
}

查看

@model Monet.ViewModel.ZipCodeIndex

    @using(Html.BeginForm("Index", "ZipCodeTerritory", FormMethod.Post))
    {
        <div id="searchBox" class="boxMe">
            <div id="zipBox">
                @Html.Raw("Zip Code")
                @Html.TextAreaFor(model => model.searchZip, new { style = "width: 300px;", placeholder = "Enter up to 35 comma separated zip codes" })
            </div>
            <div id="dateBox">
                @Html.LabelFor(model => model.searchDate)
                @Html.TextBoxFor(model => model.searchDate, new { style="width: 80px;"})
            </div>
            <div id="stateBox">
                @Html.LabelFor(model => model.searchState)
                @Html.TextBoxFor(model => model.searchState, new { style = "width: 25px;" })
                <button type="submit">Search</button>
            </div>
        </div>
        <div id="errorStatus">
            @ViewBag.ErrorMessage            
        </div>
        <div style="clear: both;"></div>
    }

<br/>
@Html.ActionLink("Create New", "Create")
<br/>

@if (Model != null)
{
    using(Html.BeginForm("Update", "ZipCodeTerritory", FormMethod.Post))
    {
        <div id="cloneBox">
            @Html.LabelFor(model => model.newTerritory)
            @Html.TextBoxFor(model => model.newTerritory, new { style="width: 30px;padding-left:10px;"})
            @Html.LabelFor(model => model.newDescription)
            @Html.TextBoxFor(model => model.newDescription, new { style = "width: 250px;padding-left:10px;" })  
            @Html.LabelFor(model => model.newEffectiveDate)     
            @Html.TextBoxFor(model => model.newEffectiveDate, new { style = "width: 80px;padding-left:10px;" })   
            <button type="submit">Clone Selected Items</button>                      
        </div>
    }    

    <table id="thetable" class="tablesorter" >
        <thead>
            <th></th>
            <th>Channel</th>
            <th>Territory</th>
            <th>Description</th>
            <th>State</th>
            <th>Zip</th>
            <th>Effective</th>
            <th>End Date</th>
            <th>Last Update By</th>
            <th>Last Update Date</th>
            <th></th>
        </thead>
        <tbody>
            @foreach (var item in Model.zipCodeTerritory)
            {
                <tr>
                    <td>@Html.CheckBoxFor(model => item.Update)</td>
                    <td>
                        @Html.DisplayFor(model => item.ChannelCode)
                    </td>
                    <td>
                        @Html.DisplayFor(model => item.IndDistrnId)
                    </td>
                    <td>
                        @Html.DisplayFor(model => item.DrmTerrDesc)
                    </td>
                    <td>
                        @Html.DisplayFor(model => item.StateCode)
                    </td>
                    <td>
                        @Html.DisplayFor(model => item.ZipCode)
                    </td>
                    <td>
                        @Html.DisplayFor(model => item.EffectiveDate)
                    </td>
                    <td>
                        @Html.DisplayFor(model => item.EndDate)
                    </td>
                    <td>
                        @Html.DisplayFor(model => item.LastUpdateId)
                    </td>
                    <td>
                        @Html.DisplayFor(model => item.LastUpdateDate)
                    </td>
                    <td>
                        @Html.ActionLink("Edit", "Edit", new { id = item.Id })
                    </td>
                </tr>
            }
        </tbody>
    </table>    
}

控制器

    public ViewResult Index(ZipCodeIndex search)
    {
        try
        {
            //If search criteria is null page is loading for the first time so send blank view
            if (String.IsNullOrWhiteSpace(search.searchZip) &&
                String.IsNullOrWhiteSpace(search.searchDate) &&
                String.IsNullOrWhiteSpace(search.searchState))
            {
                return View();
            }

            //Determine if necessary search criteria has been sent
            if (String.IsNullOrWhiteSpace(search.searchZip) && String.IsNullOrWhiteSpace(search.searchState))
            {
                ViewBag.ErrorMessage = "Either State or Zip Code Must be Specified";
                return View(search);
            }

            DateTime effectiveDate;

            //Convert date string to DateTime type
            if (String.IsNullOrWhiteSpace(search.searchDate))
            {
                effectiveDate = DateTime.MinValue;
            }
            else
            {
                effectiveDate = Convert.ToDateTime(search.searchDate);
            }

            //Conduct search by State Code/Date alone
            if (String.IsNullOrWhiteSpace(search.searchZip))
            {
                search.zipCodeTerritory = (from z in db.ZipCodeTerritory
                                           where z.StateCode.Equals(search.searchState) &&
                                                 z.EffectiveDate >= effectiveDate
                                           select z).ToList();
                return View(search);
            }

            //Zip codes have been requested to conduct zip search
            string[] zipArray;

            //Create array and remove white spaces
            zipArray = search.searchZip.Split(',').Distinct().ToArray();
            for (int i = 0; i < zipArray.Length; i++)
            {
                zipArray[i] = zipArray[i].Trim();
            }

            //Determine if state code is being used in search
            if (String.IsNullOrWhiteSpace(search.searchState))
            {
                foreach (var zip in zipArray)
                {
                    var item = from z in db.ZipCodeTerritory
                               where z.ZipCode.Equals(zip) &&
                                      z.EffectiveDate >= effectiveDate
                               select z;
                    search.zipCodeTerritory.AddRange(item);
                }
            }
            else
            {
                foreach (var zip in zipArray)
                {
                    var item = from z in db.ZipCodeTerritory
                               where z.ZipCode.Equals(zip) &&
                                      z.EffectiveDate >= effectiveDate &&
                                      z.StateCode.Equals(search.searchState)
                               select z;
                    search.zipCodeTerritory.AddRange(item);
                }
            }
        }
        catch (DbEntityValidationException dbEx)
        {
            ViewBag.ErrorMessage = "An error has occurred, we apologize for the incovenience. IT has been notified and will resolve the issue shortly.";
            SendEmail.ErrorMail(Common.ErrorCheck.CombineDbErrors(dbEx));
        }
        catch (Exception ex)
        {
            ViewBag.ErrorMessage = ErrorCheck.FriendlyError(ex);
            SendEmail.ErrorMail(ex);
        }

        return View(search);
    }


    [HttpPost]
    public ActionResult Update(ZipCodeIndex updateZip)
    {
        foreach (var zipCode in updateZip.zipCodeTerritory)
        {
            if (zipCode.Update)
            {
                try
                {
                    if (!string.IsNullOrEmpty(updateZip.newTerritory)) zipCode.IndDistrnId = updateZip.newTerritory;
                    if (!string.IsNullOrWhiteSpace(updateZip.newDescription)) zipCode.DrmTerrDesc = updateZip.newDescription;
                    if (!string.IsNullOrWhiteSpace(updateZip.newEffectiveDate)) zipCode.EffectiveDate = Convert.ToDateTime(updateZip.newEffectiveDate);

                    db.Entry(zipCode).State = EntityState.Modified;
                    db.SaveChanges();
                }
                catch (DbEntityValidationException dbEx)
                {
                    ViewBag.ErrorMessage = "An error has occurred, we apologize for the incovenience. IT has been notified and will resolve the issue shortly.";
                    SendEmail.ErrorMail(Common.ErrorCheck.CombineDbErrors(dbEx));
                }
                catch (Exception ex)
                {
                    ViewBag.ErrorMessage = "An error has occurred, we apologize for the incovenience. IT has been notified and will resolve the issue shortly.";
                    SendEmail.ErrorMail("Zip Code not updated: " + zipCode.ToString() + " |MESSAGE| " + ex.Message);
                }
            }
        }

        return RedirectToAction("Index", updateZip);
    }

编辑

我已将以下隐藏字段添加到第二个表单(发布到 Update 方法)。这将发回搜索条件,但 List 对象仍为空。

@if (Model != null)
{
    using(Html.BeginForm("Update", "ZipCodeTerritory", FormMethod.Post))
    {
        @Html.HiddenFor(model => model.searchZip)
        @Html.HiddenFor(model => model.searchDate)
        @Html.HiddenFor(model => model.searchState)
        @Html.HiddenFor(model => model.zipCodeTerritory)

        <div id="cloneBox">

【问题讨论】:

  • 是你的 Model.zipCodeTerritory 没有被返回吗?
  • 不,返回的是 ZipCodeIndex 视图模型。我会在帖子中记下这一点,谢谢。
  • 抱歉,您希望查看模型的哪一部分不是。底部的列表还是其他东西。
  • 我希望列表出现在Update 方法中,以及搜索框中的任何内容(zip、状态、日期)中。基本上,当页面回发到 Update 方法时,从 Index 控制器方法发回视图的所有内容都需要存在。从Index 发回的内容与发送到Update 的内容之间的唯一区别应该是每个 ZipCodeTerritory 列表对象的布尔字段是否已设置为 true(通过表中的复选框)。
  • 好吧,我认为对于搜索条件,它们采用不同的形式是不会喜欢的。那么对于列表显示for不转发到服务器,您需要在其旁边放置另一个隐藏字段以保存数据。我会尝试一两个并测试它。如果其中任何一个有帮助,请把它放在答案中。

标签: c# .net asp.net-mvc asp.net-mvc-3 asp.net-mvc-4


【解决方案1】:

当我们使用 Html Helper 方法Html.DisplayFor() 时,它只是将数据显示为纯文本。您可以通过浏览器中的查看页面资源进行检查。你所要做的就是使用Html.HiddenFor helper 方法来绑定你发布后需要的数据。或者你也可以使用 JQuery.Ajax

绑定数据

【讨论】:

    【解决方案2】:

    好吧,如果添加 hiddenfor 不起作用,我会尝试使其成为这样。

    @for (int i = 0; i < Model.OrdItems.Count; i++)
    {
    
    @Html.DisplayFor(model => model.zipCodeTerritory[i].channelCode)@Html.HiddenFor(model => model.zipCodeTerritory[i].channelCode)
    @Html.DisplayFor(model => model.zipCodeTerritory[i].zipCode)@Html.HiddenFor(model => model.zipCodeTerritory[i].zipCode)
    
    }
    

    【讨论】:

    • 我仍然需要能够更改 zipCodeTerritory 列表项的布尔属性。
    • 你应该还是可以的,只是@Html.CheckBoxFor(model =>model[zipCodeTerritory[i].update)
    【解决方案3】:

    以上帖子是解决问题的低效且不正确的方法。 ASP.NET MVC 在模型绑定过程中保留并使用“模型”一词作为关键字。您需要在操作结果参数中将名称“搜索”更改为“模型”。这应该可以解决您的搜索数据不发回的问题。

    【讨论】:

      【解决方案4】:

      这没什么,只是当您在控制器中返回视图的实际结果时,然后创建该模型的对象并将其仅传递给视图。

      【讨论】:

        【解决方案5】:

        转到App_start 中的RouteConfig.cs,然后您可以在RegisterRoutes 方法中正确地看到url:{controller}/{action}/{id}。浏览器会走这条路线。您的编辑操作是否有输入参数调用id?可能名字不一样。

        【讨论】:

          【解决方案6】:

          我建议尝试使用 KnockoutJS,从服务器发回实际数据会更容易,刚刚更新。 如果您需要示例,请告诉我,我很乐意提供一些示例。

          如果这不是一个选项 - 注意你创建的表单(BeginForm)里面有什么,因为你想要的大部分都不在里面,所以它不会在 post 时提交给控制器。

          【讨论】:

          • 他在使用 knockoutJS 时仍然会遇到同样的问题
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-08-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多