1. Trang chủ
  2. » Công Nghệ Thông Tin

Professional ASP.NET 3.5 in C# and Visual Basic Part 136 pdf

10 252 0

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 277,98 KB

Nội dung

Evjen c28.tex V2 - 01/28/2008 3:52pm Page 1313 Chapter 28: Using Business Objects file for a second time. Using this method meant that when you upgraded a component, you automatically upgraded all the utilizing applications. However, this practice didn’t work out so well. In fact, it became a very big contributor to DLL hell and the main reason why Microsoft began promoting the practice of installing private .NET component assemblies. After you have your components physically in place, the only remaining task is to register the ActiveX component using regsvr32, just as you would when deploying an ActiveX-enabled application. Public Assemblies The opposite of a private assembly is a public assembly. Public assemblies share the RCW Interop DLL for other applications. In order to create a public assembly, you must put the RCW file into the Global Assembly Cache (GAC), as shown in Figure 28-11. MyApp.exe C:\Program Files\First Application Location\ YourApp.exe C:\Program Files\Second Application Location\ Interop.MyCOM.dll Global Assembly Cache (GAC) MyCOM.dll C:\Program Files\Third Party COM Controls\ (Managed Code) (RCW) (Managed Code) (ActiveX DLL) Figure 28-11 You can find the GAC at C: \ Windows \ assembly . Installing items in the GAC can be as simple as dragging- and-dropping the item into this folder through Windows Explorer. Although the GAC is open to every- one, it is not recommended that you blindly install your components into this section unless you have a very good reason to do so. You can also add items to the GAC from the command line using the Global Assembly Cache Tool (Gacu- til.exe). It enables you to view and manipulate the contents of the global assembly cache and download cache. While the Explorer view of the GAC provides similar functionality, you can use Gacutil.exe from build scripts, makefile files, and batch files. It is hard to find a very good reason to install your ActiveX Interop Assemblies into the GAC. If we had to pick a time to do this, it would be if and when we had a highly shared ActiveX component that many .NET applications would be utilizing on the same machine. In a corporate environment, this might occur when you are upgrading existing business logic from ActiveX to .NET enablement on a server that many applications use. In a commercial setting, we avoid using the GAC. 1313 Evjen c28.tex V2 - 01/28/2008 3:52pm Page 1314 Chapter 28: Using Business Objects Using .NET from Unmanaged Code .NET provides the opposite of COM interoperability by enabling you to use your newly created .NET components within unmanaged code. This section discusses using .NET components with Visual Basic 6 executables. The techniques shown in this section are identical when you are using ActiveX OCXs or DLLs instead of executables. The COM-Callable Wrapper (CCW) is the piece of the .NET Framework that enables unmanaged code to communicate with your .NET component. The CCW, unlike the RCW, is not a separate DLL that you distribute with your application. Instead, the CCW is part of the .NET Framework that gets instantiated once for each .NET component that you are using. Figure 28-12 shows how the CCW marshals the communication between the unmanaged code and the .NET component in much the same way that the RCW marshals the code between managed code and COM code. Your ActiveX Code .NETs Built-In Interoperability Technology Your .NET Component Code Managed CodeUnmanaged Code COM Code COM- Callable Wrapper (CCW) .NET Component Figure 28-12 The COM-Callable Wrapper The COM-Callable Wrapper or CCW, as previously stated, is not a separate DLL like the RCW. Instead, the CCW uses a specially created type library based on the .NET component. This type library is called an Interop Type Library. The Interop Type Library is statically linked with the unmanaged code so that this code can communicate with the CCW about the .NET component included in your application. In order for a .NET component to generate an Interop Type Library, you tell Visual Studio 2008 to gen- erate it when the component is built. Both Visual Basic and C# projects have a setting in the Compile properties section of the Class Library project’s Property Pages dialog. Right-click the project in the Solution Explorer and choose Properties to see the project’s properties. Figure 28-13 shows the project’s properties for a Visual Basic 2008 Class Library application. This is shown directly in the Visual Studio document window. 1314 Evjen c28.tex V2 - 01/28/2008 3:52pm Page 1315 Chapter 28: Using Business Objects Figure 28-13 C# has a slightly different dialog, as shown in Figure 28-14. In both dialogs, the property is called Register for COM Interop. In Visual Basic, you can find this property on the Compile page; in C#, you can find it on the Build tab of the properties pages. After you set this option by checking the check box, when you build the project a separate type library file ( .tlb ) is generated for the DLL that you are building. This .tlb file is your key to including .NET components in COM applications. Normally in Visual Basic, when you add a reference to a DLL, you navigate from the References section of the Visual Basic project to find the ActiveX DLL that you want to add. If you use .NET components, they cannot be properly referenced in this manner because they are not ActiveX. Instead, you reference the Interop Type Library, which makes the functionality of the corresponding .NET component available to your application. The .NET Framework also gives you a method to create Interop Type Library files manually for .NET components. You do this through a command-line tool called the Type Library Exporter (as compared to the Type Library Importer used for COM Interoperability). The Type Library Exporter is invoked using the tlbexp.exe executable. 1315 Evjen c28.tex V2 - 01/28/2008 3:52pm Page 1316 Chapter 28: Using Business Objects Figure 28-14 For example, to create the Interop Type Library for the NameComponent.dll in the next example, you use the following command: tlbexp NameComponent.dll /out:NameComponentEx.tlb The /out: parameter specifies the name of the Interop Type Library that is to be created. If you omit this parameter, you get a file with the same name as the ActiveX component, but with a .tlb extension. The Type Library Exporter is useful when you are not using Visual Studio 2008 as your development environment, if you want to have more control over the assemblies that get created for you, or if you are automating the process of connecting to .NET components. Using .NET Components Within COM Objects The next example illustrates how .NET components can be utilized within COM code. To begin, create and compile the .NET code found in Listing 28-5 in either Visual Basic or C#. After you have typed your code into your Class Library project, build the component and call it Name- Component . Remember to choose to include the Register for the COM Interop setting of True (by checking the appropriate check box) from the project properties pages, as shown in Figure 28-13 for Visual Basic code and Figure 28-14 for C# code. If you aren’t using Visual Studio 2008, you can use tblexp.exe to generate the Interop Type Library manually as described previously. 1316 Evjen c28.tex V2 - 01/28/2008 3:52pm Page 1317 Chapter 28: Using Business Objects Listing 28-5: The .NET component VB Public Class NameFunctions Private m_FirstName As String Private m_LastName As String Public Property FirstName() As String Get Return m_FirstName End Get Set(ByVal Value As String) m_FirstName = Value End Set End Property Public Property LastName() As String Get Return m_LastName End Get Set(ByVal Value As String) m_LastName = Value End Set End Property Public Property FullName() As String Get Return m_FirstName + " " + m_LastName End Get Set(ByVal Value As String) m_FirstName = Split(Value, " ")(0) m_LastName = Split(Value, " ")(1) End Set End Property Public ReadOnly Property FullNameLength() As Long Get FullNameLength = Len(Me.FullName) End Get End Property End Class C# using System; using System.Runtime.InteropServices; namespace NameComponent Continued 1317 Evjen c28.tex V2 - 01/28/2008 3:52pm Page 1318 Chapter 28: Using Business Objects { [ComVisible(true)] public class NameFunctions { private string m_FirstName; private string m_LastName; public string FirstName { get { return m_FirstName; } set { m_FirstName=value; } } public string LastName { get { return m_LastName; } set { m_LastName=value; } } public string FullName { get { return m_FirstName + " " + m_LastName; } set { m_FirstName=value.Split(’ ’)[0]; m_LastName=value.Split(’ ’)[1]; } } public long FullNameLength { get { return this.FullName.Length; } } } } 1318 Evjen c28.tex V2 - 01/28/2008 3:52pm Page 1319 Chapter 28: Using Business Objects After you have created the .NET component, you can then create the consuming Visual Basic 6 code shown in Listing 28-6. Listing 28-6: VB6 code using the .NET component Option Explicit Public Sub Main() Dim o As NameComponent.NameFunctions Set o = New NameComponent.NameFunctions o.FirstName = "Bill" o.LastName = "Evjen" MsgBox "Full Name is: " + o.FullName MsgBox "Length of Full Name is: " + CStr(o.FullNameLength) o.FullName = "Scott Hanselman" MsgBox "First Name is: " + o.FirstName MsgBox "Last Name is: " + o.LastName o.LastName = "Evjen" MsgBox "Full Name is: " + o.FullName Set o = Nothing End Sub Remember to add a reference to the .NET component. You choose Project ➪ References and select the .NET component that was created either by Visual Studio or by manually using tlbexp.exe . When you run the code in Listing 28-6, you see that Visual Basic 6 does not miss a beat when communi- cating with the .NET component. It is also possible to register the assemblies yourself. Earlier you learned how to manually create Interop Type Libraries with the Type Library Exporter. This tool does not register the assemblies created but instead generates only the type library. To register the assemblies yourself, you use the Assembly Registration Tool ( regasm.exe ). This tool is similar the regsvr32.exe for .NET components. To use regasm.exe , use a command syntax similar to the following example: regasm NameComponent.dll /tlb:NameComponentEx.tlb /regfile:NameComponent.reg The /tlb: option specifies the name of the type library, and the /regfile: option specifies the name of a registry file to be created that can be used later in an installation and deployment application. 1319 Evjen c28.tex V2 - 01/28/2008 3:52pm Page 1320 Chapter 28: Using Business Objects Early versus Late Binding The preceding example illustrates the use of early binding, the technique most Visual Basic 6 developers are used to. However, in some cases, it is desirable to use late binding. Performing late binding with .NET components is similar to performing late binding with ActiveX components, as shown in Listing 28-7. Listing 28-7: Late binding with VB6 Option Explicit Public Sub Main() Dim o As Object Set o = CreateObject("NameComponent.NameFunctions") o.FirstName = "Bill" o.LastName = "Evjen" MsgBox "Full Name is: " + o.FullName MsgBox "Length of Full Name is: " + CStr(o.FullNameLength) o.FullName = "Scott Hanselman" MsgBox "First Name is: " + o.FirstName MsgBox "Last Name is: " + o.LastName o.LastName = "Evjen" MsgBox "Full Name is: " + o.FullName Set o = Nothing End Sub Error Handling Handling errors that are raised from .NET components in Visual Basic 6 is easily accomplished via the Interop functionality. Listing 28-8 shows code for both Visual Basic and C# to throw exceptions for a custom error. When the Numerator or the Denominator parameters are greater than 1000 in the Divide function, a custom exception is thrown up to the calling code, which is Visual Basic 6 in this example. Notice how the divide-by-zero error possibility is not handled in this example. This is done intentionally to demonstrate how interoperability handles unhandled errors. Listing 28-8: Raising errors VB Public Class CustomException Inherits Exception 1320 Evjen c28.tex V2 - 01/28/2008 3:52pm Page 1321 Chapter 28: Using Business Objects Sub New(ByVal Message As String) MyBase.New(Message) End Sub End Class Public Class DivideFunction Public Function Divide(ByVal Numerator As Double, _ ByVal Denominator As Double) As Double If ((Numerator > 1000) Or (Denominator > 1000)) Then Throw New CustomException("Numerator and denominator both " & _ "have to be less than or equal to 1000.") End If Divide = Numerator / Denominator End Function End Class C# using System; namespace DivideComponent { public class CustomException:Exception { public CustomException(string message):base(message) { } } public class DivideFunction { public double Divide(double Numerator, double Denominator) { if ((Numerator > 1000) || (Denominator > 1000)) throw new CustomException("Numerator and denominator " + "both have to be less than or equal to 1000."); return Numerator / Denominator; } } } Now that you have the code for the .NET component, compile it with the Register for COM Interop flag set to True in the project’s Property Pages dialog and call the component DivideComponent . The consuming Visual Basic 6 code is shown in Listing 28-9. Remember to add a reference to the Interop Type Library of the DivideComponent generated by Visual Studio. 1321 Evjen c28.tex V2 - 01/28/2008 3:52pm Page 1322 Chapter 28: Using Business Objects Listing 28-9: VB6 experiencing .NET errors Option Explicit Public Sub Main() Dim o As DivideComponent.DivideFunction Set o = New DivideComponent.DivideFunction MsgBox "1 divided by 3: " + CStr(o.divide(1, 3)) MsgBox "1 divided by 0: " + CStr(o.divide(1, 0)) MsgBox "2000 divided by 3000: " + CStr(o.divide(2000, 3000)) Set o = Nothing End Sub The Visual Basic 6 code example in Listing 28-9 does not handle the errors thrown by the .NET compo- nent, but it can easily do so using On Error , Visual Basic 6’s method for trapping raised errors. Instead of trapping the errors, make sure that the Error Trapping setting in the Options dialog of Visual Basic 6 is set to Break in Class Module. When the application is run, the first example of 1 divided by 3 works fine; you see the output properly. The second example, which you would expect to end in a divide-by-zero error, does not. Instead, an invalid property value is returned to Visual Basic 6. The final example, which does not pass the custom error handling in the .NET component, raises a Visual Basic error, as you would expect. Deploying .NET Components with COM Applications Deploying .NET components with COM applications is similar to deploying COM components. There are two scenarios in this deployment scheme: ❑ Using private assemblies ❑ Using shared assemblies The following sections discuss these two scenarios. Private Assemblies Private assemblies mean the deployment of the .NET component is installed in each individual directory where the application is installed, within the same machine. The only needed component is the .NET DLL and the calling application. The Interop Type Library that you created earlier with Visual Studio 2008 or tlbexp.exe is statically linked with the component or application that references the .NET component. The only additional task you must complete is to properly register the .NET assembly using regasm.exe . This is an extra step that is not needed in 100 percent .NET applications; it is required only for the 1322 . many applications use. In a commercial setting, we avoid using the GAC. 131 3 Evjen c28.tex V2 - 01/28/2008 3: 52 pm Page 131 4 Chapter 28: Using Business Objects Using .NET from Unmanaged Code .NET provides. in some cases, it is desirable to use late binding. Performing late binding with .NET components is similar to performing late binding with ActiveX components, as shown in Listing 28-7. Listing. components. Using .NET Components Within COM Objects The next example illustrates how .NET components can be utilized within COM code. To begin, create and compile the .NET code found in Listing 28 -5 in

Ngày đăng: 05/07/2014, 19:20