1

For a minute please ignore the travesty that is this complicated model, and assume you are stuck with it :)

public class Foo
{
   public FooList Foos{get;set;}
}

public class FooList
{
    public object SomeBar {get; set;}
}

public class Bar
{
    public string Name {get;set;}
}

public class AnotherBar
{
    public bool IsCrazy{get;set;}
}

So we will give the Action a Foo and the foo will have a FooList Which contians either Bar or AnotherBar. What SomeBar contains doesn't really matter..it is an object of a few KNOWN types, but we don't know which one...oh and they don't inherit from a common ancestor.

Ok, so when you post json to an action that takes a Foo. the Foo object will be deserialized, but FooList is null. If I create a custom ModelBinder, manually read in the stream and tell JsonConvert to deserialize it. everything works

From what I understand MVC4 uses JsonConvert under the covers. What is the difference here? Why would the built-in deserialization not work and me explicitly using JsonConvert does?

I am probably going to have to bounty this, and I plan on putting as much as I can (500?)

ps. I am not asking for a work around. I really just want to know what is going on to cause the behavior.

Now for the code:

//some sample JSON: {"Foos":{"SomeBar":{"Name":"Insanity"}}}


public ActionResult Test(Foo foo)
{
     //Foo.FooList is null
    return new EmptyResult();
}

public ActionResult BinderTest([ModelBinder(typeof(FooModelBinder))] Foo foo)
{ 
    //Everything is as it should be
    return new EmptyResult();
}

public class FooModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var request = controllerContext.HttpContext.Request;
        request.InputStream.Seek(0, SeekOrigin.Begin);

        var jsonString = new StreamReader(request.InputStream).ReadToEnd();

        Foo foo = JsonConvert.DeserializeObject<Foo>(jsonString);

        return foo;
    }
}

And some client code

$(function () {
        $('#button1').click(function () {
            var data = '{"Foos":{"SomeBar":{"Name":"Insanity"}}}';
            $.post('/home/bindertest', data);
        });

        $('#button2').click(function () {
            var data = '{"Foos":{"SomeBar":{"Name":"Insanity"}}}';
            $.post('/home/test', data);
        });
    });
  • Have you checked the `ModelState` collection for simple binding errors? – asawyer Jul 30 '13 at 17:12
  • @asawyer Yes I have and nothing seems wrong there. –  Jul 30 '13 at 17:14
  • I have encoutered the exact same issue.. seen here. http://stackoverflow.com/questions/17309076/can-i-use-json-net-de-serialization-by-default-with-asp-net-web-api-and-mvc-3 if you just a use JSON convert it works. We ended up having to write a proxy class so not my method looks like this. `MyActionResultMethod([JsonNet] DTO.MyDTO) { ` Fun times... – recneps Jul 30 '13 at 17:28
  • @recneps If you read my question I post that using JsonConvet works. I am trying to find out why :) –  Jul 30 '13 at 17:31
  • It most likely boils down to what the post data looks like. Fire up Fiddler2 and take a look at the raw post. Most likely the problem is incorrect formatting there. – asawyer Jul 30 '13 at 18:01
  • @asawyer I have done that. The data is the exact same. Nothing has changed between the two except in one I use a model binder to manually deserialize the data –  Jul 30 '13 at 18:29
  • Fire up a basic MVC4 site and use the code I provided above. You can easily test it –  Jul 30 '13 at 18:30

1 Answers1

2

The default serializer for Web API controllers (classes inheriting from ApiController) in MVC 4 is Json.Net. However, I believe the default serializer for standard MVC 4 controllers (classes inheriting from Controller) is still the JavaScriptSerializer (for backward compatibility reasons). See this question. So that could very well explain the difference in behavior.

Community
  • 1
  • 1
Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
  • ahhh that makes perfect sense! And here I was under the impression MVC4 as a whole was using Json.net. Thanks! –  Jul 30 '13 at 19:08