Click to Rate and Give Feedback
Related Articles
Here the author introduces SQL Server Data Services, which exposes its functionality over standard Web service interfaces.

By David Robinson (July 2008)
Here the author answers questions regarding the Entity Framework and provides an understanding of how and why it was developed.

By Elisa Flasko (July 2008)
Here we present techniques for programmatic and declarative data binding and display with Windows Presentation Foundation.

By Josh Smith (July 2008)
Systems that handle failure without losing data are elusive. Learn how to achieve systems that are both scalable and robust.

By Udi Dahan (July 2008)
More ...
Articles by this Author


By Ken Spencer (May 2004)


By Ken Spencer (April 2004)


By Ken Spencer (January 2004)


By Ken Spencer (December 2003)


By Ken Spencer (November 2003)


By Ken Spencer (October 2003)


By Ken Spencer (September 2003)
Ken Spencer introduces data binding in Visual Basic .NET.

By Ken Spencer (August 2003)
More ...
Popular Articles
Animating with Silverlight is easier than you think. Here we create a 3D app that folds a polyhedron using XAML, C#, and by emulating the DirectX math libraries.

By Declan Brennan (April 2008)
Here we present a rundown of the various language paradigms of CLR-based languages via short language introductions and code samples.

By Joel Pobar (May 2008)
Joel Pobar presents an introduction to how compilers work and how you can write your own compiler to target the .NET Framework.

By Joel Pobar (February 2008)
Systems that handle failure without losing data are elusive. Learn how to achieve systems that are both scalable and robust.

By Udi Dahan (July 2008)
More ...
Read the Blog
Windows Presentation Foundation (WPF) offers excellent support for managing the display and editing of complex data. In the December 2007 edition of MSDN Magazine, John Papa did a great job of explaining essential WPF data binding concepts. ...
Read more!
The most fundamental form of Web testing is HTTP request/response testing. This involves programmatically sending an HTTP request to the Web application, fetching the HTTP response, and examining the response for an expected value. In the May 2008 issue of MSDN Magazine, Read more!
In the November issue of MSDN Magazine, Jeffrey Richter demonstrates some recent additions to the C# programming language that make working with the APM significantly easier. In the June ...
Read more!
The July 2008 issue of MSDN Magazine is now available online. Here's what's in the issue: Data Services: Develop ...
Read more!
The June 2008 issue features the first installment of a new MSDN Magazine column on software design fundamentals. We’ll discuss design patterns and principles in a manner that isn't bound to a specific tool or lifecycle methodology. In this issue, Jeremy Miller starts the Patterns in Practice column ...
Read more!
In the April 2008 issue of MSDN Magazine, Kenny Kerr introduced the Windows Imaging Component (WIC), showing you how you can use it to encode and decode different image ...
Read more!
More ...
Advanced Basics
Extracting Data from .NET Assemblies
Ken Spencer

Code download available at: AdvancedBasics0403.exe (137 KB)
Browse the Code Online

Q How can I get a list of all of the methods, properties and events in a particular assembly? For instance, I need to know this information regarding Windows® Forms and ADO.NET. Ideally, I would also like to get information on the datatype of a property and the datatype of a function's return value. I also need to have this information appear in a spreadsheet.
Q How can I get a list of all of the methods, properties and events in a particular assembly? For instance, I need to know this information regarding Windows® Forms and ADO.NET. Ideally, I would also like to get information on the datatype of a property and the datatype of a function's return value. I also need to have this information appear in a spreadsheet.

A This is an interesting question. Let me show you the application I built to do this, then I'll explain the code. Figure 1 shows the app's main interface run against the System.Windows.Forms assembly. It shows that 28,932 members were processed. I would not want to look through that list manually!
A This is an interesting question. Let me show you the application I built to do this, then I'll explain the code. Figure 1 shows the app's main interface run against the System.Windows.Forms assembly. It shows that 28,932 members were processed. I would not want to look through that list manually!
Figure 1 Assembly Info Viewer 
Figure 2 shows a detailed list of methods, properties, and events from the assembly. It's what you would expect if you were looking at the ComboBox control. As you can see from the File menu in Figure 2, you can also save this detail to a file as comma-separated values. Then you can import the data into Microsoft® Excel or a myriad of other applications. Of course, you could also export the data as XML; maybe I'll build that into a future version of the application.
Figure 2 Save As Comma-separated Values 
The first form (frmMain) has a simple interface with a main menu and several label controls. The main menu has two top-level menu items, File and View. The File menu contains these items: Open Assembly, Open Assembly in GAC, and Exit.
The View menu only has one submenu: View Assembly Items.
First, I needed to figure out how to use reflection on assemblies that are in the global assembly cache (GAC). Here I load an assembly where mAssemblyName is the complete file path:
mAssembly = [Assembly].LoadFrom(mAssemblyName)
Once the assembly is loaded, I can examine its types using mAssembly. I tried this with assemblies in the GAC. I figured that I could use Load instead of LoadFrom. So far, so good. Since the Load method takes the display name of an assembly, I thought I could use the names I saw displayed in the GAC Viewer (see Figure 3).
Figure 3 GAC Viewer 
You can see that I have highlighted the Windows.Forms class from the Microsoft .NET Framework version 1.1. I thought I'd be able to pass "System.Windows.Forms" to Load. Wrong! For assemblies in the GAC, I must use the assembly's full name, which includes the assembly's version, culture, and public key token. So, I did some digging using the command prompt (see Figure 4).
Figure 4 Windows Forms Directory 
Figure 4 shows the GAC directory for the Windows Forms assembly. Notice the entire directory path. You can actually take the entire path and use it with LoadFrom, like so:
C:\WINNT\assembly\GAC\System.Windows.Forms\
1.0.5000.0__b77a5c561934e089\System.Windows.Forms.dll
But that's not really the way I wanted to handle it, and the GAC folders may be in another location on the user's machine. So I decided to find out what the display name really was. It turns out it looks like this:
System.Windows.Forms, Version=1.0.3300.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
Clearly, the display name for strong-named assemblies contains a lot more than just the name.
At any rate, now that I know what the full names look like, let me allow the user to select them. But how do I get the display names for all assemblies in the GAC? I could figure out some cool ways, such as using interop to access the unmanaged Fusion API, but I needed the info quickly, so I took the easy way out. I simply opened the Visual Studio® command prompt and ran GACUtil.exe with the following command:
Gacutil /l > gaclist.txt
This copied a list of all assemblies in the GAC to gaclist.txt. Then I opened the text file and stripped out the header and everything after the display names. Next, I removed the tab spaces and saved the file in the application's Bin directory. At this point I added the code shown in Figure 5 to load this file into the global dtGACAssemblies datatable. This code is then loaded into the DataGrid in frmGACAssemblies.vb, thus allowing the user to select an assembly.
Now, let's see how to pull information from the assemblies. I used the same approach I used in my February 2003 column (see Figure 6). The LoadClassesMemberInfo method takes two parameters. The first is the AssemblyFullFileName, which can be either the assembly file name or the display name. If the display name is used, the second parameter should be set to True. This parameter is checked in the first part of the method's code to determine if Load or LoadFrom should be called:
If Not UseAsDisplayName Then
    mAssembly = [Assembly].LoadFrom(mAssemblyName)
Else
    mAssembly = [Assembly].Load(mAssemblyName)
End If
Now the application has an assembly loaded, so you can work with it using reflection.
Now, let's analyze the assembly. I use a For Next loop to iterate over all exported types from the assembly (only public classes are exported). This loop calls the GetMemberInfo method (shown in Figure 7) and passes it the reference to the current type (t). The first bit of Figure 7 calls GetMembers to pull the members from the type, returning an array of MemberInfo objects:
lMemberInfo = t.GetMembers((BindingFlags.Public Or _
    BindingFlags.Instance Or BindingFlags.InvokeMethod))
Now you can loop through this array and process the data for each member. All finished, right? Not so fast.
I also wanted to extract the DataType for each member; while it's possible to get this from MemberInfo by casting it to the appropriate derived type, I took another approach. First, in the loop which processes members, I filter out methods, properties, and events with the If block so that only other members, such as fields and constructors, remain. Second, I added three more For Each loops, one each for methods, properties, and events.
Each one of these member types has a corresponding info class, all of which are derived from MemberInfo.
MethodsMethodInfo
EventsEventInfo
PropertiesPropertyInfo
Each of these classes exposes the attributes of the corresponding member and provides access to its metadata. And just as I was able to use Type's GetMembers to retrieve all members of a type, I can use Type's GetMethods, GetProperties, and GetEvents methods to return arrays of the corresponding info objects. Thus, adding the other three For Each loops to process these items separately adds the information to the datatable returned from GetMemberInfo. I still need to pull out the parameters for each method, but that's pretty easy to do. In fact, if you look at my code in the aforementioned February 2003 installment, you will see this in action.
The code in the download is pretty simple, so I will leave it to you to explore (see the link at the top of this article). Check out the MouseUp event in frmGACAssemblies.vb. This event shows an alternate way of handling selection events in a DataGrid. There are many times when handling the MouseUp event is preferable to using another event, such as Click, because MouseUp provides more information about the performed action.

Send your questions and comments for Ken to  basics@microsoft.com.


Ken Spencer works for 32X Tech (http://www.32X.com), where he provides training, software development, and consulting services on Microsoft technologies.

Page view tracker