Using SOAP Extensions
Summary
SOAP Extensions allow you to plug into the SOAP architecture of the .NET
Framework in order to perform some pre- or post-processing on SOAP messages.
When a SOAP message is received by the Web Service's HTTP handler, the SOAP
message is de-serialized into objects (for example, SoapHeader
for header information and SoapMessage for the
body), and eventually passed into some Web Method. After the Web Method has
finished, the result as well as any SoapHeader, SoapMessage,
or SoapException objects are serialized into a SOAP
message and sent back up the chain and to the client.
You can hook up into the request chain before and after the SOAP message is
de-serialized into objects to be processed by the Web Service, and after the Web
Service has finished processing the call and objects are serialized back into
SOAP for transmission back to client.
When working with SOAP extensions, there are two stages for each call direction:
- Client to Web Service
- BeforeDeserialize
This stage occurs before the SOAP request is de-serialized into
objects and sent to the requested Web Service. Here you still have
access to the original SOAP request message. In the figure below
this is before Phase 2.
- AfterDeserialize
This stage occurs after the SOAP request message is de-serialized into
objects and sent to the requested Web Service. You now have access to
the objects that represent the original SOAP request message. In
the figure below this after Phase 2.
- Web Service to Client
- BeforeSerialize
This stage occurs after the Web Service has finished processing and
before the returned objects are serialized back into a SOAP response
message and
sent to the client. Now you have access to all the objects that will be
serialized into a SOAP response message. In the figure below this is before
Phase 3.
- AfterSeriazlize
This stage occurs after the Web Service has finished processing and
after the returned objects are serialized back into a SOAP response
message and
sent to the client. Now you have access to the SOAP message sent back to
the client. In the figure below this after Phase 3.
The following figure illustrates the overall process:

SOAP extensions differ from HTTP modules in a couple of things:
- You can selectively places extensions on certain Web Methods and
ignore other ones (much more difficult to do with HTTP modules).
- You can access the de-serialized objects in the AfterDeserialized
and BeforeSerialize stages but you cannot access
these objects in the HTTP modules (which allow you to see only the SoapMessage
object.)
- It is easier to modify the values before and after the Web Method has
processed the request by using extensions instead of HTTP modules.
SOAP extensions are similar to custom sinks in .NET Remoting: Both are
pluggable extensions into the .NET Framework that are used to perform some pre-
or post-processing on some message. Like .NET Remoting, SOAP extensions can be
used to encrypt/decrypt SOAP messages, to compress/decompress SOAP messages, and
so on. In this chapter, SOAP messages are used to log the actual SOAP messages
sent in requests and responses.
How to create a SOAP Extension
The basic steps to build a Web Service SOAP extension and have it run with an
XML Web Service are:
- Derive a class from SoapExtension. This
derived class is the one that will perform the functionality of the SOAP
extension.
- Save a reference to the Stream representing
future SOAP messages by overriding the SoapExtension.ChainStream
method.
- Initialize SOAP extension-specific data. In the example below, this
specific data is the name of the log file.
- Code SoapExtension.ProcessMessage to process
SOAP message in the pertinent stages. This method is called several times by
ASP.NET at each of the stages defined in SoapMessageStage
enumeration. Each time this function gets called, a SoapMessage or a
class deriving from it is passed in, with information about the SOAP message
at that particular stage.
- Configure the resulting SOAP-extension to run with a specific Web Service
method.
How SOAP extensions are called
The following lists the order of invoking SOAP extension methods when
invoking a Web Service method. The following assumes that the SOAP extension is
running on both client and server.
Client Side
- A client invokes a method on the proxy class.
- A new instance of the SOAP extension is created on the client.
- If this is the first time that the SOAP extension has executed with this
XML Web Service on the client, the GetInitializer()
method is invoked on the SOAP extension running on the client.
- The Initialize() method is invoked.
- The ChainStream() method is invoked.
- The ProcessMessage() method is invoked with SoapMessageStage
set to BeforeSerialize.
- ASP.NET on the client computer serializes the arguments of the XML Web
Service method into XML.
- The ProcessMessage() method is invoked with SoapMessageStage
set to AfterSerialize
- ASP.NET on the client computer sends the SOAP message over the network to
the Web server hosting the Web Service.
Server Side
- ASP.NET on the server receives the SOAP message.
- A new instance of the SOAP extension is created on the server.
- If this is the first time that the SOAP extension has executed with this
XML Web Service on the server side, the GetInitializer()
method is invoked on the SOAP extension running on the server.
- The Initialize() method is invoked.
- The ChainStream() method is invoked.
- The ProcessMessage() method is invoked with SoapMessageStage
set to BeforeDeserialize.
- ASP.NET deserializes the arguments within the XML.
- The ProcessMessage() method is invoked with SoapMessageStage
set to AfterDeserialize.
- ASP.NET creates a new instance of the class implementing the XML Web
Service and invokes the requried method, passing in the deserialized
arguments. This object resides on the same computer as the Web Service.
- The Web Service method executes its code.
- The ProcessMessage() method is invoked with SoapMessageStage
set to BeforeSerialize.
- ASP.NET on the web server serializes the return values and out parameters
into XML.
- The ProcessMessage() method is invoked with SoapMessageStage
set to AfterSerialize.
- ASP.NET sends the SOAP response message over the network to the client.
This example uses SOAP extensions to capture the actual SOAP messages sent
between a Web Service and its clients. It can be a great tool to debug and
understand SOAP requests and responses. The following lists describes the
classes used in this example:
- SoapLoggerAttribute class
This class is used to associate a particular extension with a Web class. This class derives from
SoapExtensionAttribute and is an extension attribute.
An extension attribute is a custom attribute deriving from SoapExtensionAttribute
class. Derived attributed must override the ExtensionType
property to return the type of extension that is associated with the
attribute. This is what the .NET Framework architecture uses to
determine the class that will be implementing the SOAP extension.
Note that a constructor of this class allows you to pass in the full path of
the log file, whereas the Priority property specifies the order in which
this SOAP extension should be executed in relation to other SOAP extensions
that are applied to a given Web Service (this means that multiple SOAP
extensions can be applied to the same Web Service.) A value of 0 tell the
.NET Framework SOAP extension architecture to give this extension the
highest priority.
- SoapLogger class
This class derives from SoapExtension class and is used to include your
extension in the chain, including the ProcessMessage method which is called
each time .NET encounters a new stage. This is where you would perform the
actual processing.
The following illustrates a sample log file generated by the SOAP extension
which allows you to look at the actual SOAP messages being sent around:
**Begin SOAP Request - 3/24/2003 09:26:19
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetCustomer xmlns="http://tempuri.org/" />
</soap:Body>
</soap:Envelope>
**End SOAP Request - 3/24/2003 09:26:19
**Begin SOAP Response - 3/24/2003 09:26:26
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetCustomerResponse xmlns="http://tempuri.org/">
<GetCustomerResult>
<strFirstName>Yazan</strFirstName>
<strLastName>Diranieh</strLastName>
<strCity>NetVille</strCity>
</GetCustomerResult>
</GetCustomerResponse>
</soap:Body>
</soap:Envelope>
**End SOAP Response - 3/24/2003 09:26:26