Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 109 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
109
Dung lượng
1,97 MB
Nội dung
CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES388 To rectify the situation, create a new configuration file named Vb2005CarClient.exe.config and save it in the same folder containing the Vb2005CarClient.exe application, which in this exam- ple would be C:\MyApp. Open this file and enter the following content exactly as shown (be aware that XML is case sensitive!): <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath="MyLibraries"/> </assemblyBinding> </runtime> </configuration> .NET *.config files always open with a root element named <configuration>. The nested <runtime> element may specify an <assemblyBinding> element, which nests a further element named <probing>. The privatePath attribute is the key point in this example, as it is used to specify the subdirectories relative to the application directory where the CLR should probe. Do note that the <probing> element does not specify which assembly is located under a given subdirectory. In other words, you cannot say, “CarLibrary is located under the MyLibraries subdirec- tory, but MathUtils is located under the Bin subdirectory.” The <probing> element simply instructs the CLR to investigate all specified subdirectories for the requested assembly until the first match is encountered. ■Note Be very aware that the privatePath attribute cannot be used to specify an absolute (C:\SomeFolder\ SomeSubFolder) or relative ( \SomeFolder\AnotherFolder) path! If you wish to specify a directory outside the client’s application directory, you will need to make use of a completely different XML element named <codeBase>, described later in the chapter. Multiple subdirectories can be assigned to the privatePath attribute using a semicolon-delimited list. You have no need to do so at this time, but here is an example that informs the CLR to consult the MyLibraries and MyLibraries\Tests client subdirectories: <probing privatePath="MyLibraries;MyLibraries\Tests"/> Once you’ve finished creating Vb2005CarClient.exe.config, run the client by double-clicking the executable in Windows Explorer. You should find that Vb2005CarClient.exe executes without a hitch (if this is not the case, double-check it for typos in your XML document). Next, for testing purposes, change the name of your configuration file (in one way or another) and attempt to run the program once again. The client application should now fail. Remember that *.config files must be prefixed with the same name as the related client application. By way of a final test, open your configuration file for editing and capitalize any of the XML elements. Once the file is saved, your client should fail to run once again (as XML is case sensitive). Configuration Files and Visual Studio 2005 While you are always able to create XML configuration files by hand using your text editor of choice, Visual Studio 2005 allows you create a configuration file during the development of the client program. To illustrate, load the Vb2005CarClient (or CSharpCarClient) solution into Visual Studio 2005 and insert a new Application Configuration File item (see Figure 13-13) using the Project ➤ Add New Item menu selection. Before you click the OK button, take note that the file is named app.config (don’t rename it!). If you look in the Solution Explorer window, you will now find app.config has been inserted into your current project. 5785ch13.qxd 3/31/06 10:56 AM Page 388 CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES 389 At this point, you are free to enter the necessary XML elements for the client you happen to be creating. Now, here is the cool thing. Each time you compile your project, Visual Studio 2005 will automatically copy the data in app.config to the \bin\Debug directory using the proper naming convention (such as Vb2005CarClient.exe.config). However, this behavior will happen only if your configuration file is indeed named app.config. Using this approach, all you need to do is maintain app.config, and Visual Studio 2005 will ensure your application directory contains the latest and greatest content (even if you happen to rename your project). ■Note For better or for worse, when you insert a new app.config file into a VB 2005 project, the IDE will add a good deal of data within an element named <system.diagnostics>, which has nothing to do with assembly binding. For the remainder of this chapter, I will assume that you will delete this unnecessary XML data and author the XML elements as shown in the remaining code examples. Introducing the .NET Framework 2.0 Configuration Utility Although authoring a *.config file by hand is not too traumatic, the .NET Framework 2.0 SDK does ship with a tool that allows you to build XML configuration files using a friendly GUI editor. You can find the .NET Framework 2.0 Configuration utility under the Administrative folder of your Control Panel. Once you launch this tool, you will find a number of configuration options, as shown in Figure 13-14. Figure 13-13. The Visual Studio 2005 app.config file 5785ch13.qxd 3/31/06 10:56 AM Page 389 CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES390 To build a client *.config file using this utility, your first step is to add the application to con- figure by right-clicking the Applications node and selecting Add. In the resulting dialog box, you may find the application you wish to configure, provided that you have executed it using Windows Explorer. If this is not the case, click the Other button and navigate to the location of the client pro- gram you wish to configure. For this example, select the CSharpCarClient.exe application created earlier in this chapter (look under the Bin folder). Once you have done so, you will now find a new subnode, as shown in Figure 13-15. If you right-click the CSharpCarClient node and activate the Properties page, you will notice a text field located at the bottom of the dialog box where you can enter the values to be assigned to the privatePath attribute. Just for testing purposes, enter a subdirectory named MyLibraries (see Figure 13-16). Figure 13-14. The .NET Framework 2.0 Configuration utility Figure 13-15. Preparing to configure CSharpCarClient.exe 5785ch13.qxd 3/31/06 10:56 AM Page 390 CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES 391 Once you click the OK button, you can examine the CSharpCarClient\Bin\Debug directory and find that a new *.config file has been updated with the correct <probing> element. ■Note As you may guess, you can copy the XML content generated by the .NET Framework 2.0 Configuration utility into a Visual Studio 2005 app.config file for further editing. Using this approach, you can certainly decrease your typing burden by allowing the tool to generate the initial content. Understanding Shared Assemblies Now that you understand how to deploy and configure a private assembly, you can begin to exam- ine the role of a shared assembly. Like a private assembly, a shared assembly is a collection of types and (optional) resources. The most obvious difference between shared and private assemblies is the fact that a single copy of a shared assembly can be used by several applications on a single machine. Consider all the applications created in this text that required you to set a reference to System. Windows.Forms.dll. If you were to look in the application directory of each of these clients, you would not find a private copy of this .NET assembly. The reason is that System.Windows.Forms.dll has been deployed as a shared assembly. Clearly, if you need to create a machine-wide class library, this is the way to go. As suggested in the previous paragraph, a shared assembly is not deployed within the same directory as the application making use of it. Rather, shared assemblies are installed into the Global Assembly Cache. The GAC is located under a subdirectory of your Windows directory named Assembly (e.g., C:\WINDOWS\Assembly), as shown in Figure 13-17. Figure 13-16. Configuring a private probing path graphically 5785ch13.qxd 3/31/06 10:56 AM Page 391 CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES392 ■Note You cannot install executable assemblies (*.exe) into the GAC. Only assemblies that take the *.dll file extension can be deployed as a shared assembly. Understanding Strong Names Before you can deploy an assembly to the GAC, you must assign it a strong name, which is used to uniquely identify the publisher of a given .NET binary. Understand that a “publisher” could be an individual programmer, a department within a given company, or an entire company at large. In some ways, a strong name is the modern day .NET equivalent of the COM globally unique identifier (GUID) identification scheme. If you have a COM background, you may recall that AppIDs are GUIDs that identify a particular COM application. Unlike COM GUID values (which are nothing more than 128-bit numbers), strong names are based (in part) on two cryptographically related keys (termed the public key and the private key), which are much more unique and resistant to tampering than a simple GUID. Formally, a strong name is composed of a set of related data, much of which is specified using assembly-level attributes: • The friendly name of the assembly (which you recall is the name of the assembly minus the file extension) • The version number of the assembly (assigned using the <AssemblyVersion> attribute) • The public key value (assigned using the <AssemblyKeyFile> attribute) • An optional culture identity value for localization purposes (assigned using the <AssemblyCulture> attribute) • An embedded digital signature created using a hash of the assembly’s contents and the private key value To provide a strong name for an assembly, your first step is to generate public/private key data using the .NET Framework 2.0 SDK’s sn.exe utility (which you’ll do momentarily). The sn.exe utility responds by generating a file (typically ending with the *.snk [Strong Name Key] file extension) that contains data for two distinct but mathematically related keys, the “public” key and the “private” key. Once the VB 2005 compiler is made aware of the location for your *.snk file, it will record the full public key value in the assembly manifest using the .publickey at the time of compilation. Figure 13-17. The GAC 5785ch13.qxd 3/31/06 10:56 AM Page 392 CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES 393 The VB 2005 compiler will also generate a hash code based on the contents of the entire assembly (CIL code, metadata, and so forth). As you recall from Chapter 6, a hash code is a numerical value that is unique for a fixed input. Thus, if you modify any aspect of a .NET assembly (even a single character in a string literal), the compiler yields a unique hash code. This hash code is combined with the private key data within the *.snk file to yield a digital signature embedded within the assem- bly’s CLR header data. The process of strongly naming an assembly is illustrated in Figure 13-18. Understand that the actual private key data is not listed anywhere within the manifest, but is used only to digitally sign the contents of the assembly (in conjunction with the generated hash code). Again, the whole idea of making use of public/private key data is to ensure that no two com- panies, departments, or individuals have the same identity in the .NET universe. In any case, once the process of assigning a strong name is complete, the assembly may be installed into the GAC. ■Note Strong names also provide a level of protection against potential evildoers tampering with your assem- bly’s contents. Given this point, it is considered a .NET best practice to strongly name every assembly regardless of whether it is deployed to the GAC. Strongly Naming CarLibrary.dll Using sn.exe Let’s walk through the process of assigning a strong name to the CarLibrary assembly created earlier in this chapter (go ahead and open up that project using your IDE of choice). The first order of busi- ness is to generate the required key data using the sn.exe utility. Although this tool has numerous command-line options, all you need to concern yourself with for the moment is the -k flag, which instructs the tool to generate a new file containing the public/private key information. Create a new folder on your C drive named MyTestKeyPair and change to that directory using the .NET Command Prompt. Now, issue the following command to generate a file named MyTestKeyPair.snk: sn -k MyTestKeyPair.snk Now that you have your key data, you need to inform the VB 2005 compiler exactly where MyTestKeyPair.snk is located. When you create any new VB 2005 project workspace using Visual Figure 13-18. At compile time, a digital signature is generated and embedded into the assembly based in part on public and private key data. 5785ch13.qxd 3/31/06 10:56 AM Page 393 CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES394 Studio 2005, you will receive a project file (located under the My Project node of Solution Explorer) named AssemblyInfo.vb. By default, you cannot see this file; however, if you click the Show All Files button on the Solution Explorer, you will see this is the case, as shown in Figure 13-19. This file contains a number of attributes that describe the assembly itself. The AssemblyKeyFile assembly-level attribute can be used to inform the compiler of the location of a valid *.snk file. Simply specify the path as a string parameter, for example: <Assembly: AssemblyKeyFile("C:\MyTestKeyPair\MyTestKeyPair.snk")> In the AssemblyInfo.vb file, you will find another attribute named <AssemblyVersion>. Initially the value is set to 1.0.0.0. Recall that a .NET version number is composed of these four parts: (<major>.<minor>.<build>.<revision>). <Assembly: AssemblyVersion("1.0.0.0")> At this point, the VB 2005 compiler has all the information needed to generate strong name data (as you are not specifying a unique culture value via the <AssemblyCulture> attribute, you “inherit” the culture of your current machine). Compile your CarLibrary code library and open the manifest using ildasm.exe. You will now see a new .publickey tag is used to document the full pub- lic key information, while the .ver token records the version specified via the <AssemblyVersion> attribute, as shown in Figure 13-20. Figure 13-19. The hidden AssemblyInfo.vb file Figure 13-20. A strongly named assembly records the public key in the manifest. 5785ch13.qxd 3/31/06 10:56 AM Page 394 CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES 395 Assigning Strong Names Using Visual Studio 2005 Before you deploy CarLibrary.dll to the GAC, let me point out that Visual Studio 2005 allows you to specify the location of your *.snk file using the project’s Properties page (in fact, this is now consid- ered the preferred approach). To do so, select the Signing node, supply the path to the *.snk file, and select the “Sign the assembly” check box (see Figure 13-21). Installing/Removing Shared Assemblies to/from the GAC The final step is to install the (now strongly named) CarLibrary.dll into the GAC. The simplest way to install a shared assembly into the GAC is to drag and drop the assembly to C:\WINDOWS\Assem- bly using Windows Explorer, which is ideal for a quick test (know that copy/paste operations will not work when deploying to the GAC). In addition, the .NET Framework 2.0 SDK provides a command-line utility named gacutil.exe that allows you to examine and modify the contents of the GAC. Table 13-1 documents some relevant options of gacutil.exe (specify the /? flag to see each option). Table 13-1. Various Options of gacutil.exe Option Meaning in Life /i Installs a strongly named assembly into the GAC /u Uninstalls an assembly from the GAC /l Displays the assemblies (or a specific assembly) in the GAC Using either technique, deploy CarLibrary.dll to the GAC. Once you’ve finished, you should see your library present and accounted for, as shown in Figure 13-22. Figure 13-21. Specifying an *.snk file via the Properties page 5785ch13.qxd 3/31/06 10:56 AM Page 395 CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES396 ■Note You may right-click any assembly icon to pull up its Properties page, and you may also uninstall a specific version of an assembly altogether from the right-click context menu (the GUI equivalent of supplying the /u flag to gacutil.exe). Consuming a Shared Assembly When you are building applications that make use of a shared assembly, the only difference from consuming a private assembly is in how you reference the library using Visual Studio 2005. In reality, there is no difference as far as the tool is concerned (you still make use of the Add Reference dialog box). What you must understand is that this dialog box will not allow you to reference the assembly by browsing to the Assembly folder. Any efforts to do so will be in vain, as you cannot reference the assembly you have highlighted. Rather, you will need to browse to the \bin\Debug directory of the original project via the Browse tab, which is shown in Figure 13-23. Figure 13-22. The strongly named, shared CarLibrary (version 1.0.0.0) Figure 13-23. Correct! You must reference shared assemblies by navigating to the project’s \bin\Debug directory using Visual Studio 2005. 5785ch13.qxd 3/31/06 10:56 AM Page 396 CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES 397 This (somewhat annoying) fact aside, create a new VB 2005 console application named SharedCarLibClient and exercise your types as you wish: Imports CarLibrary Module Program Sub Main() Dim mycar As New SportsCar() mycar.TurboBoost() Console.ReadLine() End Sub End Module Once you have compiled your client application, navigate to the directory that contains SharedCarLibClient.exe using Windows Explorer and notice that Visual Studio 2005 has not copied CarLibrary.dll to the client’s application directory. When you reference an assembly whose manifest contains a .publickey value, Visual Studio 2005 assumes the strongly named assembly will most likely be deployed in the GAC, and therefore does not bother to copy the binary. Exploring the Manifest of SharedCarLibClient Recall that when you generate a strong name for an assembly, the entire public key is recorded in the assembly manifest. On a related note, when a client references a strongly named assembly, its manifest records a condensed hash-value of the full public key, denoted by the .publickeytoken tag. If you were to open the manifest of SharedCarLibClient.exe using ildasm.exe, you would find the following: .assembly extern CarLibrary { .publickeytoken = (21 9E F3 80 C9 34 8A 38) .ver 1:0:0:0 } If you compare the value of the public key token recorded in the client manifest with the public key token value shown in the GAC, you will find a dead-on match. Recall that a public key represents one aspect of the strongly named assembly’s identity. Given this, the CLR will only load version 1.0.0.0 of an assembly named CarLibrary that has a public key that can be hashed down to the value 219EF380C9348A38. If the CLR does not find an assembly meeting this description in the GAC (and cannot find a private assembly named CarLibrary in the client’s directory), a FileNotFound exception is thrown. ■Source Code The SharedCarLibClient application can be found under the Chapter 13 subdirectory. Configuring Shared Assemblies Like a private assembly, shared assemblies can be configured using a client *.config file. Of course, because shared assemblies are found in a well-known location (the GAC), you will not specify a <privatePath> element as you did for private assemblies (although if the client is using both shared and private assemblies, the <privatePath> element may still exist in the *.config file). You can use application configuration files in conjunction with shared assemblies whenever you wish to instruct the CLR to bind to a different version of a specific assembly, effectively bypassing the value recorded in the client’s manifest. This can be useful for a number of reasons. For example, imagine that you have shipped version 1.0.0.0 of an assembly and discover a major bug sometime 5785ch13.qxd 3/31/06 10:56 AM Page 397 [...]... System.Configuration.AppSettingsReader type As shown in the following code, the first parameter to GetValue() is the name of the key in the *.config file, whereas the second parameter is the underlying type of the key (obtained via the VB 20 05 GetType operator): Imports System.Configuration Module Program Sub Main() 57 85ch13.qxd 3/31/06 10 :56 AM Page 4 05 CHAPTER 13 ■ INTRODUCING NET ASSEMBLIES Dim ar As... End Sub 57 85ch14.qxd 3/31/06 1 :51 PM Page 4 15 CHAPTER 14 ■ TYPE REFLECTION, LATE BINDING, AND ATTRIBUTE-BASED PROGRAMMING The logic to display a type’s properties is similar: ' Display property names of type Public Sub ListProps(ByVal t As Type) Console.WriteLine("***** Properties *****") Dim pi As PropertyInfo() = t.GetProperties() For Each prop As PropertyInfo In pi Console.WriteLine("->{0}", prop.Name)... End Sub Implementing Main() The Main() method of the Program class prompts the user for the fully qualified name of a type Once you obtain this string data, you pass it into the Type.GetType() method and send the extracted System.Type into each of your helper methods This process repeats until the user enters Q to terminate the application: 4 15 5785ch14.qxd 416 3/31/06 1 :51 PM Page 416 CHAPTER 14 ■.. .57 85ch13.qxd 398 3/31/06 10 :56 AM Page 398 CHAPTER 13 ■ INTRODUCING NET ASSEMBLIES after the fact One corrective action would be to rebuild the client application to reference the correct version of the bug-free assembly (say, 1.1.0.0) and redistribute the updated client and new library to each and every target machine Another option is to ship the new code library and a *.config file... our examination of ADO.NET (Chapter 24), you will learn about the new configuration element and new types within the System.Configuration namespace These NET 2.0 specific items provide a standard manner to handle connection string data ■ Source Code The AppConfigReaderApp application can be found under the Chapter 13 subdirectory The Machine Configuration File The configuration files... printing the name of the method using the MethodInfo.Name property Of course, MethodInfo has many additional members that allow you to determine whether the method is shared, virtual, or abstract As well, the MethodInfo type allows you to obtain the method’s return value and parameter set You’ll spruce up the implementation of ListMethods() in just a bit Reflecting on Fields and Properties The implementation... reference to the assembly; therefore, the caller’s manifest has no direct listing of the assembly At first glance, you may not understand the value of late binding It is true that if you can “bind early” to a type (e.g., set an assembly reference and allocate the type using the VB 20 05 New keyword), you should opt to do so For one reason, early binding allows you to determine errors at compile time, rather... note that the name of the file containing the public/private key pair will also need to be supplied via the /keyf option (Remember, publisher policy files are deployed to the GAC, and therefore must have a strong name!) Once the al.exe tool has executed, the result is a new assembly that can be placed into the GAC to force all clients to bind to version 2.0. 0.0 of CarLibrary.dll, without the use of... location (via the href 403 57 85ch13.qxd 404 3/31/06 10 :56 AM Page 404 CHAPTER 13 ■ INTRODUCING NET ASSEMBLIES property) of the assembly to load If you were to delete version 2.0. 0.0 of CarLibrary.dll from the GAC, this client would still run successfully, as the CLR is able to locate the external assembly under C:\MyAsms However, if you were to delete the MyAsms directory from your machine, the client... using the graphical NET Framework 2.0 Configuration utility Like the process of building a *.config file for private assemblies, the first step is to reference the *.exe to configure To illustrate, delete the SharedCarLibClient.exe.config you just authored Now, add a reference to SharedCarLibClient.exe by right-clicking the Applications node Once you do, expand the plus sign (+) icon and select the Configured . functionality found in version 2. 0. 0 .0. Under .NET, you are free to ship version 2. 0. 0 .0 to the target machines, and have ver- sion 2. 0. 0 .0 run alongside the older version 1 .0. 0 .0. If necessary, existing. name="MathLibrary" publicKeyToken=" ;21 9ef380c9348a38"/> <bindingRedirect oldVersion= " ;2. 5 .0. 0" 57 85ch13.qxd 3/31 /06 10: 56 AM Page 400 CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES 401 newVersion= "3 .0. 0 .0& quot;/> </dependentAssembly> </assemblyBinding> </runtime> </configuration>. ■ INTRODUCING .NET ASSEMBLIES388 To rectify the situation, create a new configuration file named Vb2 00 5CarClient.exe.config and save it in the same folder containing the Vb2 00 5CarClient.exe application,