從ASP.NET MVC 1.0切換到ASP.NET MVC 2 Beta後,我遇到了一些不同的行爲。我檢查了突破性的變化,但不清楚問題出在哪裏。ASP.NET MVC 2 Beta - 默認模型綁定器
該問題與默認模型聯編程序和實現IDataErrorInfo的模型有關。
的性質(IDataErrorInfo.Item):
public string this[string columnName]
不再被調用爲每個屬性。我錯過了什麼?
從ASP.NET MVC 1.0切換到ASP.NET MVC 2 Beta後,我遇到了一些不同的行爲。我檢查了突破性的變化,但不清楚問題出在哪裏。ASP.NET MVC 2 Beta - 默認模型綁定器
該問題與默認模型聯編程序和實現IDataErrorInfo的模型有關。
的性質(IDataErrorInfo.Item):
public string this[string columnName]
不再被調用爲每個屬性。我錯過了什麼?
經過一些進一步的調試工作,我相信我明白爲什麼在我的特殊情況下IDataErrorInfo.Item
沒有被調用。下面的代碼是在ASP.NET MVC 2測試版用於驗證IDataErrorInfo
屬性:
internal sealed class DataErrorInfoPropertyModelValidator : ModelValidator
{
public DataErrorInfoPropertyModelValidator(ModelMetadata metadata, ControllerContext controllerContext)
: base(metadata, controllerContext)
{
}
public override IEnumerable<ModelValidationResult> Validate(object container)
{
if (Metadata.Model != null)
{
var castContainer = container as IDataErrorInfo;
if (castContainer != null)
{
string errorMessage = castContainer[Metadata.PropertyName];
if (!String.IsNullOrEmpty(errorMessage))
{
return new[] { new ModelValidationResult { Message = errorMessage } };
}
}
}
return Enumerable.Empty<ModelValidationResult>();
}
}
我的模型包含一個屬性,是System.Nullable<int>
,當模型綁定從HTML結合後的空字符串,Metadata.Model
等於null,因此驗證不會運行。
這與ASP.NET MVC 1.0有着根本的區別,在這種情況下,此方案將驗證器一直激活到調用IDataErrorInfo.Item
。
我只是沒有按照預期的方式使用某些東西?
DefaultModelBinder在MVC 1.0:
protected virtual void OnPropertyValidated(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value)
{
IDataErrorInfo model = bindingContext.Model as IDataErrorInfo;
if (model != null)
{
string str = model[propertyDescriptor.Name];
if (!string.IsNullOrEmpty(str))
{
string key = CreateSubPropertyName(bindingContext.ModelName, propertyDescriptor.Name);
bindingContext.ModelState.AddModelError(key, str);
}
}
}
DefaultModelBinder在MVC 2.0測試版:
protected virtual void OnPropertyValidated(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value)
{
ModelMetadata metadata = bindingContext.PropertyMetadata[propertyDescriptor.Name];
metadata.Model = value;
string prefix = CreateSubPropertyName(bindingContext.ModelName, metadata.PropertyName);
foreach (ModelValidator validator in metadata.GetValidators(controllerContext))
{
foreach (ModelValidationResult result in validator.Validate(bindingContext.Model))
{
bindingContext.ModelState.AddModelError(CreateSubPropertyName(prefix, result.MemberName), result.Message);
}
}
if ((bindingContext.ModelState.IsValidField(prefix) && (value == null)) && !TypeHelpers.TypeAllowsNullValue(propertyDescriptor.PropertyType))
{
bindingContext.ModelState.AddModelError(prefix, GetValueRequiredResource(controllerContext));
}
}
它不使用IDataErrorInfo的這個[字符串COLUMNNAME]屬性...好像一個漏洞,因爲DefaultModelBinder仍然使用Error屬性。至少是不一致的。
編輯
我用反射鏡,發現DataErrorInfoPropertyModelValidator似乎並沒有被使用,所以我創建了自己的類:
public class DataErrorInfoModelPropertyValidatorProvider : ModelValidatorProvider
{
// Methods
public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context)
{
if (metadata == null)
{
throw new ArgumentNullException("metadata");
}
if (context == null)
{
throw new ArgumentNullException("context");
}
var validators = new List<ModelValidator>();
validators.Add(new DataErrorInfoPropertyModelValidator(metadata, context));
return validators;
}
internal sealed class DataErrorInfoPropertyModelValidator : ModelValidator
{
// Methods
public DataErrorInfoPropertyModelValidator(ModelMetadata metadata, ControllerContext controllerContext)
: base(metadata, controllerContext)
{
}
public override IEnumerable<ModelValidationResult> Validate(object container)
{
if (container != null)
{
IDataErrorInfo info = container as IDataErrorInfo;
if (info != null)
{
string str = info[Metadata.PropertyName];
if (!string.IsNullOrEmpty(str))
{
ModelValidationResult[] resultArray = new ModelValidationResult[1];
ModelValidationResult result = new ModelValidationResult();
result.Message = str;
resultArray[0] = result;
return resultArray;
}
}
}
return Enumerable.Empty<ModelValidationResult>();
}
}
}
然後我用:
ModelValidatorProviders.Providers.Add(new DataErrorInfoModelPropertyValidatorProvider());
它工作:)這只是臨時解決方案。將要在最後的MVC 2
編輯
我也改變if (base.Metadata.Model != null)
到如果(容器!= NULL)在DataErrorInfoPropertyModelValidator
Validate()
方法進行修正。
對metaData.GetValidators的調用應產生一個DataErrorInfoPropertyModelValidator。調用其Validate應導致直接調用IDataErrorInfo接口。它似乎沒有做到這一點。 – Rudy 2009-11-19 21:04:14
如果是我的重複:http://stackoverflow.com/questions/1760039/is-idataerrorinfo-ignored-during-model-validation-in-mvc-2 – LukLed 2009-11-19 08:35:27
似乎沒有答案。驗證工作,但行爲不同。在我的情況下,簡單的類型,如System.Nullable。 –
Rudy
2009-11-19 18:22:26