RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Use Reflection to Validate Assembly References—Before Your Customers Do : Page 2

Developers are familiar with reflection as a way to create object instances, and discover and call object properties and methods, but reflection's usefulness extends even further—you can also use it to create a diagnostic tool to discover and validate dependencies for deployed code, and to report missing dependencies.

Building the AssemblyValidator
The first step in validating the currently executing assembly's dependencies is to retrieve a handle to the currently executing assembly, because you need a handle to the topmost assembly for the process in which the validation code is running. The System.Reflection namespace's Assembly class provides the GetEntryAssembly() function that you can use to obtain a handle to this assembly. The function returns an Assembly object, which represents an assembly that has been loaded into memory.

   Dim objAssembly_Self As Assembly
   ObjAssembly_Self = Assembly.GetEntryAssembly()
For reference, the Assembly class provides access to the metadata exposed by a particular instance of an assembly. It is important to note that the Assembly class is tied to an instance of an assembly loaded into memory because it is possible, especially with the Xcopy deployment methods promulgated by Microsoft, to have many identical assemblies that differ only by their locations. If you are interested in only the generic information about an assembly, use the AssemblyName class.

The AssemblyName class stores enough information about an assembly to enable you to load an instance into memory—more specifically, it provides enough information for the .NET Framework to find and load it for you. One key detail used by .NET is the assembly's FullName property, which holds an assembly's name, version, culture, and public key. This combination of attributes ensures that .NET loads the exact assembly you intend—no two assemblies should ever have an identical FullName. When you query the assembly metadata for referenced assemblies the Assembly class returns a list of referenced assemblies as AssemblyName objects.

So, after you get a reference to the entry assembly, you can request the list of assemblies it references, returned as an array of AssemblyName objects. You can then iterate through the array, passing each AssemblyName object to a recursive method named ValidateAssembly. The recursive nature of this function ensures that the AssemblyValidator validates all the dependencies that exist in the hierarchical assembly dependency structure.

      Dim objDepAssembly As AssemblyName
      For Each objDepAssembly in _
Internally, the ValidateAssembly method uses an Assembly_List object defined in the validation tool to keep track of which assemblies have been referenced and to maintain details about each of the referenced assemblies. Other than keeping track of assembly details, the most important role of the Assembly_List object is to avoid repeatedly validating assemblies that have already been validated. Worse than the small amount of additional time required to re-verify assemblies, you could quickly cause a stack overflow if the recursive calls exhausted your application's memory resources. So, before adding another assembly to the Assembly_List object, the AssemblyValidator first checks the list to see if it's already been verified. If so (it exists in the list), the tool stops the recursion and returns from the ValidateAssembly method.

The ValidateAssembly method first attempts to load the assembly using the AssemblyName object provided as a parameter. The Assembly class provides a shared overloaded Load method; the sample application uses the overload version that accepts an assembly name object. The CreateAssembly method shown below demonstrates how to use the AssemblyName object to load assemblies. Note the possible common exceptions raised by the Load method.

   'attempt to create the assembly using the assembly name object
   Private Function CreateAssembly( _
      ByVal p_objAssemblyName As AssemblyName, _
      ByRef p_strError As String) As Assembly
      Dim objAssembly As System.Reflection.Assembly
      '---- try to create the assembly
         objAssembly = System.Reflection.Assembly.Load( _
         p_strError = ""
      Catch exSystem_BadImageFormatException As _
         p_strError = "File is not a .NET assembly"
         objAssembly = Nothing
      Catch exSystem_IO_FileNotFoundException As _
         p_strError = "Could not load assembly -- " & _
            "file not found"
         objAssembly = Nothing
      Catch ex As Exception
         p_strError = "An error occurred loading the assembly"
         objAssembly = Nothing
      End Try
      Return objAssembly
   End Function
If the assembly cannot be loaded, then recursion stops at this level, and the AssemblyValidator logs an error in the Assembly_List indicating why the assembly could not be loaded. When the assembly loads successfully, the AssemblyValidator adds the assembly details to the Assembly_List object, and recursively verifies each of this assembly's referenced assemblies. This process continues until all the dependencies have been verified. Listing 1 shows the complete ValidateAssembly method.

At the end of the process, the Assembly_List class provides a FormatList method used to produce a string representation of the list of referenced assemblies. By default, the AssemblyValidator displays only assemblies that could not be loaded, because it's far too difficult to scroll through the lists of dependencies manually, looking for problems—even simple "Hello World" WinForms projects produce long lists of dependencies.

As an exercise, I recommend that you modify the sample code to instruct the Assembly_List to display all dependencies (without duplicates), including those assemblies that loaded successfully, and observe the list that is produced. To make this modification, open the Assembly_Validator class in the AssemblyDependencyValidator project, and modify the last line of the ValidateEntryAssembly method, changing the parameter to the FormatList method to be False, as shown below:

   m_strResults = strValidatorResults & vbCrLf & _

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date