-9-

 

The Class Browser

 

In this chapter, we have picked up one of the Microsoft samples called the Class Browser and presented it to you in a straightforward and uncomplicated format, stripped of all its convolutions.

This sample displays the following:

 

     all the namespaces

     the classes within each namespace

     the functions within each class

     the parameters of each function, and so on.

 

It is a considerably large program, and hence appears intimidating. As is customary, we shall first partition this program into smaller programs and after deciphering every small part, we shall coalesce them together to form one composite program.

 

At the end of this explanation, you would not only be in a position to write complex ASP.Net code, but you would also have unraveled the mysteries of the Reflection API, which is a technique used to determine the contents of a class.

 

We have retained the function names and variable names as given in the original code, with the anticipation that sooner or later, you would be motivated enough to read the source code written by the programmers at Microsoft. Our example will work as effectively, sans the comely appearance of the original code.

 

Our first program displays a series of namespaces in a single column. These names are displayed as hyperlinks. Before we dive headlong into the program, we first need to create the file named web.config in the sub-directory c:\inetpub\wwwroot.

 

web.config

<configuration>

  <configSections>

    <sectionGroup name="system.web">

      <section name="ClassBrowser" type="System.Configuration.NameValueSectionHandler,System"/>

    </sectionGroup>

  </configSections>

  <system.web>

       <compilation debug="true"/>

    <ClassBrowser>

     <add key="Data Library" value="System.Data" />

     <add key="ASP.NET Class Library" value="System.Web" />

     <add key=".NET Framework class Library" value="mscorlib" />

    </ClassBrowser>

  </system.web>

</configuration>

 

a.aspx

<%@ Import NameSpace="System.Collections"  %>

<%@ Import NameSpace="System.Collections.Specialized" %>

<%@ Import NameSpace="System.Reflection" %>

<html>

<head>

<script runat="server" language="C#">

ArrayList ModuleName = new ArrayList();

void Page_Load(Object Sender, EventArgs e)

{

NameValueCollection ConfigSettings;  

ConfigSettings = (NameValueCollection)Context.GetConfig("system.web/ClassBrowser");

Response.Write(ConfigSettings.Count.ToString() + "<br>");

for (int i = 0; i < ConfigSettings.Count; i++)

{

Response.Write(ConfigSettings[i].ToString() + "<br>");

ModuleName.Add(ConfigSettings[i].ToString());

}

DisplayNamespaces(); 

}

void DisplayNamespaces()

{

ArrayList NameSpaceList   = new ArrayList();

Hashtable NameSpaceHash = new Hashtable();

Response.Write(ModuleName.Count.ToString() + "<br>");

for (int y = 0; y < ModuleName.Count; y++)

{

Assembly a = Assembly.Load(ModuleName[y].ToString());

Module[]  CorRuntime = a.GetModules();

Type[]   CorClasses = CorRuntime[0].GetTypes();

Response.Write(ModuleName[y].ToString() + " Modules:" + CorRuntime.Length.ToString() + " Type:" + CorClasses.Length.ToString() + "<br>"  );

 

for( int x=0; x < CorClasses.Length; x++ )

{

if ( CorClasses[x].Namespace != null )

{

if (!NameSpaceHash.ContainsKey(CorClasses[x].Namespace) && CorClasses[x].IsPublic)

{

NameSpaceHash.Add(CorClasses[x].Namespace,"");

NameSpaceList.Add(CorClasses[x].Namespace);

}

}

}

}

NameSpaceList.Sort();

Namespace1.DataSource = NameSpaceList;

Namespace1.DataBind();

}

</script>

</head>           

<body>

<form runat="server">

<asp:DataList runat=server id="Namespace1" RepeatLayOut="flow">

<headertemplate>

Namespaces <br>

</headertemplate>

<itemtemplate>

<asp:HyperLink runat="server" text=<%# Container.DataItem %> NavigateUrl=<%# "a.aspx?namespace=" + Container.DataItem %> />

</itemtemplate>

<selecteditemtemplate>

<b><asp:HyperLink runat=server text=<%# Container.DataItem %>/></b>

</selecteditemtemplate>

</asp:DataList>                        

</form>

</body>

</html>           

 

Output

3

System.Data

System.Web

mscorlib

3

System.Data Modules:1 Type:427

System.Web Modules:1 Type:663

mscorlib Modules:1 Type:1410

 

Namespaces

 

Microsoft.Win32

System

System.Collections

System.Configuration.Assemblies

System.Data

System.Data.Common

System.Data.OleDb

System.Data.SqlClient

System.Data.SqlTypes

System.Diagnostics

System.Diagnostics.SymbolStore

System.Globalization

System.IO

System.IO.IsolatedStorage

System.Reflection

System.Reflection.Emit

System.Resources

System.Runtime.CompilerServices

System.Runtime.CompilerServices.CSharp

System.Runtime.InteropServices

System.Runtime.InteropServices.Expando

System.Runtime.Remoting

System.Runtime.Remoting.Activation

System.Runtime.Remoting.Channels

System.Runtime.Remoting.Contexts

System.Runtime.Remoting.Lifetime

System.Runtime.Remoting.Messaging

System.Runtime.Remoting.Metadata

System.Runtime.Remoting.Metadata.W3cXsd2001

System.Runtime.Remoting.Proxies

System.Runtime.Remoting.Services

System.Runtime.Serialization

System.Runtime.Serialization.Formatters

System.Runtime.Serialization.Formatters.Binary

System.Security

System.Security.Cryptography

System.Security.Cryptography.X509Certificates

System.Security.Permissions

System.Security.Policy

System.Security.Principal

System.Text

System.Threading

System.Web

System.Web.Caching

System.Web.Configuration

System.Web.Handlers

System.Web.Hosting

System.Web.Mail

System.Web.Security

System.Web.SessionState

System.Web.UI

System.Web.UI.HtmlControls

System.Web.UI.WebControls

System.Web.Util

System.Xml

 

In the web.config file, within the configSections tags, we have added the name ClassBrowser and specified the type of information that it will contain. Thereafter, all the data is inserted within the ClassBrowser tag. The data within this tag is in the key-value pair format. It is always a good idea to store all the data in a file, and then read this file at runtime. How we exploit these key-value pairs, will be substantiated in the ASP+ program, whose explanation follows.

 

In a.aspx, we commence with the usual suspect, the import namespaces command. An instance variable named ModuleName of type ArrayList is initially created outside all the functions. It is done to enable apportioning and sharing of this type ArrayList by all functions. In our example, this ArrayList will store strings.

 

In the function Page_Load that gets called at the server end, initially a variable named ConfigSettings is created, which is an instance of a NameValueCollection class. A NameValueCollection class stores the key-value pairs in an efficient way, so that retrieval of the values is more rapid compared to an ArrayList. The principal advantage of this is that we can effectively figure out whether a key-value pair entry already exists or not.

 

In the aspx file, it is our intention to access all the key-value pairs that are defined within the ClassBrowser tag in the configuration file. The Context property in the Page class, returns an HttpContext object. This Object has a function called GetConfig, whose only task is to return the configuration of the name supplied as a parameter. The Object returned by this function is then cast into a NameValueCollection.

 

In order to verify that the values have been actually placed, we display the Count member of the NameValueCollection object. We see a value of 3, since we have 3 key-value pairs in the ClassBrowser tag, within the web.config file.

 

   <add key="Data Library" value="System.Data" />

     <add key="ASP.NET Class Library" value="System.Web" />

     <add key=".NET Framework class Library" value="mscorlib" />

 

To display the values contained in the web.config file, the for loop is used thrice, to iterate through all the 3 values.

 

In the loop, we add the variable ModuleName to the ArrayList, with the values retrieved from the web.config file. At the conclusion of the execution of the for loop, the ArrayList contains the names of the 3 modules or dll's, whose details are to be displayed. These details include the namespaces contained in them, the classes in the namespaces, et al. You may recall that, the System.Web.dll contains all the Web classes that we have been working on.

 

The ArrayList now holds the three module names. Hence, the for loop iterates thrice. The class called Assembly in the namespace System.Reflection has a static function named Load, which accepts the name of a module and loads it into memory. The module gets loaded into the address space of the program that is running this function, and returns an Assembly object that represents the assembly. The function GetModules in the assembly class returns an array of modules that are currently present in the assembly.

 

In our program, CorRuntime, which is an array variable of type Module, contains the modules in the assembly. An assembly can easily contain more than one module, the first module being the most significant, at the moment. This module object returns the number of types using the GetTypes function. We store the types in the CorClasses array variable of type Types. Thus, the hierarchy is assembly, modules and then, types.

 

The output very unambiguously conveys to us the following:

 

     System.Web assembly has 1 module and 663 types.

     System.Data assembly has 1 module and 427 types.

     mscorlib has 1 module and 1410 types.

 

Within the for loop, we add one more for loop for every type, because we intend to include all the unique namespaces from the assemblies in the ArrayList called NameSpaceList. The crucial word in the above statement is 'unique'. The Add function in HashTable and ArrayList is used to add the namespace in NameSpaceHash and the NameSpaceList object respectively. If we stop at this stage, the list will contain duplicate Namespaces. Hence, we first employ the ContainsKey function to check whether the namespace is already added or not.  If it does, then the namespaces are not added again. ContainsKey returns true if a name already exists. The property IsPublic is employed to discover whether the type of the namespace is public or not.

 

Thus, namespaces marked public in the assembly, are added only if they don't already exist in the list. The Type class has a member called Namespace that returns the namespace that the type belongs to. A type is a synonym for a class or interface, etc.

 

The array list is then sorted and assigned to the DataSource member of the DataList called Namespace1. Finally, using the DataBind function, a list of namespaces is displayed.

 

In our presentation logic, our DataList Namespace1 now contains a list of namespaces. The template is executed for each item in the DataList. However, the template named headertemplate is executed only once, thereby, showing the word Namespaces only once in the window. It is the template named itemtemplate that is called thrice. The HyperLink tag displays the namespaces like a URL. A URL is generated each time we click on a link. This URL is decided by the NavigateUrl property and looks like http://localhost/a.aspx?namespace=Microsoft.Win32 . This is so because the Container.DataItem contains the namespace name that we clicked on, and the ?namespace is given as a literal. The Text property displays the name of the namespace. Also, the items that we have selected in the past, will be displayed as per the template named selecteditemtemplate. This template displays the namespace name in a bold tag.

 

Let us proceed to the next example, where we propose to display a list of classes belonging to the namespace.

 

a.aspx

<%@ Import NameSpace="System.Collections"  %>

<%@ Import NameSpace="System.Reflection" %>

<html>

<head>

<script runat="server" language="C#">

public String SelectedNameSpace;   

public ArrayList ModuleName = new ArrayList();

void Page_Load(Object Sender, EventArgs e)

{

NameValueCollection ConfigSettings = new NameValueCollection(); 

ConfigSettings = (NameValueCollection)Context.GetConfig("system.web/ClassBrowser");

 

for (int i = 0; i < ConfigSettings.Count; i++)

{

ModuleName.Add(ConfigSettings[i].ToString());

}

DisplayNamespaces(); 

if (Request.QueryString["namespace"] == null)

SelectedNameSpace = "System";

else

SelectedNameSpace = Request.QueryString["namespace"];

if (Request.QueryString["class"] != null)

DisplayClass(Request.QueryString["class"]);

else

DisplayClassList(SelectedNameSpace);

}

private void DisplayNamespaces()

{

ArrayList NameSpaceList   = new ArrayList();

Hashtable NameSpaceHash = new Hashtable();

for (int y = 0; y < ModuleName.Count; y++) {

Module[]  CorRuntime = Assembly.Load(ModuleName[y].ToString()).GetModules();

Type[]     CorClasses = CorRuntime[0].GetTypes();

for( int x=0; x < CorClasses.Length; x++ ) {

if ( CorClasses[x].Namespace != null )

{

if (!NameSpaceHash.ContainsKey(CorClasses[x].Namespace) && CorClasses[x].IsPublic ) {

NameSpaceHash.Add(CorClasses[x].Namespace,"");

NameSpaceList.Add(CorClasses[x].Namespace);

}

}

}

}

NameSpaceList.Sort();

Namespace1.DataSource = NameSpaceList;

Namespace1.DataBind();

}

private void DisplayClassList (String CurrentNameSpace)

{

ArrayList ClassList     = new ArrayList();

ArrayList InterfaceList = new ArrayList();

for( int y=0; y < ModuleName.Count; y++ ) {

Module[]  CorRuntime = Assembly.Load(ModuleName[y].ToString()).GetModules();

Type[]     CorClasses = CorRuntime[0].GetTypes();

for (int x=0; x < CorClasses.Length; x++ ) {

if ( CorClasses[x].Namespace == CurrentNameSpace && CorClasses[x].IsPublic) {

if ( CorClasses[x].IsInterface )

InterfaceList.Add(CorClasses[x].Name); 

else

ClassList.Add(CorClasses[x].Name);

}

} 

}

if (InterfaceList.Count > 0)

IHeader.Visible = true;

if (ClassList.Count > 0)

CHeader.Visible = true;

ClassList.Sort();

Classes.DataSource = ClassList;

Classes.DataBind();

InterfaceList.Sort();

Interfaces.DataSource = InterfaceList;

Interfaces.DataBind();

}

private void DisplayClass(String className)

{

}

public String GetUrl(Hashtable table) {

return "a.aspx?namespace=" + table["Namespace"] + "&class=" + table["GetType"];

}

</script>

</head>           

<body>

<form runat="server">

<table>

<td width=25% bgcolor=#CCCCFF valign=top >

<br>

<asp:DataList runat=server id="Namespace1" RepeatLayOut="flow">

<headertemplate>

Namespaces <br>

</headertemplate>

<itemtemplate>

<asp:HyperLink runat="server" text=<%# Container.DataItem %> NavigateUrl=<%# "a.aspx?namespace=" + Container.DataItem %> />

</itemtemplate>

<selecteditemtemplate>

<b>

<asp:HyperLink runat=server text=<%# Container.DataItem %>/>

</b>

</selecteditemtemplate>

</asp:DataList>

<p>

<td valign=top >

<span runat=server id="CHeader" visible="false" style="text-indent:8">

 <b>

<font size=4 color=#000666>Classes in

<%= SelectedNameSpace %>  </b>

</font>

</span>

<asp:DataList EnableViewState="false" runat=server id="Classes" RepeatColumns="3" Gridlines=None borderstyle=none borderwidth=0 >

<itemtemplate>

<asp:HyperLink runat=server text=<%# Container.DataItem %> NavigateUrl=<%# "a.aspx?namespace=" + SelectedNameSpace + "&class=" + Container.DataItem %> />

</itemtemplate>

</asp:DataList>

<span runat=server id="IHeader" visible="false" style="text-indent:8">

<b>

<font size=4 color=#000666>Interfaces in <%= SelectedNameSpace %> 

</font>

</b>

</span>

<asp:DataList EnableViewState="false" runat=server id="Interfaces" RepeatColumns="4" Gridlines=None borderstyle=none borderwidth=0 >

<itemtemplate>

<asp:HyperLink runat=server  text=<%# Container.DataItem %> NavigateUrl=<%# "a.aspx?namespace=" + SelectedNameSpace + "&class=" + Container.DataItem %>/>

</itemtemplate>

</asp:DataList>

</form>

</body>

</html>           

 

In the above program, two panes are displayed. The pane on the left hand side has a list of namespaces, while the pane on the right hand side contains a list of classes in the Systems namespace. If you click on any of the namespaces, the classes displayed in the right pane will change correspondingly. The URL generated reads as follows: http://localhost/a.aspx?namespace=Microsoft.Win32.

 

We shall only explain the extra lines of code that have been added to the program, to display in the right pane, only those classes that are contained in a specific namespace.

 

The DisplayNamespaces function has not been altered. It displays the namespaces contained in the three dlls. Thereafter, we verify if the namespace variable contains any value. Similar to the functioning of Request.QueryString, here also it is assumed that the form is reloaded with the namespace variable containing a value. Since we have loaded the file for the first time, the namespace parameter does not come into existence. Hence, the string variable named SelectedNameSpace is initialized to System. It is for this reason that we see the classes belonging to the System namespace, at startup.

 

Since we do not have a parameter called class with our URL, the next function to be called is DisplayClassList. This function displays a list of classes belonging to the namespace name, which is currently stored in SelectedNamespace.

 

In the DisplayClassList function, two ArrayList objects named ClassList and InterfaceList are created. ClassList holds the list of classes and InterfaceList holds the list of interfaces. As always, we go through the rigmarole of fetching each and every type, just as we did earlier, and then checking whether the class or type belongs to the namespace specified in the parameter named CurrentNameSpace. If it is so, then using the IsInterface property, we determine whether the type is a class or an interface, as follows:

 

     If the IsInterface property returns a value of true, it means that the type is an interface. Hence, it gets added to the InterfaceList.

     If the IsInterface property returns a value of false, it means that the type is a class. Hence, it gets added to the ClassList.

 

Once the ArrayLists have been filled up, we determine the number of entries in them, using their Count member. If the value returned by Count in the Interface List is greater than zero, the visible property of a span IHeader is set to true. In this situation, the static text 'Interfaces in' is displayed, followed by the name of the namespace, in a bold format. The same procedure is repeated for the ClassList also. A span is useful when many items have to be placed together, because all of them can be manipulated as a single item.

 

Finally, we have two more DataList objects named Classes and Interfaces. Their DataSource members are initialized to the list of classes and interfaces stored in the two ArrayList objects named ClassList and InterfaceList, respectively.

 

 

Thus, as you can see in the above program, we have created an ArrayList and filled it up with data. Then, we request the DataSource property of some DataList to display it.

 

The output in the browser should show the namespaces and the list of classes, concurrently. This can be accomplished only by means of a table. So, we have a table tag containing two table columns.

 

The first table column called td has a background color and occupies 25% of the table width. This ensures that the first DataList is in one column.

 

In the next td, the names of the classes and the interfaces are displayed side by side.

 

The template itemtemplate is repeated for all the classes in the DataSource. Each class name is displayed as a hyperlink, and the URL that is required to navigate to it, contains the following:

 

     the file name a.aspx.

     the name of the namespace.

     the name of the class given to parameters namespace and class.

 

http://localhost/a.aspx?namespace=System.Collections&class=ArrayList

 

The same process is repeated for the interfaces.

 

Let us now attempt to display the list of functions in a class.

 

a.aspx

<%@ Import NameSpace="ClassInfo" %>

<%@ Import NameSpace="System.Collections"  %>

<%@ Import NameSpace="System.Collections.Specialized" %>

<%@ Import NameSpace="System.Reflection" %>

<html>

<head>

<script runat="server" language="C#">

public String SelectedAssembly;

public String SelectedNameSpace;

public ArrayList ModuleName = new ArrayList();

protected void Page_Load(Object Sender, EventArgs e) {

NameValueCollection ConfigSettings = (NameValueCollection)Context.GetConfig("system.web/ClassBrowser");

for (int i = 0; i < ConfigSettings.Count; i++)

ModuleName.Add(ConfigSettings[i].ToString());

DisplayNamespaces();

if (Request.QueryString["namespace"] == null)

  SelectedNameSpace = "System";

else

   SelectedNameSpace = Request.QueryString["namespace"];

if (Request.QueryString["assembly"] == null )

      SelectedAssembly = "mscorlib";

else

  SelectedAssembly = Request.QueryString["assembly"];

 

if (Request.QueryString["class"] != null && Request.QueryString["assembly"] != null)

DisplayClass(Request.QueryString["assembly"], Request.QueryString["class"]);

else

DisplayClassList(SelectedNameSpace);

}

private void DisplayNamespaces() {

ArrayList NameSpaceList   = new ArrayList();

Hashtable NameSpaceHash = new Hashtable();

for (int y = 0; y < ModuleName.Count; y++) {

Module[]  CorRuntime = Assembly.Load(ModuleName[y].ToString()).GetModules();

Type[]    CorClasses = CorRuntime[0].GetTypes();

for( int x=0; x < CorClasses.Length; x++ )

{

if ( CorClasses[x].Namespace != null )

{

if (!NameSpaceHash.ContainsKey(CorClasses[x].Namespace) && CorClasses[x].IsPublic ) {

NameSpaceHash.Add(CorClasses[x].Namespace,"");

NameSpaceList.Add(CorClasses[x].Namespace);

}

}

}

}

NameSpaceList.Sort();

Namespace1.DataSource = NameSpaceList;

Namespace1.DataBind();

}

private void DisplayClassList(String CurrentNameSpace) {

ArrayList ClassList     = new ArrayList();

ArrayList InterfaceList = new ArrayList();

for( int y=0; y < ModuleName.Count; y++ ) {

Module[]  CorRuntime = Assembly.Load(ModuleName[y].ToString()).GetModules();

Type[]    CorClasses = CorRuntime[0].GetTypes();

for (int x=0; x < CorClasses.Length; x++ )

{

   if ( CorClasses[x].Namespace == CurrentNameSpace && CorClasses[x].IsPublic) {

SortTable props = new SortTable("GetType");

props["GetType"] = CorClasses[x].Name;

props["Namespace"] = CorClasses[x].Namespace;

props["Assembly"]= CorClasses[x].Assembly.GetName().Name;

if ( CorClasses[x].IsInterface )

InterfaceList.Add(props);

 else

ClassList.Add(props);

}

}

}

if (InterfaceList.Count > 0)

  IHeader.Visible = true;

if (ClassList.Count > 0)

   CHeader.Visible = true;

   ClassList.Sort();

   Classes.DataSource = ClassList;

   Classes.DataBind();

   InterfaceList.Sort();

   Interfaces.DataSource = InterfaceList;

   Interfaces.DataBind();

}

private void DisplayClass(String asmName, String className) {

 Assembly a = Assembly.Load(asmName);

 Type ClassType = a.GetType(SelectedNameSpace.ToString() + "." + className, false, true);

if ( ClassType == null ) {

DisplayClassList(SelectedNameSpace);

              return;

}

DisplayMethods MethodDetails      =  new DisplayMethods(ClassType, className);

   if(MethodDetails.Count != 0 )

        Methods.DataSource = MethodDetails;

    DataBind();

   if (ClassType.IsInterface)

         spnClassName.InnerHtml = "Interface " + SelectedNameSpace + "." + className;

         else

    spnClassName.InnerHtml = "Class " + SelectedNameSpace + "." + className;

           NameSpacePanel.Visible=false;

            ClassPanel.Visible=true;

        }

        public String GetUrl(Object objTable) {

        if ( objTable is String ) {

       return "a.aspx?assembly=" + SelectedAssembly + "&namespace=" + SelectedNameSpace + "&class=" + objTable;

        }

        if ( ! (objTable is Hashtable) ) {

         Response.Write(objTable.GetType().ToString());

          Response.End();

        }

        Hashtable table = (Hashtable) objTable;

       return "a.aspx?assembly=" + table["Assembly"] + "&namespace=" + table["Namespace"] + "&class=" + table["GetType"];

        }

    </script>

</head>

<body>

  <form runat="server">

    <table>

      <tr>

        <td width=25% bgcolor=#CCCCFF valign=top >

          <br>

  <asp:DataList EnableViewState="false" runat=server id="Namespace1" RepeatLayOut="flow">

              <HeaderTemplate>Namespaces <br> </HeaderTemplate>

              <ItemTemplate>

             <asp:HyperLink runat="server" text=<%# Container.DataItem %> NavigateUrl=<%# "a.aspx?namespace=" + Container.DataItem %> />

              </ItemTemplate>

              <SelectedItemTemplate>

                <b><asp:HyperLink  runat=server text=<%# Container.DataItem %>/></b>

              </SelectedItemTemplate>

            </asp:DataList>

            <p>

        </td>

        <td valign=top >

         <div id="ClassPanel" style="margin-top:15;margin-left:10" visible="false" runat="server">

<b><font size=4 color="000666"><span style="text-indent:8" id="spnClassName" EnableViewState="false" runat="server"/></font></b>

</div>

<div id="NameSpacePanel" runat="server">

<table class="main" width=100%>

<tr>

<td class="main_header">

<span runat=server id="CHeader" visible="false" style="text-indent:8"> <b><font size=4 color=#000666>Classes in  <%= SelectedNameSpace %>  </b> </font></span>

</td>    </tr>

<tr>

<td align="left">

<asp:DataList EnableViewState="false" runat=server id="Classes" RepeatColumns="3" Gridlines=None borderstyle=none borderwidth=0>

<ItemTemplate>

<asp:HyperLink runat=server text=<%# ((SortTable) Container.DataItem)["GetType"] %> NavigateUrl=<%# GetUrl(Container.DataItem) %> />

</ItemTemplate>

</asp:DataList>

</td>

</tr>

</table>

<table class="main" width=100% >

<tr>

<td class="main_header" >

<span runat=server id="IHeader" visible="false" style="text-indent:8"> <b>

<font size=4 color=#000666>Interfaces in <% =SelectedNameSpace %>  </font> </b> </span>

</td>

</tr>

<tr>

<td align="left">

<asp:DataList EnableViewState="false" runat=server id="Interfaces" RepeatColumns="4" Gridlines=None borderstyle=none borderwidth=0>

<ItemTemplate>

<asp:HyperLink runat=server  text=<%# ((SortTable) Container.DataItem)["GetType"] %> NavigateUrl=<%# GetUrl(Container.DataItem) %>/>

</ItemTemplate>

</asp:DataList>

</td>

</tr>

</table>

</div>

<p>

<asp:DataList EnableViewState="false" id="Methods" runat="server"

Gridlines=None borderstyle="none" borderwidth="0" width="100%">

<HeaderTemplate>

<table cellspacing=0  >

<tr><td class="class_header"><b><font size=2> Methods </font></b></td></tr>

<tr bgcolor="eeeeee">

<td width="75" ><b><u>Visibility</td>

<td width="100"><b><u>Return </td>

<td width="100"><b><u>Name</td>

<td width="600"><b><u>Parameters</td>

</tr>

</HeaderTemplate>

<ItemTemplate>

<tr bgcolor="eeeeee">

<td  width="75"><nobr><span runat=server InnerHtml=<%# ((SortTable)

Container.DataItem)["Access"]%> /></nobr></td>

<td width="100">

<asp:HyperLink runat=server NavigateUrl=<%# GetUrl(Container.DataItem) %> text=<%# ((SortTable) Container.DataItem)["Type"]%>/>

</td>

<td width="100"><span runat=server InnerHtml=<%# ((SortTable)

Container.DataItem)["Name"]%>/></td>

<td  width="900">

<asp:DataList EnableViewState="false" runat=server

datasource=<%# ((SortTable) Container.DataItem)["Params"] %>

RepeatLayout=Flow RepeatDirection="Horizontal" showfooter=true >

<HeaderTemplate>

(

</HeaderTemplate>

<ItemTemplate>

<asp:HyperLink text=<%# ((SortTable) Container.DataItem)["ParamType"].ToString() %> NavigateUrl=<%# GetUrl(Container.DataItem) %> runat=server />

<span InnerHtml=<%# ((SortTable) Container.DataItem)["ParamName"] %>  runat=server />

</ItemTemplate>

<SeparatorTemplate> ,</SeparatorTemplate>

<FooterTemplate> ) </FooterTemplate>

</asp:DataList>

</td>

</tr>

</ItemTemplate>

<FooterTemplate>

</table>

</FooterTemplate>

</asp:DataList>

<p><p>

<asp:DataList EnableViewState="false" id="Interface1" runat=server style="margin-left:10" RepeatDirection="horizontal"

RepeatLayout="Flow"  width="100%">

<HeaderTemplate>

<font size=2><b> Implements </b></font> <br>

</HeaderTemplate>

<ItemTemplate>

<asp:HyperLink runat=server NavigateUrl=<%# GetUrl(Container.DataItem) %> text=<%# ((SortTable) Container.DataItem)["FullName"]%> />

</ItemTemplate>

<SeparatorTemplate>

<font face="Verdana" style="font-size:8pt">,

</SeparatorTemplate>

</asp:DataList>

<p>

<p>

</td>

</tr>

</table>

</td>

</tr>

</table>

</form>

</body>

</html>     

 

b.cs

using System ;

using System.Web;

using System.Web.UI;

using System.Collections;

using System.Reflection;

namespace ClassInfo {

public class SortTable : Hashtable, IComparable {

public String sortField;

public SortTable() : this(null) {

}

public SortTable(String sField) {

sortField = sField;

}

public int CompareTo(Object b) {

if ( sortField == null ) {

return 0;

}

return ((String)this[sortField]).CompareTo((String)((SortTable)b)[sortField]);

}

}

public class DisplayMethods : ArrayList {

public DisplayMethods(Type classType, String myclassname) {

System.Reflection.MethodInfo[] methodInfos = classType.GetMethods() ;

if (methodInfos == null)

                 return;

for (int x=0; x<methodInfos.Length; x++) {

if((String.Compare(myclassname,methodInfos[x].DeclaringType.Name )==0)&&(methodInfos[x].IsPublic || methodInfos[x].IsFamily) && (!(methodInfos[x].IsSpecialName)) ) {

 SortTable MethodDetails = new SortTable("Name");

 MethodDetails["Assembly"] = methodInfos[x].GetType().Assembly.GetName().Name;

 MethodDetails["Name"] = methodInfos[x].Name;

 MethodDetails["Type"] = methodInfos[x].ReturnType.Name;

 if(( methodInfos[x].ReturnType.IsArray && methodInfos[x].ReturnType.Name !="Array") ||  methodInfos[x].ReturnType.IsPointer) {

Type ReturnElementType =  methodInfos[x].ReturnType.GetElementType();

while(ReturnElementType.IsArray) {

ReturnElementType =  ReturnElementType.GetElementType();

}

MethodDetails["GetType"]   = ReturnElementType.Name ;

MethodDetails["Namespace"] = ReturnElementType.Namespace ;

} else {

MethodDetails["GetType"] = methodInfos[x].ReturnType.Name;

MethodDetails["Namespace"] = methodInfos[x].ReturnType.Namespace ;

}

if (methodInfos[x].IsPublic == true) {

         MethodDetails["Access"] = "public ";

} else if (methodInfos[x].IsPrivate == true) {

       MethodDetails["Access"] = "private ";

} else if (methodInfos[x].IsFamily == true) {

         MethodDetails["Access"] = "protected ";

}

if (methodInfos[x].IsStatic == true) {

 MethodDetails["Access"] = ((String) MethodDetails["Access"]) + "static ";

 }

System.Reflection.ParameterInfo[] paramInfos = methodInfos[x].GetParameters();

if (paramInfos != null) {

ArrayList paramTable = new ArrayList();

for (int y=0; y<paramInfos.Length; y++) {

SortTable paramDetails = new SortTable();

paramDetails["Assembly"]  = paramInfos[y].GetType().Assembly.GetName().Name;

paramDetails["ParamName"] = paramInfos[y].Name;

paramDetails["ParamType"] = paramInfos[y].ParameterType.Name;

if(( paramInfos[y].ParameterType.IsArray && paramInfos[y].ParameterType.Name != "Array" )  || paramInfos[y].ParameterType.IsPointer) {

paramDetails["GetType"]   = paramInfos[y].ParameterType.GetElementType().Name ;

paramDetails["Namespace"] = paramInfos[y].ParameterType.GetElementType().Namespace ;

} else {

paramDetails["GetType"]   = paramInfos[y].ParameterType.Name;

paramDetails["Namespace"] = paramInfos[y].ParameterType.Namespace ;

 }

paramTable.Add(paramDetails);

}

 MethodDetails["Params"] = paramTable;

}

this.Add(MethodDetails);

}

}

this.Sort();

}

}

}

 

To run the above program, you need to first place the file b.cs in the sub-directory c:\inetpub\wwwroot\bin and compile it as follows:

 

>csc /target:library b.cs

When a.aspx is loaded in the browser, the list of namespaces is displayed on the left, and the list of classes belonging to the System namespace is seen on the right. If you click on any class, a list of functions belonging to that class will be displayed. The data is displayed in a tabular format in four columns.

 

     The first column represents the visibility. The values contained in it, are either public, or private or protected.

     The second column indicates the return data type.

     The third column displays the names of the functions.

     The fourth column holds the parameters with their names and data types.

 

All types are hyper linked, so when we click on any one of them, a screen comes forth, displaying the functions or methods that the specified type supports.

 

When we click on the name of a class, the following URL gets generated:

 

http://localhost/a.aspx?assembly=mscorlib&namespace=System&class=Exception

 

The Page_Load function calls the DisplayClass function, since the class and the assembly parameter contains a value. This proves that the DisplayClassList function is called only in the first round, while loading the page.

 

In the DisplayClass function, we first need the type of the object. The static function called GetType, belonging to the Type class, returns a type when it is supplied with the full name of the class. So, we concatenate the namespace name stored in the instance variable SelectedNameSpace, with the parameter className, and then pass the full name to this function. The Type returned by the GetType function is stored in a variable called ClassType.

 

Next, we create an object called MethodDetails of type DisplayMethods, which requires two parameters, the Type and the className. DisplayMethods is, in turn, derived from the class ArrayList. The ArrayList object named MethodDetails, obviously contains the details about the methods. Using the Count member, we can determine the total number of methods in the class. If the value returned is greater than 0, we initialize the DataSource member called Methods, of the DataList, to this ArrayList. The span control called spnClassName, then displays the name of the namespace and that of the class.

 

We have two div tags having the ids ClassPanel and NameSpacePanel. Their visible property is set to either true or false, thereby, ensuring that all the div contents are either displayed or hidden from view. In the DisplayClass, we have hidden the data contained within these tags by setting the Visible property to false. Thus, in one stroke, we can conceal or reveal a large number of entities. These tags are extremely useful because our browser's real estate is restricted, and we do not have the space to display everything.

 

Let us now scrutinize the presentation logic. As we mentioned earlier, the DataList called Methods displays all the method names neatly formatted. You may have been ambushed by the revelation that a simple DataList was able to display everything. The template named headertemplate is called once, to display the four column headers of the table. The table tag does not end with the template, as each method is now displayed as a table row. The bold and underline tags have been provided to produce visually stunning output.

 

The DisplayMethods class uses the indexer method to retrieve the values of the Visible and Type members. Thus, in the span tag, we use the array syntax to display the Access and Type members. The function GetUrl navigates to the relevant type by creating a URL, followed by the parameters called assembly, namespace and class, filled up with relevant values. From the browser's point of view, it does not make any difference whether we click on the class name in the first screen or in the second one.

 

Life is not very straightforward now, since we have made an endeavor to display the parameters of the method, which could number from nil to infinity. In order to achieve this, we create another DataList within the Methods DataList and initialize the DataSource parameter to the Params value in the DisplayMethods object. To display the parameters, a template with a hyper link is utilized. It shows the data type or ParamType as a hyperlink. The URL to this link is generated by the GetUrl function. The ParamName is displayed as normal text.

 

The whole code is enclosed in open and close brackets, and is available in the headertemplate and footertemplate. The template named separatortemplate supplies the commas to separate the individual parameter names and values. To summarize, we are using a nested DataList to display an array of values within another array.

 

We have a confession to make at this juncture. The class named DisplayMethods has not been supplied by Microsoft. It is created in the file b.cs. This class is derived from ArrayList and gives us all the details of every method that exists in a type.

 

Let us now focus on the class DisplayMethods in the file b.cs.

This is a perfect example of a two-tier illustration, where the presentation logic is placed in one file, and the C# code that handles Reflection, is placed in another file.

 

The class DisplayMethods has to extend the ArrayList class, because in the aspx file, we are initializing the DataSource member of the Methods DataList to this data type. Also, the constructor  in the DisplayClass function has been supplied with two parameters, namely, the Type and className.

 

DisplayMethods MethodDetails= new DisplayMethods(ClassType, className);

 

There exists a static method called GetMethods in the Type class, that returns a MethodInfo array. The methodInfos array reveals every aspect of the function. No parameter is supplied indicating that the default rules are to be applied when locating a function. In case there are no methods available in a class, a null value is stored in the array variable.

 

The Length member of the array stores a count of the number of methods contained in the array. Thereafter, using a for loop we iterate through each and every method. A 'foreach' loop could also be used to achieve the same functionality. In the loop, we use a Compare function of the String class, to verify the validity of the method. The property DeclaringType returns a Type or the class that consists of this method. Type in turn, has a property called Name, that represents the name of the class. Compare takes this name and checks it with the parameter myclassname, which is a parameter passed to the constructor. It is just an additional check.

 

We also ensure that the method is public or it belongs to the family (current of derived class) that can access it. The compiler treats functions that possess special names, differently. For example, the constructor is given a special name, i.e. .ctor. These methods are not to be included in our list of methods, and hence, the ! sign is used. The method must successfully pass all the above conditions, or else, it will not be incorporated as a part of the methods list that is returned.

 

On passing the above test, the next task is to gain access to the template in the aspx file. To accomplish this, an indexer or an array is employed. It returns an object that is an instance of a Hashtable. For the ones who walked in late, the Hashtable class lets us access data in an efficient manner, and also offers us an indexer support.

 

MethodDetails is an instance of the SortTable class, which consecutively extends the class Hashtable. The single parameter constructor of the SortTable is called using the Name parameter. The constructor stores the value contained in the Name variable, in a public variable called sortField. Thereafter, using the indexer features of the Hashtable class, the following is achieved:

 

     The name of the assembly is stored in an indexer variable called Assembly.

     The name of the method is stored in an indexer variable called Name.

     The name of the return type is stored in the indexer variable called Type.

 

The name of the return type or class is obtained as follows:

The MethodInfo class has a property called ReturnType that returns the Type of the return value. The Type in turn, has a member called Name that holds the name of the Type.

 

There are instances where a multi-dimension array or a pointer is returned. These being exceptional cases, separate 'if 'statements are required to handle them. First, using the property IsArray, the name property in ReturnType is checked. If the name contains the word 'Array' or the ReturnType is a pointer, we can safely conclude that the function returns a Multi-Dimensional array. So, we use the function GetElementType in ReturnType, to return the Type of the object encompassed, or referenced by either an array, or a pointer, or by ByRef.

 

The predicament with arrays is that their dimensions could range from 2 to infinity, which could put us in a tight spot. To tide over this situation, we use a loop construct like a while or a for loop. Thus, using IsArray, we keep looping, until the Type becomes an array. All arrays, multi-dimensional or otherwise, have a Type name. Ignoring the fact that it is an array, we initialize the indexer variable GetType to this Type name, and initialize the namespace variable to the namespace of this type. This course of action is essential if we aspire to display the final data type of the array.

 

Under normal circumstances, the return type is generally a Type object. In such cases, we can use the same Name and Namespace properties to retrieve its value and store it in the MethodDetail Indexer.

 

The next task in sequence is to store the access modifiers, which our function has been tagged with. We intend to determine whether the method is public, private or protected. To achieve this, we use the three properties named, IsPublic, IsPrivate and IsFamily. Accordingly, the relevant access modifier is stored in the indexer variable called Access. The function is also checked to establish if it is static. To accomplish this, the property IsStatic is used. If it returns a value of true, the string static is added to the Access indexer variable.

 

Now, we have arrived at a relatively uncomplicated part.

The names and the data types of the parameters have to be retrieved. The number of parameters to a function can range from zero to infinity. We initialize an object called paramInfos by calling the GetParameters function, which returns a ParameterInfo array. A separate ArrayList is now required to store this variable set of data. So, we create a separate ArrayList object called paramTable, which stores certain information about the parameters, such as the name and type.

 

Depending upon the length of the array, the loop is repeated a specific number of times, wherein, the Name property of a ParameterInfo object, is assigned to an indexer variable called ParamName. The ParameterInfo class also contains a property called ParameterType, whose Type member holds the name of the Type. Thereafter, as before, we check if the return type is a Multi-dimensional array. If so, the final type of the Multi-Dimensional array is figured out. Eventually, the GetType and Namespace are initialized from the normal types of the multi-dimensional arrays, to the return type of the function and the namespace of the type, respectively. Thereafter, this single record of paramDetails is added to the paramTable ArrayList. This loop is repeated for every method in the class. Once the loop terminates, the indexer variable Params in MethodDetails, is initialized to the paramTable object.

 

Finally, the MethodDetails is added to the ArrayList and the ArrayList is sorted. Sortng of the list is not obligatory.

 

To recapitulate, the MethodDetails class consists of multiple records that can be accessed through an indexer, using parameter names like GetType and Namespace. The Params parameter in the MethodDetail indexer is made up of another ArrayList, and has members like ParamName and ParamType.

 

The interface IComparable attains significance because it contains the CompareTo function from the string class.

 

Now, for the grand finale! We shall delve upon the class browser application from the Microsoft Samples.

 

 

web.config

<configuration>

<configSections>

<sectionGroup name="system.web">

<section name="ClassBrowser" type="System.Configuration.NameValueSectionHandler,System"/>

</sectionGroup>

</configSections>

<system.web>

<ClassBrowser>

<add key="WinForms Library" value="System.Windows.Forms" />

<add key="Drawing Library" value="System.Drawing" />

<add key="Data Library" value="System.Data" />

<add key="Xml Library" value="System.Xml" />

<add key="Messaging Library" value="System.Messaging" />

<add key="Directory Services Library" value="System.DirectoryServices" />

<add key="ASP.NET Class Library" value="System.Web" />

<add key=".NET Framework class Library" value="mscorlib" />

</ClassBrowser>

</system.web>

</configuration>

 

a.aspx

<%@ Page Language="C#" Debug="True" %>

<%@ Import NameSpace="ClassInfo" %>

<%@ Import NameSpace="System.Collections"  %>

<%@ Import NameSpace="System.Collections.Specialized" %>

<%@ Import NameSpace="System.Reflection" %>

<html><head>

<script runat="server" language="C#">

  public String SelectedAssembly;

  public String SelectedNameSpace;

   public ArrayList ModuleName = new ArrayList();

   protected void Page_Load(Object Sender, EventArgs e) {

 NameValueCollection ConfigSettings = (NameValueCollection)Context.GetConfig("system.web/ClassBrowser");

for (int i = 0; i < ConfigSettings.Count; i++) {

      ModuleName.Add(ConfigSettings[i].ToString());

}

DisplayNamespaces();

if (Request.QueryString["namespace"] == null)

SelectedNameSpace = "System";

else

SelectedNameSpace = Request.QueryString["namespace"];

 

if (Request.QueryString["assembly"] == null )

      SelectedAssembly = "mscorlib";

 else

      SelectedAssembly = Request.QueryString["assembly"];

if (Request.QueryString["class"] != null && Request.QueryString["assembly"] != null)

       DisplayClass(Request.QueryString["assembly"], Request.QueryString["class"]);

else

      DisplayClassList(SelectedNameSpace);

}

private void DisplayNamespaces() {

      ArrayList NameSpaceList   = new ArrayList();

      Hashtable NameSpaceHash = new Hashtable();

      for (int y = 0; y < ModuleName.Count; y++) {

      Module[]  CorRuntime = Assembly.Load(ModuleName[y].ToString()).GetModules();

                Type[]    CorClasses = CorRuntime[0].GetTypes();

      for( int x=0; x < CorClasses.Length; x++ ) {

       if ( CorClasses[x].Namespace != null ) {

       if (!NameSpaceHash.ContainsKey(CorClasses[x].Namespace) && CorClasses[x].IsPublic ) {

      NameSpaceHash.Add(CorClasses[x].Namespace,"");

      NameSpaceList.Add(CorClasses[x].Namespace);

      }

      }

      }

      }

      NameSpaceList.Sort();

      Namespace1.DataSource = NameSpaceList;

      Namespace1.DataBind();

  }

   private void DisplayClassList(String CurrentNameSpace) {

      ArrayList ClassList     = new ArrayList();

      ArrayList InterfaceList = new ArrayList();

     for( int y=0; y < ModuleName.Count; y++ ) {

      Module[]  CorRuntime = Assembly.Load(ModuleName[y].ToString()).GetModules();

      Type[]    CorClasses = CorRuntime[0].GetTypes();

      for (int x=0; x < CorClasses.Length; x++ ) {

         if ( CorClasses[x].Namespace == CurrentNameSpace && CorClasses[x].IsPublic) {

                        SortTable props = new SortTable("GetType");

                        props["GetType"] = CorClasses[x].Name;

                        props["Namespace"] = CorClasses[x].Namespace;

                        props["Assembly"] = CorClasses[x].Assembly.GetName().Name;

 

                        if ( CorClasses[x].IsInterface )

                            InterfaceList.Add(props);

                        else

                            ClassList.Add(props);

                    }

                }

            }

 

            if (InterfaceList.Count > 0)

                IHeader.Visible = true;

 

            if (ClassList.Count > 0)

               CHeader.Visible = true;

 

            ClassList.Sort();

            Classes.DataSource = ClassList;

            Classes.DataBind();

 

            InterfaceList.Sort();

            Interfaces.DataSource = InterfaceList;

            Interfaces.DataBind();

        }

 

        private void DisplayClass(String asmName, String className) {

 

            Assembly a = Assembly.Load(asmName);

            Type ClassType = a.GetType(SelectedNameSpace.ToString() + "." + className, false, true);

            if ( ClassType == null ) {

                DisplayClassList(SelectedNameSpace);

                return;

            }

            ArrayList SubClassDetails = new DisplaySubClasses(ClassType, ModuleName);

DisplayConstructors  ConstructorDetails =  new DisplayConstructors(ClassType);

DisplayFields        FieldDetails       =  new DisplayFields(ClassType);

DisplayProperties    PropertyDetails    =  new DisplayProperties(ClassType);

DisplayMethods       MethodDetails      =  new DisplayMethods(ClassType, className);

DisplaySuperclasses  SuperClassDetails  =  new DisplaySuperclasses(ClassType);

DisplayInterfaces    InterfaceDetails   =  new DisplayInterfaces(ClassType);

DisplayEvents        EventDetails       =  new DisplayEvents(ClassType);

if(ConstructorDetails.Count != 0 )

      Constructors.DataSource = ConstructorDetails;

if(SubClassDetails.Count != 0 )

     SubClasses.DataSource = SubClassDetails;

if(FieldDetails.Count != 0 )

      Fields.DataSource = FieldDetails;

if(PropertyDetails.Count != 0 )

      Properties.DataSource = PropertyDetails;

if(MethodDetails.Count != 0 )

      Methods.DataSource = MethodDetails;

if(InterfaceDetails.Count != 0 )

      Interface1.DataSource = InterfaceDetails;

if(SuperClassDetails.Count != 0 )

      SuperClasses.DataSource = SuperClassDetails;

if(EventDetails.Count != 0 )

      Events.DataSource = EventDetails;

DataBind();

if (ClassType.IsInterface)

  spnClassName.InnerHtml = "Interface " + SelectedNameSpace + "." + className;

else

 spnClassName.InnerHtml = "Class " + SelectedNameSpace + "." + className;

NameSpacePanel.Visible=false;

ClassPanel.Visible=true;

}

 

public String GetUrl(Object objTable) {

 if ( objTable is String ) {

   return "a.aspx?assembly=" + SelectedAssembly + "&namespace=" + SelectedNameSpace + "&class=" + objTable;

 }

 if ( ! (objTable is Hashtable) ) {

        Response.Write(objTable.GetType().ToString());

         Response.End();

 }

 Hashtable table = (Hashtable) objTable;

 return "a.aspx?assembly=" + table["Assembly"] + "&namespace=" + table["Namespace"] + "&class=" + table["GetType"];

        }

</script>

</head>

<body>

  <form runat="server">

  <table width=100% height=700 cellpadding=0 cellspacing=0>

   <tr>

   <td width=25% bgcolor=#CCCCFF valign=top > <br>

  <asp:DataList EnableViewState="false" runat=server id="Namespace1" RepeatLayOut="flow" ItemStyle-Font-Size="9pt" HeaderStyle-Font-Size="12pt" >

<HeaderTemplate>

<div left-margin="10">  Namespaces <br>

</HeaderTemplate>

<ItemTemplate>

<asp:HyperLink runat="server" text=<%# Container.DataItem %> NavigateUrl=<%# "a.aspx?namespace=" + Container.DataItem %> />

</ItemTemplate>

<SelectedItemTemplate>

<b><asp:HyperLink  runat=server text=<%# Container.DataItem %>/></b>

</SelectedItemTemplate>

</asp:DataList>

<p>

</td>

<td valign=top >

 <div id="ClassPanel" style="margin-top:15;margin-left:10" visible="false" runat="server">

  <b><font size=4 color="000666"><span style="text-indent:8" id="spnClassName" EnableViewState="false" runat="server"/></font></b>

         </div>

         <div id="NameSpacePanel" runat="server">

          <table class="main" width=100%>

            <tr> <td class="main_header">

                <span runat=server id="CHeader" visible="false" style="text-indent:8"> <b><font size=4 color=#000666>Classes in

                  <%= SelectedNameSpace %>  </b> </font></span>

              </td> </tr>

            <tr>

              <td align="left">

<asp:DataList EnableViewState="false" runat=server id="Classes" RepeatColumns="3" Gridlines=None borderstyle=none borderwidth=0 >

<ItemTemplate>

<asp:HyperLink runat=server text=<%# ((SortTable) Container.DataItem)["GetType"] %> NavigateUrl=<%# GetUrl(Container.DataItem) %> />

</ItemTemplate>

</asp:DataList>

</td>

</tr>

</table>

<table class="main" width=100% >

<tr>

<td class="main_header" >

<span runat=server id="IHeader" visible="false" style="text-indent:8"> <b><font size=4 color=#000666>Interfaces in

 <%= SelectedNameSpace %>  </font> </b> </span>

</td>

</tr>

<tr>

<td align="left">

<asp:DataList EnableViewState="false" runat=server id="Interfaces" RepeatColumns="4"

Gridlines=None borderstyle=none borderwidth=0 >

<ItemTemplate>

<asp:HyperLink runat=server  text=<%# ((SortTable) Container.DataItem)["GetType"] %> NavigateUrl=<%# GetUrl(Container.DataItem) %>/>

</ItemTemplate>

                </asp:DataList>

              </td>

            </tr>

          </table>

 

          </div>

 

          <table class="main" width=100% cellpadding=0 cellspacing=0 >

            <tr>

              <td class="main_header" valign="top" >

                <asp:DataList EnableViewState="false" id="Constructors" runat="server" Gridlines=None borderstyle="none" borderwidth=0  width="100%">

                  <HeaderTemplate>

                    <table cellspacing=0 width="100%">

                      <tr><td class="class_header"><b><font size=2> Constructors </font></b></td></tr>

                      <tr bgcolor="eeeeee">

                        <td width="75" > <b><u> Visibility     </u> </td>

                        <td width="100"> <b><u> Constructor    </u> </td>

                        <td> <b><u> Parameters     </u> </td>

                      </tr>

                  </HeaderTemplate>

 

                  <ItemTemplate>

                    <tr bgcolor="eeeeee">

                      <td width="75">

                        <span runat=server InnerHtml=<%# ((SortTable) Container.DataItem)["Access"] %> />

                      </td>

                      <td width="100">

                        <span runat=server InnerHtml =<%# ((SortTable) Container.DataItem)["Name"] %> />

                      </td>

                      <td width="1000">

                        <asp:DataList

                            EnableViewState="false"

                            runat=server

                            RepeatDirection="Horizontal"

                            RepeatLayout=Flow

showfooter=true datasource=<%# ((SortTable) Container.DataItem)["Params"]%> >

<HeaderTemplate> ( </HeaderTemplate>

<ItemTemplate>

<asp:HyperLink text=<%# ((SortTable) Container.DataItem)["ParamType"] %> NavigateUrl=<%# GetUrl(Container.DataItem) %> runat=server />

<span innerhtml=<%# ((SortTable) Container.DataItem)["ParamName"] %> runat=server />

</ItemTemplate>

 <SeparatorTemplate>, </SeparatorTemplate>

  <FooterTemplate> ) </FooterTemplate>

  </asp:DataList>

 </td>

 </tr>

</ItemTemplate>

 <FooterTemplate>

  </table>

</FooterTemplate>

</asp:DataList>

 <p>

 <asp:DataList EnableViewState="false" id="Fields" runat="server" Gridlines=None BorderStyle="none"  width="100%" BorderWidth=0>

<HeaderTemplate>

<table cellspacing=0  width="100%">

<tr><td class="class_header"><b><font size=2> Fields </font></b></td></tr>

<tr bgcolor="eeeeee">

<td width="120" ><b><u> Visibility </td>

<td width="100"><b><u> Type       </td>

<td ><b><u> Name       </td>

</tr>

</HeaderTemplate>

<ItemTemplate>

<tr bgcolor="eeeeee">

<td width="120">

<nobr><span InnerHTML=<%# ((SortTable) Container.DataItem)["Access"]%> runat=server /></nobr>

</td>

<td width="100">

<asp:HyperLink text=<%# ((SortTable) Container.DataItem)["Type"] %> NavigateUrl=<%# GetUrl(Container.DataItem) %> runat=server/>

</td> <td>

<span InnerHTML=<%# ((SortTable) Container.DataItem)["Name"] %> runat=server />

</td>

</tr>

</ItemTemplate>

<FooterTemplate>

</table>

</FooterTemplate>

</asp:DataList>

<p>

<asp:DataList EnableViewState="false" id="Events" runat="server" Gridlines=None BorderStyle="none"  width="100%" BorderWidth=0>

<HeaderTemplate>

<table cellspacing=0  width="100%">

<tr><td class="class_header"><b><font size=2> Events </font></b></td></tr>

<tr bgcolor="eeeeee">

<td width="120" ><b><u> Multicast </td>

<td width="100"><b><u> Type       </td>

<td ><b><u> Name       </td>

</tr>

</HeaderTemplate>

<ItemTemplate>

<tr bgcolor="eeeeee">

<td width="120">

<nobr><span InnerHTML=<%# ((SortTable) Container.DataItem)["Access"]%> runat=server /></nobr>

</td>

<td width="100">

<asp:HyperLink text=<%# ((SortTable) Container.DataItem)["Type"] %> NavigateUrl=<%# GetUrl(Container.DataItem) %> runat=server/>

</td>

<td>

<span InnerHTML=<%# ((SortTable) Container.DataItem)["Name"] %> runat=server />

</td>

</tr>

      </ItemTemplate>

      <FooterTemplate>

      </table>

      </FooterTemplate>

      </asp:DataList>

      <p>

      <asp:DataList EnableViewState="false" id="Properties" runat="server" Gridlines=None BorderStyle="none" BorderWidth=0 width="100%">

      <HeaderTemplate>

      <table cellspacing=0 width="100%" >

      <tr><td class="class_header"><b><font size=2> Properties </font></b></td></tr>

     <tr bgcolor="eeeeee">

      <td width="75"><b><u>Visibility</td>

      <td width="100"><b><u>Type</td>

      <td width="150"><b><u>Name</td>

      <td><b><u>Accessibility</td>

      </tr>

      </HeaderTemplate>

      <ItemTemplate>

      <tr bgcolor="eeeeee">

      <td width="75"><span InnerHTML=<%# ((SortTable) Container.DataItem)["Visibility"] %> runat=server /> </td>

      <td width="100">

      <asp:HyperLink runat=server runat="server" text=<%# ((SortTable) Container.DataItem)["Type"] %> NavigateUrl=<%# GetUrl(Container.DataItem) %>/> </td>

      <td width="150"><span InnerHTML=<%# ((SortTable) Container.DataItem)["Name"]%> runat=server/>

     <asp:DataList EnableViewState="false" runat=server RepeatLayout="Flow" ShowFooter=true                       RepeatDirection="Horizontal"  datasource=<%# ((SortTable) Container.DataItem)["Params"] %>>

<ItemTemplate>

( <asp:HyperLink runat=server text=<%# ((SortTable) Container.DataItem)["ParamType"]%> NavigateUrl=<%# GetUrl(Container.DataItem) %>  />

<span InnerHtml=<%# ((SortTable) Container.DataItem)["ParamName"] %> runat=server /> )

</ItemTemplate>

</asp:DataList>

</td><td><span InnerHTML=<%# ((SortTable) Container.DataItem)["Access"]%> runat=server/></td>

  </tr>

</ItemTemplate>

<FooterTemplate>

</table>

</FooterTemplate>

</asp:DataList>

<p>

<asp:DataList EnableViewState="false" id="Methods" runat="server" Gridlines=None borderstyle="none" borderwidth="0" width="100%">

<HeaderTemplate>

<table cellspacing=0  >

<tr><td class="class_header"><b><font size=2> Methods </font></b></td></tr>

<tr bgcolor="eeeeee">

<td width="75" ><b><u>Visibility</td>

<td width="100"><b><u>Return </td>

<td width="100"><b><u>Name</td>

<td width="600"><b><u>Parameters</td>

</tr>

</HeaderTemplate>

<ItemTemplate>

<tr bgcolor="eeeeee">

<td  width="75"><nobr><span runat=server InnerHtml=<%# ((SortTable) Container.DataItem)["Access"]%> /></nobr></td>

<td width="100">

 <asp:HyperLink runat=server NavigateUrl=<%# GetUrl(Container.DataItem) %> text=<%# ((SortTable) Container.DataItem)["Type"]%>/>

</td>

<td width="100"><span runat=server InnerHtml=<%# ((SortTable) Container.DataItem)["Name"]%>/></td>

<td  width="900">

<asp:DataList EnableViewState="false" runat=server

datasource=<%# ((SortTable) Container.DataItem)["Params"] %>

RepeatLayout=Flow RepeatDirection="Horizontal" showfooter=true >

<HeaderTemplate>

(

</HeaderTemplate>

<ItemTemplate>

<asp:HyperLink text=<%# ((SortTable) Container.DataItem)["ParamType"].ToString() %> NavigateUrl=<%# GetUrl(Container.DataItem) %> runat=server />

<span InnerHtml=<%# ((SortTable) Container.DataItem)["ParamName"] %>  runat=server />

</ItemTemplate>

<SeparatorTemplate> ,</SeparatorTemplate>

<FooterTemplate>

)

</FooterTemplate>

</asp:DataList>

</td>

</tr>

</ItemTemplate>

<FooterTemplate>

  </table>

</FooterTemplate>

</asp:DataList>

<p>

<asp:DataList EnableViewState="false" id="SuperClasses" style="margin-left:10" runat="server" RepeatLayout="Flow"

RepeatDirection="horizontal"  width="100%">

<HeaderTemplate>

  <font size=2><b> Hierarchy </b></font> <br>

</HeaderTemplate>

<ItemTemplate>

<asp:HyperLink runat=server NavigateUrl=<%# GetUrl(Container.DataItem) %> text=<%# ((SortTable) Container.DataItem)["FullName"]%> />

</ItemTemplate>

<SeparatorTemplate>

<font face="Verdana" style="font-size:8pt"><nobr>---></nobr>

</SeparatorTemplate>

</asp:DataList>

<p>

<asp:DataList EnableViewState="false" id="Interface1" runat=server style="margin-left:10" RepeatDirection="horizontal"

RepeatLayout="Flow"  width="100%">

<HeaderTemplate>

   <font size=2><b> Implements </b></font> <br>

</HeaderTemplate>

<ItemTemplate>

<asp:HyperLink runat=server NavigateUrl=<%# GetUrl(Container.DataItem) %> text=<%# ((SortTable) Container.DataItem)["FullName"]%> />

</ItemTemplate>

<SeparatorTemplate>

<font face="Verdana" style="font-size:8pt">,

</SeparatorTemplate>

</asp:DataList>

<p>

<asp:DataList EnableViewState="false" id="SubClasses" style="margin-left:10" runat=server

RepeatLayout="Flow" RepeatDirection="horizontal"  width="100%">

<HeaderTemplate>

<font size=2> <b>Subclassed By </b></font>  <br>

 </HeaderTemplate>

<ItemTemplate>

<asp:HyperLink runat=server NavigateUrl=<%# GetUrl(Container.DataItem) %> text=<%# ((SortTable) Container.DataItem)["FullName"]%> />

</ItemTemplate>

<SeparatorTemplate>

   <font face="Verdana" style="font-size:8pt">,

</SeparatorTemplate>

</asp:DataList>

<p>

</td>

</tr>

</table>

</td>

</tr>

</table>

</form>

</body>

</html>     

 

b.cs

using System ;

using System.Web;

using System.Web.UI;

using System.Collections;

using System.Reflection;

namespace ClassInfo {

public class SortTable : Hashtable, IComparable {

        public String sortField;

        public SortTable() : this(null) {

        }

        public SortTable(String sField) {

           sortField = sField;

        }

        public int CompareTo(Object b) {

            if ( sortField == null ) {

                return 0;

            }

            return ((String)this[sortField]).CompareTo((String)((SortTable)b)[sortField]);

        }

    }

public class DisplayEvents : ArrayList {

public  DisplayEvents(Type classType) {

System.Reflection.EventInfo[] eventInfos = classType.GetEvents();

    if (eventInfos == null)

            return;

    ArrayList eventTable = new ArrayList();

   for (int x=0; x<eventInfos.Length; x++) {

            SortTable eventDetails = new SortTable("Name");

eventDetails["Assembly"]    = eventInfos[x].EventHandlerType.Assembly.GetName().Name;

eventDetails["Name"]        = eventInfos[x].Name;

eventDetails["Type"]        = eventInfos[x].EventHandlerType.Name;

eventDetails["GetType"]     = eventInfos[x].EventHandlerType.Name;

eventDetails["Namespace"]   = eventInfos[x].EventHandlerType.Namespace;

if (eventInfos[x].IsMulticast == true) {

                eventDetails["Access"] = "multicast ";

            }

this.Add(eventDetails);

}

this.Sort();

}

}

public class DisplayFields : ArrayList

{

    public  DisplayFields(Type classType)

    {

   System.Reflection.FieldInfo[] fieldInfos = classType.GetFields();

   if (fieldInfos == null)

            return;

   ArrayList fieldTable = new ArrayList();

   for (int x=0; x<fieldInfos.Length; x++) {

            SortTable fieldDetails = new SortTable("Name");

            fieldDetails["Assembly"] = fieldInfos[x].GetType().Assembly.GetName().Name;

            fieldDetails["Name"] = fieldInfos[x].Name;

            fieldDetails["Type"] = fieldInfos[x].FieldType.Name;

            if(( fieldInfos[x].FieldType.IsArray && fieldInfos[x].FieldType.Name != "Array") ||  fieldInfos[x].FieldType.IsPointer)  {

                fieldDetails["GetType"]   = fieldInfos[x].FieldType.GetElementType().Name;

                fieldDetails["Namespace"] = fieldInfos[x].FieldType.GetElementType().Namespace;

            }

            else {

                fieldDetails["GetType"]   = fieldInfos[x].FieldType.Name;

                fieldDetails["Namespace"] = fieldInfos[x].FieldType.Namespace;

            }

            if (fieldInfos[x].IsPublic == true){

                fieldDetails["Access"] = "public ";

            }

            else if (fieldInfos[x].IsPrivate == true){

                fieldDetails["Access"] = "private ";

            }

            else if (fieldInfos[x].IsFamily == true){

                fieldDetails["Access"] = "protected ";

            }

            if (fieldInfos[x].IsStatic == true){

                fieldDetails["Access"] = ((String) fieldDetails["Access"]) + "static ";

            }

            if (fieldInfos[x].IsLiteral == true){

                fieldDetails["Access"] = ((String) fieldDetails["Access"]) + "const ";

            }

            this.Add(fieldDetails);

       }

         this.Sort();

    }

}

public class DisplayConstructors : ArrayList {

    public DisplayConstructors(Type classType) {

        System.Reflection.ConstructorInfo[] constructorInfos = classType.GetConstructors();

        if (constructorInfos == null)

            return;

        for (int x=0; x<constructorInfos.Length; x++) {

            SortTable constructorDetails = new SortTable();

            constructorDetails["Assembly"] = constructorInfos[x].GetType().Assembly.GetName().Name;

            constructorDetails["Name"] = classType.Name;

            if (constructorInfos[x].IsPublic == true) {

                constructorDetails["Access"] = "public ";

            }

            else if (constructorInfos[x].IsPrivate == true) {

                constructorDetails["Access"] = "private ";

            }

            else if (constructorInfos[x].IsFamily == true)  {

                constructorDetails["Access"] = "protected ";

            }

            System.Reflection.ParameterInfo[] paramInfos = constructorInfos[x].GetParameters();

      if (paramInfos != null) {

           ArrayList paramTable = new ArrayList();

      for (int y=0; y<paramInfos.Length; y++) {

                    SortTable paramDetails = new SortTable();

                    paramDetails["Assembly"]  = paramInfos[y].GetType().Assembly.GetName().Name;

                    paramDetails["ParamName"] = paramInfos[y].Name;

                    paramDetails["ParamType"] = paramInfos[y].ParameterType.Name;

                    if ( ( paramInfos[y].ParameterType.IsArray && paramInfos[y].ParameterType.Name !="Array" ) || paramInfos[y].ParameterType.IsPointer ) {

                        paramDetails["GetType"]   = paramInfos[y].ParameterType.GetElementType().Name ;

                        paramDetails["Namespace"] = paramInfos[y].ParameterType.GetElementType().Namespace ;

                    }

                   else {

                  paramDetails["GetType"]   = paramInfos[y].ParameterType.Name;

                        paramDetails["Namespace"] = paramInfos[y].ParameterType.Namespace ;

                    }

                    paramTable.Add(paramDetails);

                }

                constructorDetails["Params"] = paramTable;

            }

            this.Add(constructorDetails);

        }

    }

}

public class DisplayProperties : ArrayList {

    public  DisplayProperties(Type classType) {

        System.Reflection.PropertyInfo[] propertyInfos = classType.GetProperties();

        if (propertyInfos == null)

            return;

        ArrayList propertyTable = new ArrayList();

        for (int x=0; x<propertyInfos.Length; x++) {

            SortTable propertyDetails = new SortTable("Name");

            if(propertyInfos[x].GetGetMethod() != null)  {

                if(( propertyInfos[x].GetGetMethod().ReturnType.IsArray && propertyInfos[x].GetGetMethod().ReturnType.Name !="Array" ) || propertyInfos[x].GetGetMethod().ReturnType.IsPointer ) {

                    propertyDetails["GetType"]   = propertyInfos[x].GetGetMethod().ReturnType.GetElementType().Name;

                    propertyDetails["Namespace"] = propertyInfos[x].GetGetMethod().ReturnType.GetElementType().Namespace;

 

                } else {

                    propertyDetails["GetType"]   = propertyInfos[x].GetGetMethod().ReturnType.Name;

                    propertyDetails["Namespace"] = propertyInfos[x].GetGetMethod().ReturnType.Namespace;

                }

                propertyDetails["Type"]      = propertyInfos[x].GetGetMethod().ReturnType.Name;

                propertyDetails["Assembly"]  = propertyInfos[x].GetGetMethod().ReturnType.Assembly.GetName().Name;

                propertyDetails["Name"]      = propertyInfos[x].Name;

 

    if (propertyInfos[x].GetGetMethod().IsPublic == true) {

                     propertyDetails["Visibility"] = "public";

    } else if (propertyInfos[x].GetGetMethod().IsPrivate == true) {

                     propertyDetails["Visibility"] = "private";

    } else if (propertyInfos[x].GetGetMethod().IsFamily == true) {

                    propertyDetails["Visibility"] = "protected";

    }

   if (propertyInfos[x].GetGetMethod().IsStatic == true) {

                    propertyDetails["Visibility"] = ((String)  propertyDetails["Visibility"]) + " static";

                }

   if (propertyInfos[x].GetSetMethod() == null) {

             propertyDetails["Access"] =  "[Get]" ;

                } else {

                propertyDetails["Access"] = "[Get , Set]" ;

    }

   System.Reflection.ParameterInfo[] paramInfos = propertyInfos[x].GetGetMethod().GetParameters();

      if (paramInfos != null) {

            ArrayList paramTable = new ArrayList();

      for (int y=0; y<paramInfos.Length; y++) {

            SortTable paramDetails = new SortTable();

            paramDetails["Assembly"] = paramInfos[y].GetType().Assembly.GetName().Name;

                        paramDetails["ParamName"] = paramInfos[y].Name;

                        paramDetails["ParamType"] = paramInfos[y].ParameterType.Name;

     if (( paramInfos[y].ParameterType.IsArray && paramInfos[y].ParameterType.Name !="Array") ||paramInfos[y].ParameterType.IsPointer ) {

        paramDetails["GetType"]   = paramInfos[y].ParameterType.GetElementType().Name ;

        paramDetails["Namespace"] = paramInfos[y].ParameterType.GetElementType().Namespace ;

} else {

         paramDetails["GetType"]   = paramInfos[y].ParameterType.Name;

          paramDetails["Namespace"] = paramInfos[y].ParameterType.Namespace ;

       }

paramTable.Add(paramDetails);

}

 propertyDetails["Params"] = paramTable;

}

} else if(propertyInfos[x].GetSetMethod() != null) {

propertyDetails["GetType"]   = propertyInfos[x].GetSetMethod().ReturnType.Name;

                propertyDetails["Namespace"] = propertyInfos[x].GetSetMethod().ReturnType.Namespace;

                propertyDetails["Type"]      = propertyInfos[x].GetSetMethod().ReturnType.Name;

                propertyDetails["Assembly"]  = propertyInfos[x].GetGetMethod().ReturnType.Assembly.GetName().Name;

                propertyDetails["Name"]      = propertyInfos[x].Name;

if (propertyInfos[x].GetSetMethod().IsPublic == true) {

                     propertyDetails["Visibility"] = "public";

                } else if (propertyInfos[x].GetSetMethod().IsPrivate == true) {

                     propertyDetails["Visibility"] = "private";

                } else if (propertyInfos[x].GetSetMethod().IsFamily == true) {

                    propertyDetails["Visibility"] = "protected";

                }

if (propertyInfos[x].GetSetMethod().IsStatic == true) {

 propertyDetails["Visibility"] = ((String) propertyDetails["Visibility"]) + " static";

}

propertyDetails["Access"] = "[ Set ]" ;

System.Reflection.ParameterInfo[] paramInfos = propertyInfos[x].GetSetMethod().GetParameters();

if (paramInfos != null) {

       ArrayList paramTable = new ArrayList();

 

                    for (int y=0; y<paramInfos.Length; y++) {

                        SortTable paramDetails = new SortTable();

                        paramDetails["Assembly"] = paramInfos[y].GetType().Assembly.GetName().Name;

                        paramDetails["ParamName"] = paramInfos[y].Name;

                        paramDetails["ParamType"] = paramInfos[y].ParameterType.Name;

                        if(( paramInfos[y].ParameterType.IsArray && paramInfos[y].ParameterType.Name !="Array") || paramInfos[y].ParameterType.IsPointer) {

                            paramDetails["GetType"]   = paramInfos[y].ParameterType.GetElementType().Name ;

                            paramDetails["Namespace"] = paramInfos[y].ParameterType.GetElementType().Namespace ;

                        } else {

                            paramDetails["GetType"]   = paramInfos[y].ParameterType.Name;

                            paramDetails["Namespace"] = paramInfos[y].ParameterType.Namespace ;

                        }

                        paramTable.Add(paramDetails);

                    }

 

                    propertyDetails["Params"] = paramTable;

               }

            }

           this.Add(propertyDetails);

        }

        this.Sort();

    }

}

 

 

    public class DisplayMethods : ArrayList {

         public DisplayMethods(Type classType, String myclassname) {

             System.Reflection.MethodInfo[] methodInfos = classType.GetMethods() ;

 

             if (methodInfos == null)

         return;

        for (int x=0; x<methodInfos.Length; x++) {

                 if((String.Compare(myclassname,methodInfos[x].DeclaringType.Name )==0)&&(methodInfos[x].IsPublic || methodInfos[x].IsFamily) && (!(methodInfos[x].IsSpecialName)) ) {

         SortTable MethodDetails = new SortTable("Name");

         MethodDetails["Assembly"] = methodInfos[x].GetType().Assembly.GetName().Name;

          MethodDetails["Name"] = methodInfos[x].Name;

          MethodDetails["Type"] = methodInfos[x].ReturnType.Name;

if(( methodInfos[x].ReturnType.IsArray && methodInfos[x].ReturnType.Name !="Array") ||  methodInfos[x].ReturnType.IsPointer) {

Type ReturnElementType =  methodInfos[x].ReturnType.GetElementType();

     while(ReturnElementType.IsArray) {

        ReturnElementType =  ReturnElementType.GetElementType();

}

MethodDetails["GetType"]   = ReturnElementType.Name ;

MethodDetails["Namespace"] = ReturnElementType.Namespace ;

} else {

MethodDetails["GetType"] = methodInfos[x].ReturnType.Name;

MethodDetails["Namespace"] = methodInfos[x].ReturnType.Namespace ;

}

if (methodInfos[x].IsPublic == true) {

         MethodDetails["Access"] = "public ";

} else if (methodInfos[x].IsPrivate == true) {

        MethodDetails["Access"] = "private ";

} else if (methodInfos[x].IsFamily == true) {

         MethodDetails["Access"] = "protected ";

}

if (methodInfos[x].IsStatic == true) {

 MethodDetails["Access"] = ((String) MethodDetails["Access"]) + "static ";

 }

System.Reflection.ParameterInfo[] paramInfos = methodInfos[x].GetParameters();

if (paramInfos != null) {

                        ArrayList paramTable = new ArrayList();

for (int y=0; y<paramInfos.Length; y++) {

  SortTable paramDetails = new SortTable();

   paramDetails["Assembly"]  = paramInfos[y].GetType().Assembly.GetName().Name;

    paramDetails["ParamName"] = paramInfos[y].Name;

     paramDetails["ParamType"] = paramInfos[y].ParameterType.Name;

if(( paramInfos[y].ParameterType.IsArray && paramInfos[y].ParameterType.Name != "Array" )  || paramInfos[y].ParameterType.IsPointer) {

     paramDetails["GetType"]   = paramInfos[y].ParameterType.GetElementType().Name ;

     paramDetails["Namespace"] = paramInfos[y].ParameterType.GetElementType().Namespace ;

 } else {

    paramDetails["GetType"]   = paramInfos[y].ParameterType.Name;

    paramDetails["Namespace"] = paramInfos[y].ParameterType.Namespace ;

}

        paramTable.Add(paramDetails);

 }

 MethodDetails["Params"] = paramTable;

}

 this.Add(MethodDetails);

}

}

this.Sort();

}

}

public class DisplayInterfaces : ArrayList {

    public DisplayInterfaces(Type classType) {

             Type[] classInterfaces = classType.GetInterfaces();

             for(int x = 0 ; x < classInterfaces.Length ; x++) {

                SortTable interfaceDetails = new SortTable();

                interfaceDetails["Assembly"]     = classInterfaces[x].Assembly.GetName().Name;

                interfaceDetails["FullName"]     = classInterfaces[x].FullName;

                interfaceDetails["GetType"]      = classInterfaces[x].Name;

                interfaceDetails["Namespace"]    = classInterfaces[x].Namespace;

                this.Add(interfaceDetails);

             }

         }

    }

  public class DisplaySuperclasses : ArrayList {

        public DisplaySuperclasses(Type classType) {

           Type SuperClass ;

           SortTable classDetails = new SortTable();

           classDetails["Assembly"]     = classType.Assembly.GetName().Name;

           classDetails["FullName"]     = classType.FullName;

           classDetails["GetType"]      = classType.Name;

           classDetails["Namespace"]    = classType.Namespace;

          this.Add(classDetails);

           while (classType.BaseType != null) {

              SortTable superclassDetails = new SortTable();

               SuperClass =  classType.BaseType ;

               classType   =  SuperClass        ;

               superclassDetails["Assembly"]     = SuperClass.Assembly.GetName().Name;

               superclassDetails["FullName"]     = SuperClass.FullName;

               superclassDetails["GetType"]      = SuperClass.Name;

               superclassDetails["Namespace"]    = SuperClass.Namespace;

               this.Add(superclassDetails)    ;

           }

           this.Reverse() ;

        }

   }

    public class DisplaySubClasses : ArrayList {

        private Type        classType ;

        private Module[]    CorRuntime ;

        private Type[]      CorClasses;

        private String      myclassname ;

        private Type[]      classInterfaces;

        public DisplaySubClasses(Type classtype, ArrayList ModuleName) {

            this.classType = classtype;

            myclassname = classType.FullName ;

            if (classType.IsInterface ) {

for(int y = 0 ; y <  ModuleName.Count ;y++) {

 CorRuntime = Assembly.Load(ModuleName[y].ToString()).GetModules();

 CorClasses   = CorRuntime[0].GetTypes() ;

  for(int x= 0 ; x < CorClasses.Length; x++) {

       classType       =  CorClasses[x];

        classInterfaces =  classType.GetInterfaces() ;

  for(int  i = 0 ; i < classInterfaces.Length ; i++) {

   if(String.Compare(myclassname , classInterfaces[i].FullName )==0) {

SortTable subclassDetails     = new SortTable("FullName");

subclassDetails["Assembly"]     = classType.Assembly.GetName().Name;

subclassDetails["FullName"]     = classType.FullName;

subclassDetails["GetType"]      = classType.Name;

subclassDetails["Namespace"]    = classType.Namespace;

this.Add(subclassDetails) ;

 }

}

}

}

} else {

for(int y = 0; y < ModuleName.Count ; y++) {

CorRuntime = Assembly.Load(ModuleName[y].ToString()).GetModules();

                    CorClasses  = CorRuntime[0].GetTypes();

for( int x= 0 ; x< CorClasses.Length ;x++) {

classType = CorClasses[x].BaseType ;

if ( null != classType  ) {

if( String.Compare(classType.FullName, myclassname)==0) {

    SortTable subclassDetails     = new SortTable("FullName");

     subclassDetails["Assembly"]     = CorClasses[x].Assembly.GetName().Name;

     subclassDetails["FullName"]     = CorClasses[x].FullName;

     subclassDetails["GetType"]      = CorClasses[x].Name;

      subclassDetails["Namespace"]    = CorClasses[x].Namespace;

     this.Add(subclassDetails) ;

      }

      }

      }

      }

     }

            this.Sort();

        }

    }

}

 

In the web.config file, there are far more assemblies than is desirable, to carry out a search for the names of namespaces. In the a.aspx, we have not introduced too many structural changes. The code is voluminous, but most of it has been explained earlier. Hence, we shall make a quick run through.

 

In the Page_Load function, where life originates for our aspx application, we first display the namespaces, depending upon the existence of a parameter called class in the Url.

 

     If the class parameter is available, all the details of that class are displayed, using the function DisplayClass.

     If it is not present, a set of classes from the namespace, are displayed using the function DisplayClassList.

 

The DisplayClassList function remains the same as before. Modifications have been incorporated in the DisplayClass function. Where we had created one object earlier, which was an instance of DisplayMethods, we now have created seven objects. All these classes reside in the file b.cs. We therefore, have seven occurrences of the 'if' statement. They initialize seven DataList objects DataSource members by these ArrayList types, when the Count property is greater than zero. In their order of appearance, we have ArrayList objects that store details of the following:

 

     Sub-classes

     Constructors

     Fields

     Methods

     Superclasses

     Interfaces

 

We start with a DataList named Namespace1 that displays the list of Namespaces in the first column. Then, we have a div spnClassName that either displays the interface name or the class name. As mentioned earlier, the table, td and tr tags are utilized for display purposes. 

 

The DataList Classes store the class names, while the DataList Interfaces store the names of the Interfaces belonging to a Namespace. To display the list of constructors, we use a DataList called Constructors. In the template named headertemplate for constructors, we simply display the headings' Visibility and Parameters in a tabular format. In the class DisplayConstructors, indexers with names like Access and Name, are created and used in the itemtemplate.

 

There is always a likelihood of a complication stirring in situations, where the number can vary. Here, the number of parameters passed to the constructor, varies. Hence, we need a DataList within a DataList. The inner DataList is not assigned any name, but its DataSource member is initialized to the indexer variable called Params. Params is an ArrayList with members having the name of ParamType, etc. This is exactly what we had done earlier, in the case of methods. There is no alteration in the basic ground rules.

 

The mechanism employed to display different items, is as follows:

 

     To display the fields, a DataList called Fields is put into action.

     To display properties, a DataList called Properties is used.

     Superclasses are retrieved by a DataList called SuperClasses.

     Interfaces are retrieved by a DataList called Interface1.

     Sub-classes need their own DataList called SubClasses.

 

It is definitely not our concern, as to how the code that figured out the sub-classes, was written. We are not going to get distracted by the C# code written by someone else. We shall primarily focus on the presentation logic in the aspx file. The central idea of a class browser is that, some C# code is responsible for creating an ArrayList. Thereafter, the DataList in the aspx file displays it in a presentable form.

 

The main chunk of the source code lies in the classes present in the file b.cs. We have already seen as to how methods are to be retrieved. The rest of the code is quite similar. Let us commence with the mechanism for retrieving the constructors that are present in a specific type.

 

The class that retrieves fields is called DisplayFields. It is derived from ArrayList. The GetFields function is used to return an array of FieldInfo objects. The code to fill up the ArrayList object remains the same as that used for methods. The class named DispalyConstructors uses the function GetConstructors to generate a list of ConstructorInfo objects. Similarly, the class called DisplayProperties uses the function GetPropeties to return a PropertyInfo array. Here, one more function named GetSetMethod is added, which returns a null value, if the property accessor has only a get accessor. The class DisplayInterfaces is similar to the method class.

 

We need to be acquainted with the class hierarchy, which consists of the list of all the classes that a specific class is derived from, and also, all the classes that derive from it. The class DisplaySuperclasses meets the requirement, but uses a very original approach.

 

We create an object SuperClass, derived from Type and a Hashtable object classDetails. We initialize three indexer variables named FullName, GetType and Namespace, to the properties FullName, Name and Namespace, which are present in the class Type, respectively. Then, we append this data to the ArrayList class. 

 

A Type has a property called dBaseType, which is set to null, whenever the Type has no base Type. Putting it differently, only the Objects type will have the BaseType property set to null, since all types are finally derived from the class Object. The while loop will repeat itself for the number of types that we have derived from.

 

For each type, a Hashtable called superclassDetails is created and the SuperClass Type object is initialized to the BaseType. This value is also stored in the parameter variable named ClassType, because we shall lose the earlier value of SuperClass, in the next iteration of the while loop. Once again, the FullName, GetType and Namespace indexer variables are initialized, and thereafter, the new Hashtable object is added to the ArrayList.

 

The while loop stores data in the ArrayList in the reverse order. We intend to display the class Object first, leading upto the class whose details we are interested in. Thus, we need to reverse the order of the data in the ArrayList.