Displaying business rules on the Web UI (Validation Controls)

Displaying business rules on the Web UI (Validation Controls)

Old forum URL: forums.lhotka.net/forums/t/3606.aspx


chrislw posted on Thursday, September 27, 2007

I know this has been done before, but I wanted to post some of the code that I used to do this.  My goal was to take some of the simple business rules such as required, value range, string length, and regex expressions and express them as client validated rules so the postback does not occur before validation.

Can anything tell me if there is a better or more efficient way than this?

First, I had to get the rules from the data source.  Then I took the string() of rule descriptions and converted it to the RuleDescription class (until it is built into the call for getting the descriptions).

Then I iterated through the rules and matched known rule types with validation controls and created them.  I extended FormView control for my test of this functionality.

Sorry if you are C# folks.  I usually write in C#, but this time it had to be VB.NET

The following code gets the data from the CSLA data source.

If Not dataSource Is Nothing Then

   ' Instantiate Object

   Dim result As Type = Nothing

   If Not String.IsNullOrEmpty(dataSource.TypeAssemblyName) Then

      ' explicit assembly name provided

      result = Type.GetType(String.Format("{0}, {1}", dataSource.TypeName, dataSource.TypeAssemblyName), True, True)

   ElseIf dataSource.TypeName.IndexOf(",") > 0 Then

      ' assembly qualified type name provided

      result = Type.GetType(dataSource.TypeName, True, True)

   End If

 

   ' Read rules and save them in a collection

   If (Not result Is Nothing) Then

      Dim obj As Object = result.Assembly.CreateInstance(result.FullName)

      Dim method As MethodInfo = result.GetMethod("GetRules")

      If Not method Is Nothing Then

         Return CType(method.Invoke(obj, Nothing), String())

      End If

   End If

End If

 

The next block goes in the CreateChildControls of the custom control.  Keep in mind that if the code is called more than once, your code must be smart enough to not create multiples of the same validators (I checked for the existing control ID and reset all the properties to what they should be):

Protected Overrides Sub CreateChildControls()

   MyBase.CreateChildControls()

   ' Get the CSLA business rules

   Dim rules As String()

   If ViewState("RuleList") Is Nothing Then

      rules = GetRuleList()

      ViewState("RuleList") = rules

   Else

      rules = CType(ViewState("RuleList"), String())

   End If

   ' The rule description class is not serializable, so we have to recreate it based on the CSLA Rule string()

   Dim ruleList As New System.Collections.Generic.List(Of RuleDescription)

   For Each rule As String In rules

      ruleList.Add(New RuleDescription(rule))

   Next

 

   AddRulesToPage(ruleList)

End Sub

Posting all of the code is not neccesary, so the following is just a snip of the functionality (I skipped lines including error handling, comments, and other specific implementation:

For Each rule As RuleDescription In ruleList

   Dim baseRule As BaseValidator = Nothing

   Dim validatedControl As Control = FindControl(rule.PropertyName + suffix)

   If Not validatedControl Is Nothing Then

      Dim ruleType As SupportedRuleType = CType([Enum].Parse(GetType(SupportedRuleType), rule.MethodName, True), SupportedRuleType)

      Select Case ruleType

         Case SupportedRuleType.StringRequired

            baseRule = GetRequiredRule(validatedControl, rule, ruleType, caption)

         Case SupportedRuleType.StringMinLength, SupportedRuleType.StringMaxLength

            baseRule = GetLengthRule(validatedControl, rule, ruleType, caption)

         Case SupportedRuleType.IntegerMaxValue, SupportedRuleType.IntegerMinValue, SupportedRuleType.MaxValue, SupportedRuleType.MinValue

            baseRule = GetValueRule(validatedControl, rule, ruleType, caption)

         Case SupportedRuleType.RegExMatch

            baseRule = GetRegExRule(validatedControl, rule, ruleType, caption)

      End Select

      ' Set common rule properties      

If Not baseRule Is Nothing Then

         SetCommonRuleProperties(validatedControl, baseRule)

         ' If the validator is not already on the page, then add it. Some validators are used by multiple rules

         If (Not control.Parent.Controls.Contains(baseRule)) Then

            validatedControl.Parent.Controls.AddAt(validatedControl.Parent.Controls.IndexOf(validatedControl) + 1, baseRule)

         End If

      End If

   End If

Next ' Rule

Each call to Get___Rule returns the specific configured validation rule. Each rule has different requirements and properties set so I have not found a way to combine the methods.

 

cwgraves replied on Wednesday, October 10, 2007

Thanks for posting the snippet of code. I am trying to do the same thing that you discuss in this post.

Any chance of you attaching the complete code? It would be GREATLY appreciated!

Thanks,

Curtis

chrislw replied on Wednesday, October 10, 2007

Hi Curtis.  I don't think I would be allowed to post some of the other code as it gets into details that I worked with on the client.  However, I don't believe there would be any reason I couldn't answer any questions that you have or help you through it.  It is probably good to talk here, but you could also contact me via email.  chrisw@do_not_spam_magenic.com_do_not_spam. Just take the do_not_spam parts out ;)

david.wendelken replied on Monday, October 15, 2007

Did you solve the problem of adding comparison rules between properties?

It's a bit of a chicken and egg problem, in that the other field might not be initialized on the screen when this control is being pre-rendered.

chrislw replied on Tuesday, October 16, 2007

No.  Actually, as for rendered controls, I call the code from the CreateChildControls and make sure that all the child controls are created first.  However, I only did basic rules such as required, value range, and regular expressions (standard validators).  Everything else is done by the business object.  Another option though, might be to call ASP AJAX to call the BO validate method and display an error to the user.

decius replied on Friday, June 13, 2008

I know this is months old, but Can someone help me on this? Where does the code that gets the data from the CSLA datasource need to go? 

Plus, what is this "SupportedRuleType"?  Is this something that only relates to VB?

Plus, how is the SetCommonRuleProperties() function implemented???

Any help would be greatly appreciated! :P

 

decius replied on Monday, June 16, 2008

Kay', I got most of that figured out now except 1 thing, I could really use some help regarding what "SupportedRuleType" is, it's the only thing I'm stuck with now.... I can't seem to find it anywhere in the Csla framework, and there's no documentation about this anywhere.  Can someone lend a hand? :/

The only thing I can find in CSharp that possibly could be used is the CommonRules class..... but it's of static tye and can't be used like is shown here....  anyone?

decius replied on Tuesday, June 17, 2008

Perhaps I'm talking alone here, but I have made progress with working around this mysterious "SupportedRuleType" class.  However now I have a new question :)

Can anyone tell me how to overcome this issue with the FindControl( rule.PropertyName ) line in the AddRulesToPage function??? I can't seem to find any of the controls to validate in my Extended Contol at runtime and I'm at a loss on how else this could be done :( 

Any help would be greatly appreciated. If I get this working I can post all my code in Csharp for all to benefit.  I feel I'm getting closer if I could just overcome this.

 

p.s. rule.PropertyName is returning correctly.

Copyright (c) Marimer LLC