将JSON对象传递给MVC Controller时,string.empty转换为null

时间:2012-10-04 19:03:23

标签: c# javascript jquery asp.net-mvc

我正在将一个对象从客户端传递给服务器。在此过程中,表示为string.empty的对象的属性将转换为null。当对象类型支持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,所以我不想在服务器上单独检查属性。

5 个答案:

答案 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;数据选项。就像那样,你不会遇到空值问题。当然,您必须在服务器端反序列化。