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.

Reusing validation rules

See original GitHub issue

Hey @JeremySkinner

You’ve said repeatedly that FV is just for UI validation, but I got it working for domain validation as well.

However I need to duplicate rules again and again - e.g. if I want to validate a Product entity’s Name, then I need a validator and a validation rule for the entity itself, and for the create action, and the edit action, etc. This is not a unique problem, every large system has it.

I want to define a shared set of validation rules for a Product, and reuse them in various places. For example, to validate the create action’s CreateProductViewModel:

public class CreateProductViewModelValidator : AbstractValidator<CreateProductViewModel>
{

  public CreateProductValidator()
  {
    var productRules = new ProductRules<CreateProductViewModel>();
    productRules.Name(v => v.Name);
    productRules.Code(v => v.Code);
    // ...more rules...
  }

}

So instead of redefining rules, I just pick and choose from the shared rules.

Implementation of the shared rules class, which I copied from AbstractValidator.RuleFor():

public class ProductRules<T>
{

  // validation rule for "Name"
  public IRuleBuilderOptions<T, string> ruleForName(Expression<Func<T, string>> expression)
  {
    // first create the rule builder
    var rule = PropertyRule.Create(expression, () => CascadeMode.Continue);
    var ruleBuilder = new RuleBuilder<T, string>(rule);

    // now define the rule
    ruleBuilder.NotNull().NotEmpty().Length(1, 20);
    return ruleBuilder;
  }

  // validation rule for "Code"
  public IRuleBuilderOptions<T, int> ruleForCode(Expression<Func<T, int>> expression)
  {
    var rule = PropertyRule.Create(expression, () => CascadeMode.Continue);
    var ruleBuilder = new RuleBuilder<T, int>(rule);
    
    ruleBuilder.GreaterThan(0).LessThan(2000);
    return ruleBuilder;
  }

  // ...more rules...
}

So I can validate a Product in various places, e.g. Product, CreateProductViewModel, EditProductViewModel, CreateDiscountedProductViewModel, DeleteObsoleteProductCommand, etc. etc. Although the “shape” of each entity/viewmodel/DTO will differ, their properties are almost identical - so each has its own validator, but I can pick and choose which rules to run without repeating myself.

Have I broken FV somehow?

  • The validator just includes a rule defined in another class instead of defining it itself, but I think the expression caching etc. will still work as normal?
  • I used PropertyRule and RuleBuilder which you’ve defined in the “internal” FluentValidation.Internal namespace. So my code can break whenever FV is updated because I’m (ab)using internal methods. Is there a non-internal way to create those objects?

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:10 (4 by maintainers)

github_iconTop GitHub Comments

3reactions
JeremySkinnercommented, Jun 8, 2017

You may have already thought about this already and discounted it for some reason, but could you not just do this with extension methods & generics to make it a lot simpler?

public static class ProductRules {
  public static IRuleBuilderOptions<T, string> Name<T>(this IRuleBuilder<T,string> ruleBuilder) {
    return ruleBuilder.NotNull().NotEmpty().Length(1, 20);
  }
}

…and then use this from inside your CreateProductViewModelValidator like:

RuleFor(x => x.Name).Name();

…that way you don’t need to mess with PropertyRule or AddRule directly. Also makes it much easier to read and takes advantage of the existing fluent interface.

1reaction
granthoff1107commented, Jan 7, 2018

@grokky1 I’m implementing a validator based off of entity state, Thanks, You just save me a day of troubles.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Laravel 6 - Best way to reuse existing request validators ...
If you want to use the same validation rules in multiple places, perhaps use a trait and then use it in multiple form...
Read more >
Reuse validation rules in form request in another ...
Hello, I have about 4 form requests with almost the same fields in each 1 for example as you can see i need...
Read more >
Reuse of Validation Rules
Validation rules must be named before they can be reused. You can assign a technical name in one of the following ways: You...
Read more >
how to reuse validation rule for update / create in controller?
how to reuse validation rule for update / create in controller? Copy public function update(Snippet $snippet) { $this->validate(request(), ...
Read more >
Re-use Validation Rules | IdeaExchange
Re-use Validation Rules ... Ability to share validation rules, or for validation rules to be able to call methods in Apex classes. Right...
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