【问题标题】:Model displays properly but posts back null模型显示正确但回发 null
【发布时间】:2013-01-24 05:40:32
【问题描述】:

我使用强类型模型填充了局部视图。在这种局部视图中是一种形式。当我提交表单时,它告诉我模型中的对象为空,即使它们不是因为部分视图基于同一模型渲染了所有元素。

更具体地说,我在传回所有复选框时遇到了麻烦。如果您查看我的控制器,您会发现我检查CompanyOptions 是否为空,并且每次我运行程序时它都会打印STUFF IS NULL,这意味着它是空的。

型号:

public class Company
{
    public string Name { get; set; }
    public string DatabaseName { get; set; }
    public CompanyOptions CompanyOptions;
}

 public class CompanyOptions
    {

        public CompanyLicenseOptions CompanyLicenseOptions { get; set; }
    }

 public class CompanyLicenseOptions
    {
        public List<CompanyLicenseOption> CompanyLicenseOptionsList;
}

查看:

@using (Html.BeginForm("Action", FormMethod.Post))
{
    for (int i = 0; i < Model.CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList.Count; i++)
    {
        @Html.CheckBoxFor(model => model.CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[i].IsLicensed, checkboxHtmlAttributes);
        <label for="@Model.CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[i].LicenseName">@Model.CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[i].LicenseName</label>                                                                                       
        <br/>
    } 
    @Html.HiddenFor(model => model.DatabaseName)
    <input id="submit_licenses" type="submit" style="display:none;" />
}

控制器:

       [HttpPost]
        public void Action(Company model)
        {
            System.Diagnostics.Debug.WriteLine("STUFF:" + model.DatabaseName);
            if(model.CompanyOptions!=null)foreach (var item in model.CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList) System.Diagnostics.Debug.WriteLine("STUFF:" + item);
            else System.Diagnostics.Debug.WriteLine("STUFF IS NULL");
        }

生成的 HTML:

<input class="licenses" data-val="true" disabled="" id="CompanyOptions_CompanyLicenseOptions_CompanyLicenseOptionsList_0__IsLicensed" name="CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[0].IsLicensed" type="checkbox" value="true" /><input name="CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[0].IsLicensed" type="hidden" value="false" />

不相关的 JS

$('#save_licenses').click(function () {
        swap_licenses(true);
        $('#submit_licenses').click();
    });

发布:

Request URL:http://localhost:3080/Controller/Action
Request Method:POST
Status Code:200 OK

CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[0].IsLicensed:false
    CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[1].IsLicensed:false
    CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[2].IsLicensed:false
    CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[3].IsLicensed:false
    CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[4].IsLicensed:false
    CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[5].IsLicensed:false
    CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[6].IsLicensed:false
    CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[7].IsLicensed:false
    CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[8].IsLicensed:false
    CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[9].IsLicensed:false
    CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[10].IsLicensed:false
    CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[11].IsLicensed:false
    CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[12].IsLicensed:false
    DatabaseName:myDb

【问题讨论】:

  • 我认为@Html.CheckBoxFor(model =&gt; model.CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[i].IsLicensed, checkboxHtmlAttributes); 会产生模型绑定器所期望的错误命名约定。复选框呈现的 HTML 标记是什么?
  • 您的提交按钮似乎被隐藏了 (style="display:none;") 那么您是如何提交此表单的呢?你在使用一些javascript吗?阿贾克斯?还有什么?你能展示你提交这个表单的真实代码吗?
  • @AdrianRefuerzo,不,它不会产生错误的命名约定。
  • 是的,我正在为按钮使用 JS。
  • @Johannes,那你还在等什么?我们无法读懂你的想法。这个js在哪里?有机会看到吗?

标签: c# asp.net-mvc-3 forms razor


【解决方案1】:
<input class="licenses" data-val="true" disabled="" id="CompanyOptions_CompanyLicenseOptions_CompanyLicenseOptionsList_0__IsLicensed" name="CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[0].IsLicensed" type="checkbox" value="true" /><input name="CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[0].IsLicensed" type="hidden" value="false" />

这是你的问题:

disabled=""

你的复选框是disabled,所以不会有任何东西被发送到服务器。这就是 HTML 的工作原理。禁用的元素永远不会被发送。所以去掉这个属性。

如果您想阻止用户修改值,但初始值被发送到服务器,请使用readonly 属性,而不是disabled

我在您的代码中看到的另一个问题是CompanyLicenseOptionsList 集合字段。它应该是具有公共 getter 和 setter 的属性:

public class CompanyLicenseOptions
{
    public List<CompanyLicenseOption> CompanyLicenseOptionsList { get; set; }
}

CompanyOptions 字段也是如此(您已将其定义为字段,而它应该是属性):

public class Company
{
    public string Name { get; set; }
    public string DatabaseName { get; set; }
    public CompanyOptions CompanyOptions { get; set; }
}

更新:

现在您已经解决了缺少 getter 和 setter 的问题,剩下的就是确保干预此对象图中的所有模型都具有默认(无参数)构造函数。如果您希望它们显示为动作参数,这是一个要求,因为否则默认模型绑定器将不知道如何实例化它们。如果由于某种原因您无法为所有对象添加默认构造函数,我强烈建议您修改对象层次结构并立即开始使用视图模型。

【讨论】:

  • 我提交表单时并没有禁用它,但出于测试目的,我将其完全删除,但问题仍然存在。
  • 您能展示一下您在 FireBug 中看到的内容吗? POST 请求的确切负载?
  • 好吧,POST 有效负载似乎很好,并且尊重命名约定。我已经用您的代码注意到的另一个问题更新了我的答案。
  • 用那个 getter/setter 很好。不幸的是,行为没有改变。
  • CompanyLicenseOption 类中的 IsLicensed 布尔字段怎么样?你确定它有一个公共的 getter 和 setter 吗?顺便说一句,我还注意到您的控制器操作是void。通常控制器动作应该返回ActionResult。我不认为这与您的问题有关,我只是为了良好的做法而提及它。
【解决方案2】:

您应该使用 foreach 循环而不是简单的 for,这样:

@using (Html.BeginForm("Action", FormMethod.Post))
{
    foreach (var option in Model.CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList)
    {
        @Html.CheckBoxFor(o => o.IsLicensed, checkboxHtmlAttributes);
        <label for="@option.LicenseName">@option.LicenseName</label>                                                                                       
        <br/>
    } 
    @Html.HiddenFor(model => model.DatabaseName)
    <input id="submit_licenses" type="submit" style="display:none;" />
}

【讨论】:

    【解决方案3】:

    由于所有这些复选框的端点都是List&lt;T&gt;,因此您需要确保在使用前对其进行实例化:

    public class CompanyOptions
    {
        public CompanyLicenseOptions CompanyLicenseOptions { get; set; }
    }
    public class CompanyLicenseOptions
    {
        public List<CompanyLicenseOption> CompanyLicenseOptionsList;
        public CompanyLicenseOptions() 
        {
             CompanyLicenseOptionsList = new List<CompanyLicenseOption>();
        }
    }
    

    编辑:为了确保读者获得正确的答案并避免混淆,我复制了上面的 OP 代码。

    【讨论】:

    • -1,默认模型绑定器无法使用字段。只有属性。所以你用这种方法得到的只是一个空集合而不是 NULL。您将永远无法绑定来自视图的值。有关详细信息,请参阅我的答案。
    • 我刚刚使用了 OP 中提供的内容,Darin。我很欣赏你在 SO 上张贴的原始能量
    • 但是OP提供的内容是错误的!所以使用它是错误的。这就是重点。这就是为什么我不赞成你的回答。因为它没有回答问题。
    • 你的也没有,但人们在有足够的机会反思和审查之前不会投反对票。
    • 是什么让您认为我的帖子没有回答问题?我已经明确指出了 OP 显示的代码存在的问题。他使用字段而不是属性,并且他的对象没有无参数构造函数。这就是他的问题的根源,也是他在控制器操作中获得 NULL 的原因。就您的更新而言,它仍然存在问题。请参阅我对您的回答的第一条评论。
    猜你喜欢
    • 2017-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-26
    • 2023-02-02
    • 1970-01-01
    • 2020-05-08
    • 2020-08-31
    相关资源
    最近更新 更多