- 将验证逻辑添加到模型类本身。
- 不是最好的方法,因为你会用逻辑炸毁 POCO,你最终会使用 ActiveRecord 模式,它不那么干净。
- 为环绕我的 Operation 对象的验证逻辑创建一个装饰器类。
- 认为这是一种更好的方法,不同之处在于您必须包装已经存在的包装器,并且您最终也会破坏抽象级别,因此也不推荐。
- 创建一个服务类,只要我想验证它,我就会调用它来传递操作。
- 完成这些事情可能也不是你的情况(如果我正确理解你所说的关于 web 服务或其他类型的远程服务),如果你对这些验证规则有限制,那么这个解决方案更合适,例如集中用于多个客户端,而不是紧贴具体应用程序。
我赞成以下解决方案:
向您的解决方案添加一个验证器项目,其中将包含:
所以:
1-您的 POCO 将包含属性和一个简单的验证 SelfValidate():
namespace Core.Domain {
public class Operation : ValidatableDomainObject {
#region Properties
public virtual String Name { get; set; }
public virtual ISet Phases { get; set; }
#endregion Properties
#region Validation
public override ValidationResult SelfValidate() {
return ValidationHelper.Validate(this);
}
#endregion Validation
}
}
2-您的 POCO 验证器将包含应应用于基于您的 XML 文件验证 POCO 的规则:
#region Usings
using System.Linq;
using FluentValidation;
using FluentValidation.Results;
#endregion Usings
namespace Core.Validation {
public class OperationValidator : AbstractValidator {
#region .Ctors
///
/// .Ctor used for operation purpose
///
public OperationValidator() {
Validate();
}
#endregion .Ctors
///
/// Validation rules for Operation
///
private void Validate() {
//here you may get validations rules from you xml file and structure the following code after your requirements
//Name
RuleFor(x => x.Name).Length(2, 20).WithMessage("Operation name should have length between 2 and 20 symbols");
//ApplicationFormsWrapper
Custom(entity => {
foreach (var item in entity.Phases)
if (item.PhaseState == null)
return new ValidationFailure("Phases", "First Phase is missing");
return null;
});
}
}
}
3-添加 ValidatableDomainObject 类,它实现 System.ComponentModel.IDataErrorInfo (提供提供自定义错误信息的功能,用户界面可以绑定到):
#region Usings
using System.ComponentModel;
using System.Linq;
using FluentValidation.Results;
using Core.Validation.Helpers;
#endregion Usings
namespace Core.Domain.Base {
public abstract class ValidatableDomainObject : DomainObject, IDataErrorInfo {
public abstract ValidationResult SelfValidate();
public bool IsValid {
get { return SelfValidate().IsValid; }
}
public string Error {
get { return ValidationHelper.GetError(SelfValidate()); }
}
public string this[string columnName] {
get {
var validationResults = SelfValidate();
if (validationResults == null) return string.Empty;
var columnResults = validationResults.Errors.FirstOrDefault(x => string.Compare(x.PropertyName, columnName, true) == 0);
return columnResults != null ? columnResults.ErrorMessage : string.Empty;
}
}
}
}
4-添加以下 ValidationHelper:
#region Usings
using System;
using System.Text;
using FluentValidation;
using FluentValidation.Results;
#endregion Usings
namespace Core.Validation.Helpers {
public class ValidationHelper {
public static ValidationResult Validate(TK entity)
where T : IValidator, new()
where TK : class {
IValidator validator = new T();
return validator.Validate(entity);
}
public static string GetError(ValidationResult result) {
var validationErrors = new StringBuilder();
foreach (var validationFailure in result.Errors) {
validationErrors.Append(validationFailure.ErrorMessage);
validationErrors.Append(Environment.NewLine);
}
return validationErrors.ToString();
}
}
}
它将允许您在应用程序代码中执行以下操作:
- 在服务或视图模型级别,您可以这样做以获得验证错误:
var operation = new Operation(){Name="A"};
var validationResults = operation.SelfValidate();
- 在视图级别,您可以编写类似这样的内容(在这种情况下,如果出现任何验证错误,它们直接来自 OperationValidator 类):
<TextBox Text="{绑定 CurrentOperation.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}">
注意:实现基于 FluentValidation(一个用于 .NET 的小型验证库,它使用流畅的接口和 lambda 表达式),请参阅http://fluentvalidation.codeplex.com/,但当然你可以使用另一个,希望我成功了描述从域对象中解耦验证的机制。