The old CSLA (1.X) business base object used to have two functions that you could override:
public override BrokenRulesCollection GetBrokenRulesCollection();
public override string GetBrokenRulesString();
The idea behind overriding this functions was similar to overriding the IsValid and IsDirty methods, in other words, you could override this methods and bring a collection of broker rules containing all of the broken rules *including* the children broken rules.
Although I realize that I can add similar functionality to my objects if I needed it, I am curios for the reason why they were removed in the first place, they seem to come in pretty handy to me, what happened?
Thanks.
Rocky,
I agree about the Base class. Every project should have them even if they are empty. Then if the need arises later you can easily add code to them and all of your BOs which derive from it get the new behavior.
I did a quick test of the code you mentioned and it does return a nice string of the broken rules for the current object. But it does not return any broken rules for contained BOs.
That is why I re-wrote the AllRules implementation from 1.x in 2.x in this thread: http://forums.lhotka.net/forums/thread/6283.aspx
For a given BO it checks the rules for it plus all of its children and returns a complete string. This conecpt has worked well for me and I wanted to be able to keep doing it.
It was impossible for me to figure out how to do it with generics so I switched to Interfaces and I think it works now.
Joe
Do I have the right to disagree?
Let me begin by saying that I was aware that there are all kind of methods on the broken rules collection class to get what I need, but that wasn’t really my problem, my main beef was about why the function where removed from where they should be.
Like I said before, I am aware that I can extend my objects to meet my needs anyway I want but…. I still think that these methods belong in the BusinessBase object, at least a method that a user could call and get back a BrokenRules collection containing all of the broke rules *including* the children broken rules.
Quite honestly, as a newbie using the CSLA 2, I am already not liking the ValidationRules idea. The reason I don’t like it is because it looks to me like this class is being used to make the code “cleaner” but not because it’s a required abstraction of a business need.
To me, a business object has a collection of broken rules, a collection of validation rules etc. I just don’t see the ValidationRules class coming into play here.
Further more, if exposing an overrideable BrokenRulesCollection property on the business base (just like on the 1.X version) is a bad idea then why is exposing the IsDirty property ok? The IsDirty property is already available on the ValidationRules class too so why not just retrieve the value from there directly? Why is it ok to have an IsDirty property on the business object but not a BrokenRules collection? Why the double standard? What makes the IsDirty property so special?
One more thing, I hope I am not appearing to be donkeys butt here, I am really not qualify to criticize anything at this point because for one thing I am an idiot, and the second reason is because I didn’t apply myself reading the book but instead I just examined the code to see what is doing and I am using the book as a reference so I hope I am not being to stupid with what I am saying here.
Thanks.
Whooooops! You are right (as always), I just saw the BrokenRulesCollection overridable property. I can’t believe I didn’t see it before.
This is definitely great but there is just one little problem. The constructor on BrokenRulesCollection class is marked as internal, this makes in impossible for a class outside the CSLA assembly to create an instance of BrokenRulesCollection. Without being able to instantiate a new BrokenRulesCollection class there is no way we can use it to populate it with all of the parent and child broken rules.
The easies way that I can think of how to solve this problem with minimal impact to the CSLA would be to create a new “Combine” static method on the BrokenRulesCollection as follows:
public static BrokenRulesCollection Combine(BrokenRulesCollection col1, BrokenRulesCollection col2)
{
BrokenRulesCollection combinedRules = new BrokenRulesCollection();
foreach (BrokenRule br in col1)
{
combinedRules.IsReadOnly = false;
combinedRules.Add(br);
combinedRules.IncrementCount(br);
combinedRules.IsReadOnly = true;
}
foreach (BrokenRule br in col2)
{
combinedRules.IsReadOnly = false;
combinedRules.Add(br);
combinedRules.IncrementCount(br);
combinedRules.IsReadOnly = true;
}
return combinedRules;
}
---------------------------------------
This method will return a fresh BrokenRulesCollection without messing anything else. Note that the code below is untested and it’s also candidate to some efficiency improvement, it’s just there to get the point across.
Please advice, other that my suggestion above, is there something I am missing?
What I am trying to do is just to get a list of all the broken rules for the complete object (parent and children) like the sample below:
The reason for this is because my current UI implementation is to display the first broken rule available on the broken rules collection after the user clicks the OK button (assuming the object is invalid). It does not matter if the broken rule is a parent or a child broken rule.
That’s why I want a single broken rules collection that contains the full list of all broken rules so I don’t have to worry about it. It juts makes things simpler.
In some forms I do display a message box showing all of my broken rules, similar to what Xal did but I display them on a simple message box because the number of rules to display is very small so the error tree view is overkill for me.
If doing what I suggested with the code on my previous post will violate the single-responsibility principle, then I think you need to make the:
public virtual Validation.BrokenRulesCollection BrokenRulesCollection
{
get { return ValidationRules.GetBrokenRules(); }
}
property non-virtual because the only valid return is the value returned by default, so there is no point on making this property overridable.
By the way, yes I know that my current UI validation implementation is cheese, I am planning to enhance it later and take advantage of data binding and the works but for right now my current implementation has been working great for the last 2 years so no point on trying to change that at this time.
Frankly I don’t see the problem with combining the broken rules into a BrokenRulesCollection, as far as I am concern, a BrokenRulesCollection object used to show all of the broker rules for the full object (parent and child) is as good logical as one used to show broken rules for a single business object, its just used on a different context, what’s wrong with that?
Rocky,
One issue that I discovered when writing the code to build the list of rules for a BO and its contained BOs is that you "short circuit" the call to IsValid in the framework. This makes sense for efficiency purposes but it leaves child objects in the incorrect State. The assumption is that a call to IsValid may involve re-running CheckRules "one last time" and then making the call. e.g. The user may have edited the form and modified some values to fix things that were previously Broken. The call to CheckRules fixes the broken rule. When the call is cascaded the pattern repeats itself. So in a child collection I could fix an object but the rule is not removed from Broken rules because you short circuited the call when you found a problem in some other child first. So even though the user fixed something it still shows up as broken in the list of rules.
By eliminating the short circuit behavior in IsValid, we can be sure that all rules are checked for all BOs before returning the string of broken rules. I Override it in my Base class for BusinessList.
'override CSLA2 code to look like this - no short circuiting involved here.
'run through all the child objects and if any are invalid then the collection is invalid
'call IsValid on all children so that when we examine Broken Rules we get the right set of values.
'Rocky stopped looping after he found the first invalid child.
Public Overrides ReadOnly Property IsValid() As Boolean Implements IBusinessCollection.IsValid
Get
Dim result As Boolean = True
For Each child As C In Me
If Not child.IsValid Then
result = False
End If
Next
Return result
End Get
End Property
Joe
PS - http://forums.lhotka.net/forums/thread/6283.aspx
The above thread shows the steps I had to take in Csla2 to use Interfaces to find all the contained BOs within a given BO. It was not trivial but I used the AllRules code from 1.x forum as the basis for it. It seems to work but I only have only given it cursory testing.
Copyright (c) Marimer LLC