代码改变世界

MVC 2.0: ConvertEmptyStringToNull 带来烦恼

  无常  阅读(2622)  评论(2编辑  收藏  举报

把一个mvc1.0的项目迁移到2.0遇到了些问题,部分表更新时提示某字段值不能为NULL,跟踪发现表单中为没填写的字符串类型字段都为null。

下载2.0源码,发现DefaultModelBinder有了不少改动,找到了源头:

1
2
3
4
5
6
7
8
9
protected virtual object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder) {
    object value = propertyBinder.BindModel(controllerContext, bindingContext);
 
    if (bindingContext.ModelMetadata.ConvertEmptyStringToNull && Object.Equals(value, String.Empty)) {
        return null;
    }
 
    return value;
}

 

这里多了个步骤,如果ModelMetadata的ConvertEmptyStringToNull属性为true,则把空字符串转为null。

ConvertEmptyStringToNull值从何来?再找到到DataAnnotationsModelMetadataProvider中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
DisplayFormatAttribute displayFormatAttribute = attributeList.OfType<displayformatattribute>().FirstOrDefault();
if (displayFormatAttribute == null && dataTypeAttribute != null) {
    displayFormatAttribute = dataTypeAttribute.DisplayFormat;
}
if (displayFormatAttribute != null) {
    result.NullDisplayText = displayFormatAttribute.NullDisplayText;
    result.DisplayFormatString = displayFormatAttribute.DataFormatString;
    result.ConvertEmptyStringToNull = displayFormatAttribute.ConvertEmptyStringToNull;
 
    if (displayFormatAttribute.ApplyFormatInEditMode) {
        result.EditFormatString = displayFormatAttribute.DataFormatString;
    }
}
</displayformatattribute>

如果属性有DisplayFormatAttribute,则按照此属性设置的ConvertEmptyStringToNull值。

可是我项目中之前并没有给模型设置有DataAnnotations Attribute!

再找到ModelMetadata类的定义,发现其private bool _convertEmptyStringToNull = true; !

ModelMetadata.ConvertEmptyStringToNull默认值竟是true!

自己写个ModelMetadataProvider来解决此问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class MyDataAnnotationsModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
    {
        var md = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
 
        DataTypeAttribute dataTypeAttribute = attributes.OfType<DataTypeAttribute>().FirstOrDefault();
        DisplayFormatAttribute displayFormatAttribute = attributes.OfType<DisplayFormatAttribute>().FirstOrDefault();
        if (displayFormatAttribute == null && dataTypeAttribute != null)
        {
            displayFormatAttribute = dataTypeAttribute.DisplayFormat;
        }
        if (displayFormatAttribute == null)
        {
            md.ConvertEmptyStringToNull = false;
        }
 
        return md;
    }
}

最后,还需要在Application_Start中替换掉默认的ModelMetadataProvider:

1
2
3
4
protected void Application_Start()
{
    ModelMetadataProviders.Current = new GUET.OA.Web.Mvc.NoConvertStringMetadataProvider();
}

 

mvc 2.0功能加了挺多,比如这个DataAnnotation Metadata,让我们在验证上节省了不少时间。

先吃螃蟹的人问题要付出些代价的。

编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
历史上的今天:
2007-01-20 [翻译]jQuery 选择器的使用
点击右上角即可分享
微信分享提示