|
SYS-CON.TV Webcasts
Comments
Did you read today's front page stories & breaking news?
SYS-CON.TV
|
Top Links You Must Click On
Advanced Techniques Generic Object Configuration
A total solution
By: Jerry Dixon
May. 20, 2005 11:00 AM
In a previous article (DNDJ Volume 3, issue 4), I discussed an application that had to load, process, and transmit data received from multiple customers. The system had to perform a specific set of tasks or steps for each customer. Because of the diverse needs of each customer, however, the actual implementation of each step could vary widely, often on a per-customer basis. In addition, new customers would be added long after the application was completed, and the unique requirements of these new customers would also have to be met.
While this approach did solve the problem, it also introduced a new one: How does one write a configuration program for an application that works in this manner? The standard approach to writing a configuration program is to "hard code" a certain amount of knowledge about each object that can be configured. This was not only distasteful to me, but it didn't answer my main question: How can the configuration program accommodate objects that will be created long after the configuration program itself is written? Steve Henke (a fellow co-worker and the ultimate author of the configuration program) and I got together to hammer this out. During a brainstorming session, we determined that the best approach was to somehow encode each object with "metadata" that could be read by the configuration program. This "metadata" would describe the unique configuration needs of each object. We then remembered that the .NET framework provided support for class and method attributes, and that custom attributes could be created. This turned out to be the answer. We created one custom attribute that each configurable object would use to describe its configuration requirements. We created another custom attribute for each property in that object, so that the properties could be displayed on screen in an appropriate manner. The configuration program used some of the classes in the Reflection namespace to read this data. This approach allowed each object to provide enough information about itself that a generic configuration program could be written. The remainder of this article describes the .NET technologies used by this configuration system. It shows how to create custom attributes for your own classes and how to read the information that these attributes supply. It also explains some of the challenges that we faced, and how implementing a custom base class for our configurable objects allowed these challenges to be overcome. Finally, it demonstrates how the Reflection namespace classes can be used to access object properties and invoke object methods in a completely generic manner. Attributes As you can see, by using the .NET framework's built-in attributes, the developer can exert a good deal of control over how particular classes, properties, and methods are processed. Many of these built-in attributes can be applied not only to framework classes, but to those created by the developer as well. In addition, when existing attributes are not sufficient, custom attributes can be created to fill the gap. Custom Attributes Listing 4 shows how the Employee object could use the DataClassAttribute to provide information to a configuration program. (Note that in VB.NET, the word "Attribute" is used in an attribute definition, but is omitted when the attribute is used. The "DataClassAttribute" is specified correctly as "DataClass" in this example.) Using this information, a program could determine that the Employee class is configurable (IsConfigurable:=True), that it should be displayed on screen with a particular label (Label:="Employee"), and that the names of the Employee object's methods are "Delete," "Insert," "Update," and "Get" (DeleteMethod, GetMethod, etc.). The program could do this generically, without having to have specific information hard-coded into it. Our configuration program also needed to be able to extract information about each configurable object's properties. The ConfigurationAttribute in Listing 5 was created for this. This attribute, which can be used only on properties, provided information about how the property should be displayed on screen and how it should be validated. An example of its actual use is shown in Listing 6. Custom Object Base Class To simplify things, we decided to derive each configurable object from a common base class that would encapsulate all of the Reflection code. In Listing 7, you can see examples of some of the methods of this base class. First, a new class called ConfigurationInfo was created to hold the actual property attribute information. This class was derived from our ConfigurationAttribute class, but included fields to specify the object's property name and type. Next, the GetPropertyConfigura-tionData method was used to return a list (actually a HybridDictionary) of these ConfigurationInfo objects. It did this by iterating through each explicitly declared public property and processing only those properties that possessed a ConfigurationAttribute. For those properties, a ConfigurationInfo object was instantiated and populated with data about the property. This included the custom attribute data. The GetClassConfigurationData method performed a similar task for the configurable object itself, returning a DataClassAttribute to the caller. Once the base class existed, we found many other uses for it. Code for common tasks such as validation and exception handling was moved to the base class. This served to further simplify the configurable objects themselves. Configuration Program The last remaining problem was how to examine and/or invoke an object's properties and methods in a generic manner. The Reflection namespace once again provided a ready-made solution. A PropertyInfo object was used to represent each property of the configurable object. The PropertyInfo object's GetValue and SetValue methods were used to read and write property values. Similarly, a MethodInfo object was used to represent each method of the configurable object, and the MethodInfo's Invoke method used to execute the appropriate methods. During the design of our customer classes, we had already decided that each class would contain shared (static, or non-instance) methods for managing the creation, modification, and deletion of instances of the class. This turned out to be fortuitous, because the configuration program could use these shared classes to create, modify, and delete object instances using methods of the MethodInfo class. No further code had to be created to manage the objects. The configuration program could now obtain a list of configurable objects, query those objects for information about any properties that needed to be configured, and invoke the appropriate add/edit/delete methods as needed. All of this could be done without having to hard-code any object-specific information into the configuration program. Total Solution Reader Feedback: Page 1 of 1
Enterprise Open Source Magazine Latest Stories . . .
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
|
SYS-CON Featured Whitepapers
Most Read This Week |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||