开发者

asp.net mvc default model binding problem

I have some problems with ASP.NET MVC’s default model binder. The View contains HTML like this:

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

This is my simplified ‘model’:

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

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

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

All this works fine if the user selects at least the first checkbox (SubDTO[0].Id). The controller ‘receives’ a nicely initialised/bound DTO. However, if the first check box is not selected but only, for example, SubDTO[1].Id the object SubDTOs is null. Can someone please explain this ‘strange’ behaviour and how to overcome it? Thanks.

Best wishes,

Christian

PS:

The controller looks like this:

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

PPS:

My problem is that if I select checkbox SubDTO[0].Id, SubDTO[1].Id, SubDTO[2].Id SubDTOs is initialised. But if I just select checkbox SubDTO[1].Id, SubDTO[2].Id (NOT the first one!!!) Sub开发者_运维知识库DTOs remains null. I inspected the posted values (using firebug) and they are posted!!! This must be a bug in the default model binder or might be missing something.


This behavior is "by design" in html. If a check-box is checked its value is sent to the server, if it is not checked nothing is sent. That's why you get null in your action and you'll not find value in the posted form either. The way to workaround this is to add a hidden field with the same name and some value AFTER the check-box like this:

<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">

In this way if you check the check-box both values will be sent but the model binder will take only the first. If the check-box is not checked only the hidden field value will be sent and you\ll get it in the action instead of null.


I think this post on Scott Hanselman's blog will explain why. The relevant line is:

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.

So, in your case because the first element is not returned (as explained by others as the default behaviour for checkboxes) the entire collection is not being initialized.


Change the markup as follows:

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

What's being returned by your original markup is an unrelated set of parameters, i.e. like calling RedirectToRouteResult Create(SubDTO[0].id, SubDTO[1].id, ..., SubDTO[n].id) which is clearly not what you want, you want an array returned into your DTO object so by giving all the checkboxes the same name the return value to your function will be an array of ids.

EDIT

Try this:

<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">

You have to return something to make sure there is an element for each index, I suspect that any gap will cause a problem so I'd suggest using a 'null' ID, for example 0 or -1 and then process that out later in your code. Another answer would be a custom model binder.

There is always the alternate option of adding a property to your class that takes an array of strings and creates the SubDTO array from that.

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 });
        }
    }
}

or something like that

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜