Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

Action argument of IList<T> will be bound as Null instead of an empty List<T> #1579

Closed
harshgMSFT opened this issue Nov 18, 2014 · 8 comments

Comments

@harshgMSFT
Copy link
Contributor

Today CollectionModelBinder returns false if a value provider cannot provide a value, it is the mutable object binder which creates a model for it.
Since it is the CollectionModelBinder which is responsible for binding collections, it should be the one which creates empty object and not let it slip for other model binders.

@yishaigalatzer
Copy link
Contributor

What are the side effects here, and how is it different from MVC 5/Web API?

@harshgMSFT
Copy link
Contributor Author

The problem is since today CollectionModelBinder returns false, the MutableObjectBinder takes over and creates empty collection, going forward since the mutable object binder has to deal with object creation based on IBinderMetadata (to support uber binding), it will now in addition to creating top level object will try to bind inner properties and will have all sorts of problems.
Even design wise for collection models CollectionModelBinder should return true and the model binding process should stop there.

is it different from MVC 5/Web API?
Web api and MVC did not create the object if there was no value.
Mvc 6 today does create an empty collection.

@yishaigalatzer yishaigalatzer modified the milestones: 6.0.0-rc1, 6.0.0-beta2 Nov 26, 2014
@danroth27 danroth27 modified the milestones: 6.0.0-beta2, 6.0.0-rc1 Dec 11, 2014
@yishaigalatzer yishaigalatzer modified the milestones: 6.0.0-rc1, 6.0.0-beta3 Jan 14, 2015
@yishaigalatzer
Copy link
Contributor

, it will now in addition to creating top level object will try to bind inner properties and will have all sorts of problems.

@harshgMSFT please provide concrete repro for what is going to break. If you think this is critical for Beta3 milestone please raise a flag

@harshgMSFT
Copy link
Contributor Author

Ok .. sorry about not including a code sample : here is the actual issue ( after the Uber dust has settled 😄 ).

public class HomeController : Controller 
{
           public void Action(IList<Model>  model)
           {
                  // Does something.
           }

        public override void OnActionExecuting(ActionExecutingContext context)
        {
            // context.ActionArguments["model"] is null here.
        }
}

and consider a URL like so :

http://localhost/home/Action

With no value provider having a value for Model or its properties, what happens is the model object created is null.

This is because GenericModelBinder ( which is the entry point for binding any collection based model) or more specifically CollectionModelBinder, does not create the model when it does not see a value with a value provider.

This is contrary to what what we do with models in MVC 6.0. (we always create them).
Ideally the CollectionModelBinder should have returned true after creating a default (non null) collection.

This is not a MUST fix as the user scenario is not broken but this provides an inconsistency in the system.

@yishaigalatzer yishaigalatzer changed the title CollectionModelBinder does not create the model if there is no value provider providing a value. Action argument of IList<T> will be bound as Null instead of an empty List<T> Jan 26, 2015
@danroth27 danroth27 modified the milestones: 6.0.0, 6.0.0-rc1 Mar 16, 2015
@bgeihsgt
Copy link

We just ran into this in our project and broke a core assumption we had about MVC. In the beta 3 code, we had different behavior whether an action array parameter was null (when the param was not on the URL) or empty (the param is on the URL but empty). When we changed to beta 4, the array parmeter is always empty whether you specify anything on the URL or not. This caused a bug in our code. We've updated our code based on the new behavior, but wanted to let you know that this is a change that broke compat with older versions of MVC.

@dougbu
Copy link
Member

dougbu commented May 11, 2015

@bgeihsgt we need to confirm the MVC 5 null versus empty collection behaviour and should probably align with that -- not the behaviour in earlier MVC 6 releases. However there's another consistency issue that may be all-important: Action parameters of complex types are always non-null but will be uninitialized if the request contains no data.

So, we'll make a call here and pick back-compatibility or consistency. Either way you'll see a resolution on this issue. If the result is a further change, we'll also use the Announcements repo.

@harshgMSFT
Copy link
Contributor Author

@bgeihsgt thanks for letting us know, as @dougbu said, we will need to pick back-compat or consistency. MVC 5.0 behavior for collections was to not create the collection (have them null) if there was no data on wire. (hence the back-compat vs consistency discussion :).

rynowak added a commit that referenced this issue May 19, 2015
This change treats 'top-level' collection-type models similarly to
top-level POCO model - namely that they will always be instantiated even
if there's no data to put inside.
rynowak added a commit that referenced this issue May 21, 2015
This change treats 'top-level' collection-type models similarly to
top-level POCO model - namely that they will always be instantiated even
if there's no data to put inside.
rynowak added a commit that referenced this issue May 22, 2015
This change treats 'top-level' collection-type models similarly to
top-level POCO model - namely that they will always be instantiated even
if there's no data to put inside.
@rynowak
Copy link
Member

rynowak commented May 22, 2015

8f38650

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants