Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

string.empty converted to null when passing JSON object to MVC Controller

I'm passing an object from client to server. Properties of the object which are represented as string.empty are being converted to null during this process. I was wondering how to prevent this when the objects type supports string.empty.

enter image description here

console.log("DataToPost:", dataToPost);  $.ajax({     type: "POST",     contentType: 'application/json'     url: "../../csweb/Orders/SaveOrderDetails/",     data: dataToPost,     success: function (result) {         console.log(result);     },     error: function (e) {         console.error(e);     } }); 

enter image description here

My model includes nullable DateTime objects. I cannot force all nulls to string.empty on the server.

I am using AutoMapper, so I would prefer not to have to inspect properties individually on the server.

like image 449
Sean Anderson Avatar asked Oct 04 '12 19:10

Sean Anderson


2 Answers

This is a MVC feature which binds empty strings to nulls.

This logic is controlled with the ModelMetadata.ConvertEmptyStringToNull property which is used by the DefaultModelBinder.

You can set the ConvertEmptyStringToNull with the DisplayFormat attribute

public class OrderDetailsModel {     [DisplayFormat(ConvertEmptyStringToNull = false)]     public string Comment { get; set; }      //... } 

However if you don't want to annotate all the properties you can create a custom model binder where you set it to false:

public class EmptyStringModelBinder : DefaultModelBinder  {     public override object BindModel(ControllerContext controllerContext,                                      ModelBindingContext bindingContext)     {         bindingContext.ModelMetadata.ConvertEmptyStringToNull = false;         Binders = new ModelBinderDictionary() { DefaultBinder = this };         return base.BindModel(controllerContext, bindingContext);     } } 

And you can use the ModelBinderAttribute in your action:

public ActionResult SaveOrderDetails([ModelBinder(typeof(EmptyStringModelBinder))]         OrderDetailsModel orderDetailsModel) { } 

Or you can set it as the Default ModelBinder globally in your Global.asax:

ModelBinders.Binders.DefaultBinder = new EmptyStringModelBinder(); 

You can read more about this feature here.

like image 165
nemesv Avatar answered Sep 21 '22 04:09

nemesv


Instead of creating a ModelBinder which modifies the ModelMetadata as some answers suggested, a cleaner alternative is to provide a custom ModelMetadataProvider.

public class EmptyStringDataAnnotationsModelMetadataProvider : System.Web.Mvc.DataAnnotationsModelMetadataProvider  {     protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)     {         var modelMetadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);         modelMetadata.ConvertEmptyStringToNull = false;         return modelMetadata;     } } 

Then in Application_Start()

ModelMetadataProviders.Current = new EmptyStringDataAnnotationsModelMetadataProvider(); 
like image 43
LostInComputer Avatar answered Sep 19 '22 04:09

LostInComputer