Binding problem when Sending JSON object to MVC3

25. May 2012 16:59 by Mrojas in ASP.NET, Razor, Visual Studio  //  Tags: , , ,   //   Comments (0)

After a frustrating couple of hours trying to determine WHY WHY my object did not bind with MVC3 I finally found why.

The story began like this.

I have a very simple method in a controller. Something like this:

 

public class Form1Controller : Controller
    {
        //
        // GET: /Form1/

        public ActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public ActionResult DoButton1(Person zzz)
        { 
            System.Diagnostics.Debug.WriteLine(zzz.Name);
            return Json(data: "Good Test");
        }
   
       

    }
 
And I called that code with a jquery Statement like:
var person= JSON.stringify({ Name: "Mauricio", LastName: "Rojas" });              $.ajax({                                    
                    url: "/Form1/DoButton1/",
                    type: "POST",
                    dataType: "json",
                    data: person,
                    success: function () {
                        alert("OK");
                    },
   
                });
 
But!!! (maybe you already saw the obvious mistake) no matter what I sent, the Person object was not bind.
The action method got called but I was not able to see the sent values. I used Chrome developer tools and the network that show the
values I had modified.
SO WHYYYYY!!!!
I tried to debug the MVC code, but VS studio could not load the pdb, something I get that I still not sure why.
So how could I intercept what was happening? Simple with a ModelBinder.
A ModelBinder is class that is used to bind your request to a model object.
So I went to the Global.asax file and register my binder, and set some breakpoints.
//Code in Global.asax to register a Person Binder
    protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            ModelBinders.Binders.Add(typeof(Person), new PersonBinder());
            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
        }

    public class PersonBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var contentType = controllerContext.HttpContext.Request.ContentType;
            if (!contentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
                return (null);

            string bodyText;

            using (var stream = controllerContext.HttpContext.Request.InputStream)
            {
                stream.Seek(0, SeekOrigin.Begin);
                using (var reader = new StreamReader(stream))
                    bodyText = reader.ReadToEnd();
            }

            if (string.IsNullOrEmpty(bodyText)) return (null);

            var xx = new JavaScriptSerializer().Deserialize<Person>(bodyText);

            return xx;
        }
    }
 
And voila!! the content type I was getting was something like:application/x-www-form-urlencoded
 
So I just added the content type parameter to my javascript code:
$.ajax({                                    
                    url: "/Form1/DoButton1/",
                    type: "POST",
                    dataType: "json",
                    data: viewModelStr,
                    success: function () {
                        alert("inside");
                    }//,
                    contentType: 'application/json; charset=utf-8' 
                });