Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Data Validation Using .NET and External Metadata : Page 3

Data validation is a task that we perform every day when writing code. Applying the techniques described here can make your systems more robust and eliminate the constant rebuilding of applications every time a business rule changes.

Putting It All Together
Now that you have defined your data validation you can use the .NET classes to easily validate your data in a consistent manner that is easy to implement. In the future you can add or remove data validation from any particular class and data member without rebuilding your application. If you decide that you need a new validator, you can build that separately from the main application, add the metadata to your validation file (or SQL Server tables), and the application can take advantage of the newly available validation code. Let's see how it all fits together.

XmlDocument doc = new XmlDocument(); doc.Load("DataValidation.xml");

The document is stored in the main application. Each time you create a new instance of a class the application will check to see if it implements the IValidator interface. If it does you need to initialize the validation routines.

Foo foo = new Foo(); IValidator v = foo as IValidator; if (null != v) { v.Initialize(bar.GetValidationData( foo.ToString())); }

The main application class, bar, was used to load the data validation information. Now you must get the validation information needed for Type Foo so you'll call foo.ToString(). The code overrides the ToString method to return the name of the class. Normally the ToString method will return the .NET type name for objects that are classes. You don't want a decorated name so the code returns something easier to read. You'll use the returned string to search through the metadata to find the validators necessary for that class. The Initialize method is defined on the IValidator interface and it takes an XMLDocumentFragment as its lone parameter. Listing 2 shows how to initialize the data validation rules.

The code to create and initialize the validators has been omitted from Listing 2. I want to note one thing here. You can get information about the properties of a class using the Type class and return an array of PropertyInfo objects. You will use this to store a hash able of class data members and their associated properties. One extra task you'll perform is to check each property for a custom attribute. If the property has the custom attribute defined on it, then it gets loaded into the hash table. If not, ignore it. You can use this technique to exclude certain pieces of data that you know you do not need to validate. Listing 3 shows how easy it is to create and use a custom attribute class.

Each instance of a Type that you need to validate will contain an ArrayList of objects of Type Validator. The Validator class is a proxy for the real validator. In addition to loading the real validator, it is responsible for communicating with the class being validated using the hash table created above to retrieve and store data values. You can do this because of a method defined on the IValidator interface so that you don't need to know the underlying details of the class you want to validate.

Now that you've ensured that the validation routine is available and properly constructed, your initialization is complete. You just need to call the Validate interface method on the class object instance. This method iterates through the list of validators, calling each Validate method, and stores any returned error messages. The Validate method of the Validator class creates an XML document containing all the parameters necessary to invoke the data validation method, and then uses the InvokeMember method of the Type class.

object[] objArgs = new object[] {doc}; object result = true; // use reflection services to dynamically invoke // real validator here try { result = m_Type.InvokeMember(m_strMethodName, BindingFlags.Default | BindingFlags.InvokeMethod, null, m_InstanceObj, objArgs); } catch(Exception e) { if (null != e.InnerException) throw e.InnerException; else throw e; }

You can use the existing instance of an object in an assembly to use the InvokeMember method of the Type class, passing an XML document by reference. The external assembly class receives the XML document, parses it, and performs its internal routines to validate and modify the data as necessary. Because the XML document gets passed by reference you can change the contents of the data in the external assembly and return the updates to modify the instance data. As the code parses the XML document upon return it can invoke the class property to update the data value as in the following sample code:

Type t = obj.GetType(); PropertyInfo info = t.GetProperty(v.GetAccessor(strFieldName)); object objValue = Convert.ChangeType(child.InnerText, info.PropertyType); info.SetValue(obj, objValue, null);

Although the above sample validates a single data member of a class you can use it to validate multiple members of a class at one time. We currently perform this on address data using third-party software that we invoke from our AddressValidator using the p/Invoke System.Runtime.InteropServices namespace for calling functions in external Win32 DLLs. With additional modifications you could easily access information in other classes contained within the class you are currently validating.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date