ASP.NET MVC 2 Beta - привязка модели по умолчанию - PullRequest
0 голосов
/ 19 ноября 2009

Я испытываю другое поведение после перехода с ASP.NET MVC 1.0 на ASP.NET MVC 2 Beta. Я проверил последние изменения, но не ясно, в чем проблема.

Проблема связана со связывателем модели по умолчанию и моделью, реализующей IDataErrorInfo.

Свойство (IDataErrorInfo.Item):

public string this[string columnName]

больше не вызывается для каждого свойства. Чего мне не хватает?

Ответы [ 2 ]

1 голос
/ 20 ноября 2009

После некоторой дальнейшей работы по отладке я думаю, что понимаю, почему в моем конкретном случае 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 равен нулю, поэтому проверка не выполняется.

Это принципиально отличается от ASP.NET MVC 1.0, где этот сценарий запускает валидатор вплоть до вызова IDataErrorInfo.Item.

Разве я не использую что-то, как это было задумано?

1 голос
/ 19 ноября 2009

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 это свойство [string columnName] ... Похоже на ошибку, потому что DefaultModelBinder все еще использует свойство Error. Это как минимум несоответствие.

EDIT

Я использовал отражатель и заметил, что 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.

EDIT

Я также изменил if (base.Metadata.Model != null) на if (container! = Null) в Validate() методе DataErrorInfoPropertyModelValidator.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...