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'
});
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'
});
ASP.NET has gone a long way. And it might be the right time to start moving your sites to ASP.NET.
But what happens if you have a big investment in JSP. Will I lose all my JSP skills?
Well ASP.NET is not the same as JSP but the MVC view engine concept can help you retain some of the JSP flavor.
A good MVC View Engine project is SharpTiles this project provides a partial implementation of JSTL and Tiles.
Just take a look at the the SharpTiles. Just as they say SharpTiles if for you if “You are a Java Developer and you don’t like .aspx”