Pull up CSLA BO’s validation message

2008 October 14
by Frank Mao

By default the CSLA BO’s brokenRulesCollection doesn’t contain child BO’s brokenrules, I tried to create a GetValidationMessages() method in MyBusinessBase class, the difficult I had was to cast and detect the generic type. Thanks to this post, I made it happen by creating an IsDerivedFromGenericType method.

I don’t need to call this:  if (child.GetType().IsSubclassOf(typeof(MyBusinessBase<>)))

Or if (child is MyBusinessBase<>)

Actually those two won’t work. This IsDerivedFromGenericType is handy.

if (IsDerivedFromGenericType(child.GetType(), typeof(MyBusinessBase<>) ) )

But it’s too complex, especially I had to call reflection to  call this GetValidationMessages recursively. Because I don’t know how to do this:

((MyBusinessBase<>)child).GetBOValidataionMessage()

Instead I had to call reflection:

        private string GetBOValidataionMessage(object v)
        {
            // Would be nice if I can cast to MyBusinessBase
            // T is an unknow onject type below, so I had to use reflection to invock method.
//            MyBusinessBase bo = (MyBusinessBase)v;
//            return bo.GetValidationMessage();

            string childValidataionMessage = "";
            // invoke method to get validation message from child BO.
            // kind of recursive call here.
            var flags =
                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
            MethodInfo method = v.GetType().GetMethod("GetValidationMessage", flags);

            if (method != null)
            {
                childValidataionMessage = (string)method.Invoke(v, null);

            }
            return childValidataionMessage;
        }

In fact, it could be much easier if I just simply override the BrokenRulesCollection property. (Idea from this post.)

        public override BrokenRulesCollection BrokenRulesCollection
        {
            get
            {
                BrokenRulesCollection brokenRules = BrokenRulesCollection.CreateCollection();
                // Get root broken rules.
                brokenRules.Merge(this.ToString(), base.BrokenRulesCollection);

                foreach (var child in this.FieldManager.GetChildren())
                {
                    if (child is IEnumerable)
                    {
                        foreach (var v in (IEnumerable)child)
                        {
                                if (v is BusinessBase){
                                    brokenRules.Merge(v.ToString(), ((BusinessBase) v).BrokenRulesCollection);
                                }
                        }
                    }
                    else
                    {
                        if (child is BusinessBase)
                        {
                            brokenRules.Merge(child.ToString(), ((BusinessBase)child).BrokenRulesCollection);
                        }
                    }
                }

                return brokenRules;
            }
        }

        // BrokenRule class doesn't have an "Owner" field, which is useful in this kind of
        // multi-level object map to locate the actual error message from.
        // Fortunately, the rulename contains object name, so I can do this stupid string parse here.
        public string ExtractObjectName(string ruleName)
        {
            string result;

            // get namespace
            string spacename = this.GetType().Namespace;

            // get rid of namespace
            result = ruleName.Replace(spacename + ".", "");

            // get rid of everything after the dot
            int start = result.LastIndexOf("//") + 2;
            int end = result.IndexOf(".") ;
            result = result.Substring(start, end - start);

            return result;
        }
        public string GetValidationMessage()
        {
            StringBuilder sb = new StringBuilder();

            foreach (var x in this.BrokenRulesCollection)
            {
                 sb.AppendLine(string.Format("{0}.{1}: {2}", ExtractObjectName(x.RuleName),x.Property,  x.Description));
             }

            return sb.ToString();
        }

No comments yet

Leave a Reply

Note: You can use basic XHTML in your comments. Your email address will never be published.

Subscribe to this comment feed via RSS