【问题标题】:How can I return additional (i.e. more than just field=>error message) validation information from custom validation code to the Controller or View?如何从自定义验证代码向控制器或视图返回其他(即不仅仅是字段=>错误消息)验证信息?
【发布时间】:2012-06-19 00:24:21
【问题描述】:

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

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);

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

【问题讨论】:

  • 我已经计算了 MVC3 中很多不同的地方,其中 ModelValidationError 被转换为 ModelState,所以我认为没有简单的方法可以做到这一点。

标签: asp.net-mvc modelstate asp.net-mvc-validation


【解决方案1】:

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

public class CustomValidationResult: ValidationResult
{
   // additional properties
}

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

更新:

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

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

我正在浏览源代码,发现是ValidatableObjectAdapterIEnumerable&lt;ValidationResult&gt; 转换为IEnumerable&lt;ModelValidationResult&gt;。我看不出扩展这个类有多大好处,但我们可以通过实现ModelValidator并复制Validate代码轻松创建自定义ValidatableObjectAdapter

我们必须创建一个自定义的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 在 Global.asax.cs 的Application_Start 事件中使用我们的CustomValidatableObjectAdapter

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

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

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

【讨论】:

  • 感谢您的回复。我以前试过这个,但找不到可以在控制器中访问的变量,我可以强制转换。你能指出我正确的方向吗?我已经尝试过 ModelState,但如上所述,这只有 ModelError 而不是 ValidationResults。
  • 阅读您博客上的帖子prideparrot.com/blog/archive/2012/4/…。 IClientValidatable 是一个很好的提示 - 它与我正在尝试的目标有一些相似的目标。
  • @Illan 不知何故我找到了一种方法。我会在一分钟内更新答案。
  • @Ilan 我更新了答案,看起来没那么容易!
  • 感谢您所做的一切。我明天试试,然后在这里更新。 MVC 显然没有在设计时考虑到复杂的 ValidationResults。而不是重复框架所做的事情 - 并且会随着下一次更新而改变 - 我可能会坚持我所拥有的黑客 - 至少它很简单。顺便说一句,您查看了哪个 MVC 源? 3 还是 4?
猜你喜欢
  • 2018-11-17
  • 2017-02-25
  • 1970-01-01
  • 2014-11-15
  • 2017-05-07
  • 1970-01-01
  • 2021-02-24
  • 2012-08-28
  • 1970-01-01
相关资源
最近更新 更多