asp.net mvc默认的模型绑定问题

时间:2010-05-12 10:08:00

标签: asp.net-mvc

我对ASP.NET MVC的默认模型绑定器有一些问题。视图包含这样的HTML:

<input name="SubDTO[0].Id" value="1" type="checkbox">
<input name="SubDTO[1].Id" value="2" type="checkbox">

这是我的简化'模型':

public class SubDTO
{
    public virtual string Id { get; set; }
}

public class DTO
{
    public List<SubDTO> SubDTOs { get; set; }

    public DTO()
{
    SubDTOs = new List< SubDTO>();
}
}

如果用户至少选择第一个复选框(SubDTO [0] .Id),则所有这一切都正常。控制器'接收'一个很好的初始化/绑定DTO。但是,如果未选中第一个复选框,但仅限于,例如,SubDTO [1] .Id对象SubDTOs为空。有人可以解释一下这种“奇怪”行为以及如何克服它吗?谢谢。

祝福,

基督教

PS:

控制器如下所示:

     [Transaction]
        [AcceptVerbs(HttpVerbs.Post)]
        public RedirectToRouteResult Create(DTO DTO)
        {
...
}

PPS:

我的问题是,如果我选择复选框SubDTO [0] .Id,SubDTO [1] .Id,SubDTO [2] .Id SubDTOs已初始化。但是,如果我只选择复选框SubDTO [1] .Id,SubDTO [2] .Id(不是第一个!!!)SubDTOs保持为空。我检查了发布的值(使用firebug)并发布了!这必须是默认模型绑定器中的错误,或者可能缺少某些内容。

3 个答案:

答案 0 :(得分:2)

此行为在html中是“按设计”。如果选中复选框,则将其值发送到服务器,如果未选中则不发送任何内容。这就是为什么你在你的行动中得到null并且你也不会在发布的形式中找到价值。解决此问题的方法是在复选框之后添加一个具有相同名称和一些值的隐藏字段,如下所示:

<input name="SubDTO[0].Id" value="true" type="checkbox">
<input name="SubDTO[0].Id" value="false" type="hidden">
<input name="SubDTO[1].Id" value="true" type="checkbox">    
<input name="SubDTO[1].Id" value="false" type="hidden">

这样,如果选中复选框,将同时发送两个值,但模型绑定器仅采用第一个。如果未选中该复选框,则仅发送隐藏字段值,您将在操作中获取该值而不是null。

答案 1 :(得分:1)

更改标记如下:

<input name="SubDTOs" value="<%= SubDTO[0].Id %>" type="checkbox">
<input name="SubDTOs" value="<%= SubDTO[1].Id %>" type="checkbox">

原始标记返回的是一组不相关的参数,比如调用RedirectToRouteResult Create(SubDTO[0].id, SubDTO[1].id, ..., SubDTO[n].id),这显然不是你想要的,你想要一个数组返回你的DTO对象,所以给所有的复选框都一样命名函数的返回值将是一个id数组。

<强> 修改

试试这个:

<input name="SubDTO[0].Id" value="<%= SubDTO[0].Id %>" type="checkbox">
<input name="SubDTO[0].Id" value="false" type="hidden">
<input name="SubDTO[1].Id" value="<%= SubDTO[1].Id %>" type="checkbox">
<input name="SubDTO[1].Id" value="false" type="hidden">

你必须返回一些内容以确保每个索引都有一个元素,我怀疑任何间隙都会导致问题所以我建议使用'null'ID,例如0或-1然后处理稍后在您的代码中。另一个答案是自定义模型绑定器。

总是有一个替代选项,即在类中添加一个属性,该属性接受一个字符串数组并从中创建SubDTO数组。

public List<string> SubDTOIds 
{ 
    get { return SubDTO.Select(s=>s.Id).ToList(); }
    set
    {
        SubDTOs = new List< SubDTO>();
        foreach (string id in value) 
        {
            SubDTOs.Add(new SubDTO { Id = id });
        }
    }
}

或类似的东西

答案 2 :(得分:1)

我认为Scott Hanselman博客上的this帖子将解释原因。相关的一行是:

The index must be zero-based and unbroken. In the above example, because there was no people[2], we stop after Abraham Lincoln and don’t continue to Thomas Jefferson.

因此,在您的情况下,因为没有返回第一个元素(正如其他人所解释的那样是复选框的默认行为),整个集合没有被初始化。