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

Tài liệu Java Testing and Design- P7 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 (532.89 KB, 50 trang )

Preparation and Setup Agents 279
The agent begins the main body of the commands by opening the com-
mands file.
dbfile = open( target )
The default open command opens a file for read access.
The agent then duplicates the command constants originally defined in
Prepare_Setup_Agent. The agent loops through each record in the com-
mand.db file and processes each command. While the
post_message()
function does not actually send a request to a Web-enabled application, it
does print the
reply message with the correct indentation to the screen.
The agent then creates variables used during command processing,
including a counter for the number of commands processed, an identifier for
the next new message, and an integer value to track the indentation of the
next
reply message in the tree of reply messages.
Setup_agent processes each command in the commands file. The for
command loops through every line in the commands file.
for line in dbfile.readlines():
The agent creates a list variable called commands by reading a line from
the commands file and splitting it into a list of individual values by delimiting
each value by a comma character using the split function.
commands = line.split(",")
The commands variable is a list so commands[0] refers to the first value
found in the current line of the commands file. In the discussion system
example, the first time through this loop
commands[0] contains a
new_thread command.
The agent handles commands and takes action accordingly. When han-
dling a


new_thread command, the agent indicates the command has been
handled, bumps up the number of handled commands, posts the message
using the
post_message() function, pushes the indentation value onto the
stack using the
push() function, then bumps up the number of messages and
the indentation value.
if int( command ) == new_thread:
handled=1
tick += 1
node=post_message(next_message,indent, \
PH069-Cohen.book Page 279 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
280 Chapter 8 State, Design, and Testing
"top-message",commands[1],commands[2])
push( indent )
next_message += 1
indent += 1
The handled variable is a simple flag that the agent uses to make sure
every command is recognized and executed. If handled is still 0 at the end of
the next block of code, then an error is thrown.
if handled==0:
print "Unknown command!"
print line
Prepare_Setup_Agent
automatically runs Setup_agent using the exec-
file
command. When execfile is used, Setup_agent exits back to Prepare
_Setup_Agent
then execution continues after the execfile command.

Using Databases to Configure Tests
Earlier in this chapter we learned how the preparation stage of a test formats
configuration instructions into a command file. The configuration instruc-
tions may be manually coded into a preparation test agent retrieved from a
file or database. This section shows how an intelligent test agent that was
built in TestMaker interacts with relational database systems.
TestMaker provides a rich environment for building intelligent test agents,
but at its heart TestMaker is just another application written in Java. The Java
language provides database connectivity through the JDBC API. JDBC driv-
ers are available for most commercial and open source databases, including
Oracle, Microsoft SQL Server, and PostgreSQL.
Following is a test agent that demonstrates how to use JDBC functions
from within a test agent environment.
# DB_meister.a
# Created on: July 3, 2002
# Author:
print "Agent running: DB_meister.a"
print "Description:"
print " Shows how an agent may use a relational "
print " database to receive or record data."
print
PH069-Cohen.book Page 280 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Using Databases to Configure Tests 281
print " NOTE: THIS AGENT DOES NOT ACTUALLY RUN since "
print " there is no relational database source"
print " available and this agent print depends on "
print " a JDBC driver that you must supply."
print
# Please configure this agent and then remove the

# sys.exit command
print
print "Stopping agent: Please configure this agent to your"
print "own JDBC driver and relational database source."
print
sys.exit
# Import tells TestMaker where to find TOOL, JDBC objects
import sys
from java.sql import DriverManager
# JDBC Driver information
# Note: You must provide these parameters to
# use your provided JDBC driver. You must also add the JDBC
# driver code to the TestMaker classpath. Set the classpath
# by changing the testmaker/testmaker/bin/ide.cfg file.
JDBCDriverClassName = "com.ashna.jturbo.driver.Driver"
jdbcURL = "jdbc:JTurbo://myrelationaldatabase:1410:MSSQL"
jdbcUserID = "myuserid"
jdbcPassword = "thepassword"
# Load the JDBC driver
try:
java.lang.Class.forName( JDBCDriverClassName )
myConn = DriverManager.getConnection( jdbcURL, jdbcUse-
rID, jdbcPassword )
except:
print
print "Could not load JDBC driver: ", \
JDBCDriverClassName
sys.exit
PH069-Cohen.book Page 281 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.

282 Chapter 8 State, Design, and Testing
# Show example of reading from a relational database
print
print "==================================================="
print "Information from the Customers table:"
# Customer count
query1 = "select count(*) from Customers"
try:
statement = myConn.createStatement()
results = statement.executeQuery( query1 )
results.next()
except Exception, ex:
print "Exception while counting customers: ",ex
sys.exit
print
print " Customer count: ", results.int
# Customer list
query2 = "select customer_number, last_name, "
query2 += "salutation, city, year"
query2 += " from table"
query2 += " order by last_name"
try:
statement2 = myConn.createStatement()
r2 = statement.executeQuery( query2 )
except Exception, ex:
print "Exception while getting customer list: ",ex
sys.exit
print
print " Complete customer list (sorted by last name):"
while results2.next():

print " ",r2.getString,r2.getString,r2.getString, \
r2.getString(4),r2.getString(5)
#
PH069-Cohen.book Page 282 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Using Databases to Configure Tests 283
# Inserting data into a table
insert1 = "insert into customers files (id, name,"
insert1 += "manager, phone) "
insert1 += "VALUES (1001, 'Simpson', 'Mr.', "
insert1 += "'Springfield', 2001)"
try:
i1 = myConn.createStatement();
ir1 = s2.executeQuery( insert1 );
except Exception, ex:
print "Exception while inserting a record: ",ex
print
print "Agent ended."
Let us look at the agent script’s individual sections to learn what the script
does to communicate with a relational database. Unlike most of the other test
agents presented in this book, the
DB_meister agent does not actually run
since at the time of writing this book there was no publicly available relational
database source for the agent to connect to. Check the h-
totest.com Web site to see if an example database source is now available.
sys.exit
By default this agent starts and then exits. To run this agent, please config-
ure the agent to connect to an available database and then remove the
sys.exit command.
The

Import command tells TestMaker where to find the standard Java
libraries that implement an interface to the JDBC driver.
from java.sql import DriverManager
A JDBC driver implements all the code needed to communicate with a
specific type of database and an interface that conforms to the JDBC specifi-
cation published by Sun for the Java platform. Database providers and third-
party driver manufacturers provide JDBC drivers. A driver is packaged as a
JAR file. Adding the driver JAR file to the TestMaker classpath is required to
give test agents access to the driver’s functions. For instructions on adding
resources to the classpath, see the TestMaker documentation.
PH069-Cohen.book Page 283 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
284 Chapter 8 State, Design, and Testing
The test agent sets four basic parameters to tell the JDBC driver where
and how to connect to the database.
JDBCDriverClassName points to the
driver object in a Java namespace defined by the driver manufacturer. The
jdbcURL parameter describes which JDBC driver to use (JTurbo), the URL
to the database, and the database name (
ORCL.)
JDBCDriverClassName = "com.ashna.jturbo.driver.Driver"
jdbcURL = "jdbc:JTurbo://myrelationaldatabase:1527:ORCL"
Driver and database manufacturers define the format to the JDBCDriver-
ClassName and jdbcURL parameters. Here is a short list of common JDBC
drivers and their parameters:
For IBM DB2 (), the agents use:
JDBCDriverClassName = "COM.ibm.db2.jdbc.net.DB2Driver"
jdbcURL = "jdbc:db2://myrelationaldatabase.com/test"
For Oracle (), agents use:
JDBCDriverClassName = "oracle.jdbc.driver.OracleDriver"

jdbcURL = "jdbc:oracle:thin:@myrelationaldata-
base.com:1527:ORCL
JTurbo is a JDBC driver for MS SQL server ( />index.jsp):
JDBCDriverClassName = "com.ashna.jturbo.driver.Driver"
jdbcURL = "jdbc:JTurbo://myrelationaldatabase.com:1433/ \
dbhost/sql70=true"
JDBC drivers use Java’s class loader functions to find and access a driver’s
functions. Note that the agent code uses the
try/except format so as to trap
an error that may happen when the driver loads. Possible errors include Java
not finding the driver, the driver not being able to connect to the database, or
the wrong configuration information.
try:
java.lang.Class.forName( JDBCDriverClassName )
myConn = DriverManager.getConnection( jdbcURL, \
jdbcUserID, jdbcPassword )
except:
print
print "Could not load driver: ", JDBCDriverClassName
sys.exit
PH069-Cohen.book Page 284 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Using Databases to Configure Tests 285
Now that the driver is loaded, the agent shows a few SQL functions to
retrieve data from the Customers table in the database. The Customers table
has these fields and descriptions:

customer_number long
• last_name char(50)
• salutation char(10)

• city char(50)
• year char(10)
The first query counts the number of customers in the Customers table
using a SQL select statement.
query1 = "select count(*) from Customers"
Executing the query requires a connection object and statement object.
The agent uses the
try/except format to catch errors that happen while
processing the database function.
try:
statement = myConn.createStatement()
results = statement.executeQuery( query1 )
results.next()
except Exception, ex:
print "Exception while counting customers: ",ex
sys.exit
The query result is returned in the results object. Using the next() method
retrieves the first row of the database results. In this case there is only a single
row, which is formatted and printed to the TestMaker output window.
print " Customer count: ", results.int
The second query demonstrates a more complex database command that
returns more than one row of results. The
query2 += "" format builds the
query statement from multiple parts.
query2 = "select customer_number, last_name, "
query2 += "salutation, city, year"
query2 += " from table"
query2 += " order by last_name"
PH069-Cohen.book Page 285 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.

286 Chapter 8 State, Design, and Testing
The agent makes a connection to the database and returns the results2
object that holds the response from the database. The while command loops
through all the rows in the response.
while results2.next():
print " ",r2.getString,r2.getString,r2.getString, \
r2.getString(4),r2.getString(5)
The third example shows how the agent inserts new rows into the Custom-
ers table. The setup for the database command is the same as the previous
two queries.
insert1 = "insert into customers files (id, name, "
insert1 += "manager, phone) "
insert1 += "VALUES (1001, 'Simpson', 'Mr.', "
insert1 += "'Springfield', 2001)"
To make the query, the agent builds a new connection object and uses the
executeQuery command to process the Insert command.
try:
i1 = myConn.createStatement();
ir1 = s2.executeQuery( insert1 );
except Exception, ex:
print "Exception while inserting a record: ",ex
The TestMaker script language provides access to all of JDBC’s many
methods. Consult your driver documentation for examples of additional
JDBC functions.
Using Lingo to Make Test Content
Close to Real
In the discussion system example presented earlier in this chapter, the
Setup_agent creates a new discussion group by posting messages and reply
messages. Experience shows us that when the message content is uniform, the
underlying systems (Web-enabled application servers, database servers, net-

work routers, and load balancers) try to use optimization technology to
enhance the performance of the system. Rarely, if ever, in the real world would
we find a discussion where every message contained the same content. There-
PH069-Cohen.book Page 286 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Using Lingo to Make Test Content Close to Real 287
fore, TestMaker includes a handy Lingo utility to automatically generate
pseudo-English-like content for message subject lines and message bodies.
For example, suppose the test agent needed to create a new message. The
Lingo utility object creates this paragraph:
Lipsem it quantos surbatton ditchek surbatton deplorem
ventes so surbatton quantos infreteres ipsem aqua sit
ventes. Campus ad surbatton ad infreteres ad novus surbatton
deplorem it delorum novus. Campus quantos ditchek quantos.
Via surbatton novus surbatton. Novato quantos ditchek deplo-
rem novus ditchek ventes.
The important thing is that Lingo creates a different paragraph each time
it is called, which defeats the system’s attempt to optimize performance while
running tests where the message content is always the same.
Following is a test agent in its entirety that demonstrates Lingo’s many
uses. An explanation of the Lingo functions follows the agent.
# Lingo_meister.a
# Author:
# Import tells TestMaker where to find TOOL objects
from com.pushtotest.tool.util import Lingo
print
print "==================================================="
print "Technique 1: A simple message example"
myLingo = Lingo()
print "Subject:",myLingo.getSubject( 4 )

print "Message:"
print myLingo.getMessage()
print "-end of message-"
print
print "==================================================="
print "Technique 2: URL encoded message example"
print
print "If we needed to include a message in an HTTP POST"
print "command the message would need to be URL encoded."
print "Here is a Lingo message that is URL encoded:"
print
PH069-Cohen.book Page 287 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
288 Chapter 8 State, Design, and Testing
print myLingo.getMessageEncoded( 100 )
print
print "==================================================="
print "Technique 3: A complete Lingo letter"
print
print "Here is an example business memo using several"
print "Lingo methods."
print
print "Dear Mr.",myLingo.getSingleCap(),":"
print
print "We have found the manuscript you were searching"
print "for and it includes the following excerpt:"
print
# Next we use a special version of getMessage
# to include a starting capital letter, ending period
# and encoding. The format is:

# getMessage(int size, boolean startCap,
# boolean endPeriod, boolean encoded)
print myLingo.getMessage(15, 1, 1, 0)
print
print "As you can see we are not certain what dialect the"
print "text is written in. Please do your best to let us"
print "know what it means."
print
print "Sincerely,"
print
print myLingo.getSingleCap()
print
print "==================================================="
print "Technique 4: Making your own Lingo language"
print
print "Here is the same example business memo from"
print "technique 3 but using French words to form the"
print "Lingo gibberish."
print
caps = [ "Francois", "Sanjournais", "Berjerack", "Mon", \
"La", "Le", "Incroyable! " ]
tokens = [ "devrait","ouvrir","le","cortËge,","entourÈ", \
PH069-Cohen.book Page 288 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Using Lingo to Make Test Content Close to Real 289
"d'une","bonne","partie","de","ses","adjoints","et","des",\
"dÈputÈs","parisiens","de","gauche.","les","Ècologistes", \
"seront","fortement","reprÈsentÈs","la","droite","elle,\
","ne","dÈpÍchera","que","les","quelques","membres",\
"d'on","est" ]

frenchLingo = Lingo( caps, tokens )
print "Dear Mr.",frenchLingo.getSingleCap(),":"
print
print "We have found the manuscript you were searching"
print "for and it includes the following excerpt:"
print
# Next we use a special version of getMessage which
# has options to include a starting capital letter,
# ending period and encoding. The format is:
# getMessage(int size, boolean startCap,
# boolean endPeriod, boolean encoded)
print frenchLingo.getMessage(15, 1, 1, 0)
print
print "As you can see we are not certain what dialect the"
print "text is written in. Please do your best to let us"
print "know what it means."
print
print "Sincerely,"
print
print frenchLingo.getSingleCap()
print
print "Agent done."
Lingo_meister
is a simple agent to show the capabilities of the Lingo
object provided in TestMaker’s TOOL. Lingo provides English-like gibberish
that is well suited to be the content of a posted test message.
Lingo objects
are created by using an
Import command to identify the Lingo object to the
Jython script language.

from com.pushtotest.tool.util import Lingo
The Lingo object is instantiated and then used by accessing its many
methods.
myLingo = Lingo()
PH069-Cohen.book Page 289 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
290 Chapter 8 State, Design, and Testing
The getSubject() function returns a string of gibberish words with a car-
riage return character terminating the string. The optional value in
getSub-
ject()
identifies how many gibberish words to include in the result.
print "Subject:",myLingo.getSubject( 4 )
The getMessage() function returns a random amount of paragraphs of gib-
berish words. Each paragraph is terminated with two carriage return characters.
print myLingo.getMessage()
When working in HTTP/HTML environments, a request to a host must
often be URL encoded. In URL encoding, characters such as
< and > would
invalidate the HTML code so they are encoded into
&lt; and &gt; codes
that the host will decode. The
getMessageEncoded() function returns a
URL-encoded group of paragraphs of gibberish.
print myLingo.getMessageEncoded( 100 )
The third example in Lingo_meister shows how a Lingo object may be
used within print commands to generate a sample memorandum letter.
print "Dear Mr.",myLingo.getSingleCap(),":"
The getSingleCap() method returns a single gibberish word that is capi-
talized. The body of the memo uses a special version of the

getMessage()
function that features options to include a starting capital letter, ending
period, and encoding. The format for the special method is:
getMessage(int size, boolean startCap, boolean endPeriod,\
boolean encoded)
The last technique in Lingo_meister shows how an agent can define its
own dictionary of gibberish words. Lingo requires a list of capitalized words
and lowercase words. These are passed to Lingo when the agent instantiates
a new
Lingo object.
frenchLingo = Lingo( caps, tokens )
Now, Lingo chooses gibberish words from the new list of capital and low-
ercase words.
PH069-Cohen.book Page 290 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Summary 291
Summary
This chapter discussed system state, including the repeatable lifecycle that
defines the preparation, setup, execution, and analysis stages of a test. This
chapter showed TestMaker test agent script examples that use the resources
of a database system to initialize the state of a system prior to testing.
The next chapter shows how to use intelligent test agents in Microsoft
.NET environments and in secure environments.
PH069-Cohen.book Page 291 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
PH069-Cohen.book Page 292 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
293
Chapter
9

Integrating with .NET
Web Services
icrosoft delivers a broad and comprehensive solution for enterprises
needing to build, deploy, and run Internet-based Web services.
Microsoft’s support of many popular open Internet protocols even lets them
offer technology to interoperate with non-Windows systems. Microsoft built
its enterprise solution on Windows NT and XP technologies over time.
Before the arrival of .NET, the Microsoft acronym for all its enterprise solu-
tions technologies was DNA, which stands for Distributed iNternet Architec-
ture. So what is .NET?
.NET is a product strategy that overhauls and elevates the Microsoft
development environment and tools to a new level of sophistication, ease-of-
use, and interoperability over previous Microsoft development tools. .NET is
Microsoft’s way to add a new Common Language Runtime (CLR) to its
object-oriented development tools and to add XML technology to everything
Microsoft does.
Microsoft is working with the European Computer Manufacturers Associ-
ation to put forward open standards for CLR (TG3) and the C# language
(TG2). The ECMA Web site hosts working documents on these efforts: http:/
/www.ecma-international.org/. Additional information is at ne-
texperts.com/ecma/index.html and at />.NET defines the Microsoft Intermediate Language (IL) code and CLR is
the IL runtime virtual machine environment that provides memory manage-
ment, automatic garbage collection, security, and threading. CLR enables
M
PH069-Cohen.book Page 293 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
294 Chapter 9 Integrating with .NET Web Services
Microsoft development tools to support a variety of object-oriented lan-
guages, including C, C++, VB.NET, C#, and J#. The single CLR run-time
can run components built in any of these languages that can output IL. So

the Microsoft development tools work with all those languages. Following is
an example C# and C++ program written in Microsoft Visual Studio .NET
that features a mixture of programming languages. Visual Studio .NET com-
piles this program into a single unit that CLR runs.
1
# We begin with a method defined using C# . . .
class Vector
{
/// <summary>
/// Compute the length of the vector
/// </summary>
public double Length
{
get
{
return(Math.Sqrt(x * x + y * y));
}
}
}
# . . . then add some C++ code to the mix . . .
unsafe static int AddArrayUnsafe(int[] numbers)
{
int result = 0;
for (int it = 0; it < Iterations; it++)
{
fixed (int* pNumber = numbers)
{
int* pCurrent = pNumber;
int* pLimit = pNumber + numbers.Length;
while (pCurrent < pLimit)

{
result += *pCurrent;
pCurrent++;
}
}
}
return result;
}
1. A pretty good introduction to .NET is on the Microsoft Web site at http://
www.microsoft.com/net/basics/whatis.asp.
PH069-Cohen.book Page 294 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Interoperability and Integration 295
The example code shows NET’s mechanism to manage C++ pointers in
the otherwise memory-managed safe environment of C#. The same mecha-
nism works in other CLR compatible languages.
In many ways .NET is Microsoft’s best effort yet to use XML. XML
enables Microsoft development tools to offer standardized configuration,
description, and deployment definitions. For example, while Microsoft Biz-
Talk Server, SQL Server, and Exchange Server still use the Windows Regis-
try, they also now use XML for configuration and management features.
Microsoft product strategies build XML into all its technology by coding
configuration information in XML formats stored in files and databases.
XML also becomes the Microsoft common language for all its APIs. In
effect, it is not unreasonable for software developers to expect any Microsoft
API to be available as a SOAP-based XML interface that adheres to a
WSDL description.
.NET benefits IT managers, software developers, and QA analysts:
•With the emphasis on XML, configuration and management
files become more open and more standardized. Third-party

system management solutions such as HP’s OpenView and IBM
Tivoli should more easily and rapidly support Microsoft servers.
•QA analysts will find testing .NET applications easier than prior
Microsoft-built applications since the APIs to these applications
self-describe valid data.
Microsoft’s adoption of XML and delivery of a single run-time engine
enables increased productivity and efficiency as developers, IT managers,
and QA analysts deliver products built with Microsoft development tools. Of
course, like all new technologies, the .NET products come with problems
and issues that need to be understood and tested.
Interoperability and Integration
The good news for Java developers working with systems built with .NET is
that there have been no major train wrecks. For the most part, systems built
with .NET offer good interoperability with Java-based systems. The bigger
problem for Java developers is usually integration.
Consider an example where a product supply company offers a Web ser-
vice to take purchase orders. The service receives SOAP encoded orders.
PH069-Cohen.book Page 295 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
296 Chapter 9 Integrating with .NET Web Services
<order_request>
<name>DemandLine Purchasing, Inc.</name>
<product>123456</product>
<price>$59.95</price>
</order_request>
Figure 9–1 shows how a Java application uses the purchase service written
with .NET.
Visual Studio .NET makes it easy to write and expose this service. The pop-
ular Java development tools available make it easy to write the
placeOrder

method to make the Web service call. Consider that this example has three
integration problems:
1. The Java client function uses a floating-point double variable to
hold the price while the .NET function uses a string.
2. Neither the Java client nor the .NET service explicitly know the
currency expressed in the price element. For example, the Java
client may send a price expressed in U.S. dollars while the
.NET Web service expects Euros.
3. Java uses a naming convention where method names that begin
with a capital letter are usually reserved for operating system
calls. On the other hand, .NET’s convention is to use capital let-
ters to define all method names. This isn’t a show stopper like
the other two problems, but it may raise some eyebrows
between Java and .NET developers.
These are not really interoperability issues as much as they are the systems
integration issues that we typically have to deal with everyday.
Figure 9–1 The Java placeOrder function makes a SOAP request to the TakeOrder
method of the published Web service.
TakeOrder
Public String FindPrice()
order_request
<order_request>
<name>DemandLine</name>
<product>042361</product>
<price>59.95</price>
</order_request>
placeOrder
public setPrice(double pr)
.NET Java
PH069-Cohen.book Page 296 Monday, March 15, 2004 9:00 AM

Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
How Is .NET Different? 297
.NET’s support of XML and SOAP offers a solution to problems 1 and 2.
By using XML Schemas, the .NET Web service provides data typing for the
request method. The XML Schema below defines the price element to be a
String type.
<xs:schema xmlns="" xmlns:xs=" />XMLSchema">
<xs:element name="order_request">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="product" type="xs:int"/>
<xs:element name="price" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
.NET languages use a common set of tools to publish Web services so you can
expect to find a WSDL document that accompanies the service. In this example,
the Java developer needs to implement a request that conforms to the schema.
This likely means modifying the client-side code to express prices as strings in the
request and to decode the response back into a floating-point double value.
See Chapter 7 for additional SOAP-related problems you will likely
encounter, including data type interoperability, adherence to standards, and
underlying platform differences. More discussion of .NET’s use of WSDL
comes later in this chapter.
How Is .NET Different?
By their nature, the development tools we use enforce a certain thinking that
winds up in the software applications. For example, Visual Studio .NET auto-
matically generates C# code to access a given Web service using document-

style SOAP requests by default. Developers that rely solely on automated
development tools risk building interoperability problems into their systems
without knowing where to look when problems happen.
Document-style SOAP turns out to be a shrewd architectural decision, as
we will see later. However, from a testing perspective, if your .NET Web ser-
vice uses document-style SOAP encoding (the default in ASP.NET), there
PH069-Cohen.book Page 297 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
298 Chapter 9 Integrating with .NET Web Services
may be interoperability problems with other SOAP clients who only speak
RPC-encoded SOAP.
Chapter 7 shows the various styles of SOAP requests and responses. The
two most popular styles are RPC and Document. Most development environ-
ments include utilities that examine method declarations in source code files
that define an object. Then they automatically build the needed code to offer
the object’s methods as Web services. The local object makes a call to a spe-
cific method and object running on a remote server and passes parameters
defined in the method declaration. For example, the following C# code is
automatically deployed as a SOAP-based Web service:
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Web;
using System.Web.Services;
namespace myService
{
public class myService: System.Web.Services.WebService
{

public HelloService()
{
//CODEGEN: This call is required by
//the ASP.NET Web Services Designer
InitializeComponent();
}
[WebMethod]
public string greetingService
(String strMyName)
{
return "Hello, " + name +", \
and welcome to my service.";
}
[WebMethod]
public string SayGoodBye()
{
return "Goodbye!";
}
}
}
PH069-Cohen.book Page 298 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
How Is .NET Different? 299
This code is exposed as a Web service that has a greetingService
request interface. The SOAP call receives a string as a parameter and
responds with a string in its return value.
RPC-style SOAP requests are very attractive to developers because the
Web service tools that generate SOAP interfaces and WSDL descriptions do
a lot of heavy lifting for the developer. For example, the following method
returns a complex data type:

public class myComplexService{
public Hashmap greetingService( firstname name ) {
Hashmap ht = new Hashmap();
ht.put( "Event", name );
ht.put( "Keycode", keycode );
ht.put( "PcAssemblyNumber", pcassembly );
ht.put( "SoftwareDottedString", dottedsw );
ht.put( "CurrentTime", new Date() );
ht.put( "CommandKey", "7" );
return ht;
In an RPC-style SOAP request, the developer may depend on a develop-
ment tool to build the SOAP request code to handle marshaling a
Hashmap
object into XML that is sent in a SOAP request to the server. This code
would also make use of custom serializers that would convert objects like the
Hashmap into XML.
Document-style SOAP requests begin with the XML document already
defined. Instead of depending on the development tool, document-style SOAP
requests are built by populating an XML tree in the application code itself.
public class myComplexService{
public void callGreetingService( firstname name ) {
body = new SOAPBody();
body.addElement ( "Event", name );
body.addElement ( "Keycode", keycode );
body.addElement ( "PcAssemblyNumber", pcassembly );
body.addElement ( "SoftwareDottedString",dottedsw);
body.addElement ( "CurrentTime", new Date() );
body.addElement ( "CommandKey", "" );
. . .
SOAPRequest.send( body );

.NET is a document-style environment. By default .NET development
tools create document-style SOAP requests. While .NET tools provide a
PH069-Cohen.book Page 299 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
300 Chapter 9 Integrating with .NET Web Services
switch to use SOAP RPC calls, there is very little support in .NET for RPC.
If an application makes a SOAP RPC call to a .NET Web service that expects
a document-style request, then .NET returns a fault—the Web service
equivalent of throwing an exception.
Microsoft’s choice for document-style SOAP puts a bend in the direction
most developers were headed. Many Web services developers come from the
component software worlds that are dominated by CORBA, RMI, and COM.
SOAP RPC is a natural bridge from component software architectures to
Web services. On the other hand, business-to-business (B2B) exchange infra-
structure has been XML based from the start so document-style SOAP is a
natural there.
To see a vivid example of the divergence between Web service developers
in the J2EE and .NET camps, take a look at the list of publicly available Web
services published on XMethods.net. This list cleaves in two: SOAP RPC
Web services are written in Java and document-style Web services are writ-
ten in .NET.
One last thing to consider in both RPC and document-style SOAP calls is
that the SOAP standard does not cover more complicated data elements than
arrays and structures. In the previous example we would find that Microsoft
has its own encoding for Hashmaps that do not interoperate with the other
Web service platforms. The developer is left to encode arrays of arrays as well.
We have seen the stylistic differences between SOAP RPC and document-
style SOAP. Under the covers and in the implementations of SOAP lie scal-
ability and performance issues that come with decisions to use RPC and doc-
ument-style SOAP.

Document-Style Scalability
Regardless of the SOAP call style, each SOAP message goes through the
same stages of creation. The creation process begins with a value stored in an
object. When the value is passed to a Web service, the object is translated
into a Document Object Model element and stored in memory. When the
request is marshaled to be sent to the Web service host, the Elements are
rounded up and serialized into strings in XML format. The final step then
gathers the XML formatted strings and sends the combined group over a
transport to the Web service host. Figure 9–2 illustrates this process.
The steps depicted in Figure 9–2 show four possible places where scalabil-
ity and performance problems can be introduced. The Object to Element
transformation might run into problems inherent in the way that CLR repre-
PH069-Cohen.book Page 300 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
How Is .NET Different? 301
sents data. The Object to Element transition could introduce problems since
the performance of many XML parsers is not sufficient. The serializers for
the XML-to-UTF-8 transition can be susceptible to bugs and performance
issues. Many other problems lower system scalability and performance.
In tests of Web service application servers, the early systems turned out to
have significant scalability and performance problems, especially when com-
paring SOAP RPC to document-style SOAP. The results of these tests con-
clude the following:
•Document-style SOAP operations outperform SOAP RPC.
•SOAP RPC displays significant scalability problems as the
payload size of a request and response increases.
Compare the TPS results from one popular application server:
Figure 9–2 SOAP requests start with data in an object, converts the object into a
DOM Element, and serializes the Element into an XML string. Then, they combine
the strings and send them across a transport to the Web service host.

Payload size in bytes RPC Document
600 168 410
3000 145 399
9000 100 404
2400 49 411
57000 18 401
96000 10 406
Object
Element
Flight of the Data
XML
UTF-8 String
PH069-Cohen.book Page 301 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
302 Chapter 9 Integrating with .NET Web Services
The test measured the round-trip time it took to make a request and
receive a response as measured at the client side. To run this test in your
environment, this test code and many others are available for free download
at />Note that in every case the TPS values for SOAP RPC transactions were
slower than document-style calls. Additionally, while the document-style TPS
values remained steady even under the weight of increasing payload sizes,
the SOAP RPC TPS values declined significantly.
These tests do not conclude that architecturally document-style SOAP is
any better than SOAP RPC, or vice versa. However, they do show that the
SOAP implementations tested have serious limitations and flaws. As new and
better implementations become available, a scalability and performance test
of the new SOAP stacks is needed to understand how the performance char-
acteristics change.
SOAP Headers in .NET
In the formative time of Web services, Microsoft was the first to strongly sup-

port XML Schema, WSDL, and SOAP headers. Other Web service platforms
were less convinced. So to a developer on WebSphere, Apache SOAP, and
BEA WebLogic, the XML Schema in WSDL documents and the contents of
SOAP headers in Microsoft-built Web services may appear odd. SOAP was
originally introduced in Chapter 4 with an explanation of common SOAP val-
ues and formats. This section shows how Microsoft puts its own touch on
SOAP headers.
Before we explore how .NET uses the SOAP header, you may want to
review the specifics of the SOAP header element. The SOAP 1.1 Specifica-
tion (found at and the SOAP 1.2 Work-
ing Draft indicate that a SOAP message has three possible elements: the top-
level Envelope element and two child elements (Header and Body). Follow-
ing is an example of a SOAP message with all three elements:
<soap:Envelope
xmlns:soap=" /> xmlns:xsi=" /> xmlns:xsd=" /> <soap:Header>
<PriorityHeader
xmlns=" /> <Priority>HighPriority</Priority>
PH069-Cohen.book Page 302 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
How Is .NET Different? 303
</PriorityHeader>
</soap:Header>
<soap:Body>
<PlaceOrder
xmlns=" /> <quantity>100</quantity>
</PlaceOrder>
</soap:Body>
</soap:Envelope>
The Body element holds the main data of the request and the Header
holds any metadata about the Body element. The Header is optional but it is

well used in .NET applications. As time progresses, new standards for Web
services will make significant use of the Header, including upcoming stan-
dards for security, credentials, routing, and referrals. .NET just happens to
be a little ahead of the Header usage curve.
The SOAP specification defines three optional attributes that can apply to
header blocks: the
encodingStyle attribute, the actor attribute, and the
mustUnderstand attribute. While encodingStyle is meant to be optional,
.NET servers and the SunONE Application Server expect the
encoding-
Style
attribute to be present.
SOAP is going through the same evolutionary transformation as servlets
and other middleware have. While a single standalone object would respond
to Web service requests, the new architecture implements several smaller
objects that each handle a single facet of a Web service request, and are
strung together in a string of handlers. The SOAP header elements are pro-
cessed by individual .NET programs as the SOAP message moves through a
chain of handlers.
The SOAP message is already defined to be in well-formed XML format,
so unlike the headers in an HTTP request, the SOAP headers do not need to
describe the data in the SOAP message. SOAP headers, especially in .NET,
help process the data in the body. For example, in a banking environment, a
SOAP header transmits authentication and transaction information that iden-
tifies the person who sent the SOAP message and the context in which it will
be processed. Another example is an airline reservation service where the
SOAP header defines a time limit on the validity of airfares sent in the SOAP
message.
While the SOAP specification provides for any valid XML data to be
included as a SOAP header, Microsoft really levers SOAP header values. So it

PH069-Cohen.book Page 303 Monday, March 15, 2004 9:00 AM
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.

×