Tải bản đầy đủ (.pdf) (10 trang)

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

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (277.98 KB, 10 trang )

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

×