我正在将一个对象从客户端传递给服务器。在此过程中,表示为string.empty的对象的属性将转换为null。当对象类型支持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);
}
});
我的模型包含可以为空的DateTime对象。我不能强制所有空值到服务器上的string.empty。
我正在使用AutoMapper,所以我不想在服务器上单独检查属性。
答案 0 :(得分:71)
这是一个MVC功能,它将空字符串绑定到null
。
此逻辑由DefaultModelBinder
使用的ModelMetadata.ConvertEmptyStringToNull属性控制。
您可以使用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)
{
}
或者您可以在Global.asax中将其全局设置为Default ModelBinder:
ModelBinders.Binders.DefaultBinder = new EmptyStringModelBinder();
您可以阅读有关此功能的更多信息here。
答案 1 :(得分:10)
除了创建一个修改ModelMetadata的ModelBinder作为一些建议的答案,一个更清晰的选择是提供一个自定义的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();
答案 2 :(得分:2)
接受的答案对我使用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)])。没有人愿意在每个房产上做这件事,因为这很愚蠢。
答案 3 :(得分:0)
问题是当字符串为空时,AutoMapper会将nullables变为null。另一个问题是我认为满足您需求的问题:Automapper null string to empty
答案 4 :(得分:0)
使用$.ajax
发布数据时,null
不是data
选项属性的可能值。如果您使用http调试器查看请求,您将看到它已转换为空字符串。
所以我猜你的MVC控制器正在应用相反的转换。
我在ajax应用程序中为解决此问题所做的是我不使用data
的{{1}}选项,但是我将JSON中的所有内容序列化并将其放入单个字段中&#34;数据&#34;数据选项。就像那样,你不会遇到空值问题。当然,您必须在服务器端反序列化。