Understanding COM+ with VFP, Part 2
This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.
Understanding COM+ with VFP, Part 2
Craig Berntson
In Part 2 of this series, Craig Berntson examines client distribution,
security, and error handling.
In Part 1 of this series (see the May 2001 issue of FoxTalk), I
reviewed COM and MTS and introduced COM+ services under Windows 2000. I also
showed you how to create a new COM+ application and install a component on the
server. Now in Part 2, I'll look at how to get the client to use the component
on the server, security, and error handling.
Is the client always right?
Last month, I showed you how to install your application on the
server. But that doesn't do much good if you can't get to the component from the
client. The good news is, Windows 2000 makes it easy to set things up on the
client. Let's go back to the component we built and installed last month. As a
quick review, here's the component code:
DEFINE CLASS Math AS SESSION OLEPUBLIC
FUNCTION Multiply(tnNum1, tnNum2)
LOCAL lnResult, loMtx, loContext
* Create a reference to the MTS object
loMtx = CREATEOBJECT("MTXAS.APPSERVER.1")
* Create a reference to the context object
loContext = loMtx.GetObjectContext()
lnResult = tnNum1 * tnNum2
* Commit the transaction if there is one and
* tell MTS that we're done using the component
loContext.SetComplete()
RETURN lnResult
ENDFUNC
ENDDEFINE
I call this the world's dumbest COM component. All it does is multiply two
numbers. However, keeping the sample code simple allows us to concentrate on the
COM+ aspects of the example.
Now we need to do an install on the client. Let's go back to the Component
Services Manager. Expand the tree under COM+ Applications and select
MyFirstCOMApp. This is the COM+ Application that we built and installed last
month. Now right-click on MyFirstCOMApp and select Export. The COM Application
Export Wizard will appear (see
Figure 1). You're
first prompted to enter the full path and filename for the application file.
Enter C:\COMApps\MyFirstCOMAppProxy. Then make sure you've selected
"Application Proxy—Install on other machines to enable access to this
machine." (The other option, "Server Application," is used when
you want to install the component on another server.) Then click Next and then
Finish.
The wizard has created two files—MyFirstCOMAppProxy.MSI.CAB and
MyFirstCOMAppProxy.MSI. These files can be copied and installed on the client
computer. These files don't include the component. You don't need it on the
client. They contain information on the public methods and properties of the
component and pointers to the server so that Windows can find the component and
instantiate it.
Again, you never install the component on the client. Instead, you install a
proxy. Your application thinks the component is installed and running locally,
but it isn't. Make note of this. A component installed on an application server
never runs on the client. For some reason, this is a difficult concept for some
people to understand.
You instantiate the server component exactly the same way you instantiate a
local component. Try this in the Command Window:
ox = CREATEOBJECT("MyCom.Math")
? ox.Multiply(3, 4) && returns 12
ox = NULL
Why did this work? VFP makes a call to Windows, asking for the component to
be instantiated. Windows looks up the component information in the Registry and
finds that the component lives on an application server. Windows then
instantiates a proxy to the component and makes a call to the server to
instantiate the component. VFP doesn't know it's talking to the proxy; it thinks
it's talking directly to the component. When you call the Multiply method, the
proxy sends the call to the server via DCOM and the result is passed back to the
proxy, which passes it on to VFP.
Are you feeling insecure?
Now that the component is installed on the server and the client
proxies are installed, let's see how easily we can grant or prohibit access to
the component. COM+ uses role-based security. A role is a type of user. For
example, in a bank you might have tellers, managers, loan officers, customer
service people, and so forth. Each of these people is a role. You want to
prohibit tellers from making loans, so in COM+, you could set up security on a
loan component to prohibit this. The nice thing is that this is a configuration
option and easy to change using the Component Services Manager.
Roles are based on Windows users and groups, so the first step in setting up
the security scheme is to establish the Windows security groups. It can be
confusing to understand where roles fit in the hierarchy of groups and users.
The COM+ Help file states, "Roles are categories of users that have been
defined for the application for the purpose of determining access permissions to
the application's resources. The developer assigns the roles (as symbolic user
categories) to the application." That sounds a lot like a Windows user
group to me, so to keep it easy, think of a role as a user group that's
application-specific.
Now, getting back to our bank example, we'd have four groups: tellers,
managers, loan officers, and customer service. Go ahead and create them on the
server using Windows User Manager in NT or the Computer Management Applet in
Windows 2000. Enter the first user group, and then the other three.
Once those groups are created, go back to MyFirstCOMApp in the Component
Services Manager. Click on Roles, and then right-click and select New Role.
Enter the first role, Teller, and click OK (see
Figure 2).
It's not necessary to name the roles the same as the Windows user groups, but it
makes management easier. Now create the three remaining roles of Manager, Loan
Officer, and Customer Service.
Next we need to identify the users in each role. Expand the tree under
Teller. You'll see a folder labeled "Users." Click on the folder, and
then right-click and select New User. Scroll down the list of Windows users and
groups and select the Tellers user group, and then click Add. Do the same for
Managers and Customer Service. Then click OK. You'll see each of the Windows
Security groups added to the Teller role in Component Services (see
Figure 3).
When new users are added to the system, they're added to the proper Windows
group, which in turn automatically puts them in the proper role. So far, we've
identified the roles, but we haven't told Component Services to use any
security. Click on MyFirstCOMApp, right-click and select Properties, and then
select the Security tab. Check "Enforce access checks for this
application," and then click OK (see
Figure 4).
Ignore the other options for now, I'll discuss them shortly.
Now right-click on MyComm.Math and select Properties, then the Security tab.
You'll see that "Enforce component level access checks" is selected.
You'll also see the security roles listed. Simply check the roles that are to
have access to this component (see
Figure 5).
You can drill down and assign the security access to the interface or method
level if you want. This enables you to have a single component with several
interfaces, each having different security levels. If a user doesn't have the
proper access to use a component, an error message is returned stating that the
component couldn't be instantiated.
Now, let's go back to the Application Security dialog box (see
Figure 4). There are some additional options that I
need to discuss. The first is Security level. This controls when COM+ validates
the user's security. With the first option, "Perform access checks only at
the process level," role-checking won't be done at the component,
interface, or method levels. Under the second option, "Perform access
checks at the process and component level," the security role is checked
when a call is made to the component. You'll almost always use the second
option. However, the first option is useful when you've already validated the
user.
The next setting is "Authentication level for calls." There are six
options, as described in Table 1. As
you move through the list, each option gets progressively more secure. Note that
the higher the level of security, the longer it takes to validate the user. The
default level is Packet.
Table 1. Authentication levels.
|
Level |
Description |
|
None |
No authentication. |
|
Connect |
Checks security only when the client
connects to the component. |
|
Call |
Check security at the beginning of every
call. |
|
Packet |
Checks security and validates that all data
was received. |
|
Packet Integrity |
Checks security and validates that none of
the data was modified in transit. |
|
Packet Privacy |
Checks security and encrypts the packet. |
Finally, we have "Impersonation level." This sets the level of
authority that the component gives to other processes. There are four different
levels as described in Table 2. The
default is Impersonate.
Table 2. Impersonation levels.
| Level | Description |
| Anonymous | The second process knows nothing about the
client. |
| Identify | The second process can identify who the
client is. |
| Impersonate | The second process can impersonate the
client, but only for processes on the same server. |
| Delegate | The second process can impersonate the
client in all instances. |
Thus far, I've discussed declarative, role-based security, which is defined
and managed at runtime. You can also use programmatic security. This allows you
to branch your code based on the access level of the user. For example, a loan
officer might only be able to authorize a loan up to $50,000. After that, it
takes a manager's approval to authorize the loan.
DO CASE
CASE IsCallerInRole("Loan Officer")
lnMaxLoanAmt = 50000
CASE IsCallerInRole("Manager")
lnMaxLoanAmt = 1000000
OTHERWISE
lnMaxLoanAmt = 1000000000
ENDCASE
By using both role-based and programmatic security, you can support just
about any security scheme that you need.
Error handling
One of the questions I often see on online forums is, "How do I
report an error back to the user?" If you think about this, the answer
doesn't seem easy. You can't display any dialog boxes with the error from your
component. It's running on a different computer than the user interface. VFP has
the COMRETURNERROR() function to send the error message back to the client.
COMRETURNERROR() takes two parameters. The first is the name of the module where
the error occurred. The second is the message to display to the user. Let's look
at the code.
DEFINE CLASS ErrorExample AS SESSION OLEPUBLIC
PROCEDURE Error(tnError, tcMethod, tnLine)
LOCAL lcMessage
lcMessage = "Here is my error message"
COMRETURNERROR(tcMethod, lcMessage)
ENDPROC
FUNCTION CauseError
ERROR 15
RETURN "This will never be displayed"
ENDFUNC
ENDDEFINE
Now compile the code into a DLL and instantiate it.
ox = CREATEOBJECT("MyError.ErrorExample")
? ox.CauseError()
You might expect "This will never be displayed" to show on the VFP
desktop. However, an error dialog box appears instead.
You can return any error information you want in the message parameter. You
also might want to enhance the error method by capturing additional information
using AERROR() or writing information to an error log. There's one caveat: The
Error method won't fire if an error occurs in the Init method.
Conclusion
That pretty much covers installation, security, and error handling.
Next month, I'll discuss transactions and see how COM+ and VFP 7 allow us to
include VFP data in transactions, something that couldn't be done with MTS and
VFP 6.
To find out more about FoxTalk and Pinnacle Publishing, visit their website at
http://www.pinpub.com/html/main.isx?sub=57
Note: This is not a Microsoft Corporation website. Microsoft is not responsible for its content.
This article is reproduced from the June 2001 issue of FoxTalk. Copyright 2001, by Pinnacle Publishing, Inc., unless otherwise noted. All rights are reserved. FoxTalk is an independently produced publication of Pinnacle Publishing, Inc. No part of this article may be used or reproduced in any fashion (except in brief quotations used in critical articles and reviews) without prior consent of Pinnacle Publishing, Inc. To contact Pinnacle Publishing, Inc., please call 1-800-493-4867 x4209.
© Microsoft Corporation. All rights reserved.