2009-11-19 31 views
0

從ASP.NET MVC 1.0切換到ASP.NET MVC 2 Beta後,我遇到了一些不同的行爲。我檢查了突破性的變化,但不清楚問題出在哪裏。ASP.NET MVC 2 Beta - 默認模型綁定器

該問題與默認模型聯編程序和實現IDataErrorInfo的模型有關。

的性質(IDataErrorInfo.Item):

public string this[string columnName] 

不再被調用爲每個屬性。我錯過了什麼?

+0

如果是我的重複:http://stackoverflow.com/questions/1760039/is-idataerrorinfo-ignored-during-model-validation-in-mvc-2 – LukLed 2009-11-19 08:35:27

+0

似乎沒有答案。驗證工作,但行爲不同。在我的情況下,簡單的類型,如System.Nullable 。 – Rudy 2009-11-19 18:22:26

回答

1

經過一些進一步的調試工作,我相信我明白爲什麼在我的特殊情況下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

我只是沒有按照預期的方式使用某些東西?

+0

感謝您報告此問題。我和其他一些MVC開發人員進行了交流,我們懷疑在預覽版2和Beta版之間的某個時間點進行了無效檢查,但之後變得沒有必要。我提出了一個錯誤來取消支票。 – Levi 2009-11-20 19:17:53

+0

我欣賞你看着這個! – Rudy 2009-11-20 19:31:36

1

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)在DataErrorInfoPropertyModelValidatorValidate()方法進行修正。

+0

對metaData.GetValidators的調用應產生一個DataErrorInfoPropertyModelValidator。調用其Validate應導致直接調用IDataErrorInfo接口。它似乎沒有做到這一點。 – Rudy 2009-11-19 21:04:14