Does anyone have an example of how to create business rules at runtime? I have a need to create a business object whose business rules are "set" when the object is created. For example, I have an object that has a text field and I want to set whether the text field is required and its max length whent he object is first instantiated. Looking at the CSLA.NET framework code you can't add rules at runtime as they are initialized in the protected constructor for BusinessBase. I don't want to make any of the framework methods that add rules public.
There's not a great answer for something like this.
CSLA 2.0 only allowed "per-instance" rules. The cost was so high in terms of memory and performance that I created 2.1 specifically to switch to per-type rules. Per-instance rules do still exist, but are removed in CSLA 4.
So one answer is to use per-instance rules, but that'll trap you on 3.8.
In CSLA 4 it is possible to "chain" rules. So the answer will be to create a rule that dynamically loads and executes other rules.
You can sort of simulate that today by changing the scope of some elements related to BrokenRules. I'm not sure what all you'd need to change, but once upon a time (around 5 years ago) it was possible for an object to add/remove items directly from the broken rules collection. If you re-enabled that functionality you could create a rule that implemented your own rule engine.
Which is basically the same thing you'd do in CSLA 4 - create a rule that loads other types/methods/workflows/whatever, executes them, and uses the results of those methods to create rule-result objects that get returned to CSLA.
No matter how you slice it, I view this as an advanced scenario - and a costly one - because of the per-instance nature of the problem.
Doing per-instance rules on a single object that is not used a lot is not too bad. Doing per-instance rules on an object that will be in a list though - that'll almost certainly cause you heartburn due to performance and memory consuption.
Is this performance problem related to the use of reflection in the rule processing infrastructure?
Not at all. The issue is much more basic.
If you are loading a list with 500 objects, each of which has maybe 10 per-instance rules, then each object has a rule manager, which is a dictionary of lists so the rules are organized per-property. And of course each object has the 10 rules - which are delegate pointers, and each delegate is basically an object.
So instead of creating 500 objects, you are actually creating around 8000 objects while loading the list.
If you are in a 3-tier mode, the list of objects serializes to the client. CSLA is smart enough to not serialize the 7500 or so rule objects, but that means they need to be recreated on the client side after deserialization - which happens automatically.
Recreating them is much, much faster than serializing them, but is still measurable work.
The end result is a performance impact. Of course this was all back in 2004 or 2005, but Andres from Argentina put a lot of work into timing and memory analysis to prove this to me, and helped a lot in the design of 2.1 to switch to the much more efficient per-type model that has been the default ever since.
Also, for clarity, there is no reflection in the rules subsystem. It uses delegate pointers (until CSLA 4, which uses interfaces), which is not reflection.
The only place there is reflection in the rules subsystem is if you choose to use reflection to create a reusable rule method. The rules in CommonRules use reflection, but of course are completely optional.
In any case, the reflection would only occur when the rules are executed, and that'd be true whether you use per-type or per-instance rules.
fwiw, in CSLA 4 even that reflection is minimized because the old reflection code has been replaced with the use of execution trees. So reflection occurs exactly once to create the tree, and from that point forward there's no reflection. The perf impact is extremely minor, but that eliminated one of the few remaining areas where reflection was used.
I use instance rules to load rules into the business objects at runtime. Each object may have different rules depending on certain criteria. The rule metadata is stored in a database. One of the things that allows this system to work is a bit of code I wrote that allows clearing of the rule info for a BO. This gives you a clean slate from which to load/re-load rules during the objects lifetime. I listed the code for this method here: http://forums.lhotka.net/forums/p/5310/25819.aspx#25819
In my case only the rules that need to be dynamic are implemented as instance rules, and the set of BO's are relatively small, so this helps to mitigate the issues Rocky mentions.
I am looking forward to getting the new business rules subsystem finished (at least a first draft) so you can look at it and see if it meets your needs. I suspect it will allow you to do what you need, though in a different way from today.
Copyright (c) Marimer LLC