Xml based business rules

Xml based business rules

Old forum URL: forums.lhotka.net/forums/t/3342.aspx


ChristianPena posted on Tuesday, August 07, 2007

Good afternoon.

I searched on the forum and found some discussion on the topic of externalized business rules. I got the general feeling that people were wary of employing this type of mechanism, but I would like to explore the idea some more before giving up entirely.

I have a class library that I am exposing through a SOA interface through the use of DTOs. The library will be used by two different interfaces, our internal representation and our external representation. The workflow is different when using one interface or the other so here the dichotomy is justified. The other consideration is that our logic is updated fairly frequently as our business rules are fairly volatile. We certainly can code and recompile each time, but we are starting to see a maintenance overhead that might well be avoided if our rules are extracted out.

I am considering serializing the DTOs to XML and using XPath queries to validate the document created (by identifying invalid nodes, given the criteria provided). The logistics are a little sketchy at the moment, but the idea is that since these objects are being called through the web interface, they do not need to validate in real-time, as each property is set, so no calls to PropertyChanged would be made. The object properties would be validated only once all properties have been set and presumably, as I try to save the objects.

Has anyone taken this sort of approach? Any advice on going down this route?

Thank you,

Christian

RockfordLhotka replied on Tuesday, August 07, 2007

Why not leave the data in the DTOs and pump them through a rules engine like the ones in Biztalk Server or Windows Workflow Foundation or any number of third party rules engines?

No sense writing your own batch processing engine when you can use something that's a commercially supported product.

ChristianPena replied on Tuesday, August 07, 2007

Rocky,

Thanks for the response.

This process needs to be near real-time in the sense that we will need to supply a response to our users as quickly as possible. They click the submit button and we validate the input immediately. I've not done any work with either of those two technologies (we do not have BizTalk here), but from what I have read on the forum, I gathered that WWF is not appropriate for activities such as this that are not batch processes. I've been doing a lot of reading lately instead of doing, but that was what I came away with.

I just POC'ed a little "validation engine" and that aspect of the puzzle works well. It creates a business rules collection from an XML document. Each rule is executed against a serialized (Non-CSLA) class and the engine raises an event for each query that returns a node, which signals a broken rule.

Am I heading down the path to even more maintenance headaches?

Thanks,

Christian

dlambert replied on Wednesday, August 08, 2007

As Rocky indicated, there are lots of open-source and commercial business rules engines available.  A quick investigation might turn up a winner for you, and it might also reveal some features that you're not thinking about right now that may turn out to be important later.

In addition to your concern about maintenance, I'd keep a watchful eye on performance, especially as the complexity of the rules increases.

david.wendelken replied on Wednesday, August 08, 2007

I guess I'm missing something!

Internal, hard-wired example:

ValidationRules.AddRule(CommonRules.StringRequired,"LastName");

External, data-driven example:

(I'm guessing on the syntax here - especially the TypeOf code - I haven't done this, and I'm assuming that we've done a business object and business object collection to make the list of rules available in a c# environment:

// Load the rule data collection
RuleDataList ruleDataList = RuleDataList.GetList(TypeOf(this));

foreach (RuleData ruleData in ruleDataList)
{
    ValidationRules.AddRule(SomeConversionFunction(ruleData.RuleMethod),ruleDataArguments);
}

SomeConversionFunction would take the string representation of the rule method and turn it into the technical equivalent of CommonRules.StringRequired in the first example.

Is that what you are talking about?  The data source for RuleDataList could be an xml file or a database table, whichever was more convenient.

david.wendelken replied on Wednesday, August 08, 2007

and if someone has a working code sample of the second example, posting it here would be helpful! :)

ChristianPena replied on Friday, August 10, 2007

David,

What I picture is something like this:

So given a class Customer with properties Name and Account, I would expect to get a serialized version similar to:

<Customer>
<Name>David</Name>
<Account>123</Account>
</Customer>

The business rules say that your name is required and your account must be 4 characters in length and must be numeric. Your business rules XML would look like (though not exactly since you could be as granular as you wanted):

<?xml version="1.0" encoding="utf-8" ?>
<Rules>
  <RuleGroup RuleGroupID="CustomerRules" Context="/Customer">
    <Rule RuleID="NameLength" IsEnabled="True" Property="Name"
          RuleText="//Customer[string-length(Name) = 0]/Name"
          Message="Your name is required." />
    <Rule RuleID="AccountValue" IsEnabled="True" Property="Account"
          RuleText="//Customer[string-length(Account) != 4 or string(number(Account)) = 'NaN']/Account"
          Message="The account number specified is not valid. Please check the account number." />
  </RuleGroup>
</Rules>

The code I wrote will load this xml file into an object hierarchy. It goes through and executes the Context XPath query to see if their is any need to run the following rules. The rule group "CustomerRules" will identify any Customer nodes that are the root nodes of a document. If any are found, then you can run the other rules. As I execute them, I raise an event if they return a node and give detailed informaton about the error including the friendly Message to display.

Our system is not performance critical, but it is a web application that must respond to a user in a somewhat timely fashion. My initial tests show this as being quick enough that I do not have to worry so much about performance, and that is without having applied any optimizations.

This idea came about after seeing business rules scattered around two similar interfaces, many of the rules out of date. It may not be viable at all for building a scalable flexible application, but I wanted to get some feedback from others before buying into or dismissing the idea altogether.

Thanks in advance.

Christian

RockfordLhotka replied on Friday, August 10, 2007

This sort of thing is why CSLA 3.0 has the DecoratedRulesArgs class btw.

 

The idea is that you can use reflection to do the work, rather than coding anything beyond the rule methods themselves.

 

<Rule type=”Csla.Validation.CommonRules, Csla” method=”StringRequired” />

<Rule type=”Csla.Validation.CommonRules, Csla” method=”StringMaxLength”>

  <Parameter name=”MaxLength” type=”Int32” value=”20” />

</Rule>

<Rule type=”MyApp.Rules, MyApp.Library” method=”AwesomeRule”>

  <Parameter name=”MinValue” type=”Int32” value=”20” />

  <Parameter name=”MaxValue” type=”Int32” value=”100” />

  <Parameter name=”Randomize” type=”Boolean” value=”True” />

</Rule>

 

Or variations along that line. The point being that you can easily write a single bit of code that can parse a <Rule> node and create everything you need to call AddRule() – specifically a delegate pointer and a DecoratedRuleArgs object.

 

Rocky

 

david.wendelken replied on Friday, August 10, 2007

I've been building a webcontrol that reads the list of rules and automagically adds the validators necessary to enforce them.

That's why I'm particularly interested in learning how to assign the rules from a database, it allows me to add all non-custom rules without coding or re-deploying the application, and to disable any already coded rule in the same way.  In combination with my new webcontrol, I'm hoping to reduce the coding/testing/deployment/maintenance effort of business rules to about 5% of what it currently is.

un7lg replied on Friday, August 10, 2007

RockfordLhotka:

 The point being that you can easily write a single bit of code that can parse a <Rule> node and create everything you need to call AddRule() – specifically a delegate pointer and a DecoratedRuleArgs object.

Rocky



Rocky,

Could you give a piece of code how to handle this issue with DecoratedRuleArgs?
Thanks

RockfordLhotka replied on Friday, August 10, 2007

Full details are coming in the Using CSLA .NET 3.0 ebook, but this is how you use it in AddBusinessRules():

 

      Csla.Validation.DecoratedRuleArgs args =

        new Csla.Validation.DecoratedRuleArgs("Name", "Project name");

      args["MaxLength"] = 50;

      ValidationRules.AddRule(

        Csla.Validation.CommonRules.StringMaxLength,

        args);

 

And you can look at the 3.0 CommonRules class to see how to implement a rule that accepts DecoratedRuleArgs (or a subclass of it anyway – I had to do some fancier than normal work to preserve backward compatibility) rather than RuleArgs.

 

The important thing is that the rule method MUST accept a DecoratedRuleArgs parameter for this to work.

 

Rocky

 

From: un7lg [mailto:cslanet@lhotka.net]
Sent: Friday, August 10, 2007 3:47 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: Xml based business rules

 

RockfordLhotka:

 

 The point being that you can easily write a single bit of code that can parse a <Rule> node and create everything you need to call AddRule() – specifically a delegate pointer and a DecoratedRuleArgs object.

Rocky



Rocky,

Could you give a piece of code how to handle this issue with DecoratedRuleArgs?
Thanks


david.wendelken replied on Sunday, August 12, 2007

Let's assume I have the name of the rule type in a string variable, like so:

String  ruleName = "
Csla.Validation.CommonRules.StringMaxLength";

And that the rule arguments have been set up correctly in the args variable.

How would I write this line so it would work?

ValidationRules.AddRule(ruleName, args);

Copyright (c) Marimer LLC