Пользовательская проверка в Blazor с FluentValidation - PullRequest
1 голос
/ 24 марта 2020

Я пытаюсь создать пользовательскую проверку сложного типа. Я создал тип, который имеет три дочерних класса, каждый из которых имеет свой собственный валидатор. Валидатор просто идет по умолчанию. Один конкретный пример c состоит в том, что денежные суммы должны разрешать отрицательные числа, но, независимо от моих попыток, это позволяет только> 0. Любая помощь приветствуется.

Страница бритвы

<TSValidator />

TSValidator.s c

public class TSValidator : ComponentBase
{
    [CascadingParameter] private EditContext CurrentEditContext { get; set; }

    protected override void OnInitialized()
    {
        if (CurrentEditContext == null)
        {
            throw new InvalidOperationException($"{nameof(TSValidator)} requires a cascading parameter of type {nameof(EditContext)}. For example, you can use {nameof(TSValidator)} inside an {nameof(EditForm)}");
        }

        CurrentEditContext.AddFluentValidation();
    }
}

Расширение

    public static EditContext AddFluentValidation(this EditContext editContext)
    {
        if (editContext == null)
        {
            throw new ArgumentNullException(nameof(editContext));
        }

        var messages = new ValidationMessageStore(editContext);

        editContext.OnValidationRequested += (sender, eventArgs) => ValidateModel((EditContext) sender, messages);

        editContext.OnFieldChanged += (sender, eventArgs) =>
            ValidateField(editContext, messages, eventArgs.FieldIdentifier);

        return editContext;
    }

    public static void ValidateModel(EditContext editContext, ValidationMessageStore store)
    {
        var validator = GetValidatorForModel(editContext.Model);
        var validationResults = validator.Validate(editContext.Model);

        store.Clear();
        foreach (var error in validationResults.Errors)
        {
            store.Add(editContext.Field(error.PropertyName), error.ErrorMessage);
        }

        editContext.NotifyValidationStateChanged();
    }

    public static void ValidateField(EditContext editContext, ValidationMessageStore store,
        in FieldIdentifier fieldIdentifier)
    {
        var properties = new[] {fieldIdentifier.FieldName};
        var context = new FluentValidation.ValidationContext(fieldIdentifier.Model, new FluentValidation.Internal.PropertyChain(), new MemberNameValidatorSelector(properties));
        var validator = GetValidatorForModel(fieldIdentifier.Model);
        var validationResults = validator.Validate(context);

        store.Clear();
        store.Add(fieldIdentifier, validationResults.Errors.Select(error => error.ErrorMessage));

        editContext.NotifyValidationStateChanged();
    }

    public static IValidator GetValidatorForModel(object model)
    {
        var abstractValidatorType = typeof(AbstractValidator<>).MakeGenericType(model.GetType());
        var modelValidatorType = Assembly.GetExecutingAssembly().GetTypes()
            .FirstOrDefault(t => t.IsSubclassOf(abstractValidatorType));
        var modelValidatorInstance = (IValidator) Activator.CreateInstance(modelValidatorType);

        return modelValidatorInstance;
    }

Родительский класс

public class SubmissionActivity
{
    public Submission Submission { get; set; } = new Submission();
    public List<SalesActivitySubmission> SalesActivitySubmissions { get; set; } = new List<SalesActivitySubmission>();
    public RepActivitySubmission RepActivitySubmission { get; set; } = new RepActivitySubmission();

}

Родительский Valdator

public class SubmissionActivityValidator : AbstractValidator<SubmissionActivity>
{
    public SubmissionActivityValidator()
    {
        RuleFor(s => s.RepActivitySubmission).SetValidator(new RepActivitySubmissionValidator());
        RuleForEach(s => s.SalesActivitySubmissions).SetValidator(new SalesActivitySubmissionValidator());
        RuleFor(s => s.Submission).SetValidator(new SubmissionValidator());
    }
}

Дочерние классы

public class Submission
{
    [Key]
    public long SubmissionId { get; set; }
    public DateTime SubmissionDate { get; set; }
    public bool IsActive { get; set; }
    public int PropertyId { get; set; }
    public Property Property { get; set; }
    public DateTime CreatedOn { get; set; }
    public long CreatedBy { get; set; }
    public DateTime ModifiedOn { get; set; }
    public long ModifiedBy { get; set; }
}

public class SalesActivitySubmission
{
    [Key]
    public long SalesActivitySubmissionId { get; set; }
    public long? SubmissionId { get; set; }
    public Submission Submission { get; set; }
    public long? SellerId { get; set; }
    public User Seller { get; set; }
    public int? TicketHierarchyId { get; set; }
    public TicketHierarchy TicketHierarchy { get; set; }
    [Column(TypeName = "money")]
    [Range(-999999999999.99, 999999999999.99, ErrorMessage = "Please enter a positive amount of 999,999,999,999.99 or less.")]
    public decimal? Amount { get; set; }
    [Range(int.MinValue, int.MaxValue, ErrorMessage = "Please enter a valid positive number.")]
    public int? TicketSaleCount { get; set; }
    public DateTime CreatedOn { get; set; }
    public long CreatedBy { get; set; }
    public DateTime ModifiedOn { get; set; }
    public long ModifiedBy { get; set; }
}

public class RepActivitySubmission
{
    [Key]
    public int RepActivitySubmissionId { get; set; }
    public long SellerId { get; set; }
    public User Seller { get; set; }
    public long? SubmissionId { get; set; }
    public Submission Submission { get; set; }

    [Range(int.MinValue, int.MaxValue, ErrorMessage = "Please enter a valid positive number.")]
    public int? CompletedCalls { get; set; }

    [Range(int.MinValue, int.MaxValue, ErrorMessage = "Please enter a valid positive number.")]
    public int? Contacted { get; set; }

    [Range(int.MinValue, int.MaxValue, ErrorMessage = "Please enter a valid positive number.")]
    public int? Pitches { get; set; }

    [Range(int.MinValue, int.MaxValue, ErrorMessage = "Please enter a valid positive number.")]
    public int? Sales { get; set; }

    [Range(int.MinValue, int.MaxValue, ErrorMessage = "Please enter a valid positive number.")]
    public int? Referrals { get; set; }

    [Range(int.MinValue, int.MaxValue, ErrorMessage = "Please enter a valid positive number.")]
    public int? Appointments { get; set; }

    [Range(0, int.MaxValue, ErrorMessage = "Please enter a valid positive number.")]
    public int? HoursWorked { get; set; }

    [Range(0, int.MaxValue, ErrorMessage = "Please enter a valid positive number.")]
    public int? OvertimeHours { get; set; }

    [Range(0, int.MaxValue, ErrorMessage = "Please enter a valid positive number.")]
    public int? PTOHours { get; set; }

    [Column(TypeName = "money")]
    [Range(-999999999999.99, 999999999999.99, ErrorMessage = "Please enter a positive amount of 999,999,999.99 or less.")]
    public decimal? PropExpense { get; set; }
    public DateTime CreatedOn { get; set; }
    public long CreatedBy { get; set; }
    public DateTime ModifiedOn { get; set; }
    public long ModifiedBy { get; set; }
}

Дочерние валидаторы

public class SubmissionValidator : AbstractValidator<Submission>
{
    public SubmissionValidator()
    {
        RuleFor(s => s.SubmissionDate).NotEmpty().NotNull();
    }
}

public class SalesActivitySubmissionValidator : AbstractValidator<SalesActivitySubmission>
{
    public SalesActivitySubmissionValidator()
    {
        RuleFor(s => s.SalesActivitySubmissionId).NotNull().WithMessage("SalesActivitySubmissionId cannot be null");
        RuleFor(s => s.SubmissionId).NotNull().WithMessage("SubmissionId cannot be null.");
        RuleFor(s => s.SellerId).NotNull().WithMessage("SellerId cannot be null");
        RuleFor(s => s.TicketHierarchyId).NotNull().WithMessage("TicketHierarchyId cannot be null.");
        RuleFor(s => s.Amount).InclusiveBetween(0, 999999999999)
            .WithMessage("Amount must be within 0 and 999999999999, inclusively.");
        RuleFor(s => s.TicketSaleCount).GreaterThan(-1).LessThan(int.MaxValue)
            .WithMessage($"TicketSaleCount must be null or between 0 and {int.MaxValue} inclusively.");

    }
}

public class RepActivitySubmissionValidator : AbstractValidator<RepActivitySubmission>
{
    public RepActivitySubmissionValidator()
    {
        RuleFor(r => r.SellerId).NotNull().WithMessage("SellerId cannot be null.");
        RuleFor(r => r.SubmissionId).NotNull().WithMessage("SubmissionId cannot be null.");
        RuleFor(r => r.CompletedCalls).GreaterThanOrEqualTo(0).LessThanOrEqualTo(int.MaxValue)
            .WithMessage($"CompletedCalls must be between 0 and {int.MaxValue} inclusively");
        RuleFor(r => r.Contacted).GreaterThanOrEqualTo(0).LessThanOrEqualTo(int.MaxValue)
            .WithMessage($"Contacted must be between 0 and {int.MaxValue} inclusively");
        RuleFor(r => r.Pitches).GreaterThanOrEqualTo(0).LessThanOrEqualTo(int.MaxValue)
            .WithMessage($"Pitches must be between 0 and {int.MaxValue} inclusively");
        RuleFor(r => r.Sales).GreaterThanOrEqualTo(0).LessThanOrEqualTo(int.MaxValue)
            .WithMessage($"Sales must be between 0 and {int.MaxValue} inclusively");
        RuleFor(r => r.Referrals).GreaterThanOrEqualTo(0).LessThanOrEqualTo(int.MaxValue)
            .WithMessage($"Referrals must be between 0 and {int.MaxValue} inclusively");
        RuleFor(r => r.Appointments).GreaterThanOrEqualTo(0).LessThanOrEqualTo(int.MaxValue)
            .WithMessage($"Appointed must be between 0 and {int.MaxValue} inclusively");
        RuleFor(r => r.HoursWorked).GreaterThanOrEqualTo(0).LessThanOrEqualTo(int.MaxValue)
            .WithMessage($"HoursWorked must be between 0 and {int.MaxValue} inclusively");
        RuleFor(r => r.OvertimeHours).GreaterThanOrEqualTo(0).LessThanOrEqualTo(int.MaxValue)
            .WithMessage($"OvertimeHours must be between 0 and {int.MaxValue} inclusively");
        RuleFor(r => r.PTOHours).GreaterThanOrEqualTo(0).LessThanOrEqualTo(int.MaxValue)
            .WithMessage($"PTOHours must be between 0 and {int.MaxValue} inclusively");
        RuleFor(r => r.PropExpense).GreaterThanOrEqualTo(0).LessThan(1000000000000)
            .WithMessage("PropExpense must be between 0 and 999999999999.99.");
    }
}

1 Ответ

1 голос
/ 26 марта 2020

Будет ли это иметь какое-либо отношение к наличию атрибутов данных проверки диапазона, которые допускают отрицательные числа, и правил быстрой проверки, которые не допускают отрицательные числа? Похоже, вы задаете правила проверки для одних и тех же свойств дважды, используя разные поставщики проверки, и правила, указанные каждым поставщиком, различны.

Например,

Один указатель c Примером является то, что суммы денег должны разрешать отрицательные числа, но независимо от моих попыток, это позволяет только> 0

public class SalesActivitySubmission
{
    ...

    [Column(TypeName = "money")]
    [Range(-999999999999.99, 999999999999.99, ErrorMessage = "Please enter a positive amount of 999,999,999,999.99 or less.")]
    public decimal? Amount { get; set; }

    ...
}
public class SalesActivitySubmissionValidator : AbstractValidator<SalesActivitySubmission>
{
    public SalesActivitySubmissionValidator()
    {
        ...

        RuleFor(s => s.Amount).InclusiveBetween(0, 999999999999)
            .WithMessage("Amount must be within 0 and 999999999999, inclusively.");

        ...
    }
}

Обычно вы не указываете атрибуты данных при использовании свободное подтверждение - у вас должен быть единый источник правды для подтверждения, если это возможно.

В ASP. NET Проверка ядра выполняется перед другими провайдерами проверки. В этом случае встроенный поставщик не сможет проверить атрибут данных проверки диапазона на наличие отрицательных сумм, так как полная проверка уже проверила свойство и вернула ошибку проверки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...