Working with Assemblies and the GAC

Note

You must have administrator privileges on your computer to complete the examples in this section. Only an administrator can delete files from the GAC.


Often, when you create an assembly, you will want it to be shared by multiple applications. This is not really a problem because multiple applications can point to the same DLL. However, when you set a reference to a DLL inside a project, it records the path to the DLL. What if the path later changes? Or what if you don't know the final path on the eventual production machine?

As you've already read, the Global Assembly Cache, or GAC, allows you to place components into a cache that can be accessed by any application. Therefore, you could take the Healthcare.DLL and add it to the GAC, allowing applications to access it regardless of the physical location of the DLL.

Setting the Strong Name

To see this in action, the first thing you need to do is set a strong name for the component. A strong name is a way to positively identify a component. It includes some standard information, such as the assembly's name, version number, and culture information if provided. It also adds a public key and a digital signature.

Strong names are a way for the client to verify that a component is unchanged from the component referenced by that client when it was built. This means that the client can be assured that the assembly is unchanged and that it was, in fact, generated by the proper party. The use of a strong name follows this procedure:

1.
The assembly is compiled with a strong name set for it. The digital signature is created with the developer's private key, and the signature is stored in the portable executable file of the assembly. This combination of the name and a key ensures uniqueness in much the same way a GUID (Globally Unique ID) did in the world of COM.

2.
The client references the assembly. Setting this reference adds the assembly's public key as part of the reference. Technically, only a portion of the assembly's public key is added to the reference in order to save space.

3.
At runtime, the client verifies the strong name by using the public key to check the digital signature. Proper negotiation indicates that the assembly has not been tampered with, and the person owning that public key did create the assembly.

Setting a strong name also ensures that no one else can create a new version of your component. Because your component is signed with your unique key, no one else can create a new version because he does not have your key. Clients can be assured that new versions come from the original author only. Finally, strong names are used to verify that a component has not been modified since it was built, much like Authenticode technology and ActiveX controls that are downloaded and used in a browser.

To set the strong name for your Healthcare assembly, make sure that the Healthcare project is chosen in the Solution Explorer window. Click on Project, Properties to open the Healthcare property pages. Click on Strong Name in the left-hand navigation window.

You have two ways to create a strong name: You can use a key file or a key container. The key file method is not as secure as the key container method. With a key file, you include the file in the project, which means it could be shared inadvertently, and you are warned of this fact on the dialog box. The key container actually accesses the key from the runtime, and therefore does not have to store the key file in the project. For now, you'll keep it simple and use the key file.

Click Generate Key under the Key File text box, and KeyFile.snk appears in the text box. You can see this in Figure 4.5.

Figure 4.5. The Strong Name tab of the Project Properties dialog box.


After clicking the OK button, you can see that the KeyFile.snk file has been added to your project if you look in the Solution Explorer.

The next few steps will seem odd at first, but I'll explain what is happening as you go. Understand that you are about to test using the component from a specified path, and then from the GAC.

Adding the Assembly to the GAC

Now that you have set a strong name for the assembly, go ahead and build the assembly again by choosing Build Healthcare from the Build menu. Recall that, by default, you have just built the assembly in My DocumentsVisual Studio ProjectsHealthcarein (if you used the default directory to create the application). Now, however, copy the Healthcare.dll you just created and drop it in another directory; for my examples, I'll assume that it has been copied to the root of the C: drive, but you are free to copy it elsewhere. The point is you want it in a different, and easily accessible, directory.

Now, create a new Windows Application project, and call it NewHealthcareClient. Right-click on the References node in the Solution Explorer window and choose Add Reference. Click on the Projects tab, and then click the Browse button. Navigate to the root of the C: drive and point to the Healthcare.DLL you copied there, and then click OK.

You have now added a reference in your new client application to the assembly you created earlier. If you expand the References node in the Solution Explorer, click on Healthcare, and look at the Properties window, you'll notice the Path property is set to C:Healthcare.dll. This might seem to be exactly what you did in the previous example, and so far it is; in fact, the only difference so far is that the assembly has a strong name.

Now, on the form in your NewHealthcareClient project, add a button and add the following code:

Private Sub Button1_Click(ByVal sender As System.Object, _
 ByVal e As System.EventArgs) Handles Button1.Click
   Dim myPatient As New Patient()
   myPatient.FirstName = "Sue"
   MsgBox(myPatient.FirstName)
End Sub

You can go ahead and run this application in order to test it, but you will want to actually build it before continuing with the testing. Click on the Build menu and choose Build. Your NewHealthcareClient.exe file will be in My DocumentsVisual Studio ProjectsNewHealthcareClientin by default. If you look in that directory, you will see something strange: a copy of Healthcare.dll! This was automatically copied into the directory in which you compiled the application.

It isn't always desirable to have the DLL in the execution directory for each application. First, a single application might reference dozens of assemblies, and you don't want them all in the application directory. Further, you might want the component to be shared by multiple applications, so you can slipstream fixes in without having to worry about copying into a multitude of directories.

In the directory in which your EXE was compiled, run NewHealthcareClient to see whether it works. It should work flawlessly. Now, in that directory, delete the Healthcare.DLL. Run the application again, and click on the button you added. Now, you get a nasty error message, as shown in Figure 4.6.

Figure 4.6. An error indicating that an assembly could not be found.


If you click the Details button on the error message box, you will see the following information:

System.IO.FileNotFoundException: File or assembly name Healthcare, or one
 of its dependencies, was not found.

You might now be scratching your head. You referenced an assembly in the root of the C: drive, and that assembly still exists. However, your application is apparently only looking in the local directory for the file. Now that the local copy of that file is gone, the application gets all confused and indicates it cannot locate the assembly.

However, the application is also searching the GAC, and of course it is not finding the assembly there, either. You must first add the assembly to the GAC in order for the application to be able to see it.

Open a console window and go to the root of the C: drive. You are going to use gacutil to install the assembly into the GAC. However, you need to locate gacutil and either type in the full path or, as in this case, just copy it into a directory in the path. After you have located gacutil, type the following command:

gacutil /i healthcare.dll

This installs the assembly into the GAC. If you had not created a strong name, you would have received a message that you could not install an assembly without a strong name into the GAC. Because you did create a strong name for this assembly, it installs into the GAC without problems.

Now, return to your NewHealthcareClient application and run it again. This time, it runs normally. You haven't made a single change to the client application, but when it looks for the assembly, it checks not only the local directory (which no longer contains a copy of the assembly), but it also checks the GAC. In this case, of course, it finds the assembly in the GAC and uses it.

Now, remove the assembly from the GAC. Back in the console window, type the following command:

gacutil /u healthcare

Notice that you do not include the .DLL extension on the name of the assembly to remove. After you have removed the assembly, run your client again. Now, two things can happen. If you did not shut down your client before uninstalling the assembly from the GAC, the client continues to run fine. However, if you did shut down the client and now restart it, it will not run. This is because the client has cached the information about the assembly in memory, and does not notice it has been removed from the GAC unless the client is stopped and restarted.

Versioning and .NET Assemblies

Understanding how .NET assemblies are versioned is important. The first rule to remember is simple: Only assemblies with strong names have the version policies applied to them. Therefore, if you aren't using strong names, this won't be something you have to worry about.

Assume that you are going to use strong names. Maybe you want strong names because you want to use the GAC, or you'll just use strong names for a little extra security. Regardless, it is important to understand how versioning works with strongly named assemblies.

NET Version Numbers

The .NET version number consists of four parts:

							<major number>.<minor number>.<build>.<revision>
						

Assume that you are working on a project, and that you are building a new version on a regular basis, such as daily. Each day that you build the application, you will increment the build version. If you have to make multiple builds in one day, you can increment the revision number. Regardless of how you actually use the four parts of the version to track your projects, they become very important when you begin changing them.

The first two numbers are often referred to as the logical version number of an assembly. For example, in the COM world, it is often common to ask, “What version of ADO are you using?” with common answers being “2.5” or “2.6.”

Although the first two numbers might be the logical version, however, the client applications of strongly named assemblies care about all the numbers. The runtime sees assemblies with different version numbers as different assemblies, and this means your client, by default, will see these as different assemblies. It is actually possible for an administrator to override this default behavior if necessary.

Setting the version number can be accomplished in a couple of ways. If you look in the AssemblyInfo.vb file that is created as part of your project, you will see the following line:

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

This will allow you to set the version for the application. Or, you can enter the following lines in the code module for your classes:

Imports System.Reflection
<Assembly: AssemblyVersionAttribute("2.3.4.6")>

These lines have to go outside the classes you have created.

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

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