【问题标题】:FluentValidation, Validators lifecycle and using Validators to check against DbFluentValidation、验证器生命周期和使用验证器检查 Db
【发布时间】:2013-06-09 00:03:47
【问题描述】:

我在我的 MVC4 项目中使用 FluentValidation。每件事都完美运行,并且连接到我的IoCStructureMap)。

我有 2 个问题:

  1. 我应该如何管理验证器的生命周期?可以让它们单例吗?还是没有区别,我可以根据我的需要管理生命周期?这里的最佳做法是什么?

  2. FluentValidation 非常好。我一直将它用于简单验证(例如:属性不为空等)。我正在考虑使用它进行一些 Db 验证(例如:属性值是唯一的。)我可以使用 存储库 将其传递给它strong>StructureMap 并对照 Db 检查值。 这是个好主意吗?或者我应该在我的服务层而不是我的 IValidator 中实现这个逻辑?

如果您在类似的场景中使用过,您的体验如何?

【问题讨论】:

    标签: c# asp.net .net asp.net-mvc fluentvalidation


    【解决方案1】:

    我已经使用 FluentValidation 多年,并提出并解决了您的问题。

    1. 就个人而言,创建验证器的成本并不高,因此我不会将它们设为单例。我遇到了需要访问 HttpContext 才能上传文件的单例问题。发生的情况是第一个 HttpContext 始终用于验证而不是当前的。

    我个人建议你不要使用单例

    1. 我实际上一直这样做,我喜欢它。请注意,您注入的任何依赖项都应该是有效的。如果您的数据库查询执行全表扫描并且需要 30 秒,那么这不是一个好的体验。就像我上面所说的,我通常注入 HttpContext 来检查文件是否已上传,并传递一个 DataContext 来验证电子邮件是否尚未被占用。

    对此发疯,这是 FluentValidation 的一个巨大优势,只要确保依赖项在时间和资源方面并不昂贵。

    【讨论】:

    • 谢谢@Khalid。我完全同意你的看法。
    【解决方案2】:

    我自己一直在使用 unity 和 MVC 4 研究这个问题。

    我所看到的是,如果您将它们保留为瞬态对象。 FluentValidation 将为每个已验证的属性创建一个新的验证对象。所以需要一些缓存。

    对于我的缓存,我查看了验证器的每个请求缓存。这很好用,因为所有依赖组件都是 Per Request。 (每个请求是自定义代码,它在 HttpContext.Current.Items 集合上存储一个子 Unity 容器,并带有一个在请求结束时销毁/处置子容器的 HTTP 模块)

    要在验证器的 Per Request 和 Singleton 瞬间之间进行选择,取决于您如何使用它、它具有什么类型的依赖项以及 IoC Continer 的功能。

    通过统一,您可以创建一个单例验证器并使用函数(即 Func serviceFunc)注入服务工厂。

    就我而言,每次调用 serviceFunc 时,都会检索 Unity ChildContiner“服务”。因此,我仍然可以使用 ContainerControlledLifetimeManager(singleton) 定义我的“验证器”,并使用 HierarchicalLifetimeManager(Per Request) 定义“服务”。

    这样的缺点是每次调用 serviceFunc 时,它都需要检查并从子容器中检索服务。这将是我将返回“每个请求”的最可能原因)

    我刚刚更新了我的代码以使用 serviceFunc,今天将对其进行测试。我相信为您的应用找到正确的解决方案将是一次尝试。

    下面是我正在使用的验证工厂——我没有使用统一容器(就像网络上的大多数示例一样),而是将IDependencyResolver 注入其中并使用它来解析我的验证器对象。

    public class ValidatorFactory : IValidatorFactory 
    {
        private readonly IDependencyResolver _dependencyResolver;
    
        // taken from the attribute Validation factory
        public ValidatorFactory(IDependencyResolver dependencyResolver)
        {
            _dependencyResolver = dependencyResolver;
        }
    
        /// <summary>
        /// Gets a validator for the appropriate type.
        /// 
        /// </summary>
        public IValidator<T> GetValidator<T>()
        {
            return (IValidator<T>)this.GetValidator(typeof(T));
        }
    
        /// <summary>
        /// Gets a validator for the appropriate type.
        /// 
        /// </summary>
        public virtual IValidator GetValidator(Type type)
        {
            if (type == (Type)null)
                return (IValidator)null;
            var validatorAttribute = (ValidatorAttribute)Attribute.GetCustomAttribute((MemberInfo)type, typeof(ValidatorAttribute));
            if (validatorAttribute == null || validatorAttribute.ValidatorType == (Type) null)
            {
                return (IValidator) null;
            }
            else
            {
                return _dependencyResolver.GetService(validatorAttribute.ValidatorType) as IValidator;
            }
        }
    }
    

    【讨论】:

    • 感谢 Edys 的回复
    【解决方案3】:

    毫无疑问,验证是一个复杂的过程,通常取决于您的应用程序的架构,但这是我的想法。

    1. 应根据您的需要管理验证器。我通常会将静态类实例留给通常服务于基础设施问题的工厂或对象构建器。

    2. 毫无疑问,FluentValidation 库很棒。验证面临的典型问题不是您选择的库的结果,而是应用验证的方式。在大多数典型的应用程序中,对象/实体/域的验证都是上下文相关的,因此验证完全取决于您尝试执行的操作的上下文。例如,对于持久性、更改属性、更改状态、ETL 等,对同一对象的验证可能会有所不同。牢记所有这些,我相信验证属于尽可能接近正在执行的操作。

    希望这会有所帮助。

    【讨论】:

    • 非常感谢@Kane。很有帮助。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-23
    • 1970-01-01
    • 2019-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多