string.empty convertido em null ao passar o object JSON para o MVC Controller

Estou passando um object do cliente para o servidor. Propriedades do object que são representadas como string.empty estão sendo convertidas para null durante este processo. Eu queria saber como evitar isso quando o tipo de objects suporta string.empty.

insira a descrição da imagem aqui

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); } }); 

insira a descrição da imagem aqui

Meu modelo inclui objects DateTime anuláveis. Eu não posso forçar todos os valores nulos para string.empty no servidor.

Eu estou usando o AutoMapper, então eu preferiria não ter que inspecionar propriedades individualmente no servidor.

Este é um recurso do MVC que liga strings vazias a null s.

Essa lógica é controlada com a propriedade ModelMetadata.ConvertEmptyStringToNull que é usada pelo DefaultModelBinder .

Você pode definir o ConvertEmptyStringToNull com o atributo DisplayFormat

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

No entanto, se você não quiser anotar todas as propriedades, poderá criar um fichário de modelo personalizado no qual o defina como falso:

 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); } } 

E você pode usar o ModelBinderAttribute em sua ação:

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

Ou você pode configurá-lo como o ModelBinder padrão globalmente em seu Global.asax:

 ModelBinders.Binders.DefaultBinder = new EmptyStringModelBinder(); 

Você pode ler mais sobre esse recurso aqui .

Em vez de criar um ModelBinder que modifica o ModelMetadata como algumas respostas sugeriram, uma alternativa mais limpa é fornecer um ModelMetadataProvider personalizado.

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

Em seguida, em Application_Start ()

 ModelMetadataProviders.Current = new EmptyStringDataAnnotationsModelMetadataProvider(); 

A resposta aceita não funcionou para mim usando o MVC4. No entanto, a seguinte solução faz e eu pensei que ajudaria os outros.

 public class CustomModelBinder : DefaultModelBinder { public bool ConvertEmptyStringToNull { get; set; } public CustomModelBinder () { } public CustomModelBinder (bool convertEmptyStringToNull) { this.ConvertEmptyStringToNull = convertEmptyStringToNull; } protected override bool OnModelUpdating(ControllerContext controllerContext, ModelBindingContext bindingContext) { // this little bit is required to override the ConvertEmptyStringToNull functionality that we do not want! foreach (string propertyKey in bindingContext.PropertyMetadata.Keys) { if(bindingContext.PropertyMetadata[propertyKey] != null) bindingContext.PropertyMetadata[propertyKey].ConvertEmptyStringToNull = this.ConvertEmptyStringToNull; } return base.OnModelUpdating(controllerContext, bindingContext); } } 

Isso consertará o problema no MVC4 +. Parece que bindingContext.ModelMetadata.ConvertEmptyStringToNull é completamente ignorado, e isso ocorre porque a configuração existe no object PropertyMetadata para cada propriedade sendo vinculada. PropertyMetadata é recriado em BindProperty (), portanto, se você configurá-lo antes dessa chamada de método, ele será sobrescrito, a menos que exista como um atributo na propriedade do object sendo ligado (como [DisplayFormat (ConvertEmptyStringToNull = false)]). Ninguém quer fazer isso em todas as propriedades, já que isso é bobagem.

O problema é que o AutoMapper transforma nullables em null quando a string está vazia. Essa outra pergunta foi respondida com algo que acredito ser suficiente para suas necessidades: Automapper null string to empty

Ao postar dados com $.ajax , null não é um valor possível para uma propriedade da opção de data . Se você observar a solicitação com um depurador http, verá que ela é convertida em uma string vazia.

Então eu acho que o seu controlador MVC está aplicando a conversão oposta.

O que eu faço em um aplicativo ajax para trabalhar esse problema é que eu não uso a opção de data $.ajax() , mas eu serializo tudo em JSON e coloco em um único campo “data” da opção de dados. Assim você não tem problemas com valores nulos. Claro, você tem que desserializar no lado do servidor.