From Rockford Lhotka's Expert C# 2008 and VB 2008 Business Objects books
I am somewhat concerned about including the Target property for that reason.
When you say "async mutex" do you mean a solution to make a business object threadsafe? That's essentially impossible. I suppose it could be somewhat possible if you never use data binding or allow any code to hook events from a business object - but that's pretty unrealistic.
Rocky
RockfordLhotka:I'm not sure what you mean by "custom build"?
I guess i was thinking of two different things; one would be to generate code and compile a rule class, and then use it. I assume that answer would be yes.
The other part was that since its an object, you could pass arguments to it, thus giving it some state. Which could be good, or bad. I can see someone passing a reference to the BO itself, which I imagine would not be pretty.
RockfordLhotka:It will be absolutely possible for people to create bad rule objects :) Rule objects must be designed to be threadsafe - so the Rule() method must be atomic and stateless. I can't help people do that right, but I can't provide ObjectFactory-like support without putting the rule methods in an object instance.
So I take that to mean that when people create a rule type, there should be no fields whatsoever, static or instance. It also sounds like the instance RunRule should just be calling static methods to do its work.
That seems like a lot of restrictions to make it work right, and doesn't feel very OO. I do like the idea, just wonder if this is going to be one of those things that generate a lot of support issues.
RockfordLhotka:So perhaps the answer is to provide a function (maybe in the BusinessRule base class or in PropertyInfo<T>) that gets the display name value from DataAnnotations.
So moving forward it would be a requirement to use those attributes?
Requiring the DataAnnotations display name attribute is one option - which does solve the localization issue.
Another option is to leave the friendly name in PropretyInfo<T>, but to have PropertyInto<T> maintain a reference to the underlying System.Reflection.PropertyInfo, making it easy for your rule to directly reflect against the property to get the attribute if you wanted to go that direction.
But I'm rather leaning toward using only the attribute. I suspect the DataAnnotations model will rapidly become a standard, as it is used already by ADNS, MVC 2 and the SL DataForm. I'd be surprised if WPF doesn't get a DataForm, which would use it too.
In other words, every major interface technology being actively worked on and promoted now has DataAnnotations support - so why wouldn't you use them?
Normal 0 false false false MicrosoftInternetExplorer4
Mutex = rule that changes the BO.
I am thinking:
class SomeEntity : BusinessBase
{
public DateTime SomeDateProperty
private rangesStruct allowableRangesForSomeValues
public int SomeValue1Property
public int SomeValueNProperty
public override void AddBusinessRules()
ValidationRules.AddRule(getAllowableRanges, SomeDateProprty)
validationRules.AddDependentProperty(allowableRangesForSomeValues, SomeValue1Property)
validationRules.AddDependentProperty(allowableRangesForSomeValues, SomeValueNProperty)
validationRules.AddRule(checkRange, SomeValue1Property)
validationRules.AddRule(checkRange, SomeValueNProperty)
}
private static void getAllowableRanges(object target, RuleArgs args)
rangesStruct newData;
//async call to get allowableRangesForSomeValues
//in callback
newData = e.results;
mre.set();
mre.waitOne
SetProperty(target, allowableRangesForSomeValues, newData)
I would love to be able to do some kind of Async SetProperty inside of the callback... I am not so sure I have a full grasp of the
complexity there... but I was thinking something like this:
//in call back base=rule object
using(base.AsyncPropSet(target))
where AsyncPropertySet somehow tells the target.SeProperty to use read\write locks or something similar?
I am not so sure I grok the databinding problem, but wouldn't this approach ensure that no downstream property setting\reading logic
gets fired unexpectedly? The BO itself would not be threadsafe, but the properties would? Or am I really just missing something.
I suppose the argument can be the design itself is poor... better to have some factory of allowablerangesforsomevalues that must have fetched it's data before the rule has a chance to fire?
Hi Rocky,
I like your idea and I vote for the IBusinessRule concept.
I also want to throw the idea in to the discussion to think about "cross business type rules". In complex scenarios when you think about an entire tree of business object relations you sooner or later you need some kind of cross business rules that link depend properties for example between parent and child objects or between objects types at the same child level. Of cause the single business object should not know about its context or that is part of a whole. This should be implemented and managed inside the business rule? Maybe it’s only an extension of the current BusinessRuleManager which already supports dependent rules, but only inside the same object type.
Andreas
Generally speaking a child shouldn't know about its parent. But a parent can absolutely know about its children - they are part of the parent through the composition relationship.
If a child has to know about its parent, that should be abstracted through an interface if at all possible.
Though in CSLA 4 the Parent properties are all public now, so it is terribly easy for a child to cheat an interact with its parent... But that doesn't mean people have to do it wrong - as long as it is done via interface it is generally acceptible.
The point I'm making is that you can create a rule that operates against an entire object graph - that's fine. It would ideally be attached to the root node of the graph, and if it can't be, then the rule should use an interface to interact with any objects higher in the graph than the object to which the rule is attached.
None of that requires any real work on the part of CSLA - other than that we all must acknowledge that object-spanning rules must always be synchronous - trying to lock one object is nearly impossible, and trying to lock an entire object graph...ouch!
This all sounds interesting. Most of the time we are talking about rules that check the validity of a single object. I would like to have the ability to easily check the validity of objects in a collection where the collection's validity is determined based on the inter relationship of the state of object(s) in the collection. For example, if the user answers Yes to a field in one object, the collection becomes invalid until a certain answer is provided to another object in the same collection.
Jav
That's sound all valid and reasonable but I think it’s not easy to manage and from my point of view definitely not easy to implement. In our object model we make extensive use of lazy loading child objects. The instantiation of child objects depends on user interactions. So the root or parent in the tree doesn’t know if the child object is already instantiated and can be validated against its own properties. Maybe it can check this withFieldManager.FieldExists(). But it currently can do this check only with its own and direct child properties. On the other hand the child object shouldn’t know about its parent. So what if you want to reuse this child object type in other complete different object hierarchies. You better don’t want to dependent on parent object types or interfaces only because you want check if the value of an integer property is in the range of certain values of some other object property in unknown leaf somewhere in the object tree. The only thing you probably know is that it may already exits somewhere in the tree. But as soon as it exists you want to use it in your validation logic. In these scenarios I was thinking about some kind of “BusinessRule Property Registry” that is part of the csla’s BusinessRule subsystem where properties can registered to become validated when the owning business objects is instantiated. Again the current semantic of "AddDependentProperty" smells to be close to this but it should work on cross business object types or better it should work business object type agnostic.
I have played with the SL DataForm and the annotations a little and it is something I've been dreaming about for many years. We had pretty extensive discussion about the concepts some... oh boy six years ago maybe... on this forum. Some of the functionality goes to levels I disagree with (for confusing layer responsibilities), but IMO if there's a way to do the rules system such that they're exposed to the UI in useful standard ways, that is hands down the best option.
I still can't get over the thought that there should be a way to allow async access to properties (for a single object in the graph... not the whole object graph) but I have a clearer head now (I was all hopped up on NyQuil for my previous posts... now I am just hopped up on DayQuil) and I think I better understand the challenge.
That being said, I would vote for either having the Target property (for the RuleContext) be null or throw a "no async access to target" exception when in an async context. Throwing an exception would better inform the developer why target is not accessible.
Keeping the target property will allow for business rules that modify the object (which I believe is a valid use case)... the danger of course is if that rule somehow fires in an async manner. Out of curiosity, how would we specify that a rule should run async?
am_fusion: Out of curiosity, how would we specify that a rule should run async?
Out of curiosity, how would we specify that a rule should run async?
That remains an open question I'm toying with a couple ideas.
One is to have BusinessRules.CheckRules() and BusinessRules.BeginCheckRules(callback) so it is an explicit choice to run rules on a background thread. But I'm not sure this is workable, since there are implementation differences in sync vs async rules. An async rule can always (?) be run synchronously, but a sync rule must be run synchronously. I've started down this road, but I'm increasingly convinced it is wrong.
Another is to have a property in IBusinessRule such as ExecutionMode, which could be ExecutionModes.Any, ExecutionModes.SyncOnly, ExecutionModes.AsyncOnly. Then BusinessRules.CheckRules() would execute each rule based on that property value. Obviously I haven't thought this through entirely, but I rather suspect this is the correct solution.
am_fusion: That being said, I would vote for either having the Target property (for the RuleContext) be null or throw a "no async access to target" exception when in an async context. Throwing an exception would better inform the developer why target is not accessible.
Yes, I think this is a good solution - having Target throw an exception if accessed while async.