c# - net - string.empty convertido a nulo al pasar el objeto JSON al controlador MVC
mvc 5 jquery ajax (5)
Paso un objeto de cliente a servidor. Las propiedades del objeto que se representan como string.empty se convierten a null durante este proceso. Me preguntaba cómo evitar esto cuando el tipo de objetos admite string.empty.
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);
}
});
Mi modelo incluye objetos fechables de nulos. No puedo forzar todos los nulos a string.empty en el servidor.
Estoy usando AutoMapper, por lo que preferiría no tener que inspeccionar las propiedades individualmente en el servidor.
Al publicar datos con $.ajax
, null
no es un valor posible para una propiedad de la opción de data
. Si mira la solicitud con un depurador http, verá que se convierte en una cadena vacía.
Así que supongo que su controlador MVC está aplicando la conversión opuesta.
Lo que hago en una aplicación ajax para resolver este problema es que no utilizo la opción de data
de $.ajax()
, pero serializo todo en JSON y lo coloco en un solo campo "datos" de la opción de datos. Así no tienes problemas con valores nulos. Por supuesto, debe deserializar en el lado del servidor.
El problema es que AutoMapper convierte nulables en nulo cuando la cadena está vacía. Esta otra pregunta fue respondida con algo que creo que es suficiente para usted: Automapper null string to empty
En lugar de crear un ModelBinder que modifique los metadatos de modelo como algunas respuestas sugeridas, una alternativa más limpia es proporcionar un proveedor de metadatos de modelo personalizado.
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;
}
}
Luego en Application_Start ()
ModelMetadataProviders.Current = new EmptyStringDataAnnotationsModelMetadataProvider();
Esta es una característica de MVC que enlaza cadenas vacías para null
s.
Esta lógica se controla con la propiedad ModelMetadata.ConvertEmptyStringToNull que utiliza DefaultModelBinder
.
Puede configurar ConvertEmptyStringToNull
con el atributo DisplayFormat
public class OrderDetailsModel
{
[DisplayFormat(ConvertEmptyStringToNull = false)]
public string Comment { get; set; }
//...
}
Sin embargo, si no desea anotar todas las propiedades, puede crear una carpeta de modelo personalizada donde la configure en 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);
}
}
Y puede usar el ModelBinderAttribute en su acción:
public ActionResult SaveOrderDetails([ModelBinder(typeof(EmptyStringModelBinder))]
OrderDetailsModel orderDetailsModel)
{
}
O puede configurarlo como Default ModelBinder globalmente en su Global.asax:
ModelBinders.Binders.DefaultBinder = new EmptyStringModelBinder();
Puede leer más sobre esta característica here .
La respuesta aceptada no funcionó para mí usando MVC4. Sin embargo, la siguiente solución alternativa y creo que ayudaría a otros.
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);
}
}
Esto solucionará el problema bajo MVC4 +. Parece que bindingContext.ModelMetadata.ConvertEmptyStringToNull se ignora por completo, y esto se debe a que la configuración existe en el objeto PropertyMetadata para cada propiedad que se enlaza. PropertyMetadata se recrea en BindProperty () por lo que si lo configura antes de esa llamada al método, se sobreescribirá a menos que exista como un atributo en la propiedad de su objeto enlazado (como [DisplayFormat (ConvertEmptyStringToNull = false)]). Nadie quiere hacer esto en cada propiedad, ya que es una tontería.