I have a business rule on a parent object that requires traversing its child collection objects to determine if the rule is broken or not. So the first thing I tried to do was to stick with the pattern of using the “InputProperties” functionality to store the values that I need to use to determine if the rule is broken or not.
Unfortunately, I don’t believe that the current rule engine supports using the “InputProperties” property to store values from child collection objects (unless I am missing something). As far as I can see, the “InputProperties” only supports storing values from variables that are local to the object where rule is being applied on and only if the properties are value type properties.
So for cases where a rule has to access child collection objects, it looks like the only option is to get a hold of the “Context.Target” object, cast it to the needed object and to get a reference to the collection from there.
Could someone tell me if my statement above correct or am I missing something?
You are correct, InputProperties only works with properties of the object containing the rule association.
I am not sure if this is stated on the eBook or not (I didn’t find it), but just to be specific for anyone reading this post. InputProperties really only makes sense if you are storing value type variables on it (at least when it comes to thread safety).
I didn’t dive deep on the InputProperties implementation but a quick scan of the source code made me think that the CSLA does not make deep copies of reference types when saving them into InputProperties. All it appears to do is to make a copy of the reference address…. Assuming that my previous statement is correct, perhaps making deep copies of the reference types that are saved into InputProperties would be nice, that way at least reading the properties of this reference type objects would be thread safe since they are true copies.
I think you'd end up with some very surprising results though, because any changes you made to the reference value would be lost - you'd be changing an orphaned copy of the object, not the actual object.
So a complete solution would require some way to detect and copy back any changed values to the cloned object graph (because that's really what we're talking about) after the rule completes.
And even if that were possible (which it isn't with the current FieldData implementation anyway), you'd end up with reconciliation issues, where the object graph might have been changed by other async rules or by the user or other UI thread operations - and the copy-back process would overwrite those changes (or something).
Really complex stuff...
Perhaps my biggest issue with allowing passing reference objects using the InputProperties is that is not consistent with the way the CSLA treats the RuleContext .Target object
When it comes to the RuleContext .Target property you are very careful with trying to prevent user from running into all kind of multithreading issues when running the rule asynchronously. You do this by not passing the RuleContext .Target object unless the ProvideTargetWhenAsync property is set to true.
But nothing is done to prevent users from making the same mistakes when passing a reference object through the InputProperties collection.
So perhaps instead of the property being called ProvideTargetWhenAsync, maybe is should be called ProvideReferenceTypesWhenAsync. Behind the sence, if this property is set to false, the CSLA will not pass the RuleContext .Target or any reference object contained in the InputProperties collection.
Copyright (c) Marimer LLC