7

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

我有两个问题:

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

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

如果您在类似的场景中使用它,您的体验是什么?

4

3 回答 3

5

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

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

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

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

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

于 2013-06-10T13:11:04.927 回答
4

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

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

对于我的缓存,我查看了验证器的 Per Request 缓存。这很好用,因为所有依赖组件都是 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;
        }
    }
}
于 2013-06-27T20:22:42.647 回答
2

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

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

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

希望这会有所帮助。

于 2013-06-09T03:45:48.493 回答