把一个mvc1.0的项目迁移到2.0遇到了些问题,部分表更新时提示某字段值不能为NULL,跟踪发现表单中为没填写的字符串类型字段都为null。
下载2.0源码,发现DefaultModelBinder有了不少改动,找到了源头:
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中:
DisplayFormatAttribute displayFormatAttribute = attributeList.OfType().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,则按照此属性设置的ConvertEmptyStringToNull值。
可是我项目中之前并没有给模型设置有DataAnnotations Attribute!
再找到ModelMetadata类的定义,发现其private bool _convertEmptyStringToNull = true; !
ModelMetadata.ConvertEmptyStringToNull默认值竟是true!
自己写个ModelMetadataProvider来解决此问题:
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:
protected void Application_Start()
{
ModelMetadataProviders.Current = new GUET.OA.Web.Mvc.NoConvertStringMetadataProvider();
}
mvc 2.0功能加了挺多,比如这个DataAnnotation Metadata,让我们在验证上节省了不少时间。
先吃螃蟹的人问题要付出些代价的。