June 4, 2010, 7:38 a.m.
posted by angryuser
Soap ExtensionsSOAP Extensions are classes that derive from the System.Web.Services. Protocols.SoapExtension base class. A class that derives from this base class will do the work at runtime. At runtime, it will modify any SOAP messages that are sent or received. A second, optional class, System.Web.Services.SoapExtensionAttribute, indicates which methods will have the extension run. Of course, you also can run an extension for every method within an application, or even within the entire system. To do this, you need to register the extension, either in the machine.config file that controls the entire system configuration, or with the application's configuration file. It's also possible to pass method-specific information to the extension via the attribute. If you don't register a SOAP extension in the system configuration and don't use a SoapExtensionAttribute, then nothing will trigger the SOAP extension to run. Creating an extension class is fairly simple. You need to
A SOAP Extension Attribute for an Extension that Compresses and Decompresses SOAP Messages
[AttributeUsage(AttributeTargets.Method)]
public class CompressionExtensionAttribute : SoapExtensionAttribute
{
private int priority;
public override Type ExtensionType
{
get { return typeof(CompressionExtension); }
}
public override int Priority
{
get { return priority; }
set { priority = value; }
}
}
The "Soap" attribute in Listing 6.1 returns the type of the extension, which in this case is called CompressionExtension. Listing 6.2 imports the gzip.dll found in the system32 folder on Windows XP (when IIS is installed) and uses those compression methods to compress the stream. A SOAP Extension That Compresses and Decompresses SOAP Messages
public class CompressionExtension : SoapExtension
{
public CompressionExtension()
{
}
public override Object GetInitializer(
LogicalMethodInfo info,
SoapExtensionAttribute attribute)
{
return null;
}
public override Object GetInitializer( System.Type type )
{
return null;
}
public override void Initialize( Object init )
{
return;
}
public override void ProcessMessage( SoapMessage msg )
{
switch( msg.Stage )
{
case SoapMessageStage.BeforeSerialize:
break;
case SoapMessageStage.AfterSerialize:
Compress();
break;
case SoapMessageStage.BeforeDeserialize:
Decompress( msg );
break;
case SoapMessageStage.AfterDeserialize:
break;
}
}
Stream oldStream;
MemoryStream newStream;
public override Stream ChainStream( Stream s )
{
oldStream = s;
newStream = new MemoryStream();
return newStream;
}
void Compress( )
{
Byte[] bytes = newStream.ToArray();
int totalLength = bytes.Length;
String text = UTF8Encoding.UTF8 GetString( bytes );
int bufferSize = 512;
Byte[] buffer = new Byte[ bufferSize ];
IntPtr contextHandle = IntPtr.Zero;
InitCompression();
CreateCompression( out contextHandle, 1 );
int hResult = 0;
do
{
int outUsed = 0;
int inUsed = 0;
hResult = Compress( contextHandle,
bytes,
totalLength,
buffer,
bufferSize,
ref inUsed,
ref outUsed, 1 );
if( 0 != outUsed )
oldStream.Write( buffer, 0, outUsed );
totalLength -= inUsed;
}
while( hResult == 0 );
oldStream.Flush();
oldStream.Flush();
ResetCompression( contextHandle );
}
void Decompress( SoapMessage msg )
{
Byte[] bytes = new Byte[ 357 ];
oldStream.Read( bytes, 0, 357 );
int totalLength = bytes.Length;
String text = UTF8Encoding. UTF8.GetString( bytes );
int bufferSize = 512;
Byte[] buffer = new Byte[ bufferSize ];
IntPtr contextHandle = IntPtr.Zero;
InitDecompression();
CreateDecompression( out contextHandle, 1 );
int hResult = 0;
do
{
int outUsed = 0;
int inUsed = 0;
hResult = Decompress( contextHandle,
bytes,
totalLength,
buffer,
bufferSize,
ref inUsed,
ref outUsed );
if( 0 != outUsed )
newStream.Write( buffer, 0, outUsed );
totalLength -= inUsed;
}
while( hResult == 0 );
newStream.Flush();
newStream.Position = 0;
ResetDecompression( contextHandle );
}
[DllImport("c:\\winnt\\system32\\inetsrv\\gzip.dll", CharSet=CharSet.Auto)]
private static extern int InitDecompression();
[DllImport("c:\\winnt\\system32\\inetsrv\\gzip.dll", CharSet=CharSet.Auto)]
private static extern int InitCompression();
[DllImport("c:\\winnt\\system32\\inetsrv\\gzip.dll", CharSet=CharSet.Auto)]
private static extern int CreateDecompression(out IntPtr context, int flags );
[DllImport("c:\\winnt\\system32\\inetsrv\\gzip.dll", CharSet=CharSet.Auto)]
private static extern int CreateCompression(out IntPtr context, int flags );
[DllImport("c:\\winnt\\system32\\inetsrv\\gzip.dll", CharSet=CharSet.Auto)]
private static extern int Decompress( IntPtr context,
byte[] input,
int input_size,
byte[] output,
int output_size,
ref int input_used,
ref int output_used );
[DllImport("c:\\winnt\\system32\\inetsrv\\gzip.dll", CharSet=CharSet.Auto)]
private static extern int Compress( IntPtr context,
byte[] input,
int input_size,
byte[] output,
int output_size,
ref int input_used,
ref int output_used,
int compressionLevel );
[DllImport("c:\\winnt\\system32\\inetsrv\\gzip.dll", CharSet=CharSet.Auto)]
private static extern int ResetDecompression(IntPtr context );
[DllImport("c:\\winnt\\system32\\inetsrv\\gzip.dll", CharSet=CharSet.Auto)]
private static extern int ResetCompression(IntPtr context );
[DllImport("c:\\winnt\\system32\\inetsrv\\gzip.dll", CharSet=CharSet.Auto)]
private static extern int DestroyDecompression(IntPtr context );
[DllImport("c:\\winnt\\system32\\inetsrv\\gzip.dll", CharSet=CharSet.Auto)]
private static extern int DestroyCompression(IntPtr context );
}
The ProcessMessage method is called multiple times during the life of this extension. Each time it is called, a different stage is indicated in the SoapMessage class. For either the client or the server, there are two stages for the request message, and two stages for the response message. The ChainStream method is also called once for the request message and once for the response message. The SoapMessage object also contains information about the method and Web service class that is currently running. This information can be modified, just as the stream can be, but only in certain stages. In this case, we are interacting with the stream only. We are using the ChainStream method to insert our own MemoryStream, which we can use to buffer up and then compress/decompress the SOAP message. |
- Comment