FluentValidation 和 Unity
在 Silverlight 应用程序中使用 Fluent Validation 和 Unity

引言
验证通常是开发项目的痛点。它对可用性和数据完整性至关重要(并且通常与安全性相关,以确保数据不是攻击应用程序的尝试),但编写验证代码和处理所有变体可能非常耗时。幸运的是,Jeremy Skinner 创建了一个优秀的开源验证框架,称为 Fluent Validation for .NET。Jeremy 已经创建了大量的文档,因此本文将不会涵盖 Fluent Validation for .NET 的特性和用法。文档中没有涵盖的一个特性是如何在使用 Unity
(一种控制反转 (IoC) 容器)时通过依赖注入传递验证对象。本文解决了如何做到这一点。对于附带的示例,我使用了 Silverlight,但相同的方法也可以用于 WPF。
背景
依赖注入是一种有用的模式,可以实现松耦合,并简化测试,允许将依赖项替换为桩或模拟对象。通过能够将验证对象传递到业务对象或视图模型(在 MVVM 的情况下),可以为业务对象或视图模型编写测试,而无需业务对象或视图模型本身有效。验证对象可以被替换为根据需要始终通过或失败。
本文不涉及单元测试、模拟和依赖注入。假设读者已经熟悉这些技术。
使用代码
第一步是从 Fluent Validation for .NET 提供的 ValidatorFactoryBase
创建一个 Unity
验证器工厂。重要的代码是 CreateInstance
的重写,它允许工厂从 Unity
容器返回正确的验证对象。
public class UnityValidatorFactory : ValidatorFactoryBase
{
private readonly IUnityContainer _container;
public UnityValidatorFactory(IUnityContainer container)
{
_container = container;
}
public override IValidator CreateInstance(Type validatorType)
{
return _container.Resolve(validatorType) as IValidator;
}
}
下一步是将工厂注册到 Unity
容器中。在附带的示例中,这在 Bootstrapper.cs
类中完成。
Container.RegisterType<IValidatorFactory, UnityValidatorFactory>(new ContainerControlledLifetimeManager());
现在,可以通过继承 AbstractValidator
基类来创建验证类。有关如何从这个基类构建验证规则的更多信息,请参阅 Fluent Validation for .NET 文档。
public class MainPageViewModelValidator : AbstractValidator<IMainPageViewModel>
{
public MainPageViewModelValidator()
{
RuleFor(x => x.FirstName)
.NotEmpty()
.WithMessage("First name cannot be blank.");
RuleFor(x => x.LastName)
.NotEmpty()
.WithMessage("Last name cannot be blank.");
RuleFor(x => x.Age)
.NotEmpty()
.WithMessage("Age is required.");
RuleFor(x => x.Age)
.Must(a => a.IsInt32())
.When(x => !x.Age.IsNullOrEmpty())
.WithMessage("Age must be an integer.");
}
}
验证类还必须注册到 Unity
。在附带的示例中,这也注册在 Bootstrapper.cs
中。IValidator
泛型接口被分配给视图模型的接口,并且注册的实现是视图模型验证器。
Container.RegisterType<IValidator<IMainPageViewModel>, MainPageViewModelValidator>(new ContainerControlledLifetimeManager());
现在,ViewModel
可以通过将验证工厂作为依赖项传递并请求所需的验证对象来访问验证对象。
using FluentValidation;
private readonly IValidator<IMainPageViewModel> _validator;
public MainPageViewModel(IValidatorFactory validatorFactory)
{
_validator = validatorFactory.GetValidator<IMainPageViewModel>();
}
然后,可以使用验证对象,根据需要验证整个视图模型,或仅验证属性(这在实现 IDataErrorInfo
时很有用,如附带的示例所示)。下面显示了一个验证属性的示例。请注意,验证对象可以返回多个错误,因此 ValidationResult
包含一个 Errors
集合。
public string FirstName
{
get { return _firstName; }
set
{
if (_firstName != value)
{
_firstName = value;
RaisePropertyChanged("FirstName");
}
// validate - even if no change
ClearError("FirstName");
var validationResult = _validator.Validate(this, "FirstName");
if (!validationResult.IsValid)
{
validationResult.Errors.ToList().ForEach(x => SetError("FirstName", x.ErrorMessage));
}
}
}
历史
- 2011 年 7 月 - 初始发布。