Vous êtes sur la page 1sur 66

ASP.NET Web Services or .

NET Remoting: How to Choose


Building Distributed Applications with Microsoft .NET

Priya Dhawan

Tim Ewald

Microsoft Developer Network

September 2002

Applies to:

Microsoft® ASP.NET Web services

Microsoft® .NET Framework

Microsoft® .NET Remoting

Summary: Understand how the Microsoft .NET Remoting infrastructure and Microsoft ASP.NET Web services

can enable cross-process communication, how both technologies work, and how to choose the one that is right

for your application. (12 printed pages)

Contents

Overview

Serialization and Metadata

Distributed Application Design: ASP.NET Web Services vs. .NET Remoting

Choosing an Architecture

Summary

Overview

Over time, it has become common practice to build applications as a set of components that are distributed

across a network of machines and work together as part of one overall program. Traditionally, distributed

application logic called for component-object technology such as the Microsoft® Distributed Component Object

Model (DCOM), the Object Management Group's Common Object Request Broker Architecture (CORBA), or

Sun's Remote Method Invocation (RMI). These technologies provided reliable, scalable architecture to meet the

growing needs of applications.

Though these component-based technologies work very well in an intranet environment, attempting to use

them over the Internet presents two significant problems. First, the technologies do not interoperate. While

they all dealt with objects, they disagreed over the details, for example, lifecycle management, support for

constructors, and degree of support for inheritance. Second, and more important, their focus on RPC-style

communication typically led to tightly coupled systems built around the explicit invocations of object methods.

Browser-based Web applications, in contrast, are loosely coupled and remarkably interoperable. They

communicate using HTTP to exchange MIME-typed data in a wide range of formats. Web services adapt the
traditional Web programming model for use from all sorts of applications, not just browser-based ones. They

exchange SOAP messages using HTTP and other Internet protocols. Because Web services rely on industry

standards, including HTTP, XML, SOAP and WSDL, to expose application functionality on the Internet, they are

independent of programming language, platform and device.

The ASP.NET Web services infrastructure provides a simple API for Web services based on mapping SOAP

messages to method invocations. It accomplishes this by providing a very simple programming model based on

mapping SOAP message exchanges to individual method invocations. The clients of ASP.NET Web services do

not have to know anything about the platform, object model, or programming language used to build them.

The services themselves don't have to know anything about the clients that are sending them messages. The

only requirement is that both parties agree on the format of the SOAP messages being produced and

consumed, as defined by the Web service's contract definition expressed using WSDL and XML Schema (XSD).

.NET Remoting provides an infrastructure for distributed objects. It exposes the full-object semantics of .NET to

remote processes using plumbing that is both very flexible and extensible. Compared to ASP.NET Web services,

which provide a very simple programming model based on message passing, .NET Remoting offers much more

complex functionality, including support for passing objects by value or by reference, callbacks, and multiple-

object activation and lifecycle management policies. In order to use .NET Remoting, a client needs to be aware

of all these details—in short the client needs to be built using .NET. (Or with another framework that

supports .NET Remoting; the only one we are aware of is Intrinsyc's Ja.NET for Java.) The .NET Remoting

plumbing also supports SOAP messages, but it is important to note that this doesn't change its client

requirements. If a Remoting endpoint exposes .NET-specific object semantics, via SOAP or not, the client must

understand them.

The fact that the .NET Framework includes support for two distinct distributed programming models, Web

services and distributed objects, has caused a fair amount of confusion for developers. When should a system

use ASP.NET Web services and when should it use .NET Remoting? To answer this question, you have to

understand how both these technologies really work.

Serialization and Metadata

All distributed communication plumbing ultimately does two things: it marshals instances of programmatic data

types into messages that can be sent across the network, and it provides a description of what those messages

look like. The former is accomplished using some form of serialization engine, or marshaler. The latter is

achieved through some form of metadata. For instance, for most (latter day) DCOM interfaces, the serialization

engine was the Type Library Marshaler and type libraries provided the metadata. The key difference between

ASP.NET Web services and .NET Remoting is in how they serialize data into messages and the format they

choose for metadata.

ASP.NET Web Services, XmlSerializer and XSD


ASP.NET Web services rely on the System.Xml.Serialization.XmlSerializer class to marshal data to and

from SOAP messages at runtime. For metadata, they generate WSDL and XSD definitions that describe what

their messages contain. The reliance on pure WSDL and XSD makes ASP.NET Web services metadata portable;

it expresses data structures in a way that other Web service toolkits on different platforms and with different

programming models can understand. In some cases, this imposes constraints on the types you can expose

from a Web service—XmlSerializer will only marshal things that can be expressed in XSD. Specifically,

XmlSerializer will not marshal object graphs and it has limited support for container types.

Though these limitations may seem significant from a classic distributed object perspective, they help ensure

interoperability with other Web service frameworks—a basic goal of the loosely coupled Web service model.

Support for interoperability is augmented by a rich set of custom attributes that allow you to annotate your

data types to control the way in which the XmlSerializer marshals them. As a result, you have very fine-

grained control over the shape of the XML being generated when an object is serialized. In addition, an

ASP.NET-based Web service can be tailored to describe its messages in terms of literal XSD or the SOAP

encoding rules (i.e., SOAP Section 5). Literal XSD is the default, and will be the standard going forward. SOAP-

encoding support is included for interoperability with existing toolkits. This is beneficial, especially when you

need to communicate with an existing Web service or client that needs to communicate using a predefined

message format.

.NET Remoting, IFormatter and the Common Language Runtime

.NET Remoting relies on the pluggable implementations of the IFormatter interface used by the

System.Runtime.Serialization engine to marshal data to and from messages. There are two standard

formatters, System.Runtime.Serialization.Formatters.Binary.BinaryFormatter and

System.Runtime.Serialization.Formatters.Soap.SoapFormatter. The BinaryFormatter and

SoapFormatter, as the names suggest, marshal types in binary and SOAP format respectively. For

metadata, .NET Remoting relies on the common language runtime assemblies, which contain all the relevant

information about the data types they implement, and expose it via reflection. The reliance on the assemblies

for metadata makes it easy to preserve the full runtime type-system fidelity. As a result, when the .NET

Remoting plumbing marshals data, it includes all of a class's public and private members; handles object

graphs correctly; and supports all container types (e.g., System.Collections.Hashtable). However, the

reliance on runtime metadata also limits the reach of a .NET Remoting system—a client has to understand .NET

constructs in order to communicate with a .NET Remoting endpoint. In addition to pluggable formatters, the

.NET Remoting layer supports pluggable channels, which abstract away the details of how messages are sent.

There are two standard channels, one for raw TCP and one for HTTP. Messages can be sent over either channel

independent of format.

Muddying the Water: Remoting and Web Services

The presence of a SOAP formatter and an HTTP channel begs the question: Can .NET Remoting be used to build

Web services? The answer is yes and no. The standard Web service technology stack relies not only on SOAP-
based messages, but also on WSDL- and XSD-based descriptions of those messages. The Remoting plumbing

can actually generate WSDL definitions that describe the messages an endpoint produces and consumes.

However, several issues arise if you go down this path.

First, the generated WSDL files always describe messages in terms of the SOAP-encoding rules instead of literal

XSD. This isn't a problem today, but it will be going forward as more and more tools focus entirely on schemas.

Second, the generated WSDL files include extensions that are .NET Remoting-specific. For instance, here is a

simple class that uses .NET Remoting to expose its behavior.

public class Methods : MarshalByRefObject

// The Now method returns the current date and time

public string Now()

return System.DateTime.Now.ToString();

If you generate WSDL from this class, the binding information includes .NET Remoting-specific details, as

shown below.

<binding name='MethodsBinding' type='ns0:MethodsPortType'>

<soap:binding style='rpc'

transport='http://schemas.xmlsoap.org/soap/http'/>

<suds:class type='ns0:Methods' rootType='MarshalByRefObject'>

</suds:class>

<operation name='Now'>

<soap:operation soapAction=

'http://schemas.microsoft.com/clr/nsassem/RemSoap.Methods/methods#Now'/>

<suds:method attributes='public'/>

<input name='NowRequest'>...</input>

<output name='NowResponse'>...</output>

</operation>

</binding>
These extra elements are legal because the WSDL specification supports extensibility. Any well-behaved Web

service toolkit that doesn't understand them should simply ignore them. However, there are some things a Web

service toolkit cannot ignore. For instance, here is a Remoting endpoint that returns a Microsoft® ADO.NET

System.Data.DataSet.

public class Methods : MarshalByRefObject

public System.Data.DataSet GetEmptyDataSet()

return new System.Data.DataSet();

Here is the generated WSDL definition for this method's output message:

<message name='Methods.GetEmptyDataSetOutput'>

<part name='return' type='ns3:DataSet'/>

</message>

Normally, a WSDL message refers to types defined in a particular namespace using XML Schema. In this case,

however, the namespace prefix ns3 applied to the DataSet type is not defined in XSD. Instead it is implicitly

defined via the runtime. The ns3 prefix in this example is bound to an XML namespace identified by this URI:

http://schemas.microsoft.com/clr/nsassem/System.Data/System.Data%2C%20Version%3D1.0.3300.0%2C

%20Culture%3Dneutral%2C%20PublicKeyToken%3Db77a5c561934e089

Consumers of this WSDL definition are meant to understand the special significance of this "well-known" URI—it

is the four-part strong name of a specific runtime assembly included in the .NET Framework. This style of WSDL

is great for clients that are implemented using .NET Remoting because they can generate a proxy assembly

with the right information for marshaling. However, for other Web service toolkits—including ASP.NET—that do

not understand this URI and expect to find a schema definition for the DataSet type, this WSDL will be useless.

So the question remains, can you use .NET Remoting to build Web services? Yes, strictly speaking, you can.

But, will anybody who is not using the .NET Remoting plumbing be able to use them? The answer is maybe, if

you are careful to pare down your endpoint to bare bones data types and semantics. Specifically, if you want

interoperability with other Web service toolkits, you need to restrict parameters to the built-in simple types and

your own data types (don't use .NET Framework types like DataSet), and avoid client-activated objects and

events. In short, if you care about reach, you need to restrict yourself to the same set of functionality that

ASP.NET Web services support.


Or better yet, use ASP.NET Web Services, because this is exactly what they are designed for.

Distributed Application Design: ASP.NET Web Services vs. .NET Remoting

ASP.NET Web services favor the XML Schema type system, and provide a simple programming model with

broad cross-platform reach. .NET Remoting favors the runtime type system, and provides a more complex

programming model with much more limited reach. This essential difference is the primary factor in

determining which technology to use. However, there are a wide range of other design factors, including

transport protocols, host processes, security, performance, state management, and support for transactions to

consider as well.

Transport Protocols and Host Processes

Although the SOAP specification does not mandate HTTP as the transport protocol, the client can access Web

services implemented using ASP.NET Web services only over HTTP, because it is the only transport protocol

ASP.NET supports. The services are invoked via IIS and execute in the ASP.NET worker process,

aspnet_wp.exe.

.NET Remoting gives you the flexibility to host remote objects in any type of application including a Windows

Form, a managed Windows Service, a console application or the ASP.NET worker process. As previously

noted, .NET Remoting provides two transport channels—TCP and HTTP. Both channels provide communication

between arbitrary sending and receiving processes using sockets.

It is also possible to integrate the HTTP channel with IIS and the ASP.NET worker process. This is important for

several reasons. First, it is the only way to auto-start a .NET Remoting endpoint when a client request arrives.

The .NET Remoting plumbing does not include a DCOM style Service Control Manager (SCM) to start remote

servers. If you expose remote objects from arbitrary processes, you have to ensure those process are running.

You also have to ensure they are thread-safe, e.g., that thread A can't activate an object after thread B started

to shut the process down. If you expose remote objects from ASP.NET, you can take advantage of the fact that

the Aspnet_wp.exe worker process is both auto-starting and thread-safe. Second, as described in the next

section, integration with IIS is the only way you can secure a cross-process .NET Remoting call.

Both the ASP.NET Web services and the .NET Remoting infrastructures are extensible. You can filter inbound

and outbound messages, control aspects of type marshaling and metadata generation. With .NET Remoting,

you can also implement your own formatters and channels.

Security

Since ASP.NET Web services rely on HTTP, they integrate with the standard Internet security infrastructure.

ASP.NET leverages the security features available with IIS to provide strong support for standard HTTP

authentication schemes including Basic, Digest, digital certificates, and even Microsoft® .NET Passport. (You

can also use Windows Integrated authentication, but only for clients in a trusted domain.) One advantage of

using the available HTTP authentication schemes is that no code change is required in a Web service; IIS
performs authentication before the ASP.NET Web services are called. ASP.NET also provides support for .NET

Passport-based authentication and other custom authentication schemes. ASP.NET supports access control

based on target URLs, and by integrating with the .NET code access security (CAS) infrastructure. SSL can be

used to ensure private communication over the wire.

Although these standard transport-level techniques to secure Web services are quite effective, they only go so

far. In complex scenarios involving multiple Web services in different trust domains, you have to build custom

ad hoc solutions. Microsoft and others are working on a set of security specifications that build on the

extensibility of SOAP messages to offer message-level security capabilities. One of these is the XML Web

Services Security Language (WS-Security), which defines a framework for message-level credential transfer,

message integrity, and message confidentiality.

As noted in the previous section, the .NET Remoting plumbing does not secure cross-process invocations in the

general case. A .NET Remoting endpoint hosted in IIS with ASP.NET can leverage all the same security features

available to ASP.NET Web services, including support for secure communication over the wire using SSL. If you

are using the TCP channel or the HTTP channel hosted in processes other than aspnet_wp.exe, you have to

implement authentication, authorization and privacy mechanisms yourself.

One additional security concern is the ability to execute code from a semi-trusted environment without having

to change the default security policy. ASP.NET Web Services client proxies work in these environments, but

.NET Remoting proxies do not. In order to use a .NET Remoting proxy from a semi-trusted environment, you

need a special serialization permission that is not given to code loaded from your intranet or the Internet by

default. If you want to use a .NET Remoting client from within a semi-trusted environment, you have to alter

the default security policy for code loaded from those zones. In situations where you are connecting to systems

from clients running in a sandbox—like a downloaded Windows Forms application, for instance—ASP.NET Web

Services are a simpler choice because security policy changes are not required.

State Management

The ASP.NET Web Services model assumes stateless service architecture by default; it does not inherently

correlate multiple calls from the same user. In addition, each time a client invokes an ASP.NET Web service, a

new object is created to service the request. The object is destroyed after the method call completes. To

maintain state between requests, you can either use the same techniques used by ASP.NET pages, i.e., the

Session and Application property bags, or you can implement your own custom solution.

.NET Remoting supports a range of state management options and may or may not correlate multiple calls from

the same user, depending on what object lifetime scheme you choose. SingleCall objects are stateless (like

the objects used to invoke ASP.NET Web services), Singleton objects share state for all clients, and client-

activated objects maintain state on a per-client basis (with all the associated scalability and reliability issues

this raises).

Performance
In terms of raw performance, the .NET Remoting plumbing provides the fastest communication when you use

the TCP channel and the binary formatter. In almost all the tests that we carried out to compare the relative

performance of ASP.NET Web services and .NET Remoting, ASP.NET Web services outperformed .NET Remoting

endpoints that used the SOAP formatter with either the HTTP or the TCP channel. More interestingly, ASP.NET

and .NET Remoting endpoints that used the binary formatter and the HTTP channel were very similar in

performance. (See Performance Comparison: .NET Remoting vs. ASP.NET Web Services for more details.)

Enterprise Services

An ASP.NET Web Service or an object exposed via .NET Remoting can use local transactions to coordinate work

against a single database. If it needs to coordinate work against multiple resources, it can use a .NET

Enterprise Services (a.k.a. COM+) declarative transaction (a DTC distributed transaction managed by the

COM+ plumbing). It is important to note, however, that neither the ASP.NET Web services nor the .NET

Remoting plumbing supports propagating a declarative transaction, so it is impossible for either sort of endpoint

to inherit a declarative transaction via a cross-process call.

This is not necessarily a bad thing. In general, a declarative transaction is more expensive than a local

transaction and if you spread a declarative transaction across process boundaries, it becomes more expensive

still. If you really need this functionality, the easy solution is to deploy a class derived from

System.EnterpriseServices.ServicedComponent in a .NET Enterprise Services server application (see

COM+ Integration: How .NET Enterprise Services Can Help You Build Distributed Applications for more

information). Cross-process calls to the objects of that type will be handled using DCOM in order to ensure

proper propagation of transactional context. The harder solution is to use lower-level APIs to propagate a

distributed transaction by hand.

It is important to note that the classic distributed transaction model is generally not appropriate for loosely

coupled Web services. A model based on compensating transactions, that is, transactions that undo the

committed work of other transactions, make more sense because they have less stringent isolation constraints.

There is a general consensus among Web service vendors, including Microsoft, that a more flexible transaction

model is needed in the Web services space, and there is a lot of ongoing work in this space. Until a standard

approach for Web service transactions is defined, you can implement your own compensation schemes using

local or declarative transactions as appropriate.

Choosing an Architecture

If you are designing a distributed application built on .NET, you have to consider all of the issues discussed in

this paper and draw some conclusions about what your system's architecture should look like. In general, this

turns out to be easier than you might think. While there is always a special case that requires an alternate

approach, here are some general assumptions you can make that will simplify things for you.
First, use ASP.NET Web services by default. They are simpler to implement and use, they offer the broadest

possible reach to client platforms, and ASP.NET Web services client proxy code can be invoked from code run in

a sandbox under the default security policy.

If you need a more traditional distributed object model with full CLR type fidelity, you don't need

interoperability with other platforms, and you control the configuration of both clients and servers, consider

.NET Remoting. If you choose .NET Remoting, prefer the HTTP channel integrated with IIS and ASP.NET,

otherwise you have to build your own process lifecycle management and security infrastructure. Given that

.NET Remoting requires a .NET client, it makes sense to use the binary formatter instead of the SOAP

formatter; interoperability is not an issue and performance will be noticeably better.

Finally, use Enterprise Services (COM+) when you need declarative transactions. If you implement

ServicedComponents, deploy them in library applications by default, for performance reasons. Deploy them in

server applications if they need to run on remote machines. (You might also consider COM+ server applications

if you need to execute code with a different process security token than the one used by aspnet_wp.exe, even

on the same machine.)

Here are three common architectures based on these ideas.

Figure 1. A simple 3-tier architecture

Figure 1 shows a simple 3-tier architecture with a Web server farm supporting a range of different clients. All

server-side code executes in the ASP.NET worker process, aspnet_wp.exe. The three different types of clients

access the server farm by using HTTP. Browser-based clients invoke ASP.NET Web pages; rich clients (e.g.,
Windows Forms applications, Microsoft® Visual Basic® 6 applications) and other Web services use ASP.NET

Web services; and .NET rich clients (e.g., Windows Forms applications) and Web services use ASP.NET Web

services or .NET Remoting with the HTTP channel and the binary formatter (assuming it is not in a sandbox), as

desired.

Figure 2. An n-tier architecture using ASP.NET

Some very large applications use a second set of machines to offload work from the outer tier of Web servers.

This architecture is shown in Figure 2. Note that in this case, the second tier exposes functionality through

ASP.NET as well.
Figure 3. An n-tier architecture using Enterprise Services (COM+)

Figure 3 shows an alternative version of this architecture with the second tier exposing functionality using

ServicedComponents deployed in COM+.

Obviously, these are not all of the possible architectures that the .NET Framework supports. However, they

provide a reasonable place to start in the design of your own systems.

Summary

Though both the .NET Remoting infrastructure and ASP.NET Web services can enable cross-process

communication, each is designed to benefit a different target audience. ASP.NET Web services provide a simple

programming model and a wide reach. .NET Remoting provides a more complex programming model and has a

much narrower reach. It is important to understand how both technologies work and to choose the one that is

right for your application. In either case, expect to use IIS and ASP.NET to manage process lifecycle and

provide security in the general case.


Performance Comparison: .NET Remoting vs. ASP.NET Web
Services
Building Distributed Applications with Microsoft .NET

Priya Dhawan

Microsoft Developer Network

September 2002

Applies to:

Microsoft® .NET Remoting

Microsoft® ASP.NET Web Services

Summary: Compares relative performance of Microsoft ASP.NET Web services, which provide the highest

levels of interoperability with full support for WSDL and SOAP over HTTP; and Microsoft .NET Remoting, which

is designed for common language runtime type-system fidelity, and supports additional data format and

communication channels. (14 printed pages)

Download BDADotnet.msi sample code or Bdadonet_beta2.msi.

Contents

Introduction

Test Scenarios

Test Tools and Strategy

Machine Configuration

Performance Test Results

Conclusion

Introduction

ASP.NET Web services and .NET Remoting provide a full suite of design options for cross-process

communication in distributed applications. In general, ASP.NET Web services provide the highest levels of

interoperability with full support for WSDL and SOAP over HTTP, while .NET Remoting is designed for common

language runtime type-system fidelity and supports additional data format and communication channels. For

more information, see ASP.NET Web Services or .NET Remoting: How to Choose.

This article focuses on comparing relative performance of these techniques.

ASP.NET Web Services

ASP.NET provides a Microsoft® IIS-hosted infrastructure that supports industry standards such as SOAP, XML,

and WSDL. Although.NET Remoting supports IIS hosting and SOAP over HTTP, ASP.NET is designed to provide

the highest level of SOAP interoperability including support for SOAP Section 5 and document/literal.
ASP.NET can leverage the features available with IIS, such as security and logging. IIS hosting is also robust in

that it will re-spawn Aspnet_wp.exe if it terminates. Also, ASP.NET Web services are much easier to create and

consume than services exposed using .NET Remoting because configuration is simplified both at the server and

client.

For more details, see Building XML Web Services Using ASP.NET in the .NET Framework Developer's Guide.

.NET Remoting

.NET Remoting is more versatile and extensible in terms of enabling communication between objects using

different transport protocols and serialization formats. TCP, HTTP, and custom protocols are supported as are

Binary, SOAP, and custom formats. Multiple-object creation and lifetime modes are supported including

Singleton, SingleCall, and Client-Activated. Remoting requires a host process, which can be IIS, or a Microsoft®

Windows service or executable written in .NET.

A .NET Remoting object using the SOAP formatter can be exposed as an XML Web service when hosted in IIS

with ASP.NET. Since the payload is encoded in SOAP over HTTP, any client that supports the SOAP Encoding

format can access the objects over the Internet. Another advantage of using the HTTP protocol is that it

generally passes unobstructed across most firewalls. The TCP channel and the Binary formatter can be

employed in an intranet environment where both the server and client are running on the .NET Framework.

This approach is optimized for performance since raw sockets are used to transmit data across the network

using a custom protocol that is more efficient than HTTP. Though this approach offers excellent performance in

a closed environment, it cannot be employed in cross-platform scenarios where the client is not running the

.NET Framework.

IIS hosting provides secure communication for wire-level protection using Secure Sockets Layer (SSL), and you

can also leverage IIS and ASP.NET authentication and authorization. The TCP channel as well as the HTTP

channel with non-IIS hosting do not support secure socket transmission, so data is transmitted in clear text.

You are required to implement your own security if you are using the TCP channel or the HTTP channel hosted

in processes other than IIS.

For more details, please refer to the .NET Remoting Overview in the .NET Framework Developer's Guide.

Test Scenarios

Performance of cross-process communication in distributed applications depends on a number of factors:

Channels including TCP and HTTP used to transport messages between applications across remoting boundaries

impose various amounts of overheads. TCP sockets are more efficient than HTTP.

Serialization is another factor. The serialized stream can be encoded using XML, SOAP, or a compact binary

representation. ASP.NET Web services use the XMLSerializer class to serialize an object into an XML stream,

which is extremely fast with the exception that there is some overhead associated with XML parsing. Remoting
uses BinaryFormatter and SOAPFormatter to serialize an object into binary and SOAP format, respectively.

Since these formatters use reflection, they are fast for referenced objects, but can be slow for value types

which have to be boxed and unboxed to pass through the reflection API. The SOAPFormatter has some

additional overheads of generating encoded SOAP messages.

The tests used in this comparison are based on common business scenarios accessing customer and order data.

To make the test as realistic as possible, the database contains over 100,000 rows of Customer accounts. The

data is in a Microsoft® SQL Server™ 2000 database and the SQL Server .NET data provider is used to connect

to SQL Server.

The following methods are used in the performance comparison:

GetOrderStatus

The GetOrderStatus method accepts an OrderId and returns an integer representing the status of the order.

GetCustomers

The GetCustomers method accepts a CustomerId and a parameter to specify the number of customer rows

you want to read. The top n rows with CustomerId greater than the CustomerId passed to the Web Service

method are read.

We performed tests with paging through a small set of customer rows with different page sizes: 20, and 50.

Test Tools and Strategy

In our tests an ASPX Web page calls the remote object containing the test code. Although we would get better

absolute performance if we were to test the techniques directly, rather than behind a Web server, testing in a

stateless environment is realistic for common application scenarios. Moreover, there are a number of test tools

available that can appropriately stress Web pages providing multithreaded testing and reliable performance

statistics.

For our tests, we used Microsoft Application Center Test (ACT), which is designed to stress test Web servers

and analyze performance and scalability problems with Web applications, including ASPX pages and the

components they use. Refer to ACT documentation for details on how to create and run tests. Application

Center Test can simulate a large group of users by opening multiple connections to the server and rapidly

sending HTTP requests. It also allows us to build realistic test scenarios where we can call the same method

with a randomized set of parameter values. This is an important feature whereby users are not expected to call

the same method with the same parameter values over and over again. The other useful feature is that

Application Center Test records test results that provide the most important information about the performance

of the Web application.

As I mentioned earlier, there are two types of activation for remoting objects—server activation and client

activation. The server directly controls the lifetime of a server-activated object. There are two modes of
activation for server-activated objects—Singleton and SingleCall. Singleton types never have more than one

instance running at one time. All client requests are serviced by a single instance, and hence, using this

activation mode you can maintain state between clients. On the other hand, each client request is serviced by a

separate instance in the case of SingleCall types. Client-activated objects are created on the server, but the

calling application domain controls the lifetime of those objects. Using this mode allows you to maintain state

between requests from the same client. ASP.NET only supports SingleCall, i.e., each request is serviced by a

new instance, and if the service is to be stateful, then it must be managed using cookies and SessionState or

custom SOAP headers. In all of the tests that have been performed to compare the various remoting options,

SingleCall mode is used for a fair comparison.

Although ASP.NET Web services support SOAP, HTTP-GET, and HTTP-POST options we used only the SOAP

option in our tests for consistency.

HTTP/1.1 recommends that any one client can only have up to two connections to a single server. Therefore,

when using the HTTP protocol for communication (as in remoting with the HTTPChannel and ASP.NET), it only

opens 2 connections by default at any given time to a given server, while the TCP channel opens as many

connections as there are threads making requests to the server. For simulating multiple clients sending

simultaneous requests to the remote object, we changed the default of 2 to 100 connections to the server per

client using the client's configuration file:

When doing remoting with the HTTP channel—use the clientConnectionLimit attribute in the client's .config

file:

<system.runtime.remoting>

<application>

…

<channels>

<channel ref="http" clientConnectionLimit="100">

<clientProviders>

<formatter ref="soap" />

</clientProviders>

</channel>

</channels>

</application>

</system.runtime.remoting>

For ASP.NET Web Services, use the maxConnection attribute in <system.net> in the client's .config file:
<system.net>

<connectionManagement>

<add address="*"

maxconnection="100"

/>

</connectionManagement>

</system.net>

Since unlimited HTTP connections are allowed to the "localhost", i.e., when both the client and the server are

on the same machine, you don't need to change the configuration file.

Machine Configuration

The following tables provide a brief summary of the test bed configuration used to perform the tests.

Table 1. Client Machine Configuration

Number of Machine/CPU # Of Memory Disk Software


clients CPUs

1 Compaq Proliant 1130 2 1GB 16.9 GB


MHz • Windows 2000

Advance Server SP 2

• Application Center

Test

Table 2. Web Server Configuration

Number of Machine/CPU # Of Memory Disk Software


servers CPUs

3 Compaq Proliant 1000 2 1 GB 16.9 GB


MHz • Windows 2000

Advance Server SP 2

• Release version of

.NET Framework SP1

Table 3. Application Server Configuration

Number of Machine/CPU # Of Memory Disk Software


servers CPUs

1 Compaq Proliant 1126 2 1 GB 16.9 GB


MHz • Windows 2000
Advance Server SP 2

• Release version of

.NET Framework SP1

Table 4. Database Server Configuration

Number of Machine/CPU # Of Memory Disk Software


servers CPUs

1 Compaq Proliant 700 4 4 GB 18 GB


MHz • Windows 2000

Advance Server SP 2

• SQL Server Enterprise

Edition SP 2

Performance Test Results

Throughput and latency are the key performance indicators. For a given amount of data being returned,

throughput is the number of client requests processed within a certain unit of time, typically within a second.

Because peak throughput may occur at a response time that is unacceptable from a usability standpoint, we

tracked latency—measured as response time using the report generated by Application Center Test for each of

the tests run.

Cross-Machine Scenario

In the cross-machine scenario, the remoting client and the remoting object are on different computers. The ACT

clients send requests to an ASPX Web page that in turn calls the method on the remote object.

Figure 1. Cross-machine scenario


As Figure 1 shows, the tests were performed behind a Web server, and there were database access and

network hops to external machines, which added on extra overhead. Therefore, the performance numbers

generated for throughput and latency act merely as a basis to compare these technologies. They do not

represent absolute performance. Exact throughput and latency for distributed systems built using ASP.NET Web

services and .NET Remoting will depend on the architecture used.

GetOrderStatus

Here we compare the behavior of various techniques when getting a single value from the database.

Figure 2. GetOrderStatus: Throughput and latency

Note:

• ASMX: ASP.NET Web service

• All the other options represent various .NET Remoting configurations.


• In all of the other options, the name hints the host, transport protocol and format that are being used,

i.e., Host_TransaportProtocol_Format.

• 'WS' is used as an abbreviation for Windows Service, which hosts the remoting type.

• IIS_HTTP_Binary/SOAP are hosted in IIS with ASP.NET.

WS_TCP_Binary, as shown in Figure 2, in which the object is configured to use the TCP channel and the Binary

formatter with host being a Windows service, outperforms other distribution techniques. The reason for this is

that this approach transmits binary data over raw TCP sockets, which are more efficient than HTTP. and since

the data does not have to be encoded/decoded, there is less processing overhead. We see around 60%

performance spread between WS_TCP_Binary and the slowest approach.

Though IIS_HTTP_Binary produces the same binary payload as WS_HTTP_Binary does, it is slower, as there is

an extra process hop from IIS (Inetinfo.exe) to Aspnet_wp.exe. The same reason explains the performance

difference between IIS_HTTP_SOAP and WS_HTTP_SOAP.

WS_HTTP_Binary and WS_TCP_SOAP offer very similar performance. Although the former has the additional

overhead of parsing HTTP, and the latter has the additional overhead of parsing SOAP, it seems the overhead of

HTTP parsing and SOAP parsing come out about the same in this case.

The ASP.NET Web service outperforms IIS_HTTP_SOAP and WS_HTTP_SOAP, since ASP.NET XML serialization

is more efficient than .NET Remoting SOAP serialization. And as can be seen in Figure 2, the ASP.NET Web

service is very similar to IIS_HTTP_Binary in performance.

GetCustomers Using a Custom Class

In this section, the remote method retrieves the customer records from the database into a DataReader,

populates a Customers object using the data in the DataReader and returns the Customers object. We

performed tests with a result set of 20 and 50 rows to see how the amount of data returned impacts

performance.
Figure 3. GetCustomers(n=20): Throughput and latency

The relative performance of other options gains substantially over WS_TCP_Binary, as the cost of marshalling

the Customers object becomes a significant factor here. In this test we are serializing a Customers object

containing 20 Customers as compared to serializing an integer in the previous test.

IIS_HTTP_Binary is slightly slower than WS_HTTP_Binary because of the extra process hop involved in the

former case as mentioned earlier. Note that the ASP.NET Web service offers very similar performance as

IIS_HTTP_Binary.

The performance of WS_TCP_SOAP is substantially reduced with more data and it is now comparable to

WS_HTTP_SOAP and IIS_HTTP_SOAP. The reason being that most of the time is spent serializing data in this

case, which becomes the significant factor affecting performance.


Figure 4. GetCustomers(n=50): Throughput and latency

Note:

• ASMX_SOAPExtn: Uses a SOAPExtension to work around a buffering issue with ASP.NET.

As you see in Figure 4, with increase in size of data, the performance difference between WS_TCP_Binary and

other options is reduced all the more.

Note that the ASP.NET Web service has fallen behind IIS_HTTP_Binary. This is because of a known issue with

buffering of large messages in ASP.NET that has been fixed in the upcoming version. With the buffering issue

fixed, the ASMX option will be in line with IIS_HTTP_Binary, as we saw in the previous tests.

We worked around the buffering issue by implementing a SOAPExtension that provides some buffering between

the XmlSerializer and the network. As you see in the graph, the ASMX_SOAPExtn option (which uses the

SOAPExtension that we implemented) improves substantially over the ASMX option and is slightly behind
IIS_HTTP_Binary. The SOAPExtension is included in the Building Distributed Applications with .NET

downloadable sample code.

WS_TCP_SOAP, WS_HTTP_SOAP and IIS_HTTP_SOAP are similar in performance with WS_TCP_SOAP being

slightly faster.

GetCustomers Using a DataSet

In the next set of tests, the remote method retrieves the customer records from the database in a DataSet,

which is returned to the client.

Figure 5. GetCustomers(n=20): Throughput and latency

The relative performance between WS_TCP_Binary and other approaches has decreased as the overhead

associated with dataset marshalling becomes a significant factor here.

IIS_HTTP_Binary maintains a slight lead over WS_HTTP_Binary. The cost of extra process hop in the latter has

become negligible as compared to the data marshalling cost.


Note that the performance of the ASP.NET Web service has dropped so much so that it performs similar to

WS_TCP_SOAP, WS_HTTP_SOAP and IIS_HTTP_SOAP. This drop in performance is due to two known issues in

ASP.NET, which will be fixed in upcoming versions. One is the buffering issue as discussed earlier; other is

related to DataSet serialization in ASP.NET. With these issues fixed, the ASP.NET Web service will be nearly

comparable to IIS_HTTP_Binary. By working around the buffering issue with large messages, ASMX_SOAPExtn

has gained largely over ASMX, as you see in Figure 5, however, the performance is still degraded because of

the DataSet serialization issue.

Figure 6. GetCustomers(n=50): Throughput and latency

The relative performance between WS_TCP_Binary and other approaches has substantially dropped, as the size

of the dataset is larger than in the previous test. We see very similar performance offered by WS_HTTP_SOAP,

and IIS_HTTP_SOAP.

The ASP.NET Web service approach has fallen behind all the more because of the known issues we discussed

earlier. Note that just by working around the buffering issue, ASMX_SOAPExtn gains significantly over ASMX.
Conclusion

As these tests demonstrate, the various design choices available with ASP.NET Web services and .NET

Remoting carry varying amounts of overhead and therefore have vastly different performance characteristics.

The size of data being passed is also significant and multiplies the differences between the other design

choices. This comparison covers only stateless, synchronous remote procedure calls and does not cover the

performance implications of authentication, authorization, and data privacy, which are other significant factors

affecting the performance of distributed applications.

Though both the .NET Remoting infrastructure and ASP.NET Web services can implement inter-process

communication, each is designed with a particular level of expertise and flexibility in mind to benefit a different

target audience. If your application needs interoperability with other platforms or operating systems, you would

be better off using ASP.NET Web services, as they are more flexible in that they support SOAP section 5 and

Document/Literal. On the other hand, use .NET Remoting when you need the richer object-oriented

programming model. See ASP.NET Web Services or .NET Remoting: How to Choose for details. In scenarios

where performance is the main requirement with security and process lifecycle management is not a major

concern, .NET Remoting TCP/Binary is a viable option; however, keep in mind that you can increase the

performance of IIS-hosted implementations by adding a few more machines into the system, which may not be

possible when using a .NET Remoting TCP/Binary implementation.


Performance Comparison: Security Design Choices
Building Distributed Applications with .NET

Priya Dhawan

Microsoft Developer Network

October 2002

Applies to:

Microsoft® ASP.NET

Microsoft® .NET Framework SP1

Microsoft ® Windows® 2000 Advanced Server SP2

Microsoft® SQL Server™ 2000 and Enterprise Edition SP2

Microsoft Application Center Test (ACT)

Summary: Compares the relative performance of various security options available for client authentication,

hashing algorithms, cryptography techniques, and digital signatures. (19 printed pages)

Contents

Introduction

Test Tools and Strategy

Machine Configuration

Performance Test Results

Conclusion

Introduction

Design choices for securing a system affect performance, scalability and usability. There is usually a tradeoff

between security vs. performance and usability. The more secure a system is, the more you have compromised

in terms of performance and usability. When designing a secure system, you should determine all the possible

threats, vulnerabilities, and attacks and choose the techniques to implement security based on threat mitigation

first and performance second.

This article compares the relative performance of various security options available for client authentication,

hashing algorithms, cryptography techniques, and digital signatures. For simplicity we have isolated these

different categories of security and restricted the performance comparison to the options available with each

category; of course in a real secure system, the overall security will be the combination of one or more of these

categories.

Test Tools and Strategy

For our tests, we used Microsoft Application Center Test (ACT), which is designed to stress test Web servers

and analyze performance and scalability problems with Web applications, including ASPX pages and the
components they use. Refer to ACT documentation for details on how to create and run tests. Application

Center Test can simulate a large group of users by opening multiple connections to the server and rapidly

sending HTTP requests. It also allows us to build realistic test scenarios where we can call the same method

with a randomized set of parameter values. This is an important feature, whereby users are not expected to call

the same method with the same parameter values over and over again. The other useful feature is that

Application Center Test records test results that provide the most important information about the performance

of the Web application.

ACT supports Basic, Kerberos and Digest authentication. It does not handle ASP.NET Forms authentication

automatically. We explicitly edited the body of the request to mimic a client side form submission.

We used a separate machine as the domain controller. Ten thousand user accounts were held in Active

Directory. The same number of users was created for Application Center Test that picked up users at random

when a test was being run.

Machine Configuration

The following tables provide a brief summary of the test bed configuration used to perform the tests.

Table 1. Client Machine Configuration

Number of Machine/CPU # of CPUs Memory Disk Software


clients

1 Compaq Proliant 1130 2 1GB 16.9 GB


MHz • Windows 2000

Advanced Server SP 2

• Application Center

Test

Table 2. Web Server Configuration

Number of Machine/CPU # of Memory Disk Software


servers CPUs

1 Compaq Proliant 1000 2 1 GB 16.9 GB


MHz • Windows 2000

Advanced Server SP 2

• .NET Framework SP1

Table 3. Application Server Configuration

Number of Machine/CPU # of CPUs Memory Disk Software


servers

1 Compaq Proliant 1126 2 1 GB 16.9 GB


MHz • Windows 2000
Advanced Server SP 2

• .NET Framework SP1

Table 4. Database Server Configuration

Number of Machine/CPU # of Memory Disk Software


servers CPUs

1 Compaq Proliant 700 4 4 GB 18 GB


MHz • Windows 2000

Advanced Server SP 2

• SQL Server Enterprise

Edition SP 2

Performance Test Results

Throughput and latency are the key performance indicators. For a given amount of data being returned,

throughput is the number of client requests processed within a certain unit of time, typically within a second.

Because peak throughput may occur at a response time that is unacceptable from a usability standpoint, we

tracked latency—measured as response time using the report generated by Application Center Test for each of

the tests run.

Note The performance numbers generated for throughput and latency act merely as a basis to compare these
technologies. They do not represent absolute performance.

Client Authentication

A server authenticates a client by accepting its credentials and validating those credentials against some

designated authority. We will focus on the authentication modes Microsoft® ASP.NET supports, including

Microsoft IIS 5.0 authentication modes and ASP.NET Forms authentication. Please refer to ASP.NET Web

Application Security in the .NET Framework Developer's Guide for details.

Get Default Page

The test included having a single ACT user send a single request to the customer. Upon requesting the page,

the user was asked to authenticate itself by means of providing username and password. Once the user got

authenticated, the page is returned with a simple string.

Note This test does not model a scenario wherein, after getting authenticated on the first request, the user
sends subsequent requests by presenting to the Web server some sort of ticket to show that its already been
authenticated.
Figure 1. Authentication modes: RPS and response time

Note:

• Anonymous: No authentication is performed.

• User accounts were stored in Active Directory, which was on a separate box than the Web server.

• FormsAuth_AD: It uses ASP.NET Forms authentication. User accounts in Active Directory.

• FormsAuth_SQL: It uses ASP.NET Forms authentication. User accounts stored in SQL Server 2000. For

security reasons, password should not be stored in clear text in database. Rather, you should generate and

store a one-way hash of user's password combined with a salt (a cryptographically generated random

number) for added security and to mitigate threat associated with dictionary attacks. This approach is

preferred to storing an encrypted version of the user's password as it avoids key management issues

associated with encryption techniques.


As you would expect, the Anonymous authentication mode, in which no authentication is performed, offers the

best performance. The Web server does not request the client to send user credentials before the client can

view the Web page. This mode is a good choice when you want your site to be publicly available.

With all the other authentication modes, the client is required to send additional authentication messages,

which takes additional round trips to the Web server. In Basic, Digest, and Kerberos authentication, the flow of

HTTP headers looks like:

Figure 2. Authentication header flow

As shown in Figure 1, Digest and Kerberos authentication modes are very similar in performance, though they

have different overheads associated with them. In Digest authentication, the server sends a challenge (NONCE)

to the client asking for the username and password. One-way hash of the password (including the resource

being accessed and the realm) is used to encrypt the NONCE, which is then sent to the server where the client

gets authenticated. The password is not sent in clear text, which certainly is an advantage over Basic

authentication. The biggest shortcoming of Digest authentication, despite being an industry standard, is that

only a few browsers and Web servers support it, which limits its widespread use. Microsoft® Internet Explorer

5.0 is the first to adopt it along with IIS 5.0 and later. It works with Windows 2000 domain accounts only and

requires the accounts to store passwords as encrypted clear text (note that this not the case with Microsoft®

.NET® Server).

In Kerberos, the browser attempts to use the user's credentials from a domain logon. If the server rejects those

credentials, the client is prompted for a username and password by means of a dialog box. The credentials are

sent directly to the Ticket Granting service server, which authenticates the credentials and issues a Kerberos

ticket to the client. This ticket is a temporary certificate containing information that identifies the user to the

network server. Typically, the client caches the ticket so that it is used for subsequent requests to the server

until it expires.

As you see in Figure 1, Basic authentication and FormsAuth_SQL perform exactly similar. With Basic, the client

sends the user credentials to the Web server, which makes a round trip the domain controller to get the user

authenticated. Remember that Basic authentication is extremely insecure because the password is passed over

the network in clear text (actually it is base64-encoded, which can very easily be decoded). To make Basic

more secure, you can use SSL to establish a secure session. But it still is not as secure as any of the real
network authentication protocols like Kerberos and Digest, which do not send the user's secret to the remote

server.

The flow of HTTP headers for ASP.NET Forms authentication looks like:

Figure 3. Authentication header flow

Note that ASP.NET Forms Authentication is slower than all of the Windows authentication schemes. This could

be because it involves a couple of redirection before a page can be viewed. In the case of FormsAuth_AD, the

system programmatically looks up the user in Active Directory. If a username with the provided password

exists in the Active Directory, the user gets authenticated. Similarly, in the case of FormsAuth_SQL, the system

calls a SQL stored procedure to look up the user in the database. If the query succeeds, the user is

authenticated. We didn't store passwords in clear text in database; rather we stored one-way hash of user's

password combined with a salt. We used SHA1 to generate the hash. So in the FormsAuth_SQL mode, when a

user submits its credentials, the system first retrieves the hash and salt associated with the user from the

database. It then generates the hash of user-supplied password and salt that it just retrieved from the

database. If the two hashes match, the user is authenticated. This process consumes extra cycles since we are

generating a hash using an SHA1 algorithm while authenticating a user.

ASP.NET Forms authentication is as insecure as Basic since the password is sent in clear text over the network.

There's a difference, though; Forms authentication sends credentials once and then uses an encrypted ticket

thereafter, whereas Basic authentication sends credentials with each request. To make Forms authentication

more secure you can use SSL to establish a secure session, though there will be an impact on performance.

Using Forms authentication without SSL makes it susceptible to a replay attack.

Take a look at Authentication in ASP.NET: .NET Security Guidance, which discusses the advantages and

disadvantages of these authentication schemes and the environment they are best suited for.

Cryptography Techniques

Cryptography techniques provide data privacy, tamper detection, and authentication by encrypting the data

being transmitted between the server and client, assuming there is a pre-shared secret between them that has
not been exposed. We will focus on hashing algorithms including SHA1 and MD5, symmetric algorithms

including DES, RC2, 3DES and Rijndael and asymmetric algorithms including RSA and DSA. For details, see

Cryptography Overview in the .NET Framework Developer's Guide.

Hashing Algorithms

Hash algorithms map a piece of data of arbitrary size to a small unique value of fixed length. We will compare

the SHA1 and MD5 algorithms. For details, see Cryptography Overview in the .NET Framework Developer's

Guide.

ComputeHash

The method computes the hash of data stored in a file. We performed the tests with a data size of 4 KB, 135

KB, and 1 MB to see how the size of data impacts performance.

Figure 4. Hash algorithms (4 KB): RPS and response time

Note:
• .NET Framework supports various hash algorithms including MD5, SHA1, SHA256, SHA384, and

SHA512. The only difference between the various SHA implementations is the hash size that they produce.

We opted to include only SHA1 and SHA512 in our tests.

• We used System.Security.Cryptography that provides various implementations of SHA1 and MD5.

• There is just one implementation of MD5 available in System.Security.Cryptography:

MD5CryptoServiceProvider that wraps CAPI.

• SHA256, SHA384 and SHA512 are not currently available in CryptoAPI. These algorithms are

implemented directly in managed code. These algorithms have been added just to support the new key

generation requirements of AES, not to provide stronger algorithms than SHA1. The current belief is that

SHA1 is more than adequate for hashing data.

• For SHA1 and SHA512, we used managed implementations, SHA1Managed and SHA512Managed,

respectively, available in System.Security.Cryptography.

As shown in Figure 4, all the algorithms are very similar in performance with SHA512 slightly behind. MD5

produces a hash of size 128 bits. The computation process in SHA is very much modeled after MD5. It produces

a 160-bit hash.

Longer hash sizes are harder to attack using brute force methods. SHA512 generates a 512-bit hash, SHA1 a

160-bit hash, and MD5 a 128-bit hash; therefore SHA1 is harder to use brute force with than MD5. This also

assumes no weaknesses in the algorithms.


Figure 5. Hash algorithms (135 KB): RPS and response time

With increase in size of data, we see that the performance difference between the various algorithms has

increased. At 5 concurrent users, MD5 is around 33% faster than SHA1. Although there is not yet a known

method to attack MD5, there are theoretical collisions that can be exploited against it.

The performance of SHA512 has degraded with more data. It is around 55% slower than SHA1.

Bear in mind that longer hash size provides greater security at the cost of performance, as I mentioned earlier.
Figure 6. Hash algorithms (1 MB): RPS and response time

The performance difference between the algorithms is increased even more with increase in data.

MD5 is around 43% faster than SHA1 at a user load of 5 concurrent users (at other user loads it is around 20%

faster). SHA1 is around 72% faster than SHA512.

Symmetric Key Algorithms

The method that was tested encrypts the data first and then decrypts the encrypted bytes. We performed the

tests with a data size of 4 KB, 100 KB, and 500 KB to see how the size of data impacts performance.
Figure 7. Symmetric key algorithms (4 KB): RPS and response time

Note:

• We used managed wrappers for DES, 3DES and RC2 available in System.Security.Cryptography that

wrap unmanaged implementations available in CryptoAPI. These are DESCryptoServiceProvider,

TripleDESCryptoServiceProvider, and RC2CryptoServiceProvider, respectively. There is only a pure

managed implementation of Rijndael available in System.Security.Cryptography, which was used in the

tests.

• The Key and block sizes used by the algorithms to encrypt and decrypt data:

Algorithm Key Size Block Size

(Bits) (Bits)

DES 64 64
3DES 192 64

RC2 128 64

Rijndael 256 128

• 3DES, RC2, and Rijndael also support other key lengths, but we chose to encrypt and decrypt data

with the maximum key length supported by each of them. Since a longer key requires more time and effort

to attack, and therefore provides better mitigation, this could enable us to measure the performance when

the algorithm offers the maximum security.

• Longer key lengths provide greater security by decreasing the possibility of successful key search

attacks by increasing the number of key combinations that are possible.

• Different algorithms with a same key length (say 128) may not necessarily provide the same strength.

With small data, we find that Rijndael, an AES (Advanced Encryption standard), is the fastest of all the

methods. It has a variable block length and key length, which may be chosen to be any of 128, 192, or 256

bits. It also has a variable number of rounds to produce the cipher text, which depends on the key length and

the block length.

DES encrypts and decrypts data in 64-bit blocks a using 64-bit key. Each block of data is iterated 16 times to

produce the cipher text. Though it is faster than 3DES and RC2, its short key length makes it vulnerable to a

brute force attack. It is becoming more vulnerable and easily breakable with today's progressively faster and

more powerful computers.

Triple DES (3DES) was invented to improve the security of DES by applying DES encryption three times using

three different keys (note that encrypting data three times with the same key does not offer any value). It is

simply another mode of DES, but it is highly secure and therefore slower in performance. It takes a 192-bit

key, which is broken into three 64-bit subkeys to be used in the encryption procedure. The procedure is exactly

like DES, but it is repeated three times, making it much more secure. The data is encrypted with the first

subkey, decrypted with the second subkey, and encrypted again with the third subkey.

RC2 turns out to be the slowest method when the data being encrypted is small. It has an expensive

computation up front to build a key-dependent table, which apparently is high compared to the cost of

encrypting small data. RC2 is a variable key-length symmetric block cipher, which is designed to be alternatives

to DES.
Figure 8. Symmetric key algorithms (100 KB): RPS and response time

By increasing the size of data being encrypted and decrypted, we see an entirely different picture to what we

saw in the previous test. DES is the fastest, followed by RC2, which is around 20% faster than 3DES. Note that

the expensive computation in RC2 to build the key-dependent table I mentioned in the previous test is

amortized over more data. Rijndael in this case is the slowest; 25% slower than 3DES. Note that we are using

a 256-bit key for Rijndael encryption, which makes it stronger than the other methods (though there has been

some press about possible attacks against Rijndael, which might be better than brute force attack) and for the

same reason the slowest of all. Similarly, we used a 192-bit key in case of 3DES, which is longer than keys

used for DES and RC2 encryption.

One point I would like to mention again is that using a same-length key does not necessarily mean that

different algorithms will have the same strength. Different algorithms have different characteristics and hence

they may not provide the same strength.


As I mentioned earlier in the article, there is always a tradeoff between security and performance. You need to

understand the value of your data, the deployment cost, and usability/performance tradeoffs before you can

begin choosing a right algorithm for securing your data. If the cost of data that you are protecting is high, then

you must consider taking a performance hit to secure your data. Otherwise, you may be better off using a less

secure algorithm.

Figure 9. Symmetric key algorithms (500 KB): RPS and response time

With the increasing size of data being encrypted and decrypted, we see the same trend prevailed in this test

too, though the performance difference is increased between the ciphers, except between 3DES and Rijndael.

Asymmetric Key Algorithms

Encryption using asymmetric key algorithms is very slow, especially when the data size is large; hence, they

are not used when doing bulk encryption. For bulk encryption, symmetric algorithms should be used. The

asymmetric algorithms can be used to do key exchange.


The two common asymmetric algorithms are RSA and DSA. RSA can be used for both encryption and signature

generation. On the other hand, DSA can only be used to generate signature. We compared RSA and DSA

algorithms based on how fast they generate a digital signature and how fast they verify a signature.

Create Signature

Figure 10. Create signature (100 KB): RPS and response time

Note:

• We used RSACryptoServiceProvider and DSACryptoServiceProvider available in

System.Security.Cryptography, which are managed wrappers around the unmanaged RSA implementation

and unmanaged DSA implementation, respectively, provided by CryptoAPI.

• RSA used a 1024-bit Key.

• DSA used a 512-bit key.


As shown in Figure 10, DSA is around 29% faster than RSA when generating a digital signature. In the RSA

digital signature process, the private key is used to encrypt only the message digest. The encrypted method

becomes the digital signature.

Although similar to RSA, DSA does not encrypt message digests with the private key or decrypt the message

digest with the public key. Instead, DSA uses special mathematical functions to generate a digital signature

composed of two 160-bit numbers that are derived from the message digest and the private key.

Figure 11. Create signature (500 KB): RPS and response time

With more data, DSA is still faster than RSA.

Verify Signature
Figure 12. Verify signature (100 KB): RPS and response time

The results are reversed when a digital signature is verified. RSA is faster than DSA by around 29%. RSA uses

a public key to verify the signature. It generates a new message digest from the data that was received,

decrypts the original message digest with the originator's public key, and compares the decrypted digest with

the newly generated digest. If the two digests match, the integrity of the message is verified. The identity of

the originator also is confirmed because the public key can decrypt only data that has been encrypted with the

corresponding private key.

DSA also uses the public key to verify the signature, but the verification process is more complex than RSA.
Figure 13. Verify signature (500 KB): RPS and response time

With more data, the performance difference between the two algorithms has become negligible.

Conclusion

As these tests demonstrate, authentication schemes, hashing algorithms, and cryptography techniques carry

varying amounts of overhead, and therefore have vastly different performance characteristics. The size of data

being passed to hashing algorithms, as well to cryptography techniques, is also significant.

When designing a secure system, the implementation techniques should be chosen based on threat mitigation

first and performance second. For instance, basic authentication without SSL could be used for better

performance, but no matter how fast it is, it would not be useful in systems that are vulnerable to threats not

mitigated by it.
This article does not cover the overall performance impact of combining authentication and data privacy, which

is how the security is built in a real system. The performance of a secure system will vary depending on the

combination of various schemes being used.


Performance Comparison: Data Access Techniques
Building Distributed Applications with Microsoft .NET

Priya Dhawan

Microsoft Developer Network

January 2002

Summary: Compares performance of data access techniques in common application scenarios. Applies to

Microsoft .NET Framework Beta 2 and Microsoft SQL Server 2000. (23 printed pages)

Contents

Introduction

Test Scenarios

Test Tool and Strategy

Machine Configuration

Performance Test Results

Conclusion

Introduction

Architectural choices for data access affect performance, scalability, maintainability, and usability. This article

focuses on the performance aspects of these choices by comparing relative performance of various data access

techniques, including Microsoft® ADO.NET Command, DataReader, DataSet, and XML Reader in common

application scenarios with a Microsoft SQL Server™ 2000 database. In these comparisons, a reference set of

methods is executed against a reference set of Customer, Order, and OrderDetail data under a range of user

load conditions.

Code examples showing the techniques compared here are available in a related set of articles discussing

ADO.NET data access techniques. These examples cover access to single value, single row, multiple row, and

hierarchical data using ADO.NET.

Test Scenarios

Performance of any data operation depends on a number of factors:

The construction of objects used for data access and the population of those objects impose various amounts of

overhead. For example, there is more overhead associated with the instantiation and population of the

ADO.NET DataSet objects than with instantiation of the ADO.NET DataReader or XMLReader objects.

Data access techniques vary in the load they place on the database. For example, the DataSet and

DataReader use database connections differently while the application is reading the data. Data access

techniques that use stored procedures reduce the load on the database as compared to approaches that use
dynamic SQL expressions. Similarly, the transformation of relational data to and from XML uses server

resources.

The number of round trips made to the database server is also a factor, especially where locks and transactions

span multiple round trips. The amount of data sent over the network is another factor, with data represented as

XML being larger than comparable data in other formats.

We compared the ADO.NET data access choices using operations that are common in business applications,

such as getting a customer row, getting orders of a customer, and inserting an order. To make the test as

realistic as possible, the database was loaded with over 100,000 rows of Customer accounts, 1 million rows of

Orders (10 orders per Customer), and over 5 millions rows of Order details (5 details per Order). The data is in

a SQL Server 2000 database and the SQL Server .NET data provider to connect to SQL Server. Some of the

approaches compared here use the XML features of SQL Server 2000.

The methods described next were used to compare the data access techniques.

GetOrderStatus

The GetOrderStatus method accepts an OrderId and returns an integer representing the status of the order.

GetCustomer

The GetCustomer method accepts a CustomerId and returns a single row containing information about the

customer.

GetCustomers

The GetCustomers method accepts a CustomerId and a parameter to specify the number of customer rows

you want to read. The top n rows with CustomerId greater than the CustomerId passed to the Web Service

method are read.

We performed tests with paging through a large set of customer rows with different page sizes: 100, 500, and

1000.

GetOrders

The GetOrders method retrieves a hierarchy of orders and their details from the database. This method

accepts an OrderId and a parameter to specify the number of orders you want to read. The top n rows with

OrderId greater than the OrderId passed to the Web Service method and all the corresponding details are read.

We performed tests by paging through a large set of orders and their details with different page sizes of 10

orders (and 50 details), 50 orders (and 250 details), and 100 orders (and 500 details).

InsertCustomer
The InsertCustomer method accepts customer data, inserts a customer row into the database, and returns a

CustomerId as an integer.

InsertCustomers

The InsertCustomers method accepts data for multiple customers and inserts multiple customer rows into the

database.

InsertOrder

The InsertOrder method accepts data representing an order with multiple details and makes the appropriate

insertions into the Order and OrderDetails tables in the database. The tests were performed by inserting a

single order header and varying number of details.

Test Tool and Strategy

For the purpose of our tests, we used Application Center Test (ACT), which is designed to stress test Web

servers and analyze performance and scalability problems with Web applications, including ASP pages and the

components they use. Refer to ACT documentation for details on how to create and run tests. Using Application

Center Test to test data access techniques behind a Web server made sense because it provides many useful

features for performance testing. It can simulate a large group of users by opening multiple connections to the

server and rapidly sending HTTP requests. It also allows us to build realistic test scenarios where we can call

the same method with a randomized set of parameter values. This is an important feature whereby users are

not expected to call the same method with the same parameter values over and over again. The other useful

feature is that Application Center Test records test results that provide the most important information about

the performance of the Web application.

Although we would get better throughput and better response times if we were to test data access techniques

directly, rather than behind a Web server, testing in a stateless environment is realistic for common application

scenarios; moreover, because we are basically comparing relative performance of these data access

techniques, the overhead of testing in a stateless environment (that is, behind a Web server) will be same in all

the cases.

All the data access scenarios we discussed earlier were implemented as a .NET Framework assembly. To

generate user load against the assembly using Application Center Test, we implemented wrapper .aspx pages,

to which all the client requests were sent and in turn made calls to the assembly. The methods in the assembly

implement a data operation using ADO.NET techniques. They are simple SUB procedures that do not return the

data to the .aspx pages. After retrieving data rows from the database, the methods iterate through the rows

and assign the column values to local variables. By introducing a delay while reading the data off the ADO.NET

objects, we simulate the cost of doing something with the data.


The test scripts were written in Microsoft Visual Basic® Scripting Edition (VBScript). We randomized the

requests to get a different Customer or Order, depending on the method being executed from within the test

script. For example:

Dim URL

Dim UB, LB

' Set the upperbound for Orders list

UB = 1000000

' Set the lowerbound for Orders list

LB = 1

' Set the URL

URL = "http://myServer/DataAccessPerf/DataReader.aspx"

' Use the Randomize funtion to initialize the Rnd function

Randomize

Test.SendRequest(URL & "?OrderId=" & int((UB – LB + 1)*Rnd + LB))

Machine Configuration

The following tables provide a brief summary of the test bed configuration used to perform the tests.

Table 1. Client Machine Configuration

# of Machine/CPU # of Memory Disk Software


Clients CPUs

1 Dell Precision 1 512 MB 16.9


WorkStation GB • Microsoft Windows® XP
530 MT
1694 MHz
• Application Center Test

Table 2. Web Server Configuration

# of Machine/CPU # of Memory Disk Software


Servers CPUs

1 Compaq Proliant 400 4 640 MB 50 GB


MHz • Windows 2000 Advanced

Server SP 2

• .NET Framework Beta 2

Table 3. Database Server Configuration

# of Machine/CPU # of Memory Disk Software


Servers CPUs

1 American 2 1 GB 28 GB
Megatrends Atlantis • Windows 2000 Advance
800 MHz
Server SP 2

• SQL Server Enterprise

Edition SP 2

Performance Test Results

Throughput and latency are the key performance indicators. For a given amount of data being returned,

throughput is the number of client requests processed within a certain unit of time, typically within a second.

Because peak throughput may occur at a response time that is unacceptable from a usability standpoint, we

tracked latency, measured as response time using the report generated by Application Center Test for each of

the test run, and capped the testing of a given method once the response time exceeded 1 second.

GetOrderStatus

Here we compare the behavior of various data access techniques when getting a single value from the

database.
Figure 1. GetOrderStatus: throughput and latency

Notes

• All approaches use stored procedures.

• In the ExecuteScalar approach, the single value is returned using the ExecuteScalar method of the

command object.

• In the Output Parameter approach, the single value is returned as an output parameter of the

command object.

• In the DataReader approach, the DataReader is used to retrieve the single value.

• The XmlReader approach specifies a SQL query with a FOR XML clause to retrieve the single value as

XML in the XmlReader.

As shown in Figure 1, performance of the ExecuteScalar, Output Parameter, and DataReader approaches

is very similar across the entire range of user load when a single value is being retrieved.
The ExecuteScalar approach requires less code than the other approaches and may therefore be the best

option from a code maintainability perspective.

The XMLReader approach produced lower peak throughput than the other approaches and the stored

procedure containing a FOR XML query took longer to execute than the query used by the other approaches.

GetCustomer

Here we compare the behavior of the data access techniques when getting a single row from the database.

Figure 2. GetCustomer: throughput and latency

Notes

• All approaches use stored procedures.

• In the Output Parameters approach the single row is returned as output parameters of the command

object.

• In the DataReader approach the DataReader is used to retrieve the single row.
• The XmlReader approach uses a SQL query with a FOR XML clause to retrieve the single row as XML

in the XmlReader.

• The DataSet approach populates a DataSet with the single row.

As shown in Figure 2, the Output Parameters and DataReader approaches perform very similarly across the

entire range of user load and produce better peak throughput than the other two approaches. The XmlReader

approach produced slightly better peak throughput and smaller response time than the DataSet.

In the XmlReader approach the SQL query using FOR XML took longer to execute than similar queries for the

other approaches.

Overhead associated with creation of the DataSet object is responsible for lower throughput in this scenario.

GetCustomers

In this section we compare the performance when fetching multiple rows. We performed tests with a result set

of 100 rows, 500 rows, and 1000 rows to see how the amount of data returned impacts performance.

Figure 3. GetCustomers (Customers=100): throughput and latency


Notes

• All approaches use stored procedures.

• In the DataReader approach the DataReader is used to retrieve the rows.

• The XmlReader approach specifies a SQL query with a FOR XML clause to retrieve the rows as XML in

the XmlReader.

• The DataSet approach populates a DataSet with the rows.

As you would expect, getting more rows from the database will lower the requests per second, as now there are

more rows that need to be processed and sent.

Figure 3 shows that the DataReader approach nearly doubles throughput over the other two approaches. The

DataSet and XmlReader approaches offer similar performance, although the XmlReader maintains a slight

lead in throughput over the DataSet.

Figure 4. GetCustomers (Customers=500): throughput and latency


The requests per second achieved in this test for all the approaches further drops when we increased the

number of rows returned by the database to 500.

At 500 customers the DataReader widens its lead in throughput over the other approaches with more than

double the throughput. Although still similar in throughput, the DataSet approach has slightly overtaken the

XmlReader approach.

Figure 5. GetCustomers (Customers=1000): throughput and latency

With 1000 rows returned the DataReader now produces three times the throughput of the other approaches.

Testing for the DataSet and XmlReader approaches were capped at 50 users because their response time

exceeded the threshold of 1 second, as can be seen in the Response Time vs. User Load graph.

GetOrders

In this section we compare the performances when fetching a hierarchical result set. We performed tests with a

result set of 10 orders (and 50 details), 50 orders (and 250 details), 100 orders (and 500 details), and 200

orders (and 1000 details).


Figure 6. GetOrders (Orders=10, Details=50): throughput and latency

Notes

• All approaches use stored procedures.

• In the DataReader approach the DataReader is populated by a stored procedure that returns two

result sets—one containing the orders and one containing details. Because the DataReader is forward

only, orders details were not associated with their orders as they were read from the DataReader.

• The XmlReader approach specifies a SQL query with a FOR XML EXPLICIT clause to retrieve orders

and their details as hierarchical XML. Orders and details were associated as they were read from the

XmlReader.

• The DataSet approach uses the same stored procedure as the DataReader approach to populate the

DataSet. A parent/child relation is established between the orders and details DataTables and the orders

and details were associated as they were read from the DataSet.
We started with a result set of 10 orders and 50 details. As shown in Figure 6, the DataReader reached its

peak throughput at a load of 50 concurrent users with a slightly better throughput than the XmlReader, which

levels off at 20 concurrent users.

The DataSet produced lower peak throughput with greater latency. In this case, it incurs an overhead of

creating two DataTables to store order and detail rows and other sub-objects associated with the DataTables.

Figure 7. GetOrders (Orders=50, Details=250): throughput and latency

As clearly shown in the graphs in Figure 7, the DataReader offers the best throughput, although, as just

noted, the orders and details are not associated.

Although the XmlReader and DataSet approaches have similar throughput, the FOR XML EXPLICIT query used

in the XmlReader approach causes significantly greater CPU utilization on the database server than the

DataSet approach, which causes greater CPU utilization on the Web server.
Figure 8. GetOrders (Orders=100, Details=500): throughput and latency

As shown in Figure 8, the DataReader approach widens its throughput difference to double that of the other

two approaches. Remember, however, that the DataReader approach leaves more orders and details to be

associated elsewhere in an application.

DataReader vs. DataSet

In all of the preceding tests, we saw that DataReader outperformed DataSet. As mentioned earlier, the

DataReader offers better performance because it avoids the performance and memory overhead associated

with the creation of the DataSet.

The DataReader is a better choice for applications that require optimized read-only and forward-only data

access. The sooner you load the data off the DataReader, close the DataReader, and close the database

connection, the better performance you get. Because the DataReader holds a database connection that cannot

be used for any other purpose while the application reads data, it could limit scalability if the application holds

the DataReader long enough for contention to occur. The DataSet only needs to hold a connection while it is

being populated. Once it is filled, the connection may be closed and returned to the pool. Delaying reading the
data from the DataSet will not cause contention to occur, as the connection might have been returned to the

pool already.

In all of the preceding tests, the maximum connection pool size was 100 (default size), and because the

number of simultaneous users never exceeded 100, there was no connection contention as such. We wanted to

see how the DataReader and the DataSet would behave if we introduce a little delay while loading off the

data, which in turn will introduce connection contention.

In the following test, we introduced a delay of 20 milliseconds (ms) while reading the data off these objects,

and also set the maximum pool size to 10. This caused contention to occur.

Figure 9. GetCustomers (with contention): throughput and latency

Notes

• In the DataReader approach, the DataReader is used to retrieve hierarchical data containing orders

and their details.

• The DataSet approach populates a DataSet with orders and their details.
When the number of concurrent users reached 20, contention for database connection started to occur and,

hence, the performance of the DataReader started degrading, as shown in Figure 9. Note that the DataSet

outperformed the DataReader beyond 20 concurrent users. Also note that the response time of the

DataReader exceeded that of the DataSet beyond 20 concurrent users.

In the next test we introduced a delay of 50 ms while reading the data off these objects, and set the maximum

pool size to 12.

Figure 10. GetCustomers (with contention): throughput and latency

Notes

• In the DataReader approach, the DataReader is used to retrieve hierarchical data containing orders

and their details.

• The DataSet approach populates a DataSet with orders and their details.

As shown in Figure 10, the performance of the DataReader started degrading beyond 20 concurrent users

when contention for database connection actually started.


Note that the response time of the DataReader exceeded that of the DataSet beyond 20 concurrent users.

InsertCustomer

After getting an idea how the data access techniques compare when reading data, we move on to compare

them when writing data. Here we inserted a single customer in the database.

Figure 11. InsertCustomer: throughput and latency

Notes

• The Input Parameters and InsertCommand approaches use stored procedures.

• In the Input Parameters approach the input parameters of the command object are populated with

new customer's information and the ExecuteNonQuery method is executed to execute the stored

procedure.

• In the AutoGen approach, the Insert command of the DataAdapter is automatically generated

based on its Select command when the Update method is called.

• In the InsertCommand approach, the InsertCommand property of the DataAdapter is specified.


In the Autogen approach, when the Update method is called on the DataAdapter, the CommandBuilder

object associated with the DataAdapter automatically generates the Insert command, depending on the

Select command you specified for the DataAdapter. This explains why it's slower than the other two

approaches. The benefit of this approach is that it simplifies and reduces code, as you don't need to specify

your own insert, update, and delete commands. Compare the performance of this approach with the

InsertCommand approach, where we explicitly specified the InsertCommand of the DataAdapter.

In the Input Parameters approach, the input parameters of the command object are populated with the new

customer's information and the ExecuteNonQuery method is called to execute the SQL stored procedure. This

approach outperforms the other two approaches, as is clearly shown in Figure 11. The InsertCommand

approach incurs the performance and memory overhead of creating the DataSet while the Output

Parameters approach avoids this overhead and achieves better performance.

InsertCustomers

We conducted this set of tests to see how inserting multiple rows of customers affects performance of the

ADO.NET objects. We varied the number of customer rows to increase the amount of data being inserted.
Figure 12. InsertCustomers(n=5): throughput and latency

Notes

• The InsertCommand approach uses stored procedures.

• In the AutoGen approach the Insert command of the DataAdapter is automatically generated based

on its Select command when the Update method is called.

• In the InsertCommand approach, the InsertCommand property of the DataAdapter is specified.

As expected, the InsertCommand approach—wherein we specified the InsertCommand property of the

DataAdapter—is much faster than the Autogen approach. It offers smaller response time and better

throughput across the entire set of users load.

Figure 13. InsertCustomers(n=10): throughput and latency


As shown in Figure 13, the InsertCommand approach still produces greater throughput than the AutoGen

approach when more data is inserted, but the difference between the approaches is reduced as the cost of the

auto-generated command is amortized across more data.

InsertOrder

This last set of tests compares performance when inserting a hierarchy of an order and its details. We varied

the number of detail rows to increase the amount of data being inserted.

Because our Orders table has an auto increment column (OrderId) as its primary key, it was not possible to

insert hierarchical rows in the Orders (parent) and OrderDetails (child) tables using an automatically generated

Insert command for the DataAdapter associated with the Orders table. This is primarily due to the problem

with auto-generated inserts, wherein the primary key Id for an Identity column is not returned to the DataSet.

Therefore, the Autogen approach is actually a hybrid, where the InsertCommand for the Orders table is a

stored procedure (which returns OrderId) and the Insert command for the DataAdapter associated with the

OrderDetails table is auto-generated.

In the OpenXml approach, the InsertCommand property of the DataAdapter associated with the Orders

table is set to a stored procedure, which accepts an XML representation of Order and its details. After inserting

rows in the Orders and OrderDetails tables of the DataSet, the XML representation of the data stored in the

DataSet is extracted and passed to a stored procedure, which using the sp_xml_preparedocument system

stored procedure and the OPENXML method makes appropriate insertions into the Orders and OrderDetails

table in the database.


Figure 14. InsertOrder(Order=1, Details=2): throughput and latency

• The InsertCommand and OpenXml approaches use stored procedures.

• The AutoGen approach is a hybrid using a stored procedure for the Order insert and an automatically

generated Insert command for OrderDetails based on its Select command.

• In the InsertCommand approach we specified InsertCommand properties of both of the

DataAdapters.

• In the OpenXml approach, XML representing the Order and OrderDetails is passed as NVarChar to a

stored procedure, where it is parsed and the appropriate insertions are made.

As shown in Figure 14, the InsertCommand approach outperforms the hybrid AutoGen approach, which

outperforms the OpenXml approach.

The overhead associated with automatically generating the Insert command at execution time and the

efficiencies of stored procedures over dynamic SQL explains why it's slower than the InsertCommand

approach.
Even though the OpenXml approach requires fewer round trips to the database than do the other approaches,

this is not the most important factor affecting performance in this test, when only three insertions are

performed.

Figure 15. InsertOrder(Order=1, Details=10): throughput and latency

Next we tested with inserting 1 order and its 10 details. As Figure 15 shows, the relative performance of the

OpenXml approach gains substantially over the other approaches as the cost of round trips becomes a

significant factor. Here the single round trip used by the OpenXml approach replaces 11 round trips required

by the other approaches.


Figure 16. InsertOrder(Order=1, Details=100): throughput and latency

Note

• In the OpenXml approach, XML representing the Order and OrderDetails is passed as NText to a

stored procedure where it is parsed and the appropriate insertions are made.

And, finally, we tested inserting 1 order and 100 details. Here the single round trip used by the OpenXml

approach replaces 101 round trips required by the other approaches. As Figure 16 shows, the throughput of the

OpenXml approach is now far better than the other approaches. Also note that the AutoGen and

InsertCommand throughput is almost the same in this test due to amortization of the auto-generation costs.

Conclusion

Performance and scalability are among the many things to consider when choosing data access techniques. As

these comparisons have shown, throughput can often be multiplied by choosing one data access technique over

another, yet no single approach performs better in all scenarios. Because overall performance is affected by so

many factors, there is no substitute for performance testing using realistic scenarios.

Vous aimerez peut-être aussi