在GetClientValidationRules中查找复杂对象的属性值

时间:2013-12-05 13:32:58

标签: asp.net-mvc asp.net-mvc-4

需要在客户端上验证复杂的视图模型。简化为:

public class Survey
{
  public List<Question> Questions { get; set; }
}

public class Question
{
  public List<Answer> Answers { get; set; }
}

public class Answer
{
  public string FieldName { get; set; }

  [Required("Please use a number")]
  public int Number { get; set; }
}

目前,问题正在客户端上正确验证。但我们需要使用FieldName验证和显示上下文消息,如:

  

需要“儿童人数”字段。

我实施了一个CustomRequiredAttribute类(: RequiredAttribute, IClientValidatable)并用它装饰了Number属性:

[CustomRequired("{0} is mandatory")]
public int Number { get; set; }

但是,在GetClientValidationRules方法中,metadata.Model为空。

public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
              ModelMetadata metadata,
              ControllerContext context)
{
  // metadata.Model is null here!
  ModelMetadata answerFieldNameValue = ModelMetadataProviders.Current
                                        .GetMetadataForProperties(
                                              metadata.Model,
                                              metadata.ContainerType)
                        .FirstOrDefault(p => p.PropertyName == "FieldName");

  // and, therefore, answerFieldNameValue.Model is null too!
}

如果我回到此方法的第一行,并从context.Controller.ViewData.Model我得到任何Answer并将其分配给metadata.Model,那么answerFieldNameValue.Model将包含正确的字符串,这是答案的字段名称。

如何制作此元数据。模型在到达时具有适当的值?或者任何其他方式来解决这个问题?

1 个答案:

答案 0 :(得分:1)

知道了。下面的代码是我的解决方案,其灵感来自BranTheMan who found his way out of a similar problem

public class CustomModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
    private object lastQuestionLabel;

    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
    {
        ModelMetadata modelMetadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);

        object model = null;

        if (modelAccessor != null)
        {
            model = modelAccessor();
        }

        if (typeof(SurveyQuestionVM).IsAssignableFrom(containerType) && propertyName == "TreeViewLabel")
        {
            lastQuestionLabel = model;
        }

        if (typeof(SurveyAnswerVM).IsAssignableFrom(containerType))
        {
            modelMetadata.AdditionalValues.Add("QuestionLabel", lastQuestionLabel);
        }

        return modelMetadata;
    }
}