question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

"default", "*" RuleSet - hard coded string

See original GitHub issue

Is your feature request related to a problem? Please describe. I am using FV with dependency injection. I have many rules set up without a ruleset, while many others are nested under rulesets. Here’s what my validator looks like:

public const string AddRuleSet = nameof(AddRuleSet);
public const string UpdateRuleSet = nameof(UpdateRuleSet);

public SynonymValidator(IDateTimeBroker dateTimeBroker)
{
    this.dateTimeBroker = dateTimeBroker;

    RuleFor(synonym => synonym.Id).NotEmpty();
    RuleFor(synonym => synonym.Text).NotEmpty();
    RuleFor(synonym => synonym.CreatedBy).NotEmpty();
    RuleFor(synonym => synonym.UpdatedBy).NotEmpty();

    RuleSet(AddRuleSet, () =>
    {
        defaultRules();
        RuleFor(synonym => synonym.CreatedDate).Must(IsDateRecent);
        RuleFor(synonym => synonym.UpdatedDate).Equal(synonym => synonym.CreatedDate);
    });

    RuleSet(UpdateRuleSet, () =>
    {
        defaultRules();
        RuleFor(synonym => synonym.UpdatedDate).Must(IsDateRecent);
        RuleFor(synonym => synonym.CreatedDate).LessThan(synonym => synonym.UpdatedDate);
    });
}

I need all default rules to always execute.

Describe the solution you’d like

  1. validator.Validate(ruleSet: SynonymValidator.AddRuleSet, includeDefaultRuleSet: true);
  2. An alternative way to set up rulesets, rather than strings or hard-coded strings.
  3. Allow ruleSets: rule1, rule2 (using params) rather than hard coded rulesSets: "rule1, rule2, *"
  4. Provide all these constants (i.e. "*", "default" etc.) are centralized, to help users avoid hard coded strings.

Describe alternatives you’ve considered

  1. What I ended up doing because of this
ValidationResult validationResult = this.synonymValidator.Validate(synonym);

ThrowAndLogOnFailure(validationResult);

validationResult = this.synonymValidator.Validate(synonym, );

ThrowAndLogOnFailure(validationResult);
public SynonymValidator(IDateTimeBroker dateTimeBroker)
{
    this.dateTimeBroker = dateTimeBroker;

    RuleSet("*", () =>
    {
        RuleFor(synonym => synonym.Id).NotEmpty();
        RuleFor(synonym => synonym.Text).NotEmpty();
        RuleFor(synonym => synonym.CreatedBy).NotEmpty();
        RuleFor(synonym => synonym.UpdatedBy).NotEmpty();
    });

    RuleSet(AddRuleSet, () =>
    {
        RuleFor(synonym => synonym.CreatedDate).Must(IsDateRecent);
        RuleFor(synonym => synonym.UpdatedDate).Equal(synonym => synonym.CreatedDate);
    });

    RuleSet(UpdateRuleSet, () =>
    {
        RuleFor(synonym => synonym.UpdatedDate).Must(IsDateRecent);
        RuleFor(synonym => synonym.CreatedDate).LessThan(synonym => synonym.UpdatedDate);
    });
}

I’m will to contribute.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:5 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
JeremySkinnercommented, Jul 9, 2020

Thanks, let me know if you have any further questions. I’ve also opened https://github.com/FluentValidation/FluentValidation/issues/1437 to discuss the confusion around CascadeMode (which is a common occurrence).

The lock-bot locks closed issues if they’ve not had new replies in 14 days, so feel free to re-open if you want to keep this thread alive.

1reaction
JeremySkinnercommented, Jul 9, 2020

Hello,

The overload of Validate that takes a string ruleset is a shortcut/wrapper around creation of a context. If you’d prefer an alternative syntax then the simplest thing you can do is directly instantiate the context yourself:

var selector = ValidatorOptions.ValidatorSelectors.RulesetValidatorSelectorFactory(arrayOfRulesetNames);
var context = new ValidationContext<T>(instance, new PropertyChain(), selector);
validator.Validate(context);

If you wanted to, you can wrap this logic in an extension method within your project. This way you can have whatever syntax you like, without it requiring a change to the core library.

However I am open to changing things in the library, but just need to be careful this won’t cause incompatibilities or breaking changes. There is an already an overload of Validate that takes a params string[] propertyNames, so accepting a params of rulesets would not be feasible without a new method (like ValidateRulesets or something like that), or just accepting a regular array rather than a params array.

If you’d like to put together a pull request that includes a prototype to implement improvements here then I’d be happy to review it, and we could use that as a springboard for a design discussion. Some constraints to be aware of:

  • Should not introduce breaking changes
  • Should be implemented in the extension methods (either existing ones or new ones) - it shouldn’t require changes to the interface or to AbstractValidator.

I now realize that the latter rule sets are always executed first

This is not the case. Rules are always executed in the order that they’re defined. In your first example the rules outside the ruleset will be executed first, then those in the AddRuleset, then those in the UpdateRuleset because this is the order they were defined. The order that you provide the rulesets in the call to Validate doesn’t determine the execution order - they execute in the order that they’re defined in the validator class.

Setting CascadeMode to CascadeMode.StopOnFirstFailure atop the attribute’s constructor didn’t seem to have any impact on the rule-sets.

This is not how CascadeMode works. CascadeMode only applies to validators inside the same RuleFor chain (please see the documentation). Separate calls to RuleFor are completely independent and do not affect one another unless you explicitly set up dependent rules.

Read more comments on GitHub >

github_iconTop Results From Across the Web

android - How to solve this issue of Hardcoded string?
Put the curser on the hard coded string;; Press ALT + Enter ;; Enter a name for your ressource;; Click OK. After doing...
Read more >
Avoiding hard-coded format strings
How can we avoid hard-coding strings that need to be formatted? Consider, for instance, building a filepath to an i2c bus in linux:...
Read more >
I18nize Hard-Coded String - IntelliJ IDEA
Property value. By default, this field displays the value of the string to be extracted. Accept the default value or type the desired...
Read more >
Find Hard-coded String Literals via PMD
Guide on finding hard-coded strings in Java using the PMD tool. ... <description> This ruleset checks for hardcoded String literals.
Read more >
Linter rule - no hardcoded locations - Azure Resource ...
Best practice suggests that to set your resources' locations, your template should have a string parameter named location . This parameter may ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found