String.empty преобразуется в null при передаче объекта JSON в MVC Controller
Я передаю объект от клиента к серверу. Свойства объекта, которые представлены как string.empty, во время этого процесса преобразуются в нуль. Мне было интересно, как предотвратить это, когда тип объектов поддерживает 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]()
Моя модель включает в себя объекты DateTime с нулевым значением. Я не могу заставить все нули string.empty на сервере.
Я использую AutoMapper, поэтому я бы предпочел не проверять свойства на сервере.
Ответы
Ответ 1
Это функция MVC, которая связывает пустые строки с null
s.
Эта логика управляется с помощью свойства ModelMetadata.ConvertEmptyStringToNull, которое используется DefaultModelBinder
.
Вы можете установить ConvertEmptyStringToNull
с помощью атрибута DisplayFormat
public class OrderDetailsModel
{
[DisplayFormat(ConvertEmptyStringToNull = false)]
public string Comment { get; set; }
//...
}
Однако, если вы не хотите комментировать все свойства, вы можете создать настраиваемое связующее устройство, где вы установите его на 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);
}
}
И вы можете использовать ModelBinderAttribute в своем действии:
public ActionResult SaveOrderDetails([ModelBinder(typeof(EmptyStringModelBinder))]
OrderDetailsModel orderDetailsModel)
{
}
Или вы можете установить его как глобальный ModelBinder по умолчанию в свой Global.asax:
ModelBinders.Binders.DefaultBinder = new EmptyStringModelBinder();
Подробнее об этой функции здесь.
Ответ 2
Вместо создания ModelBinder, который модифицирует ModelMetadata в качестве некоторых предложенных ответов, более простой альтернативой является предоставление пользовательского 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;
}
}
Затем в Application_Start()
ModelMetadataProviders.Current = new EmptyStringDataAnnotationsModelMetadataProvider();
Ответ 3
Принятый ответ не работал у меня с использованием MVC4. Тем не менее, следующий обходной путь делает, и я думал, что это поможет другим.
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);
}
}
Это устранит проблему в MVC4+. Казалось бы, bindingContext.ModelMetadata.ConvertEmptyStringToNull полностью игнорируется, и это связано с тем, что этот параметр существует в объекте PropertyMetadata для каждого связанного свойства. PropertyMetadata воссоздается в BindProperty(), поэтому, если вы установите его перед вызовом этого метода, он будет перезаписан, если он не существует как атрибут свойства связанного объекта (например, [DisplayFormat (ConvertEmptyStringToNull = false)]). Никто не хочет делать это на каждом свойстве как на глупость.
Ответ 4
Проблема заключается в том, что AutoMapper превращает nullables в null, когда строка пуста. На этот другой вопрос ответил то, что, по моему мнению, удовлетворяет вашим потребностям: Автоматическая пустая строка для пустых
Ответ 5
При отправке данных с $.ajax
, null
не является возможным значением для свойства параметра data
. Если вы посмотрите на запрос с помощью HTTP-отладчика, вы увидите, что он преобразован в пустую строку.
Поэтому я предполагаю, что ваш MVC-контроллер применяет противоположное преобразование.
Что я делаю в приложении ajax для решения этой проблемы, так это то, что я не использую параметр data
$.ajax()
, но я сериализую все в JSON и помещаю его в одно поле "данные" данных вариант. Например, у вас нет проблем с нулевыми значениями. Конечно, вы должны десериализоваться на стороне сервера.