3

我正在寻找一种从我的自定义验证代码中返回以下信息的方法:

public enum ValidationErrorTypeFlags
{
    Error_Input = 1 << 0,               // a "field specific" error which is checked both clientside and serverside 
    Error_Input_ServerSide = 1 << 1,    // a "field specific" error which can only be checked serverside
    Error_General = 1 << 2              // serverside general error
}

在验证代码(IValidatableObject 或 ValidationAttribute)中,当我检测到错误时,我希望能够将上述错误类型之一与 ValidationResult 相关联。

然后我希望能够遍历控制器或视图中的验证错误,并区分这些错误类型。

我目前正在使用 MVC 3(很高兴升级到 4)。

注意:

  • ModelState 不保留 ValidationResults AFAIK - 您只能访问 ViewData.ModelState.Values.Items[x].Errors 中的错误 - 这些已转换为 System.Web.Mvc.ModelError
  • 似乎 MVC 验证只允许您在验证完成后访问 [key, 'error message'] 类型的验证结果。

我目前使用的 hack 是在自定义验证代码中装饰错误消息:

var field = new[] { validationContext.DisplayName };
return new ValidationResult("+Invalid format - use yyyy-mm-dd", field);

然后在控制器中查找以 +,-,* 开头的错误消息。

4

1 回答 1

3

从自定义验证代码(不知道如何从内置代码完成),您可以ValidationResult通过从基类继承并从自定义验证属性返回来创建自定义类来做到这一点。

public class CustomValidationResult: ValidationResult
{
   // additional properties
}

然后,您可以从控制器强制转换并检查验证结果是否是您的自定义类型并采取相应措施。

更新:

上面的想法不起作用,因为ValidationResult该类在 DataAnnotations 程序集中,它们被转换为ModelValidationResult,这就是我们在 MVC 中可以访问的全部内容。

似乎将数据注释验证中的额外信息传递给 MVC 看起来并不容易!

我正在浏览源代码,发现ValidatableObjectAdapter将. 我看不出扩展这个类有多大好处,但我们可以通过实现和复制代码轻松地创建自定义。IEnumerable<ValidationResult>IEnumerable<ModelValidationResult>ValidatableObjectAdapterModelValidatorValidate

我们必须创建一个自定义ModelValidationResult和自定义ValidationResult(这是ValidationResult我们将从验证中返回的自定义),并且在该ConvertResults方法中我们可以放置我们的转换代码来处理附加信息。

public class CustomValidatableObjectAdapter : ModelValidator
{
    public CustomValidatableObjectAdapter(ModelMetadata metadata, ControllerContext context)
      : base(metadata, context)
    {
    }

    public override IEnumerable<ModelValidationResult> Validate(object container)
    {
      object model = Metadata.Model;
      if (model == null)
      {
        return Enumerable.Empty<ModelValidationResult>();
      }

      IValidatableObject validatable = model as IValidatableObject;
      if (validatable == null)
      {
        throw new Exception("model is of not type validatable");
      }

      ValidationContext validationContext = new ValidationContext(validatable, null, null);

      return ConvertResults(validatable.Validate(validationContext));
    }

    private IEnumerable<ModelValidationResult> ConvertResults(IEnumerable<ValidationResult> results)
    {
      foreach (ValidationResult result in results)
      {
        // iterate the ValidationResult enumeration and cast each into CustomValidationResult
        // and conver them into enumeration of CustomModelValidationResult.
      }
    }
}

最后,我们必须告诉DataAnnotationsModelValidatorProvider我们CustomValidatableObjectAdapterApplication_StartGlobal.asax.cs 事件中的使用。

DataAnnotationsModelValidatorProvider.RegisterDefaultValidatableObjectAdapterFactory((metadata, context) => new CustomValidatableObjectAdapter(metadata, context));

所以你必须创建一个自定义ValidationResult,自定义ModelValidationResult和一个自定义ValidatableObjectAdapter

我没有对此进行测试,但我希望这会奏效。我可能会建议一个比这更好、更容易的解决方案。

于 2012-06-16T04:21:46.773 回答