views:

1358

answers:

2

Hi guys

I am having more than a little difficulty trying to debug why MVC is not binding correctly in a given case I have...

Basically, I have my action which receives a complex object which in turn has a complex child object - Activity.Location.State (Where Activity is the complex object that the action expects, Location is a complex child object and State is just a string).

Now I set up a test project which as far as I can tell exactly mimics the actually scenario I have, in this test case the binding works... But in my actually project, the binding to Activity works but not to Location... By putting break points within the Locaiton property I can tell that MVC is retrieving the complex Location object from the Activity, but its not setting any of the properties...

I am trying to debug the issue but I need access to the MVC v2 preview 2 symbols which I can't seem to track down... I would like to see what it is actually doing once it pulls out the location object (for some reason I think it might be failing internally but swallowing the exception).

Any ideas on what I could do here...

Cheers Anthony

UPDATE:

Ok I did what J.W. suggested and directly reference the MVC project...

I found the problem and there was one very small difference that I overlooked... As I result I found out that MVC does not currently support multiple levels of INTERFACE inheritance when it comes to model binding... See the following...

//MODEL
public class Location : ILocation
{
    ...
}

public interface ILocation : ILocationCore
{
    ...
}

public interface ILocationCore    //In my sample I didn't have this second level interface
{
    ...
    //MVC doesn't find any of these properties
    ...
}


public class Activity : IActivity
{
    ...
}

public interface IActivity : IActivityCore
{
    ILocation Location { get; set; }   //MVC finds this and reads its meta type as an ILocation
    //Also the implementation of this Location within Activity will always return a instance - our IoC takes care of that, so MVC should never have to create the instance
}

public interface IActivityCore
{
    ...
}

//CONTROLLER
public ActionResult Create(Activity activity)
{
}

Hence what I have found is that MVC finds the Location and reads its meta type as an ILocation, but when GetModelProperties is run within the DefaultModelBinder the following occurs -

    protected virtual PropertyDescriptorCollection GetModelProperties(ControllerContext controllerContext, ModelBindingContext bindingContext) {
        return GetTypeDescriptor(controllerContext, bindingContext).GetProperties();
        //This return no properties
    }

    protected virtual ICustomTypeDescriptor GetTypeDescriptor(ControllerContext controllerContext, ModelBindingContext bindingContext) {
        return new AssociatedMetadataTypeTypeDescriptionProvider(bindingContext.ModelType).GetTypeDescriptor(bindingContext.ModelType);
        //bindingContext.ModelType - is ILocation
    }

Hence I am assuming at this point that TypeDescriptionProvider doesn't support this style of inheritance, which i am quite surprised by. Also looking at the v1 source it looks like this was introduced with v2 - but v1 mightn't have been able to support what I am trying to do anyway.

I wouldn't say that this is really a bug, but I tried replacing my the interfaces with concrete classes and it worked fine. Hence the behavior isn't really what I would expect and is a little inconsistent.

Any thoughts??? I would have thought that this inheritance was not fairly standard but would occur often enough to be catered for. Thanks for the reply.

Cheers

+2  A: 

I would simply reference to the asp.net mvc2 source code published in codeplex. I did that, it's very straightforward.

It will give you much better understanding when you debugging through the source code.

J.W.
+38  A: 

Turns out this behavior is by design due to how interface inheritance works. Interfaces do not define implementations, thus ILocation doesn't "inherit" the properties of ILocationSource. Rather, ILocation only defines what a concrete implementation must implement.

For the full details including the section of the CLI (Common Language Infrastructure) spec which defines this behavior, check out: http://haacked.com/archive/2009/11/10/interface-inheritance-esoterica.aspx

Haacked
I think Brad Wilson's comment is how I always remember the difference and expect the appropriate behavior."Can Do vs Is A"
Ian Patrick Hughes