簡體   English   中英

除了少數之外,所有屬性都不是空的

[英]All properties notempty except a few

我是使用FluentValidation的新手,想知道是否可以為 Model 上的所有屬性設置相同的規則,除了少數屬性。

我有一系列具有 20 多個屬性的模型,除了一對之外,它們都不應該為空。

我相信這個RuleFor(x=>x).NotEmpty()應該適用於所有屬性,但我如何確保忽略 2 個屬性?

提前致謝,

這是我想出的,主要問題是表達式需要靜態類型,所以你不能為所有類型隱式定義規則。

public interface IPropertiesValidator<T>
{
    void RuleForType<TProperty>(Action<IRuleBuilder<T, TProperty>> action, CascadeMode cascadeMode = CascadeMode.Continue);
}

internal class NotNullOrEmptyPropertiesValidator<T> : AbstractValidator<T>, IPropertiesValidator<T>
{
    private readonly List<PropertyInfo> properties;

    internal NotNullOrEmptyPropertiesValidator(Func<PropertyInfo, bool> filter, Action<IPropertiesValidator<T>> customize = null)
    {
        // get the properties the notnullorempty should apply to
        properties = typeof(T)
           .GetProperties()
           .Where(filter)
           .ToList();

        var message = "{PropertyName} of {PropertyType} type cannot be null or empty";

        // we need to explicity support a type because of the generic way the validators are set on FluentValidation
        // potentially there maybe another way but couldn't figure it out, the advantage is that we can handle both nullables or not
        RuleForType<string>(x => x.NotEmpty().WithMessage(message));

        RuleForType<sbyte>(x => x.NotEmpty().WithMessage(message));
        RuleForType<byte>(x => x.NotEmpty().WithMessage(message));
        RuleForType<short>(x => x.NotEmpty().WithMessage(message));
        RuleForType<ushort>(x => x.NotEmpty().WithMessage(message));
        RuleForType<int>(x => x.NotEmpty().WithMessage(message));
        RuleForType<uint>(x => x.NotEmpty().WithMessage(message));
        RuleForType<long>(x => x.NotEmpty().WithMessage(message));
        RuleForType<ulong>(x => x.NotEmpty().WithMessage(message));
        RuleForType<float>(x => x.NotEmpty().WithMessage(message));
        RuleForType<double>(x => x.NotEmpty().WithMessage(message));
        RuleForType<decimal>(x => x.NotEmpty().WithMessage(message));
        RuleForType<DateTime>(x => x.NotEmpty().WithMessage(message));

        RuleForType<sbyte?>(x => x.NotNull().NotEmpty().WithMessage(message), CascadeMode.Stop);
        RuleForType<byte?>(x => x.NotNull().NotEmpty().WithMessage(message), CascadeMode.Stop);
        RuleForType<short?>(x => x.NotNull().NotEmpty().WithMessage(message), CascadeMode.Stop);
        RuleForType<ushort?>(x => x.NotNull().NotEmpty().WithMessage(message), CascadeMode.Stop);
        RuleForType<int?>(x => x.NotNull().NotEmpty().WithMessage(message), CascadeMode.Stop);
        RuleForType<uint?>(x => x.NotNull().NotEmpty().WithMessage(message), CascadeMode.Stop);
        RuleForType<long?>(x => x.NotNull().NotEmpty().WithMessage(message), CascadeMode.Stop);
        RuleForType<ulong?>(x => x.NotNull().NotEmpty().WithMessage(message), CascadeMode.Stop);
        RuleForType<float?>(x => x.NotNull().NotEmpty().WithMessage(message), CascadeMode.Stop);
        RuleForType<double?>(x => x.NotNull().NotEmpty().WithMessage(message), CascadeMode.Stop);
        RuleForType<decimal?>(x => x.NotNull().NotEmpty().WithMessage(message), CascadeMode.Stop);
        RuleForType<DateTime?>(x => x.NotNull().NotEmpty().WithMessage(message), CascadeMode.Stop);

        // allows for custom types rules to be set when creating the validator
        customize?.Invoke(this);
    }

    public void RuleForType<TProperty>(Action<IRuleBuilder<T, TProperty>> action, CascadeMode cascadeMode = CascadeMode.Continue)
    {
        foreach (var prop in properties
            .Where(x => x.PropertyType == typeof(TProperty)))
        {
            var expression = CreateExpression<TProperty>(prop);
            var ruleBuilder = RuleFor(expression)
                .Cascade(cascadeMode)
                .Custom((_, context) =>
                {
                    context.MessageFormatter
                        .AppendArgument("PropertyType", typeof(TProperty).Name); // TODO: this is not working
                });
            action.Invoke(ruleBuilder);
        }
    }

    private Expression<Func<T, TProperty>> CreateExpression<TProperty>(PropertyInfo propertyInfo)
    {
        var param = Expression.Parameter(typeof(T));
        return Expression.Lambda<Func<T, TProperty>>(
            Expression.Property(param, propertyInfo), param);
    }
}

public static class NotNullOrEmptyPropertiesValidatorExtensions
{
    /// <summary>
    /// Sets a single <see cref="NotNullOrEmptyPropertiesValidator{T}"/> for all the <typeparamref name="TElement"/> in the collection.
    /// </summary>
    /// <typeparam name="T">The root type</typeparam>
    /// <typeparam name="TElement">The collection element type</typeparam>
    /// <param name="ruleBuilder">The rule builder</param>
    /// <param name="filter">The filter for the properties that this validator should apply</param>
    /// <param name="customize">Optional custom property return type rules to be set</param>
    /// <returns></returns>
    public static IRuleBuilderOptions<T, IEnumerable<TElement>> ForEachNotNullOrEmptyProperties<T, TElement>(this IRuleBuilder<T, IEnumerable<TElement>> ruleBuilder, 
        Func<PropertyInfo, bool> filter, Action<IPropertiesValidator<TElement>> customize = null)
    {
        var validator = new NotNullOrEmptyPropertiesValidator<TElement>(filter, customize);
        return ruleBuilder.ForEach(x => x.SetValidator(validator));
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM