Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Business object property validation

0.00/5 (No votes)
16 May 2008 1  
How to set and validate properties in a single line of code.

Sample Image - bizobjpropertyvalidation.jpg

Introduction

Hi to everybody. I am currently developing an in-house n-tier application, and has managed to reduce vast amounts of code through Reflection. The one part that is still left to manual, tedious code entry is in the client side business objects. On the smaller objects, this isn't a real issue, but some of these objects have 100+ public read/write properties - and of course, the private field declarations to store the data. The real objection I had to this was the repetitive nature of building the properties and including some basic validation and error checking.

Using the code

The example has been simplified for easy reading, but this can be expanded and moved to different layers, depending on your needs. I have included a BusinessRules assembly, which contains a number of custom attributes. These attributes further simplify the validation process, but attributes is the topic of another article.

The properties - Structures.vb

We'll start with a structTEST structure. This will serve as the variables and properties for the business object, and will also be validated.

Option Strict Off
Option Explicit On

Imports BusinessRules.Attributes

Namespace Structures

    Public Structure structTEST
    
        'Use the custom attributes defined in the BusinessRules.Attributes 
        'namespace. These attributes will form part of the general/generic
        'business rules that apply to this property
        <NotNull(), NotEmpty(), MaxLength(50)> Public Name As String
        
    End Structure
        
End Namespace

NB: I always place my structures in a Structures namespace to keep the application ordered and logical. These structures are usually saved in the same module as the interface declaration for the server side business objects and/or DAL. They could be in a Structures project, or all stored together in a Structure code module. The choice is yours.

The validator - CProps.vb

This class does all the work... This will perform a Get/Set on the properties, perform the validation, and throw any errors/exceptions.

Option Strict Off
Option Explicit On 

Imports PropsVal.Structures

Imports BusinessRules.Attributes
Imports BusinessRules.Errors

Imports System.Reflection

Here, we set the obligatory stuff and import the appropriate namespaces. Note that we are importing the BusinessRules.Attributes and BusinessRules.Errors namespaces as well as System.Reflection.

Public Class CProps

#Region " Private Attributes "

    Private mVTProps As ValueType
    Private lType As Type

#End Region

Now, we define the class name and set about declaring some module variables. Note that the mVTProps object is declared as a ValueType.

#Region " Private Properties "

    Private ReadOnly Property VTType() As Type
        Get
            Try

                If lType Is Nothing Then
                    lType = mVTProps.GetType
                End If

                Return lType

            Catch ex As Exception

                Throw ex

            End Try
        End Get
    End Property

#End Region

Now, we define a private property that will be used later on. The role of this property is to return a System.Type to the methods within, as they need it (below).

#Region " Constructors "

    Public Sub New(ByVal typeName As String)

        Try

            Dim t As Type = Type.GetType(typeName)

            If t Is Nothing Then
                Throw New Exception("Type could not be loaded.")
                Return
            End If

            mVTProps = Activator.CreateInstance(t)

        Catch ex As Exception

            Throw ex

        End Try

    End Sub

#End Region

And on we go... The constructor is defined. Here, we initialise the module variables (above) by using the typeName (String) parameter.

#Region " Public Methods "

    Public Sub SetValue(ByVal propName As String, ByVal val As Object)

        Try

            Dim lObjFI As FieldInfo = VTType.GetField(propName)

            lObjFI.SetValue(mVTProps, val)

            BusinessRules.Validate.Validation.ValidateAndThrow(mVTProps, propName)

        Catch ex As Exception

            Throw ex

        End Try

    End Sub

And, on to the workers. As with all read/write properties, there is a Set block. This is the Set block. Now, remember above where we defined the mVTProps variable as a ValueType? This is because a structure is a value type. The FieldInfo.SetValue only works on Object types (any one who is familiar with this, please feel free to elaborate on this one).

    Public Function GetValue(ByVal propName As String)

        Try

            Dim lObjFI As FieldInfo = VTType.GetField(propName)

            Return lObjFI.GetValue(mVTProps)

        Catch ex As Exception

            Throw ex

        End Try

    End Function

    Public Function GetAllData() As ValueType

        Return mVTProps

    End Function

#End Region

End Class

...and this is the Get block and the end of the class.

The business object

The business object is what the user interface will be communicating with.

Option Strict Off
Option Explicit On 

Imports PropsVal.Structures

Imports System.Reflection

Public Class BizO

#Region " Public Properties "

    Public PROPS As CProps

#End Region

Again, we set our options and import our namespaces; define the class and the public properties. The PROPS declaration is where you would typically declare all your variables (string, int, GUID, etc.), and then you would have all your property declarations with any/all validation and error checking code.

#Region " Constructors "

    Public Sub New()

        'Initialise the PROPS object
        PROPS = New CProps(GetType(Structures.structTEST).FullName)

    End Sub

#End Region

#Region " Public Methods "

    Public Sub Load()

        'This is where you would make calls to your database, 
        'DAL, or remote objects. This would return the data 
        'and fill the PROPS object (above)

        'This model can then be expanded upon by providing similar
        'method - ie Save, Rollback, etc...

    End Sub

#End Region

End Class

The constructor is where the PROPS object is initialised. This is the critical element of this solution as the types must be correct, but even that isn't too hard. Remember the structure we created earlier? This is where we get to actually use it. The trick to making this all work is to parse the Type FullName of the structure.

Here, I have purposely left the Load method empty, but as per the code comments, you can see what can be done.

The UI - form1.vb

Yes, yes. I know it's a lazy name. The only code you will need to add is for the button.

'Declare and instantiate the BizO business object
Dim o As BizO
o = New BizO

Try
    'Set the value of the Name property in the business object
    o.PROPS.SetValue("Name", txtName.Text)

    'No exceptions/errors were detected during the value set
    'so report the success to the user
    lblErrMsg.Text = "Input tested successfully!!"
    pnlStatus.BackColor = Color.Green

Catch ex As Exception
    'An exception was thrown from within the PROPS object (inside
    'the business object
    'Report the error message to the user
    lblErrMsg.Text = ex.Message
    pnlStatus.BackColor = Color.Red
End Try

'Display the results to the user
lblResult.Text = "PROPS.GetValue: " + o.PROPS.GetValue("Name")

'Declare a local instance of structTEST structure
Dim x As Structures.structTEST
'and fill it with ALL the data from the PROPS object
x = o.PROPS.GetAllData

'Display the results to the user
lblResult.Text += vbCrLf + vbCrLf + "Local structure: " + x.Name

OK. Last piece... Here, we declare and instantiate a new business object.

Then, we try setting the Name property to the value of the textbox Text property. If there are no errors/exceptions, we display a success message and set the panel to green. Any exceptions result in the error message being displayed and the panel changing to red.

Then, purely for testing purposes, while I was building this, we retrieve the value of the Name property and display it on screen, and finally we declare a new instance of the structTEST structure and fill it with the contents/values of the PROPS object, and display the value of the Name member.

Points of interest

  • The above code has been was originally developed on the v1.1 framework. Having not used v2.0 yet, I can only assume that the above would work, but don't quote me. After porting this across to a VS2005 (Framework 2.0) solution and subsequently VS2008, no issues have occurred, and this model is in use and is being used more every day.
  • The structTEST structure is a value type, and using FieldInfo.SetValue only works on object types. Luckily, structures convert to a value type object easily.
  • Option Strict is set to Off only because casting a structure as a ValueType object without a CType fails, and I find too many other implicit type conversions fail when strict typing is set.
  • The GetAllData method can be used to parse the contents/values to a database, DAL, or remote object as the object being returned is the structTEST structure. The application I'm developing parses these structures to a remotable business object (via an interface), where it is checked and validated one final time. The structure is then parsed to the DAL, where the structure is used to fill stored procedure parameters (using the member names and further custom attributes) and parse it to the SQL database.
  • I would have liked to make use of IntelliSense for the property names as compared with a String literal, but I fear the additional load may negate any performance and/or simplicity. Any ideas?
  • I'm sure there are a number of items that could be done better, and I am more than happy to hear from you about them. After all, we're all hear to learn something.

Conclusion

These days, everybody has to do more with less help, and it's always due yesterday. Hopefully, this example may help you reduce the tedium, and let you get on with the really cool stuff. If I feel inspired again, I may submit some further articles on the various techniques I've found, created, and used to save time and code.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here