Using
COM+ Services in .NET
Summary:
Add new Microsoft .NET components to existing COM and COM+
applications and they will be able to work together; this will help
you if you need to develop a .NET application that can do things like
participate in transactions, take advantage of role-based security,
or interact with a queue.
Objectives
Learn
about using COM+ Services in Microsoft® .NET.
Create
a serviced component.
Deploy
a serviced component.
Assumptions
The following should be
true for you to get the most out of this document:
You
have used Microsoft Transaction Server (MTS) and distributed
transactions in Microsoft Visual Basic® 6.0.
You
have used role-based security with COM+ Services.
You
have created and used queues in COM+ Services.
You
are very familiar with .NET classes.
You
are familiar with creating console applications in .NET.
Contents
Using COM+ Services in
.NET
Developing Transaction-Based Components
Role-Based
Security
Using Queued Components
What's Different in COM+ Since
Visual Basic 6.0?
Summary
Using
COM+ Services in .NET
You probably have used
COM+ Applications to host components that you have written in Visual
Basic or C++. COM+ offers many valuable services, such as
transactions, queued components, just-in-time activation, role-based
security, shared properties, etc. One of the main attractions of
using COM+ to host components was that you could change the way the
component behaved without having to write any code, such as marking a
component's transaction support as Required. By setting a radio
button on your COM+ component from within the Component Services MMC
snap-in, every time your component is created, it is created in the
context of a COM+ transaction. When a component uses COM+
transactions, any database transactions are handled by the
Distributed Transaction Coordinator (DTC). Figure 1 shows an example
of setting the Required Transaction option from within the Component
Services interface.
Figure
1. Sample COM+ component that requires a transaction
Setting the security
for your component is just as easy as setting the transaction
support. You can choose which users can run which components, and
even which methods, without recompiling your code. You choose by
using the COM+ Services snap-in.
.NET
Can Use All COM+ Services
In the .NET Framework,
you can still use all of the services that COM+ offers, as long as
your classes derive from the
System.EnterpriseServices.ServicedComponent class. Any class that
derives from the ServicedComponent class will be hosted by COM+
services and can use any of the available COM+ services. Table 1
shows all of the COM+ services supported in .NET, as well as a short
description of each service.
Table
1. COM+ services available
COM+ | Description |
Automatic | Applies |
COM | Encapsulates |
Compensating | Applies |
Just-In-Time | Activates |
Loosely | Manages |
Object | Passes |
Object | Provides |
Queued | Provides |
Role-Based | Applies |
Shared | Shares |
Synchronization | Manages |
XA | Supports |
Reasons
to Use COM+ Services in .NET
If you will be writing
a .NET application that needs to be able to do things like
participate in transactions, take advantage of role-based security,
or interact with a queue, you will use the COM+ services offered in
.NET. .NET makes these services easy to implement, as you will learn
in this document.
Tip If
you do not need your .NET code to work with COM+ services, that is,
you are only going to be working in the .NET Framework, do not use
System.EnterpriseServices, because there is a performance penalty.
Overview
of COM+ Component Development
When creating
components in .NET that you want to interact with COM+ Services, you
perform the following steps. Table 2 includes an explanation of each
step.
Create a Class
Library.
Create
all classes so they inherit from the
System.EnterpriseServices.ServicedComponents class.
Create
an assembly.
Create
a strong name.
Table
2. Definition of terms used in creating a .NET component
Term | Description |
Class | A |
System.EnterpriseServices.ServicedComponents | A |
Assembly | A |
Strong | Generates |
Developing
Transaction-Based Components
In the first part of
this document, you will learn to create a .NET component that uses
the transactional services of COM+. You will learn how to write both
the component and the front-end application that interacts with this
component.
Creating
a COM+ Transaction Component
There are a few steps
that you need to go through to get a .NET component to run under COM+
services. To begin, you have to create a class that derives from the
System.EnterpriseServices.ServicedComponent class. This base class
gives you all of the appropriate methods and properties needed to
interact with COM+ services. You need to mark the class as requiring
a new transaction, and mark any methods you create as able to
automatically complete the transaction if no errors occur. Let's try
it.
Open Microsoft Visual
Studio® .NET and create a new project as a ClassLibrary project.
Rename
the Class1.vb file to COMPlusServices.vb.
Open
the COMPlusServices.vb file and change the class name from Class1 to
COMPlusServices.
Type
in the code shown below into this new class.
Imports
System.EnterpriseServices
Imports
System.Reflection
'********************************************
'COM+ Registration
details
'Supply the COM+
application name
<Assembly:
ApplicationNameAttribute("ComPlusExample")>
'Supply a strong-name
assembly
<Assembly: _
AssemblyKeyFileAttribute("bin/ComPlusExample.snk")>
'********************************************
<TransactionAttribute(TransactionOption.Required)>
_
Public Class
COMPlusServices
Inherits
ServicedComponent
Public Sub New()
MyBase.New()
End Sub
<AutoComplete()>
Public Function DoTransaction() _
As String
Return "Success
with COM+"
End Function
End Class
This code starts out by
importing a couple of namespaces to eliminate some typing when
declaring components.
Next are COM+
registration details. Enter the following line of code:
'Supply the COM+
application name
<Assembly:
ApplicationNameAttribute("ComPlusExample")>
This line assigns the
ApplicationNameAttribute a value of ComPlusExample. This is what the
name of the COM+ application will be when it is registered in the
COM+ Catalog. After the first time this component is called, when you
go into the COM+ Applications folder in the MMC snap-in, you will see
this as the application name.
The next part of the
code declares the AssemblyKeyFileAttribute attribute:
<Assembly: _
AssemblyKeyFileAttribute("bin/ComPlusExample.snk")>
This informs the COM+
catalog where the information about the strong name is located. You
will create the .SNK file in a later step, but it is the file that
describes the component to COM+.
You will now finally
declare the Class name, COMPlusServices, using the following code.
<TransactionAttribute(TransactionOption.Required)>
_
Public Public Class
COMPlusServices
The attribute in front
of this class name informs COM+ that you wish to set the transaction
attribute to Required. Adding this line of code is the same as going
into the COM+ Applications snap-in, as shown in Figure 1, and setting
this attribute manually.
The next line of code
in the class inherits from the ServicedComponent within the
System.EnterpriseServices namespace.
Inherits
ServicedComponent
If you do not include
this line, you will be unable to make this component work under COM+.
Add
a Transaction Method
Now that the setup of
this class is complete, you can create a method that will actually do
something. The function DoTransaction in the code you wrote returns a
string value, but shows the syntax you must use to have this method
participate in a transaction.
<AutoComplete()>
Public Function DoTransaction() As String
Return "Success
with COM+"
End Function
It is important that
you prefix this method with the <AutoComplete()> attribute.
This means that as long as there is not an exception in this method,
SetComplete will be automatically called when this method finishes.
If there is an exception in the method, the .NET runtime
automatically calls the SetAbort method. This is different than
writing COM components in Visual Basic 6.0, where you had to
explicitly call SetComplete and SetAbort on your own.
Create
a Strong Name
Before compiling your
component, you need to give your assembly for this component a strong
name. If you do not do this, the COM+ Catalog will not recognize your
component and will not be able to register it. Actually, you have
already done this via the AssemblyKeyFile attribute that you used
earlier, but now you need to create the strong name and associate a
GUID with your assembly by using the Strong Name Tool (Sn.exe).
Open a command prompt.
To
create the strong name, type the following at a command prompt and
then press Enter.
sn -k ComPlusExample.snk
Copy the
ComPlusExample.snk file from the root folder of your hard drive
(most likely C:/) into the bin directory under the folder where your
project is.
You now need to compile
this program so it can build the necessary files needed to register
this component with COM+. In Visual Studio .NET, on the Build
menu, click Build.
Build
a Client Test Application
Now that you have built
your component, you need to build a client application to call this
component and test it out. Create a simple console application where
the module file's Main method creates an instance of your new
component, and calls the DoTransaction() method. Here are the main
steps.
In Visual Basic .NET,
create a new console application project.
Add
a reference to the component that you just created.
Type
in the code shown below.
Module modMain
Sub Main()
Dim objCOMPlus
As New _
COMPlusJumpStart.COMPlusServices()
Console.WriteLine(objCOMPlus.DoTransaction)
Console.ReadLine()
End Sub
End Module
Try
It Out
You are finally ready
to run this application and see it work.
Open the Component
Services MMC snap-in and verify that your component was dynamically
registered into the COM+ Catalog. You should see something that
looks like Figure 2.
Compile
and run the console application.
Figure
2. The new .NET serviced component in the COM+ Catalog
Role-Based
Security
When you have many
users making calls to COM components that run under COM+, you need to
verify that only specific people have access to certain components.
COM+ allows you to define roles and assign NT users to those roles.
Once these roles are in place, you can assign which roles can run
which components, and even which methods on those components can be
run.
Let's add a method to
this same COMPlusServices class to incorporate role-based security.
You will create a role called Managers, and in the new method, test
to see if the caller is in the Managers role.
Steps
to Add Role-Based Security
Instead of directly
modifying the COM+ application from the Component Services MMC
snap-in to add the security role, you will add a new attribute to
your project. You will use the SecurityRoleAttribute class to add the
new Managers role. The constructor for this class has two arguments:
role (string) and everyone (Boolean). The role
argument specifies the name of the role to be created, and the
everyone argument
specifies whether or not the built-in Everyone group is added to the
users of the role.
Add a new security
role to the COM+ application by typing in the following code just
below the comment COM+ Registration details.
'********************************************
'COM+ Registration
details
'Role-based security
attribute
<Assembly:
SecurityRoleAttribute("Managers", False)>
Change the security
level setting to perform access checks at the process and component
level. This enables the COM+ application to have a security call
context.
Bring
up the COM+ Services snap-in.
Click
the Security
tab and change the security level, as shown in Figure 3.
Figure
3. Setting the security level property in the COM+ Catalog
As an alternative to
the manual process, you could add an attribute to your component
telling it to perform access-level checks. Below is the code to add
within the COM+ Registration detail section at the top of your
COMPlusServices class.
<Assembly:
ApplicationAccessControlAttribute
(AccessChecksLevel:=AccessChecksLevelOption.ApplicationComponent)>
Check
for a Security Role
You will now add a new
method to the class called IsManager. This method will check to see
if the user is a member of the role Managers. This method is a
function and returns a Boolean value indicating whether or not the
caller is part of the Managers role. In order to get access to the
security context of the user calling the method, you need to use the
SecurityCallContext class. You get the current caller's context by
calling the CurrrentCall method. Then, you call the IsCallerInRole
method, and pass in Managers as the name of the role.
Add the method shown
below to the COMPlusServices class.
Public Function
IsManager() As Boolean
Dim objCallContext
As SecurityCallContext = _
SecurityCallContext.CurrentCall
IsManager = _
objCallContext.IsCallerInRole("Managers")
End Function
You will now need to
rebuild the component to try out this new method.
From the Visual Studio
.NET Build
menu, click Rebuild
Solution.
Try
It Out
Modify the code in the
Sub Main() method of your console client application. Here is what
the code should look like:
Sub Main()
Dim objCOMPlus As
New _
COMPlusJumpStart.COMPlusServices()
Console.WriteLine(objCOMPlus.DoTransaction)
Console.WriteLine(objCOMPlus.IsManager().ToString)
Console.ReadLine()
End Sub
Run the console
application from the command prompt by typing in the name of the
executable you compiled.
The first time you run
the code, you should get an exception stating that access was denied
because no users were added to the Managers role. To correct this,
add yourself as a user to Managers, and re-run the application. This
time, there should not be any exceptions. You could also add
exception handling to your code. Here is what your client should like
with the exception handling code:
Sub Main()
Try
Dim objCOMPlus As
New _
COMPlusJumpStart.COMPlusServices()
Console.WriteLine(objCOMPlus.DoTransaction)
Console.WriteLine(objCOMPlus.IsManager().ToString)
Console.ReadLine()
Catch objException As
Exception
Console.WriteLine("An
error occurred. " _
& "Details:
" _
&
objException.Message)
Console.ReadLine()
End Try
End Sub
Using
Queued Components
In COM+ applications,
it is easy to add queuing support. You just make sure that the
application is running as a server application (out of process), and
then you set its Queued and Listen properties on the Queuing tab.
Once these settings are made, client applications can call your
components asynchronously or synchronously. The beauty of this
feature is that you do not have to change the code in your COM
object; you just change its properties in the COM+ Catalog.
The .NET Framework
supports queued components, and as you might expect, you can give
your components queuing support by using attributes instead of
manually changing the COM+ Catalog.
Let's add a method to
the COMPlusServices class, and call it asynchronously using COM+
Queued Components services from a .NET client application.
Make your COM+
application a server application (out of process). This is a
requirement for Queued Components. To do this via attributes, add
the following code to your project:
'********************************************
'COM+ Registration
details
<Assembly:
ApplicationActivationAttribute(ActivationOption.Server)>
Add queuing support to
your component. Make it accessible to MSMQ queues, and make it
listen to its own queue to process messages. Here is the code to do
this via attributes:
'********************************************
'COM+ Registration
details
<Assembly:
ApplicationQueuingAttribute(Enabled:=True,
QueueListenerEnabled:=True)>
Add a method to your
class called QueueTest. Make sure that it is a subroutine; it cannot
have a return value. Have it write a message to the Windows
Application Log. Here is what the code should look like:
Public Sub QueueTest()
System.Diagnostics.EventLog.WriteEntry(_
"COMPlusServces",
"Queue Test", _
Diagnostics.EventLogEntryType.Error)
End Sub
That's it. That is all
you have to do to enable your component to be a COM+ Queued
Component.
Try
It Out
You should now try out
this queued component by creating another console application and
calling this component.
Create a new console
application.
Add
the following code to the Sub Main procedure of this console
application.
Sub Main()
Dim objTest As
COMPlusJumpStart.COMPlusServices
Dim strMoniker
strMoniker = _
"queue:/new:COMPlusJumpStart.COMPlusServices"
objTest =
GetObject(strMoniker)
objTest.QueueTest()
End Sub
This asynchronously
calls the QueueTest method on your component. If you wanted to call
your method synchronously, you would call it like you have all of the
other methods in your component.
You can now run this
console application to try out this queued component.
What's
Different in COM+ Since Visual Basic 6.0?
There are many things
that you already know from Visual Basic 6.0 or COM that are the same
in .NET. But now you have the benefit of working within the .NET
Framework, which helps objects interact smoothly, with a minimum of
coding and maintenance on your part.
Typical of this sort of
streamlining, in Visual Basic 6.0, you had to explicitly call
SetComplete and SetAbort on your own. In .NET, the SetComplete and
SetAbort are called by the <AutoComplete()> attribute.
Another difference
between Visual Basic .NET and Visual Basic 6.0 is that Visual Basic
6.0 components can't make use of COM+ object pooling because they use
the Single Threaded Apartment threading model. Visual Basic .NET
components are .NET components and as such, support the Any Apartment
threading model and hence can make use of COM+ object pooling.
Summary
As you can see, the
.NET Framework makes it easy to take advantage of the services that
COM+ offers. This means that you can add new .NET components to
existing applications written with COM and COM+, and they will be
able to work together. This is very important, because it means that
you do not have to throw away all of your existing COM and COM+ code.
If you are building a new application from scratch, it is highly
recommended that you build it entirely in the .NET Framework, as it
will be much more efficient.
1
0 comments:
Post a Comment