I am making this ajax call:
$.ajax({
url: "/test/whatever",
type: 'post',
contentType: 'application/json'
data: {"fieldone":'test',"fieldtwo":'',"fieldthree":null,"fieldfour":'test'}
});
in the controller I have:
[HttpPost]
public string Whatever(MyModel object)
{
//fieldone, fieldtwo and fieldthree are all type string
//at this point:
// object.fieldone contains the string 'test'
// object.fieldtwo is NULL, but WHY?! and how can I have it correctly deserialize to blank string
// object.fieldthree is correctly null, which is fine
// I have no fieldfour in my object, so it is ignored, that makes sense.
// object.newfield is correctly null, because I didn't pass a value for it in my JS
}
So, does anyone know why blank strings are turning into nulls in this case? I found this post which talks about a bug in javascriptserializer for nullable properties:
http://blog.js-development.com/2012/02/aspnet-mvc3-doesnt-deserialize-nullable.html
But my case is even simpler than that, I just want to deseralize and object that contains descriptive fields, some of which might be blank strings.
I need to tell the difference between blank strings and nulls so that I can throw an exception if I get any nulls (my client js code isn't in sync with the c# object ususally when this happens and I want to know about it).
public class MyCustomModelBinder : IModelBinder
{
private IModelBinder fallbackModelBinder;
public MyCustomModelBinder(IModelBinder fallbackModelBinder)
{
this.fallbackModelBinder = fallbackModelBinder;
}
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
//if it's a GET or content-type is not json, then use the built in one. If ModelType is System.String this the json object should deserializes into separate strings rather than a class, the built in one does this for you
if (controllerContext.HttpContext.Request.HttpMethod.Equals("GET", StringComparison.InvariantCultureIgnoreCase) || !controllerContext.HttpContext.Request.ContentType.ToString().Contains("json") || bindingContext.ModelType.ToString()=="System.String")
{
return this.fallbackModelBinder.BindModel(controllerContext, bindingContext);
}
else
{
//ONLY do this for POST,PUT,DELETE requests that transmit application/json
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);
// JsonSerializerSettings settings = new JsonSerializerSettings();
// settings.MissingMemberHandling = Newtonsoft.Json.MissingMemberHandling.Ignore;
return JsonConvert.DeserializeObject(bodyText, bindingContext.ModelType);
}
}
}