What's New in .NET 2.0 for Assemblies and Versioning? (Cont.)
In Visual Studio 2003, you had no way to create strong name keys and you were forced to use a command line utility (SN.exe). Microsoft simply assumed that creating strong names is a relatively infrequent operation, done once per company, and it saw no need to have that functionality in Visual Studio. However, in practice, it turns out that developers often create new strong names, used for testing, learning and experimenting, branching, security, configuration management, and so on.
Visual Studio 2005 can both create the encryption keys for you and sign the assembly, all without leaving the visual environment.
Visual Studio 2005 can both create the encryption keys for you and sign the assembly, all without leaving the visual environment. In the project properties, select the Signing pane (Figure 4). By checking the Sign the assembly checkbox, you instruct the compiler to sign the assembly with the key file specified.
Figure 4: Signing the assembly.
The Choose a strong name key file combo box will allow you to either create a new key or to browse to an existing file. If you choose to create a new key, Visual Studio 2005 will launch the Create Strong Name Key dialog box shown in Figure 5.
Figure 5: Generating strong name key file.
Strong name key files come in two flavors plain and password-protected. If you uncheck the Protect my key file with a password checkbox, Visual Studio 2005 will generate a file with the name specified and with the snk (Strong Name Key) extension. However, keeping the key in such a raw format carries great liability: since the strong name uniquely identifies an assembly vendor, if the private key is compromised, any malicious party could produce components as if they came from that vendor. To reduce the risk, I strongly recommend always choosing to protect the key using a password. Visual Studio 2005 insists that the password specified has 6 characters or more. If you check the Protect my key file with a password checkbox, Visual Studio 2005 will generate a file with the name specified and with the pfx (Personal Information Exchange) extension. The pfx file is more secure because whenever another user tries to use the file, that user will be prompted for the password. The other advantage of a pfx file is that you can add it to a certificate container (see the sidebar Protecting Your Keys).
If instead of creating a new key file you would like to browse for an existing key, Visual Studio 2005 will bring up a dialog letting you browse for either .snk or .pfx files. Once you have selected a file, Visual Studio 2005 will copy that file to the project folder. There is no way to share an existing file, and every project must have its own physical copy of the file.
In addition, unlike Visual studio 2003, Visual studio 2005 does not use attributes for storing the key file name. Instead, it persists that in the project settings.
Specific Reference Version
By default, Visual Studio 2005 will not keep track of the referenced assembly version. For example, suppose you browse in Visual Studio 2005 and add a reference to version 126.96.36.199 of the assembly MyAssembly.dll. The reference properties will reflect the assembly version (Figure 6) but will not have any affinity to it. If you replace the referenced assembly on disk with version 188.8.131.52 (while keeping the same friendly name or even the strong name), next time you build the client, the client-side complier will use the metadata and type definitions from version 184.108.40.206 of the server assembly. The manifest of the client assembly will record 220.127.116.11 as the server assembly version number, and .NET will try to provide version 18.104.22.168 to the client, not version 22.214.171.124, which the client developer added a reference to. In dynamic build environments, this default behavior will allow the client developer to always be synchronized with the latest server assembly version without doing anything special about it. The default behavior works well in a client project that adds references to other projects in the same solution. Whether you change the referenced assemblies' version explicitly or let the complier do it for you, you will always get the latest assemblies for your client debug sessions.
Figure 6: Stipulating a specific version.
However, you can easily run into situations where this behavior is not what you want. Imagine developing a client application against a specific version of a control, version 126.96.36.199. The control is part of a framework that adds its components to the GAC when it is installed. The framework also provides a folder on the disk for you to add references to. If you install version 188.8.131.52 of the framework, it will add its components to the GAC, but will also override the disk folder with the newer assemblies. Consequently, your application will not be able to use version 184.108.40.206 of the control, even though it makes specific use of that version. To address this need, Visual Studio 2005 provides the Specific Version property of the assembly reference. Specific Version is set by default to False for all references. When Specific Version is set to True, Visual Studio 2005 will only build the client if it has access to the specific version of the referenced assembly. Specific Version set to True will have an affect whether the referenced assembly has a strong name or not. If Copy Local is set to true and the version number does not match, Visual Studio 2005 will not copy the referenced assembly. When trying to build the client assembly, Visual Studio 2005 will look for an assembly with a matching version. If an assembly with a matching version was not found, but the assembly has a strong name, Visual Studio 2005 will also try to look up the specific assembly version in the GAC. In this respect, the GAC on the development or build machine is actually used as a development resource, hosting side-by-side versions of component frameworks. If Visual Studio 2005 cannot find the specific version of the assembly, it displays a warning icon on the reference in the References folder, expecting the developer to resolve it.
When Specific Version is set to True, Visual Studio 2005 will only build the client if it has access to the specific version of the referenced assembly.
Note that the Specific Version property is only a build-time directive, and it has no effect on the runtime version resolution of the referenced assembly.
If the application doesn't indicate to .NET which CLR versions it requires, the application is actually telling .NET that any compatible CLR version is allowed. In that case, .NET detects the CLR version the application was compiled with and uses the latest compatible CLR version on the machine. To that end, .NET is aware of which CLR version is backward-compatible with other versions. Presently, Microsoft considers all newer .NET versions to be backward-compatible. Note that CLR backward compatibility is not the same as forward compatibility. Backward compatibility deals with the question of "Can an old CLR version assembly execute against a newer CLR version?" Forward compatibility deals with "Can an assembly that was built against a newer CLR version execute on an old CLR version?" Backward compatibility is mostly the product of changes to type definition and type behavior. Forward compatibility is governed by the metadata version. Both .NET 1.0 and .NET 1.1 have the same metadata version, and so they are both backward and forward compatible with respect to each other. .NET 2.0 has a new metadata version, and as a result it is only considered backward compatible - .NET 2.0 assemblies require the .NET 2.0 runtime. Table 1 depicts CLR version compatibility. The left column lists the CLR versions an assembly was built against and the rest of the columns list whether it can run against a particular CLR version. Note that Visual Studio 2005 can build only applications targeting CLR version 2.0.
Assemblies and CPU Architectures
In theory, any IL-based assembly could run on any target CPU because of the two-phase compilation process. If the IL has nothing in it that pertains to specific CPU architecture or machine languages, then the JIT compiler will generate the machine instructions for the target CPU at run time. However, in practice, it is possible to write un-portable assemblies. For example, C# lets you explicitly dictate the memory layout of structures. If you use explicit x86 memory layout, your code will not work on Itanium or any other 64-bit machines. In addition, if the assembly imports legacy COM objects, then the assembly will not work on 64-bit machines, because 64-bit Windows does not support COM natively. For that, your assembly will have to execute in the Win32 emulation environment (known as WOW, or Windows-on-Windows). However, if you simply load that assembly on a 64-bit Windows machine, it will run in the native 64 environment, not the WOW. The only solution for such CPU-specific assemblies is to incorporate the information on the target CPU into the binary executable that contains the assembly. That way, if an assembly which requires the 32-bit WOW emulation is loaded on a 64-bit machine, the loader will launch it in the WOW, whereas the 32-bit JIT compiler will compile it correctly. In case you develop an assembly that requires a particular CPU architecture, you need to inform Visual Studio 2005 about that CPU so that it could incorporate the information into the binary. In every project in Visual Studio 2005 in the Build tab under the project properties you'll find the Platform Target drop down list (Figure 7). The default is AnyCPU, but you can select x86, x64 or Itanium. When specifying a particular CPU, you are guaranteed that the assembly will always execute on that CPU architecture (or an emulation of it).
Figure 7: Specifying CPU architecture for your assembly.