Home arrow ASP.NET arrow Page 7 - Demonstrating Attributes and Reflection in .NET
ASP.NET

Demonstrating Attributes and Reflection in .NET


In this article, Todd Clemetson demonstrates how the combination of attributes and reflection can result in some flexible and powerful software...

Author Info:
By: Wrox Team
Rating: 5 stars5 stars5 stars5 stars5 stars / 78
January 14, 2003
TABLE OF CONTENTS:
  1. · Demonstrating Attributes and Reflection in .NET
  2. · What are Attributes?
  3. · Generic Database Manager
  4. · Attributes Applied
  5. · Generating SQL using .NET Reflection
  6. · Putting it all together
  7. · Bug Tracking Attribute
  8. · Conclusion

print this article
SEARCH DEVARTICLES

Demonstrating Attributes and Reflection in .NET - Bug Tracking Attribute
(Page 7 of 8 )

Consider the following scenario. You recently released a patch to your latest Wizbang product, and one of your developers "fixed" a bug but introduced four more showstoppers that got past your QA department. Unfortunately the code modifications made to "fix" the bug span multiple assemblies and you don't know where to start.

What if you could run a utility program that examined the source code and provided a listing of all the affected code related to this bug? Given your programmers have some discipline in using attributes to annotate source code, determining code changes could be accomplished at the click of a button.

The Issue Attribute

Let's define a custom .NET attribute that allows developers to identify areas of code affected by a bug fix. Our custom attribute will specify the issue number, name of the programmer, and a description of the change.

Developers should have the ability to place these attributes on classes, methods, properties, enumerations, etc. Here is the attribute's definition:

[AttributeUsage(AttributeTargets.All,
AllowMultiple = true, Inherited = true)]
Public class BugFixDetails : System.Attribute
{
private string _issueID;
private string _programmerName;
private string _description;

public string IssueID
{
get
{
return _issueID;
}
set
{
_issueID = value;
}
}
public string ProgrammerName
{
get
{
return _programmerName;
}
set
{
_programmerName = value;
}
}
public string Description
{
get
{
return _description;
}
set
{
_description = value;
}
}

public BugFixDetails(string ID, string programmer, string desc)
{
this.IssueID = ID;
this.ProgrammerName = programmer;
this.Description = desc;
}

}


Note that the AttributeUsage attribute allows this attribute to be applied to any of the areas supported by .NET attributes. Here is some sample code containing the BugFixDetails attribute.

[BugFixDetails("1", "John Q. Programmer",
"Changed name of class from Test to Test1")]
public class Test1
{
[BugFixDetails("2", "Suzie B. BugFree",
"Changed _var1 from type object to string")]
private string _var1;
private string _var2;

[BugFixDetails("2", "Suzie B. BugFree",
"Initialized variables in constructor")]
public Test1()
{
_var1 = "init value 1";
_var2 = "init value 2";
}
[BugFixDetails("3", "John Q. Programmer",
"Altered code to account for framework exception being thrown")]
[BugFixDetails("4", "John Q. Programmer",
"Added in code to rethrow exception being thrown from framework")]
public void Method1(int a, int b)
{
. . .
}
. . .
}


The Issue Viewer

Now let's look at a sample application that loads a .NET assembly and searches for all BugFixDetails attributes matching a particular Issue ID. The screen shot below shows the results of a query for Issue ID #1. Note that the source code download contains a sample class library annotated with BugFixDetails attributes.

Figure 4

The sample application above opens up the assembly, examines it for BugFixDetails attributes and lists the following:
  • Scope - The element that the code change was applied to (i.e. class, method, enumeration, property, etc).
  • Name - The name of the element (method name, class name, etc).
  • Programmer - The name of the programmer.
  • Description - A description of the bug
When the user clicks the Find Details for Issue button, the following code is executed:

private void btnFindIssueDetails_Click(object sender,
System.EventArgs e)
{
try
{
// make sure they supplied an issue id
if(tbIssueID.Text.Trim() == "")
{
MessageBox.Show("You must specify an issue ID.");
return;
}
if(tbAssemblyFileName.Text.Trim() == "")
{
MessageBox.Show("You must specify the path and " +
"file name of the assembly to inspect.");
return;
}
// clear all the items in the list
listView1.Items.Clear();

// load the assembly so that we can
// interrogate it
Assembly assem =
System.Reflection.Assembly.
LoadFrom(tbAssemblyFileName.Text);
// iterate through each type in the assembly
// we loaded above
foreach(Type t in assem.GetTypes())
{
// add class level issue
// descriptions for this issue id
this.AddIssueDetailsForClass(t,
tbIssueID.Text);
// add method level issue
// descriptions for this issue ID
this.AddIssueDetailsForMethods(t,
tbIssueID.Text);
// add property level issue
// descriptions for this issue ID
this.AddIssueDetailsForProperties(t,
tbIssueID.Text);
// add constructor level issue
// descriptions for this issue ID
this.AddIssueDetailsForConstructors(t,
tbIssueID.Text);
}
}
// catch any exceptions
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}


Once the code verifies that the Issue ID and assembly information is entered correctly, it loads the specified assembly and iterates through all of the types.

Next, the code adds details for bug fixes within classes, methods, properties, and constructors. Let's examine the method that locates custom BugFixDetails attributes at the method level.

private void AddIssueDetailsForMethods(Type t,
string issueID)
{
// iterate through all the methods of this object
foreach(MethodInfo mi in t.GetMethods())
{
// grab the custom attributes for each method
foreach(Attribute att in
mi.GetCustomAttributes(false))
{
// cast to our custom attribute
BugFixDetails dets =
att as BugFixDetails;

if(dets != null)
{
// do these issue IDs match?
if(dets.IssueID == issueID)
{
// add this issue to the list
this.AddIssueItemToList("Method",mi.Name,
dets.ProgrammerName,dets.Description);
}
}

}

}
}


The AddIssueDetailsForMethods first iterates through all of the methods within the type, then through all the custom attributes for each method. After verifying the custom attribute is indeed a BugFixDetails attribute, the method looks at the IssueID of the attribute and, if the Issue IDs match, adds the item to a ListView.

The code that adds the item to the ListView is listed below:

private void AddIssueItemToList(string strScope,
string strName,
string strProgrammer,
string strDescription)
{
// create the listview item for this issue
ListViewItem lvi = new ListViewItem(strScope);
// add all the sub items
lvi.SubItems.Add(strName);
lvi.SubItems.Add(strProgrammer);
lvi.SubItems.Add(strDescription);
// lets add this to our list.
listView1.Items.Add(lvi);
}


The above code block simply creates a new ListViewItem, populates it with the bug details, and adds the item to the ListView control.
blog comments powered by Disqus
ASP.NET ARTICLES

- How Caching Means More Ca-ching, Part 2
- How Caching Means More Ca-ching, Part 1
- Reading a Delimited File Using ASP.Net and V...
- What is .Net and Where is ASP.NET?
- An Object Driven Interface with .Net
- Create Your Own Guestbook In ASP.NET
- HTTP File Download Without User Interaction ...
- Dynamically Using Methods in ASP.NET
- Changing the Page Size Interactively in a Da...
- XML Serialization in ASP.NET
- Using Objects in ASP.NET: Part 1/2
- IE Web Controls in VB.NET
- Class Frameworks in VB .NET
- Cryptographic Objects in C#: Part 1
- Sample Chapter: Pure ASP.Net

Watch our Tech Videos 
Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 

Developer Shed Affiliates

 




© 2003-2017 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials