zoukankan      html  css  js  c++  java
  • FluentValidation:C#后端输入验证框架的官方文档解读

    参照 FluentValidation 的官方文档写的例子,方便日后查看和使用。

    原文:https://github.com/JeremySkinner/FluentValidation/wiki

     Home

    NuGet Packages

    Install-Package FluentValidation
    

    For ASP.NET MVC integration:

    Install-Package FluentValidation.MVC5
    

    For ASP.NET Core:

    Install-Package FluentValidation.AspNetCore

    Example

    复制代码
    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;
    复制代码

    a. Index

    Documentation table of contents

    b. Creating a Validator

    定义对象,及对象验证类

    复制代码
        public class Customer
        {
            public int Id { get; set; }
            public string Surname { get; set; }
            public string Forename { get; set; }
            public decimal Discount { get; set; }
            public Address Address { get; set; }
            public List<string> AddressLines { get; set; } = new List<string>();
            public IList<Order> Orders { get; set; }
        }
    
        /// <summary>
        /// 为Customer类定义一组规则,继承自AbstractValidator<Customer>
        /// </summary>
        public class CustomerValidator : AbstractValidator<Customer>
        {
            public CustomerValidator()
            {
                //多个验证规则
                RuleFor(customer => customer.Surname).NotNull().NotEqual("foo");
    
                //对集合中的每一项进行验证
                RuleForEach(x => x.AddressLines).NotNull();
    
                //复合属性验证的重新利用
                RuleFor(customer => customer.Address).SetValidator(new AddressValidator());
    
                //复合的集合属性验证的重新利用
                RuleFor(x => x.Orders).SetCollectionValidator(new OrderValidator());
                //用Where方法选择性验证某些项
                RuleFor(x => x.Orders).SetCollectionValidator(new OrderValidator()).Where(x => x.Cost != null);
    
                //定义名为“Names”的规则集合
                RuleSet("Names", () =>
                {
                    RuleFor(x => x.Surname).NotNull();
                    RuleFor(x => x.Forename).NotNull();
                });
            }
        }
    复制代码
    复制代码
        public class Address
        {
            public string Line1 { get; set; }
            public string Line2 { get; set; }
            public string Town { get; set; }
            public string County { get; set; }
            public string Postcode { get; set; }
        }
        public class AddressValidator : AbstractValidator<Address>
        {
            public AddressValidator()
            {
                RuleFor(address => address.Postcode).NotNull();
                //etc
            }
        }
    复制代码
    复制代码
        public class Order
        {
            public string ProductName { get; set; }
            public decimal? Cost { get; set; }
        }
        public class OrderValidator : AbstractValidator<Order>
        {
            public OrderValidator()
            {
                RuleFor(x => x.ProductName).NotNull();
                RuleFor(x => x.Cost).GreaterThan(0);
            }
        }
    复制代码

    调用

    复制代码
            public void Validate()
            {
                Customer customer = new Customer();
                customer.Orders = new List<Order> {
                    new Order { ProductName = "Foo" },
                    new Order { Cost = 5 }
                };
    
                CustomerValidator validator = new CustomerValidator();
                ValidationResult results = validator.Validate(customer);
    
                //将复杂的验证定义分解到较小的片段中,可独立使用
                //把多个规则聚集都一个规则集合中
                var result1 = validator.Validate(customer, ruleSet: "Names");
                //多个规则集合
                var result2 = validator.Validate(customer, ruleSet: "Names,MyRuleSet,SomeOtherRuleSet");
                //不在任何规则集合中的default
                var result3 = validator.Validate(customer, ruleSet: "default,MyRuleSet");
    
                if (!results.IsValid)
                {
                    foreach (var failure in results.Errors)
                    {
                        Console.WriteLine("Property " + failure.PropertyName + " failed validation. Error was: " + failure.ErrorMessage);
                    }
                }
    
                //抛出异常
                validator.ValidateAndThrow(customer);
    
            }
    复制代码

    c. Built In Validators 内置验证器 

    复制代码
    //Ensures that the specified property is not null.
    RuleFor(customer => customer.Surname).NotNull();
    
    //Ensures that the specified property is not null, an empty string or whitespace (or the default value for value types, eg 0 for int)
    RuleFor(customer => customer.Surname).NotEmpty();
    
    //Not equal to a particular value
    RuleFor(customer => customer.Surname).NotEqual("Foo");
    //Not equal to another property
    RuleFor(customer => customer.Surname).NotEqual(customer => customer.Forename);
    
    //Equal to a particular value
    RuleFor(customer => customer.Surname).Equal("Foo");
    //Equal to another property
    RuleFor(customer => customer.Password).Equal(customer => customer.PasswordConfirmation);
    
    //must be between 1 and 250 chars (inclusive)
    RuleFor(customer => customer.Surname).Length(1, 250);
    
    //Less than a particular value
    RuleFor(customer => customer.CreditLimit).LessThan(100);
    //Less than another property
    RuleFor(customer => customer.CreditLimit).LessThan(customer => customer.MaxCreditLimit);
    
    //Less than a particular value
    RuleFor(customer => customer.CreditLimit).LessThanOrEqualTo(100);
    //Less than another property
    RuleFor(customer => customer.CreditLimit).LessThanOrEqualTo(customer => customer.MaxCreditLimit);
    
    //Greater than a particular value
    RuleFor(customer => customer.CreditLimit).GreaterThan(0);
    //Greater than another property
    RuleFor(customer => customer.CreditLimit).GreaterThan(customer => customer.MinimumCreditLimit);
    
    //Greater than a particular value
    RuleFor(customer => customer.CreditLimit).GreaterThanOrEqualTo(1);
    //Greater than another property
    RuleFor(customer => customer.CreditLimit).GreaterThanOrEqualTo(customer => customer.MinimumCreditLimit);
    
    //Passes the value of the specified property into a delegate that can perform custom validation logic on the value
    //Also known as "Must"
    RuleFor(customer => customer.Surname).Must(surname => surname == "Foo");
    //Note that there is an additional overload for Must that also accepts an instance of the parent object being validated. 
    //This can be useful if you want to compare the current property with another property from inside the predicate:
    //Note that in this particular example, it would be better to use the cross-property version of NotEqual
    RuleFor(customer => customer.Surname).Must((customer, surname) => surname != customer.Forename);
    
    //Ensures that the value of the specified property matches the given regular expression. Example:
    RuleFor(customer => customer.Surname).Matches("some regex here");
    
    //Ensures that the value of the specified property is a valid email address format. Example:
    RuleFor(customer => customer.Email).EmailAddress();
    复制代码

    d. Configuring a Validator 配置验证器

    1.Override the default error message

    RuleFor(customer => customer.Surname).NotNull().WithMessage("Please ensure that you have entered your Surname");
    //'{PropertyName}' will be replaced with the name of the property being validated
    //and the value 'Surname' will be inserted.
    RuleFor(customer => customer.Surname).NotNull().WithMessage("Please ensure you have entered your {PropertyName}");
    Configuring Error Message Parameters (Placeholders)
     
    The placeholders are Used in all validators:
    '{PropertyName}' - The name of the property being validated
    '{PropertyValue}' - The value of the property being validated These include the predicate validator('Must' validator), the email and the regex validators.
     
    Used in comparison validators: (Equal, NotEqual, GreaterThan, GreaterThanOrEqual, etc.)
    { ComparisonValue} = Value that the property should be compared to
     
    Used only in the Length validator:
    { MinLength} = Minimum length
    { MaxLength} = Maximum length
    { TotalLength} = Number of characters entered
    复制代码
    //Using static values in a custom message:
    RuleFor(customer => customer.Surname).NotNull()
        .WithMessage(customer => string.Format("This message references some constant values: {0} {1}", "hello", 5));
    //Result would be "This message references some constant values: hello 5"
    
    //Referencing other property values:
    RuleFor(customer => customer.Surname).NotNull()
        .WithMessage(customer => $"This message references some other properties: Forename: {customer.Forename} Discount: {customer.Discount}");
    //Result would be: "This message references some other properties: Forename: Jeremy Discount: 100"
    复制代码

    2.Overriding the Default Property Name

    复制代码
    //The default error message would be 'Surname' must not be empty. 
    RuleFor(customer => customer.Surname).NotNull();
    //Replace just the property name by calling WithName //Now the error message would be 'Last name' must not be empty. RuleFor(customer => customer.Surname).NotNull().WithName("Last name");
    //Completely rename the property, including the Errors collection on the ValidationResult RuleFor(customer => customer.Surname).NotNull().OverridePropertyName("Last name");
    复制代码
    复制代码
    //Property name resolution is also pluggable.By default, the name of the property extracted from the MemberExpression passed to RuleFor. If you want change this logic, you can set the DisplayNameResolver property on the ValidatorOptions class.
    //这段不是太懂
    ValidatorOptions.DisplayNameResolver = (type, member) => {
        if (member != null)
        {
            return member.Name + "Foo";
        }
        return null;
    };
    复制代码
    //另外,FluentValidation 可采用 DisplayName and Display attributes,来生成错误信息中的属性名,同 WithName
    public class Person
    {
        [Display(Name = "Last name")]
        public string Surname { get; set; }
    }

    3.Specifying a condition with When/Unless 指定条件

    复制代码
    //当满足条件时才执行验证规则(Unless则相反)
    RuleFor(customer => customer.CustomerDiscount).GreaterThan(0).When(customer => customer.IsPreferredCustomer);
    
    //同时应用到多条规则
    When(customer => customer.IsPreferred, () =>
    {
        RuleFor(customer => customer.CustomerDiscount).GreaterThan(0);
        RuleFor(customer => customer.CreditCardNumber).NotNull();
    });
    复制代码

    4.Setting the Cascade mode 设置级联模式

    //默认是第一个验证失败后,继续执行第二个验证
    RuleFor(x => x.Surname).NotNull().NotEqual("foo");
    //第一个验证失败后停止,不再验证之后的规则 RuleFor(x => x.Surname).Cascade(CascadeMode.StopOnFirstFailure).NotNull().NotEqual("foo");
    The two cascade modes are:
    Continue(the default) - always invokes all validators in a rule definition
    StopOnFirstFailure - stops executing a rule as soon as a validator fails
    //在应用程序启动入口设置全局级联模式
    //这会被具体的验证器类和具体的验证规则重写
    ValidatorOptions.CascadeMode = CascadeMode.StopOnFirstFailure;
    复制代码
    //在单个验证器类中设置级联模式
    public class PersonValidator : AbstractValidator<Person>
    {
        public PersonValidator()
        {
            // First set the cascade mode
            CascadeMode = CascadeMode.StopOnFirstFailure;
    
            //Rule definitions follow
            //RuleFor(...)
            //RuleFor(...)
        }
    }
    复制代码

    e. Custom Validators 定制验证器 

    1.Using the Predicate Validator 使用断言验证器

    复制代码
    public class Person
    {
        public IList<Pet> Pets { get; set; } = new List<Pet>();
    }
    public class PersonValidator : AbstractValidator<Person> { public PersonValidator() { RuleFor(x => x.Pets).Must(list => list.Count <= 10).WithMessage("The list must contain fewer than 10 items"); } }
    复制代码
    复制代码
    //封装成扩展方法,使其可重用
    public static class MyCustomValidators
    {
        public static IRuleBuilderOptions<T, IList<TElement>> ListMustContainFewerThan<T, TElement>(this IRuleBuilder<T, IList<TElement>> ruleBuilder, int num)
        {
            return ruleBuilder.Must(list => list.Count < num).WithMessage("The list contains too many items");
        }
    }
    RuleFor(x => x.Pets).ListMustContainFewerThan(10);
    复制代码

    Using a custom message placeholder 定制消息

    复制代码
    //The resulting message will now be 'Pets' must contain fewer than 10 items.
    public static IRuleBuilderOptions<T, IList<TElement>> ListMustContainFewerThan<T, TElement>(this IRuleBuilder<T, IList<TElement>> ruleBuilder, int num)
    {
        return ruleBuilder.Must((rootObject, list, context) =>
        {
            context.MessageFormatter.AppendArgument("MaxElements", num);
            return list.Count < num;
        })
        .WithMessage("{PropertyName} must contain fewer than {MaxElements} items.");
    }
    
    public static IRuleBuilderOptions<T, IList<TElement>> ListMustContainFewerThan<T, TElement>(this IRuleBuilder<T, IList<TElement>> ruleBuilder, int num)
    {
        return ruleBuilder.Must((rootObject, list, context) =>
        {
            context.MessageFormatter
              .AppendArgument("MaxElements", num)
              .AppendArgument("TotalElements", list.Count);
    
            return list.Count < num;
        })
        .WithMessage("{PropertyName} must contain fewer than {MaxElements} items. The list contains {TotalElements} element");
    }
    复制代码

    2.Using a Custom Validator 使用定制验证器

    复制代码
    //This method allows you to manually create the ValidationFailure instance associated with the validation error. 
    RuleFor(x => x.Pets).Custom((list, context) =>
    {
        if (list.Count > 10)
        {
            context.AddFailure("The list must contain 10 items or fewer");
            // It allows you to return multiple errors for the same rule 
            context.AddFailure("SomeOtherProperty", "The list must contain 10 items or fewer");
            // Or you can instantiate the ValidationFailure directly:
            context.AddFailure(new ValidationFailure("SomeOtherProperty", "The list must contain 10 items or fewer");
        }
    });
    复制代码

    3.Writing a Custom, reusable Property Validator 使用定制可重用属性验证器

    复制代码
    //若定制的逻辑非常复杂,则可将定制逻辑放入单独的验证类中
    public class ListCountValidator<T> : PropertyValidator
    {
        private int _max;
    
        public ListCountValidator(int max)
            : base("{PropertyName} must contain fewer than {MaxElements} items.")
        {
            _max = max;
        }
    
        protected override bool IsValid(PropertyValidatorContext context)
        {
            var list = context.PropertyValue as IList<T>;
    
            if (list != null && list.Count >= _max)
            {
                context.MessageFormatter.AppendArgument("MaxElements", _max);
                return false;
            }
    
            return true;
        }
    }
    复制代码
    复制代码
    //调用方法一
    RuleFor(person => person.Pets).SetValidator(new ListCountValidator<Pet>(10));
    
    
    //调用方法二
    public static IRuleBuilderOptions<T, IList<TElement>> ListMustContainFewerThan3<T, TElement>(this IRuleBuilder<T, IList<TElement>> ruleBuilder, int num)
    {
        return ruleBuilder.SetValidator(new ListCountValidator<Pet>(10));
    }
    RuleFor(x => x.Pets).ListMustContainFewerThan(10);
    复制代码

    4.Using AbstractValidator.Custom (Deprecated in 7.0) 抽象验证器(弃用) 

    复制代码
    //从7.0版本开始弃用,推荐上文中使用的 RuleFor(x => x).Custom((x, context) => ... )
    public class PersonValidator : AbstractValidator<Person>
    {
        public PersonValidator()
        {
            Custom(person => {
                return person.Pets.Count >= 10
                   ? new ValidationFailure("Pets", "More than 9 pets is not allowed.")
                   : null;
            });
        }
    }
    复制代码
  • 相关阅读:
    让Div居中的方法
    创建对象的几种方式
    [Gport]2014移动互联网趋势——100名CEO的一句话解读
    专访腾讯云陈磊:微信云助力企业转型把握O2O时代价值
    Head First Python 学习笔记(第二章:分享你的代码)
    Head First Python 学习笔记(第一章:使用IDLE来帮助学习Python)
    《写给大家看的设计书》学习笔记
    用TreeView以递归显示选择磁盘上文件夹中全部文件夹和文件
    WebBrowser实现:自动填充网页上的用户名和密码并点击登录按钮
    C#调用免费天气预报WebService
  • 原文地址:https://www.cnblogs.com/Alex80/p/8904477.html
Copyright © 2011-2022 走看看