C# 验证:Fluentvalidation vs.Reflection-最佳实践/性能

C# 验证:Fluentvalidation vs.Reflection-最佳实践/性能,c#,performance,validation,reflection,fluentvalidation,C#,Performance,Validation,Reflection,Fluentvalidation,我有一个清单应用程序,它使用安装在计算机上的代理读取一些信息并将其传递给服务器进行进一步处理。此外,它将存储在数据库中 现在我想知道这些信息的有效性(如计算机名称、操作系统、安装的软件等) 我确实希望在代理端预先验证数据,以避免向服务器发送可能会损害数据库或以后的处理类并导致错误的数据。 当然,我还将在服务器端验证数据,以防止任何人向服务器发送有害代码。 因此,我不需要对代理进行超级精确的验证 另外,为了了解验证错误,数据必须以某种方式发送到服务器,但我想确保我知道这一点,因此可以首先以不同的方

我有一个清单应用程序,它使用安装在计算机上的代理读取一些信息并将其传递给服务器进行进一步处理。此外,它将存储在数据库中

现在我想知道这些信息的有效性(如计算机名称、操作系统、安装的软件等)

我确实希望在代理端预先验证数据,以避免向服务器发送可能会损害数据库或以后的处理类并导致错误的数据。 当然,我还将在服务器端验证数据,以防止任何人向服务器发送有害代码。 因此,我不需要对代理进行超级精确的验证

另外,为了了解验证错误,数据必须以某种方式发送到服务器,但我想确保我知道这一点,因此可以首先以不同的方式处理它。我的计划是将其发送到服务器,服务器只将其存储在日志文件中以供进一步分析

我无意中发现了反射,并发现我可以在标记的答案中使用一小段代码,只需根据正则表达式验证所有整数、字符串等:

公共类验证程序:AbstractValidator
{
公共验证器(Func筛选器){
foreach(var propertyInfo,类型为(T)
.GetProperties()
.Where(过滤器)){
var expression=CreateExpression(propertyInfo);
RuleFor(表达式).NotEmpty();
}
}
私有表达式CreateExpression(PropertyInfo PropertyInfo){
var参数=表达式参数(类型为(T),“x”);
var property=Expression.property(参数,propertyInfo);
var conversion=Expression.conversion(属性,typeof(对象));
var lambda=表达式.lambda(转换,参数);
返回lambda;
}
}
它可以这样使用:
私有静态void ConfigAndTestFluent()
{
CustomerDto customer=新CustomerDto();
Validator Validator=new Validator(x=>x.Name!=“备注”);//我们在这里为属性指定匹配的过滤器
ValidationResult=validator.Validate(客户);
}
我会将其与字符串/整数等的微分一起使用,然后就可以完成了。 但我读到,反射是超慢的,如果可能的话应该避免

按照JeremySkinner的FluentValidation手册,我将做一些事情,如他在这里所示:

使用FluentValidation;
公共类CustomerValidator:AbstractValidator{
公共CustomerValidator(){
RuleFor(customer=>customer.姓氏).NotEmpty();
RuleFor(customer=>customer.Forename).NotEmpty().WithMessage(“请指定名字”);
规则(customer=>customer.Discount).NotEqual(0).When(customer=>customer.HasDiscount);
RuleFor(customer=>customer.Address).Length(20250);
RuleFor(customer=>customer.Postcode).Must(BeAValidPostcode).WithMessage(“请指定有效的邮政编码”);
}
私有布尔BeAValidPostcode(字符串邮政编码){
//自定义邮政编码验证逻辑在这里
}
}
客户=新客户();
CustomerValidator validator=新CustomerValidator();
ValidationResult=validator.Validate(客户);
bool validationSucceeded=results.IsValid;
IList failures=结果。错误;
然后对每个错误进行迭代,重新检查属性类型和用于将其发送回服务器的规则。 缺点是我必须为每一个属性制定验证规则,我想这是最好的做法,但也需要做更多的工作

我没有找到任何明确的答案,或者我只是不明白,所以我想寻求一些意见和帮助。速度其实不是问题,但我想知道我在做什么,以及这样做可能会牺牲什么

因此,我的问题是:

  • 在我的案例中,验证的最佳实践是什么
  • 我是否应该单独验证每个属性
  • 有没有其他方法可以更好地实现同样的目标
非常感谢您的帮助


谢谢:)

关于反思的几句话。如果缓存得当,反射可能会非常快(请参阅我以前关于序列化数百万对象的回答)。因此,如果您在循环中调用同一类型的GetProperties,或者在短时间内多次调用,那么最好有一个字典。如果你只是为每个不同的类调用notempty,它不会对性能有害,可能会在程序启动时有小的延迟(如果你在启动时初始化它)。关于反射的几句话。如果缓存得当,反射可能会非常快(请参阅我以前关于序列化数百万对象的回答)。因此,如果您在循环中调用同一类型的GetProperties,或者在短时间内多次调用,那么最好有一个字典。如果您只是为每个不同的类调用notempty,它不会对性能有害,可能会在程序启动时出现小延迟(如果您在启动时初始化它)。
public class Validator<T> : AbstractValidator<T>
{
public Validator(Func<PropertyInfo, bool> filter) {
    foreach (var propertyInfo in typeof(T)
        .GetProperties()
        .Where(filter)) {
        var expression = CreateExpression(propertyInfo);
        RuleFor(expression).NotEmpty();
    }
}

private Expression<Func<T, object>> CreateExpression(PropertyInfo propertyInfo) {
    var parameter = Expression.Parameter(typeof(T), "x");
    var property = Expression.Property(parameter, propertyInfo);
    var conversion = Expression.Convert(property, typeof(object));
    var lambda = Expression.Lambda<Func<T, object>>(conversion, parameter);

    return lambda;
}
}

And it can be used as such:

private static void ConfigAndTestFluent()
{
    CustomerDto customer = new CustomerDto();
    Validator<CustomerDto> validator = new Validator<CustomerDto>(x=>x.Name!="Remarks"); //we specify here the matching filter for properties
    ValidationResult results = validator.Validate(customer);
}
using FluentValidation;

public class CustomerValidator: AbstractValidator<Customer> {
  public CustomerValidator() {
    RuleFor(customer => customer.Surname).NotEmpty();
   RuleFor(customer => customer.Forename).NotEmpty().WithMessage("Please     specify a first name");
    RuleFor(customer => customer.Discount).NotEqual(0).When(customer =>     customer.HasDiscount);
RuleFor(customer => customer.Address).Length(20, 250);
RuleFor(customer => customer.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode");
  }

  private bool BeAValidPostcode(string postcode) {
// custom postcode validating logic goes here
  }
    }

Customer customer = new Customer();
CustomerValidator validator = new CustomerValidator();
ValidationResult results = validator.Validate(customer);

bool validationSucceeded = results.IsValid;
IList<ValidationFailure> failures = results.Errors;