| By Doug Holland | Article Rating: |
|
| August 11, 2003 12:00 AM EDT | Reads: |
20,713 |
You have probably not escaped seeing the latest commercials for Microsoft Windows Server 2003, which urge listeners to "do more with less"; this has been an aim of software engineering since the very beginning.
When I started writing software using C and C++ on Unix systems, programmers aimed to do more with less by reusing others' header files and precompiled libraries.
Today I find myself doing more with less through many technologies such as COM+ components and commercial extensions to the .NET Framework.
Recently I discovered I could also do more with less through .NET Reflection and dynamically assigning controls to ASP.NET pages and panels.
This article will present an introduction to the technologies and techniques that I've discovered over the past 18 months and that ultimately resulted in the epiphany that has empowered me to do more with less. This article will present an introduction to the technologies and techniques that I've discovered over the past 18 months - and that ultimately resulted in the epiphany that has empowered me to do more with less. The source code for this article can be downloaded from http://www.sys-con.com/sourcec.cfm.
Introduction to Reflection
Unlike unmanaged environments, in which the source code you write is
ultimately compiled directly into native machine code for the specific
microprocessor upon which it is intended to run, Microsoft .NET code is
compiled into Microsoft Intermediate Language (also known as MSIL, or simply
IL).
Any Common Language Specification (CLS)compliant language can create IL, which the Common Language Runtime (CLR) can then run through a process known as just-in-time compilation to convert the IL (such as that shown in Listing 1) to machine code native to the processor on which the CLR is running. The source code for this article can be downloaded from www.sys-con.com/dotnet/sourcec.cfm
In addition to the IL generated by a managed compiler, .NET assemblies also contain metadata (data about data). Within an assembly metadata is a system of descriptors that describe the structural items of an application, e.g., the members and attributes of a given class.
Using the classes within the System.Reflection namespace you can access the information held within an assembly's metadata dynamically at runtime.
private static System.Type m_hashtable = null;
private static System.Type[] m_interfaces = null;
In the preceding C# code I have defined two variables: m_hashtable of type System.Type, and an array m_interfaces, also of type System.Type.
m_hashtable = System.Type.
GetType("System.Collections.Hashtable");
System.Type.GetType is a static method that returns a System.Type based on the supplied case-sensitive, fully qualified class name. Another way of doing this would be to use the C# type of operator as shown below:
m_hashtable = typeof(System.Collections.Hashtable);
System.Type includes many methods that can be used to discover information about the current System.Type object. One such method, GetInterfaces(), returns an array of System.Type objects representing all the interfaces implemented or inherited by the current type. Using GetInterfaces(), we now assign the array of System.Type objects representing the interfaces implemented or inherited for the Hashtable class.
m_interfaces = m_hashtable.GetInterfaces();
Compared to its predecessors, the C and C++ languages, one of the best additions to the C# language is the foreach loop, which we use now to print out the names of all the interfaces discovered by calling GetInterfaces():
foreach(System.Type t in m_interfaces)
{
Console.WriteLine("{0} Realizes {1}",
m_hashtable.Name, t.Name);
}
If you run this code you will see the following output:
Hashtable Realizes IDictionary
Hashtable Realizes ICollection
Hashtable Realizes IEnumerable
Hashtable Realizes ISerializable
Hashtable Realizes IDeserializationCallback
Hashtable Realizes ICloneable
Reflection enables you to produce highly adaptable dynamic applications. However, the very dynamic nature of using Reflection effectively requires you to program defensively.
Imagine the following scenario: you have defined a new interface, ISearchable, and wish to have your code act upon a type differently if the type supports the ISearchable interface. You then deploy your application, which functions without error for many months until a user installs a newer version of the .NET Framework.
It appears that Microsoft has been kind enough to implement their own ISearchable interface (highly possible), which causes your code to throw exceptions of type System.MissingMethodException when the code runs.
Therefore, if you ever write code such as this:
if(type.Name == "ISearchable")
{
}
you might want to consider changing it to behave a little more defensively against changes outside of your control:
if(type.Name == "ISearchable" && type.Namespace ==
"PrecisionObjects.Interfaces")
{
}
It is highly unlikely that Microsoft will implement an interface ISearchable in the namespace PrecisionObjects.Interfaces.
Dynamically Adding Controls to ASP.NET Web Forms
ASP.NET allows you to dynamically add controls to Web Forms using the
Controls property of container controls such as the System.Web.UI.WebControls.Panel control.
Panel has this ability because it directly inherits from the ASP.NET base control class System.Web.UI.Control, which provides the Controls property.
ASP.NET System.Web.UI.Page also inherits from System.Web.UI.Control and therefore also contains a Controls collection property. However, any controls added directly to the Controls collection of the page will not be rendered, and an exception of type System.Web.HttpException will be thrown when you attempt to run your code. This is demonstrated in Listing 2. Listing 3 successfully adds the new control to a System.Web.UI.WebControls.Panel control.
ASP.NET allows the developer to add controls dynamically to many other container controls. You will probably find it useful to dynamically add controls to an ASP.NET table control.
You can add controls to both the System.Web.UI.WebControls.Table Cell and the System.Web.UI.WebControls.TableRow controls. I'll show you how in the SearchPage example, which dynamically adds controls using information discovered through Reflection about another class.
Using Reflection to Empower Dynamic Control Creation
I have now introduced two techniques that are very powerful in their own
right but become even more powerful when combined to build dynamic ASP.NET
Web Forms or user controls.
If you have spent any time writing ASP.NET Web applications you will have undoubtedly discovered the usefulness of ASP.NET user controls (*.ascx controls). If you haven't yet, then you might be convinced of their usefulness after seeing the following example.
Imagine your enterprise application has a Search page that contains three System.Web.UI.WebControls.Panel controls: Search-Panel, ResultsPanel, and DetailsPanel.
SearchNavigation.ascx (see Listings 4 and 5) allows you to dynamically, through Reflection, establish a hyperlink menu for each of the panels on a Web Form and then allow the user to set the appropriate Panel.Visible property to true and all others to false.
If any further panels are subsequently added to the Web Form, the code within SearchNavigation.ascx doesn't have to be updated because it will dynamically discover the new panel at runtime.
Before we can discover the panels that exist within the System .Web.UI.Page control collection we need to retrieve the type of the page:
m_type = typeof(SearchPage);
Just as we used GetInterfaces() before to retrieve the interfaces implemented or inherited for the System.Collections.Hashtable class, we can now use GetFields() to retrieve the fields of the current type, in this case the SearchPage.
FieldInfo[] fields =
m_type.GetFields(BindingsFlags.NonPublic
| BindingsFlags.Instance);
Now we can use the C# foreach loop again to iterate through the returned fields to search for System.Web.UI.WebControls.Panel controls.
foreach(FieldInfo field in fields)
{
if(field.FieldType.FullName ==
"System.Web.UI.WebControls.Panel")
{
}
}
We can create an instance of the System.Web.UI.WebControls.LinkBut ton class for each panel found on the Web Form, while also dynamically adding an event handler for the link button's Click event (see Listing 6).
Finally, we must add the newly created TableRow object to the ASP.NET table control:
CommandTable.Rows.Add(_row);
We have now created a user control that can be used to build a menu of ASP.NET panels on any Web Form. To use the control, all you would need to change is the initial type assigned to m_type within the code; even this could be automated to produce a truly disconnected user control.
As you can see in Figure 1, the link buttons were successfully created for the three panels on the Search page, allowing the user to click between the panels. The event handler will activate the appropriate panel when the user selects a menu item.
The controls on the Search panel are also dynamically constructed at runtime using Reflection and custom attributes.
Custom Attributes
Custom attributes are another tool available to developers using the
.NET Framework; they allow you to insert additional metadata into your
assembly that can then be accessed through Reflection.
An example of a custom attribute is the System.Web.Services.WebMethodAttribute class, which you are probably more used to seeing within ASP.NET Web services as [WebMethod].
SearchPage.aspx uses another custom attribute class, SearchableAttribute, to distinguish between members of the Publisher class that are searchable and those that are not. The code for SearchableAttribute is shown in Listing 7.
You will notice the use of another attribute in the above code;
[AttributeUsage] is used to define where a custom attribute can be used. In
the case of [Searchable] we want it to be applied only to properties defined
in classes written in a CLS-compliant language. Therefore, we use the
AttributeTargets enumeration to specify this.
SearchPage.aspx
While working on a recent ASP.NET project that involved constructing
several different search pages for various entities within the system I
began thinking about a way to construct a single search page that would
dynamically construct the Search, Results, and Details panels at runtime,
enabling me to write a single dynamic search page.
Using the custom attribute [Searchable] it is possible to define in metadata which properties of a given class will be searchable through the dynamic search page. Listing 8 shows the [Searchable] attribute used in the class Publisher.
SearchPage.aspx uses the metadata injected into the Publisher assembly through the [Searchable] attribute to determine which properties of the Publisher class should be displayed within the Search-Panel.
As within the SearchNavigation.ascx user control, we start by assigning the type of the target class (in this case Publisher) to a variable of type System.Type and then get the associated interfaces to ensure that the class realizes the ISearchable interface (see Listing 9).
Assuming that we discover that Publisher does indeed realize the ISearchable interface and that ISearchable does reside within the namespace PrecisionObjects.Interfaces, we can then check which properties of Publisher we should allow our user to search upon.
We start by getting an array of type PropertyInfo, which contains all of the properties for a given type. Again, we can use the C# foreach loop to iterate through the properties and dynamically add the associated label and textbox controls to the SearchPanel.
Listing 10 shows how you can then establish whether or not a given property is adorned with the [Searchable] attribute. I have removed the code to add the controls to the SearchPanel, as it is nearly identical to the code presented previously in constructing the SearchNavigation.ascx user control.
Conclusion
Reflection continues to provide me with an excellent mechanism to
produce highly dynamic and reusable code and does enable me to do more
with less.
Some of you reading this have probably been thinking that there must be a relative degradation in performance when using Reflection and, unfortunately, all good things do come at a price. However, the performance impact of using Reflection is relatively minor; in fact many aspects of the .NET Framework and Visual Studio .NET wouldn't be possible without it.
Published August 11, 2003 Reads 20,713
Copyright © 2003 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Doug Holland
A "blue-badge" .net architect and developer at Intel Corporation since March 2007, Doug Holland is part of the Intel Mobility group and is presently working within an advanced tools and development team with an emphasis on graphics performance. He holds a Master's Degree in Software Engineering from Oxford University and has been awarded both the Microsoft MVP and Intel Black Belt Developer awards. Outside of work, Holland enjoys spending time with his wife and four children; and is also an officer in the Civil Air Patrol / U.S. Air Force Auxiliary.
- iPad3 vs Windows 8 - and the Winner Is...Cloud
- Eleven Reasons Why Windows Phone Will Overtake Android
- Windows Azure Overview Part 4: Security
- Eleven Tips for Successful Cloud Computing Adoption
- Agile Development & Enterprise Architecture Practice – Can They Coexist?
- GM to Pull Facebook Advertising: WSJ
- System Center Virtual Machine Manager 2012 as Private Cloud Enabler
- Apply Agile When Deploying Apps
- The Web – Changing the Way We Work
- EE Times and EDN Announce the 2012 UBM Electronics ACE Award Winners
- Closer Look at One NoSQL Database – MongoDB
- Why Is Scrum So Widely Adopted and So Very Dangerously Deceptive
- iPad3 vs Windows 8 - and the Winner Is...Cloud
- Cisco Unveils Visual Collaboration Solutions in the Post-PC Era, Extending the Reach of TelePresence With New Mobile-to-Immersive Offerings
- Eleven Reasons Why Windows Phone Will Overtake Android
- Windows Azure Overview Part 4: Security
- Eleven Tips for Successful Cloud Computing Adoption
- Agile Development & Enterprise Architecture Practice – Can They Coexist?
- GM to Pull Facebook Advertising: WSJ
- System Center Virtual Machine Manager 2012 as Private Cloud Enabler
- Apply Agile When Deploying Apps
- The Web – Changing the Way We Work
- Book Review: Decision Management Systems
- User Group Malaise?
- Google Maps and ASP.NET
- Converting VB6 to VB.NET, Part I
- How to Write High-Performance C# Code
- Crystal Reports XI & How It Has Changed
- Creating Controls for.NET Compact Framework in Visual Studio 2005
- Where Are RIA Technologies Headed in 2008?
- Programmatically Posting Data to ASP .NET Web Applications
- Implementing Tab Navigation with ASP.NET 2.0
- AJAX World RIA Conference & Expo Kicks Off in New York City
- i-Technology Viewpoint: "SOA Sucks"
- .NET Archives: Getting Reacquainted with the Father of C#
- i-Technology Photo Exclusive: Bill Gates & Steve Jobs In "Nerds"





















