Managing Versions of an Application

 

Mike Gunderloy
Lark Group, Inc.

February 2002

Summary: Learn new ways to set and retrieve the version number of a Microsoft Visual Basic .NET application without Visual Basic 6.0's version information and application object. (9 printed pages)

Objectives

  • Set and retrieve version information in Microsoft® Visual Basic .NET applications
  • Understand how the common language runtime handles component versions

Assumptions

The following should be true for you to get the most out of this document:

  • You are familiar with Visual Basic programming
  • You have access to Visual Basic .NET
  • You are familiar with component-based applications

Contents

Version Numbers in Visual Basic .NET
Version Compatibility
Practice Modifying Version Information at Runtime
What's New Since Visual Basic 6.0?
Summary

Version Numbers in Visual Basic .NET

One of the things that will most surprise Visual Basic 6.0 developers moving to Visual Basic .NET is the absence of version information from the Project menu's Properties item. Also missing from Visual Basic .NET is the application object. Without these two items, you'll need to learn new ways to set and retrieve the version number of a Visual Basic .NET application.

Setting Version Numbers

One of the key features of Visual Basic .NET is that there is no hidden information. When you create a new application using Visual Basic .NET, a module named AssemblyInfo.vb is automatically added to your project. This module contains settings for assembly attributes, the Microsoft .NET equivalent of project properties. Among these you will find such items as the title, description, and company name to be used in the final executable or .dll file created from this project. The AssemblyInfo.vb module also contains a line that sets the version number. By default, this is:

<Assembly: AssemblyVersion("1.0.*")>

Version numbers in Microsoft .NET have four parts:

  • Major part
  • Minor part
  • Build part
  • Revision part

Setting the Assembly Version attribute to "1.0.*" tells Visual Basic .NET to use 1 for the major part, 0 for the minor part, and to come up with build and revision part numbers automatically. In this case, Microsoft .NET will assign an arbitrary build part and an arbitrary revision part, and it will change the revision part each time you rebuild the assembly. You can also specify all four parts of the version number explicitly:

<Assembly: AssemblyVersion("1.0.4.3")>

Version numbers are stored as a 128-bit number that is logically partitioned into four 32-bit numbers. This means that each of the four parts can be any number in the range zero to 65,536.

Retrieving Version Numbers

To retrieve the version number of an application from Visual Basic .NET, you can use the AssemblyName class from the System.Reflection namespace. This class has a Version property that returns an instance of the Version class. The Version class in turn implements a set of properties that you can use to retrieve version number information:

  • Major returns an integer containing the major part.
  • Minor returns an integer containing the minor part.
  • Build returns an integer containing the build part.
  • Revision returns an integer containing the revision part.

You can use these properties to return version information from any arbitrary file whose location you know, provided that the file contains an assembly manifest. You can use the GetAssemblyName method of the AssemblyName class to retrieve an AssemblyName object from a disk file:

Dim anm As System.Reflection.AssemblyName = _
 System.Reflection.AssemblyName.GetAssemblyName( _
 "c:\winnt\microsoft.net\framework\v1.0.3617\mscorlib.dll")
MessageBox.Show(anm.Version.Major)

You can also use the GetName method of the Assembly returned by the GetExecutingAssembly method of the Assembly class in the System.Reflection namespace to retrieve version information for the current executable:

MessageBox.Show(System.Reflection. _
 Assembly.GetExecutingAssembly. _
 GetName.Version.Major) 

Version Compatibility

Although setting and retrieving version information has changed in Visual Basic .NET, it is not the major change in this area. The main use of version information is to help applications and developers determine whether a particular version of a component is compatible with an application that makes use of the component. By default, Microsoft .NET uses only the versions of components that were present when an assembly was compiled.

For example, if a Visual Basic 6.0 application calls a component named xyz.dll, and version 1 was present on the computer at the time that the application was compiled, and later version 1.1 of xyz.dll is installed, the application will automatically call version 1.1 (assuming that the new version was marked as compatible with the old version when it was recompiled). In contrast, if the same situation arises under Microsoft .NET, the application will continue to call version 1 of xyz.dll unless it is explicitly told to use the new version.

By tying assemblies to the versions of components that were present at compile time, the .NET Framework helps to avoid the "DLL Hell" syndrome in which new versions of shared libraries break existing applications.

Compatibility Levels

You're free to use whatever version numbering you'd like as you release new versions. However, it's useful to establish standards for choosing new version numbers. Here's one standard that Microsoft suggests:

  • A new major or minor part indicates that the new version is incompatible with the old one. For example, version 2.0.0.0 should be incompatible with version 1.1.2.5. You should change major version numbers whenever you introduce an incompatibility into your code.
  • A new build part indicates probable compatibility. Typically you should change minor version numbers when you introduce a service pack or a minor upgrade. For example, version 1.8.0.0 is probably compatible with version 1.7.0.0.
  • A new revision part indicates a QFE (Quick Fix Engineering) release that is compatible with the previous version and that should be installed. For example, version 1.6.5.13 might be a mandatory bug-fix upgrade to version 1.6.5.12.

Finding the Correct Version at Runtime

When you run a Microsoft .NET application that uses an external component, the Microsoft .NET runtime checks four places to determine which version of the component to load:

  1. The original version from the assembly manifest is the default version to load.
  2. The runtime then checks for the presence of an application policy file that overrides the version information for this application only.
  3. The runtime then checks for the presence of a publisher policy file that overrides the version information for this component in all applications.
  4. The runtime then checks for the presence of an administrator policy file that overrides the version information for this component systemwide.

**Warning   **Version checking is only performed on files that have strong names. To generate a strong name for a file, you must use the sn.exe utility to generate a key pair and then compile that key pair into the component. You'll see an example of this technique later in this document.

Policy Files

Policy files are XML files that can specify the version of a component to use. The general structure of a policy file follows this template:

<configuration>
   <runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
         <dependentAssembly>
            <assemblyIdentity name="ComponentName"
               publicKeyToken="PublicKey" />
            <bindingRedirect oldVersion="version"
                             newVersion="version"/>
         </dependentAssembly>
      </assemblyBinding>
   </runtime>
</configuration>

The version for the oldVersion attribute can either be a single version number such as "1.0.0.0" or a range of version numbers such as "1.0.0.0-3.0.0.0". The version for the newVersion attribute is the version number of the component that should be loaded instead of the version specified in the assembly manifest.

Tip   You don't have to edit policy files by hand. The .NET Framework includes a snap-in for the Microsoft Management Console to handle this and other Microsoft .NET Configuration tasks.

There are three policy files that the runtime checks for version information:

  • The application policy file has the same name as the application plus the extension ".config" and resides in the same directory as the application. For example, the application configuration file for MyApp.exe would be named MyApp.exe.config. In some cases the name of the application policy file is dictated by Microsoft .NET. For example, the application policy file for an ASP.NET application is always named Web.config.
  • The publisher policy file is distributed by a component publisher together with a new version of a component. The publisher policy file must be installed in the Global Assembly Cache (GAC), even though the assembly itself need not be.
  • The machine configuration file is named Machine.config and is stored in the Config directory beneath the directory where the Microsoft .NET runtime is installed.

Practice Modifying Version Information at Runtime

In the following example, you'll create two versions of a class library and a client application that calls a method from one version of the library. You'll see that even though there is a more recent version of the library installed, the older version will be used by the client application until you explicitly construct an application configuration file.

Create the Class Library

Follow these steps to create the class library that will return a string to the user interface:

  1. Open Visual Studio .NET, click Start, and then click New Project.

  2. In the left pane, from the tree view, select Visual Basic Project.

  3. Select Class Library as the project template.

  4. Set the name of the application to MiscInfo. Specify a location of C:\MiscInfo for the project. Click OK to create the project.

  5. In the Solution Explorer window, select the class called Class1.vb and rename it to Info.vb.

  6. Select the code for Class1 in Info.vb (this will be an empty class definition) and replace it with the following code:

    Public Class Info
    
        Public ReadOnly Property Version() As String
            Get
                Version = Me.GetType.Assembly.GetName. _
                 Version.ToString
            End Get
        End Property
    
    End Class
    
  7. Open the code for AssemblyInfo.vb and replace the AssemblyVersion line with this code:

     <Assembly: AssemblyVersion("1.0.0.0")>
    
  8. On the Start menu, click Programs, click Microsoft Visual Studio .NET 7.0, clicl Visual Studio .NET Tools, and then click Visual Studio .NET Command Prompt. Type the following:

    sn -k MiscInfo.snk
    

    This will create a key pair in the file Miscinfo.snk. Copy this file to the folder containing the MiscInfo project.

  9. Add the following code to the end of the AssemblyInfo.vb file:

    <Assembly: AssemblyKeyFile("C:\MiscInfo\MiscInfo.snk")>
    
  10. To create version 1.0.0.0 of the project, on the Build menu, click Build Solution.

  11. Open the code for AssemblyInfo.vb and replace the AssemblyVersion line with this code:

     <Assembly: AssemblyVersion("2.0.0.0")>
    
  12. In the Solution Explorer, select the MiscInfo project as shown in Figure 1.

    Figure 1. Selecting the MiscInfo project

  13. On the Project menu, click Properties, and under Configuration Properties, click Build. Change the Output Path property to bin2\. Click OK.

  14. To create version 2.0.0.0 of the project, on the Build menu, click Build Solution.

  15. In the command prompt window, go to the C:\MiscInfo\bin folder containing version 1 of the project and type:

    
    gacutil /i MiscInfo.dll
    

    to add this version to the Global Assembly Cache.

  16. In the command prompt window, go to the C:\MiscInfo\bin2 folder containing version 2 of the project and type

    gacutil /i MiscInfo.dll
    

    to add this version to the Global Assembly Cache.

You can verify that both versions of the project are present in the GAC by using Microsoft Windows® Explorer to view the winnt\assembly folder, as shown in Figure 2.

Figure 2. Two versions of the MiscInfo project in the GAC

The MiscInfo project implements a single Info class with a single Version property. This property uses the FileVersionInfo object to return the version string that is compiled into the MiscInfo component. By following the steps above, you've created two different versions of this component that return two different version strings.

To create the user interface project

Follow these steps to create a Windows application to test the versions of the MiscInfo project:

  1. Open Visual Studio .NET, click Start, and then click New Project.

  2. From the tree view in the left pane, select Visual Basic Project.

  3. Select Windows Application as the project template.

  4. Set the name of the application to InfoTest and click OK to create the project.

  5. In the Solution Explorer window, select the form called Form1.vb and rename it to frmInfo.vb.

  6. Create a form with a single command button by adding the appropriate controls and setting the properties of those controls, as outlined below in Table 1.

    Table 1. Form controls and properties

    Control Type Property Value
    Button Name btnInfo
      Text Info
  7. On the Project menu, click Add Reference, click the .NET tab, click Browse, and then browse to MiscInfo.dll version 1.0.0.0. Click OK.

  8. On the View menu, click Code and enter this code after the Windows Form Designer-generated code:

        Private Sub btnInfo_Click( _
         ByVal sender As System.Object, _
         ByVal e As System.EventArgs) Handles btnInfo.Click
            Dim i As New MiscInfo.Info()
            MessageBox.Show(i.Version)
        End Sub
    
  9. On the Build menu, click Build Solution to create the executable version of the InfoTest project.

  10. Locate InfoTest.exe in Windows Explorer and double-click it to run the compiled version of the project, and then click Info. The program will display 1.0.0.0, the version string from the version of MiscInfo.dll that the InfoTest project refers to.

Try It Out

To test the ability to override internal binding information at runtime, follow these steps:

  1. Click Start, click Programs, click Administrative Tools, and then click Microsoft .NET Framework Configuration.

  2. In the left pane of the .NET Framework Configuration application, select the Configured Assemblies node.

  3. In the right pane, click Configure an Assembly.

  4. In the Configure an Assembly dialog box, click Choose Assembly.

  5. In the Choose Assembly From Assembly Cache dialog box, highlight version 1.0.0.0 of the MiscInfo assembly, and then click Select.

  6. In the Configure an Assembly dialog box, click Finish. This MiscInfo Properties dialog box opens.

  7. Click the Binding Policy tab. For the Requested Version, enter 1.0.0.0. For the New Version, enter 2.0.0.0 and click OK.

  8. Run the Infotest.exe application and then click Info.

    The program displays 2.0.0.0, the version string from the version of MiscInfo.dll that was loaded by the configuration file rather than the version that was originally bound to the application.

What's New Since Visual Basic 6.0?

The handling of version information has changed substantially since Visual Basic 6.0. In particular:

  • Version information is now set in the AssemblyInfo.vb file.
  • Version information is now retrieved via the GetAssemblyName method of the AssemblyName class.
  • Version information bound into an application can be overridden at runtime by configuration files.

Summary

Microsoft .NET allows very fine control of version information. By default, an assembly will use only the versions of components that were available when the assembly was compiled. But as the developer of an application, the publisher of a component, or the administrator of a system you can override this policy and specify the versions to be used on a component-by-component basis.

About the Author

Mike Gunderloy writes about software and raises chickens in eastern Washington state. He's the co-author of Access 2002 Developer's Handbook and author of SQL Server Developer's Guide to OLAP with Analysis Services, both from Sybex. He's been writing code for Microsoft products since the prehistoric pre-Windows era, and has no intention of stopping any time soon.

About Informant Communications Group

Informant Communications Group, Inc. (www.informant.com) is a diversified media company focused on the information technology sector. Specializing in software development publications, conferences, catalog publishing and Web sites, ICG was founded in 1990. With offices in the United States and the United Kingdom, ICG has served as a respected media and marketing content integrator, satisfying the burgeoning appetite of IT professionals for quality technical information.

Copyright © 2002 Informant Communications Group and Microsoft Corporation

Technical editing: PDSA, Inc. or KNG Consulting, Inc.