Skip to content

Business Rules #30

@charlessolar

Description

@charlessolar

Running rules in entities currently involve a lot of If's thens, and throws

We can make this easier.

There's a few changes I can make right off the bat - adding a Rule method on entities to validate against the state of the entity automatically.

   public void PostInvoice() {

       // Instead of....
       if( State.Address == null )
           throw new BusinessException("No address set");
     
       // Do this!
       Rule("Address Set", x => x.Address == null, "No address set");

       Apply<Events.Posted>();            
   }

In the long term however we want to support dynamic rules and validation against data that may not be inside the entity. If for instance we want to make sure the customer is in good standing before posting invoice - we'd have to load the customer entity to check. And a business manager might want to override a rule or create his own rules without involving a programmer to do so.

The above works for static validation - so lets also add dynamic!

I want each public method on a entity to be available for rule creation dynamically via the app.

I envision some kind of extendable entity validator. Something like

    RuleFor<Invoice>()
        .When(x => x.PostInvoice)
                .Rule("Address Set", x => x.Address == null, "No address set");
    

we already know how to serialize expressions so aggregates.net would just need to keep track of rules for entities and apply them while executing commands and events.

public Task Handle(Commands.AddRuleToInvoices command, IMessageHandlerContext ctx) {
    Aggregates.For<Invoice>()
              .When(command.Action)
              .Rule(command.Name, command.Expression, command.Message);
}

Dynamically loading other entities for checking

Aggregates.For<Invoice>()
    .When(x => x.PostInvoice)
    .Load<Customer>(x => x.CustomerId)
    .Load<PaymentMethod, Customer>(customer => customer.DefaultPaymentMethodId)
    .Rule<PaymentMethod>("Payment Is CreditCard", method => method.Type == Methods.CreditCard);

Todos

  • Static RuleFor on entities
  • Expressive rules on entity types
  • Dynamic rules via serialized expressions
  • Test generation for seeing new rules in action (?)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions