[英]Is it possible to automatically map all properties except a few complicated ones with AutoMapper?
[英]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.