23.3. Programmatic Access to Assemblies

Fortunately, .NET assemblies are not just black boxes. A .NET assembly is represented by the Assembly class of the System.Reflection namespace. You can use this class to gain programmatic access to the components of an assembly. Listing 23.5 shows how to load the assemblies created earlier and explore them.

Listing 23.5. Loading and Browsing an Assembly in C#
using System;
using System.Reflection;

public class AssemblyExplore {

  public static void Main(string[] args) {

    Assembly asm = Assembly.LoadFrom("C:\BOOK\
           code\Chapter 23\Greeting.exe");
    //Prints the properties of the assembly
    PrintProperties(asm);
    //Browse the modules of the assembly
    BrowseModules(asm);
  }

  private static void PrintProperties(Assembly asm) {
    Console.WriteLine("CodeBase "+asm.CodeBase);
    Console.WriteLine("Location "+asm.Location);
    Console.WriteLine("Global Assembly Cache
           "+asm.GlobalAssemblyCache);
    Console.WriteLine("EntryPoint "+asm.EntryPoint.ToString());
    Console.WriteLine("FullName "+asm.FullName);
  }

  private static void BrowseModules(Assembly asm) {
    foreach (Module m in asm.GetModules()) {
      BrowseModule (m);
    }
  }

  private static void BrowseModule(Module m) {
    Console.WriteLine("Module "  .Name);
    foreach (Type t in m.GetTypes()) {
      Console.WriteLine("	Type "+t.FullName);
      foreach (MethodInfo method in t.GetMethods()) {
        Console.WriteLine("		Method signature
          "+method.ToString());
      }
    }
  }
}

The output of Listing 23.5 is as follows:

CodeBase file:///C:/BOOK/code/Chapter 23/Greeting.exe
Location c:ookcodechapter 23greeting.exe
Global Assembly Cache False
EntryPoint Void __EntryPoint(System.String[])
FullName Greeting, Version=0.0.0.0, Culture=neutral,
PublicKeyToken=null
Module greeting.exe
Module hello.module
Type HelloWorld
Method signature Int32 GetHashCode()
Method signature Boolean Equals(System.Object)
Method signature System.String ToString()
Method signature System.Type GetType()
Type HelloWorldDriver
Method signature Int32 GetHashCode()
Method signature Boolean Equals(System.Object)
Method signature System.String ToString()
Method signature Void Main(System.String[])
Method signature System.Type GetType()
Module goodbye.module
Type GoodByeWorld
Method signature Int32 GetHashCode()
Method signature Boolean Equals(System.Object)
Method signature System.String ToString()
Method signature System.Type GetType()
Type GoodByeWorldDriver
Method signature Int32 GetHashCode()
Method signature Boolean Equals(System.Object)
Method signature System.String ToString()
Method signature Void Main(System.String[])
Method signature System.Type GetType()

The output of Listing 23.5 should be self-explanatory based on what we did earlier while constructing the assembly. There are two modules that contain types. The hello.module file contains the HelloWorld and the HelloWorldDriver classes. The goodbye.module file contains the GoodByeWorld and GoodByeWorldDriver classes. The method signatures of the methods of these two classes are listed in the output generated by Listing 23.5.

Notice that HelloWorld, HelloWorldDriver, GoodByeWorld, and GoodByeWorldDriver are simple classes; so where did all these methods come from? Remember that all classes extend System.Object. What you see in the output are the System.Object methods inherited by these classes.

The Assembly class provides methods to retrieve information about the assembly. There are no methods provided to modify the assembly. Chapter 22 discusses the reflection emit mechanism, which can be used to create dynamic assemblies (see Listing 22.9).

So far, the assemblies we've created have been private assemblies—that is, specific to the application in question. Many times, applications depend on a shared assembly to function. The notion of sharing an assembly becomes more apparent when the assembly is a type library (a DLL file). Think of multiple EXE files using the same DLL (sound familiar?). A .NET shared assembly is more than just a static DLL that is referenced by the applications.

Consider a Java Web application deployed in a J2EE-compliant Web container. The container has library files that are infrastructure .jar files used by all applications deployed in that container. It makes little sense to deploy this common set of .jar files every time a new Web application is deployed. What is needed is a mechanism by which the container automatically knows to use the shared .jar file when an application makes a reference to it. Java handles this mechanism using a class-loader hierarchy. Because the application references the shared .jar file at runtime, it only makes sense that for the application to compile, it would need to reference that .jar file at compile time. The .jar file required at compile time need not be in the same location as the one required at runtime.

In .NET, a shared assembly is in many ways similar to that J2EE infrastructure .jar file. But .NET does not have the concept of class loaders or class paths, so how does the CLR know where to look when an application references a DLL it cannot find in its assembly? The Global Assembly Cache (GAC) is a directory (usually C:Windowsassembly or C:WINNTassembly) where the CLR can locate such shared assemblies. Although it is not necessary to put the shared assembly in the GAC, it makes for easier deployment if shared assemblies are kept there. The .NET Framework provides a tool called the GAC tool (gacutil.exe) to install shared assemblies in the GAC.

Sharing an assembly means that the assembly should have a name that is globally unique. Such a name is called the strong name of the assembly. It consists of the name, version information, culture information, and a public key for cryptography. The AssemblyInfo.cs file can be used to modify the strong name components of an assembly. To create a public key, the .NET Framework provides a strong name tool called sn.exe, which creates a key file that can be referenced in the AssemblyInfo.cs. The following command creates a Hello.snk key file containing the cryptographic public key:

sn–k Hello.snk

Next, we create the AssemblyInfo.cs file with all the strong name components specified, as shown in boldface in Listing 23.6.

Listing 23.6. AssemblyInfo with Strong Name Components (C#)
using System.Reflection;
using System.Runtime.CompilerServices;

[assembly: AssemblyTitle("MyApp")]
[assembly: AssemblyDescription("A simple app")]
[assembly: AssemblyCompany("MyCompany.com")]
[assembly: AssemblyProduct("MyApp")]
[assembly: AssemblyCopyright("This is the property of
MyCompany.com")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
						[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyKeyFile("Hello.snk")]

If you run the following command, the Hello.dll is created with a strong name:

csc /target:library /out:Hello.dll HelloWorld.cs AssemblyInfo.cs

Now store it in the GAC using this command:

gacutil /i Hello.dll

When the DLL is installed in the GAC, an application is free to use it at runtime. But first, the application must use the DLL at compile time to compile itself. To do this, we copy the DLL from the GAC into the directory where you would compile your application. Let's compile HelloWorldDriver using this new DLL:

csc /target:exe /out:MyApp.exe HelloWorldDriver.cs
/reference:Hello.dll

Now remove Hello.dll from the local directory. When we run MyApp it should print the following as output:

Hello World

We have just created an EXE (MyApp.exe) that references a shared assembly (Hello.dll).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.125.7