Quoted from:
Http://www.dotNetjunkies.com/Article/46630AE2-1C79-4D5F-827E-6C2857FF1D23.DCIKHTTP: / DEV.9CBS.NET/Develop/Article/24/24920.shtm
Compressed text is a process that reduces the size of 80% of the size of the text. This means that the storage of compressed text will be 80% less than the storage without compressed text. It also means that the content is transferred on the network requires less time. For client server applications that use text communication, it will exhibit higher efficiency, such as XML Web Services.
The main purpose of this paper is to find a method that minimizes the size of the data between the client and the server. Some experienced developers will use advanced technologies to optimize data transmitted through the Internet, such as a bottleneck in many distributed systems. One way to solve this problem is to get more bandwidth, but this is unrealistic. Another method is to minimize the transmitted data by compression.
When the content is text, it is compressed, and its size can be reduced by 80%. This means that the demand between the client and the server can also reduce similar percentage. For compression and decompression, the server and the client occupy additional resources of the CPU. However, the CPU of the upgrade server is generally cheaper than increasing bandwidth, so compression is the most effective way to improve transmission efficiency.
XML / SOAP in the network
Let's take a closer look at the SOAP when requested or responding to XML Web Service, is transmitted on the network. We created an XML Web Service that contains an add method. This method has two input parameters and returns these two numbers:
When this method is called when the XML Web Service consumer is called, it does send a SOAP request to the server:
XML Version = "1.0" encoding = "UTF-8"?>
The server responds to this SOAP request with a SOAP response:
XML Version = "1.0" encoding = "UTF-8"?>
In order to improve efficiency, we can compress these text content prior to transmission. How can we do it? Of course, use SOAP expansion!
SOAP extension
SOAP extension is an intercepting mechanism for the ASP.NET web method call, which can manipulate them before the SOAP request or response is transmitted. Developers can write a code before and after these message serialization. (SOAP extension provides the underlying API to achieve a wide range of applications.)
Using SOAP extensions When the client calls a method from the XML Web Service, we can reduce the size of the SOAP information to transmit on the network. Many times, SOAP requests are much smaller than SOAP (eg, a large data set), so in our example, only the SOAP response is compressed. Just as you can see in Figure 1, on the server, when the SOAP response is serialized, it will be compressed and then transferred to the network. Before the client, SOAP information is reverse selecinstened, SOAP information is decompressed in order to make the reverse sequence.
Figure 1. SOAP information is compressed (server) after serialization, is decompressed before the reverse sequence (client)
We can also compress SOAP requests, but in this example, the efficiency increase is not obvious.
In order to compress our Web Service's SOAP response, we need two things:
· Compress it after serializing the SOAP response information. · Deficiency it before the client deserialized SOAP information.
This work will be completed by the SOAP extension. In the paragraph below, you can see all the clients and server code.
First of all, here is an XML Web Service that returns a big data set:
Imports system.web.services
On the client, we build a Windows application to call the above XML Web Service, get that data set and displayed in DataGrid:
Public Class Form1 Inherits System.Windows.Forms.Form 'This function invokes the XML Web service, which returns the dataset'without using compression.Private Sub Button1_Click (ByVal sender As System.Object, _ByVal e As System.EventArgs) Handles Button1. Click Dim ws As New wstest.Service1 () Dim test1 As New ClsTimer () 'Start time counting ... test1.StartTiming ()' Fill datagrid with the dataset DataGrid1.DataSource = ws.getorders () test1.StopTiming () 'Stop time Count = "Total Time:" & test1.totaltime.tostring & "msec" End Sub
'This function invokes the XML Web service, which returns the dataset'using compression. Private Sub Button2_Click (ByVal sender As System.Object, _ByVal e As System.EventArgs) Handles Button2.Click Dim ws As New wstest2.Service1 () Dim test1 As New ClsTimer 'Start time counting ... test1.StartTiming ()' Fill datagrid with dataset DataGrid1.DataSource = ws.getorders () test1.StopTiming () 'Stop time counting ... TextBox4.Text = "Total time:" () & test1 .Totaltime.tostring & "msec" End Subend Class client calls two different XML Web Services, only one of them uses SOAP compression. The following Timer class is used to calculate the call time:
Public Class ClsTimer 'Simple high resolution timer class'' Methods: 'StartTiming reset timer and start timing' StopTiming stop timer '' Properties' TotalTime Time in milliseconds' Windows API function declarations Private Declare Function timeGetTime Lib "winmm" () As Long
'Local Variable Declarations Private LNGStartTime AS Integer Private LNGTOTOTIME AS INTEGER Private LNGCURTIME AS INTEGER
Public Readonly Property Totaltime () AS String Get TotalTime = LNGTOTIME End Get Property
Public Sub StartTiming () LNGTOTALTIME = 0 LNGStartTime = TimegetTime () End Sub
Public Sub Stoptiming () LNGCURTIME = TimegetTime () LNGTOTATION = (LNGCURTIME - LNGSTARTIME) End Subend Class server SOAP extension
At the server, in order to reduce the size of the SOAP response, it is compressed. Here's how to do it:
first step
Using Microsoft Visual Studio .NET, we create a new Visual Basic .Net class library project (using "Serversoapextension" as a project name), add the following class:
Imports SystemImports System.Web.ServicesImports System.Web.Services.ProtocolsImports System.IOImports zipperPublic Class myextension Inherits SoapExtension Private networkStream As Stream Private newStream As Stream
Public overloads overrides function getinitializer (Byval_MethodInfo As LogicalMethodInfo, _ Byval Attribute as sopextensionattribute) as object returnus system.dbnull.value end function
Public overloads overrides function getinitializer (Byval _WebserviceType as type) as object return system.dbnull.value end function
Public overrides subinitialize (byval initializer as object) End Sub
Public overrides sub processmessage (byval message as soapMessage) Select Case Message.Stage
Case soapMessagestage.beforserialize
Case soapMessagestage.AfterSerialize AfTerSerize (Message)
Case SOAPMESSAGESTAGE.BEFOREDSERIALIZE BEFOREDESERIALIZE (MESSAGE)
Case SoapMessagestage.AfterDeserialize
Case Else Throw New Exception ("Invalid Stage") End Selectend Sub
'Save the stream representing the SOAP request or SOAP response into a' local memory buffer.Public Overrides Function ChainStream (ByVal stream As Stream) As Stream networkStream = stream newStream = New MemoryStream () Return newStreamEnd Function
'Write the compressed SOAP message out to a file at' the server's file system .. Public Sub AfterSerialize (ByVal message As SoapMessage) newStream.Position = 0 Dim fs As New FileStream ( "c: /temp/server_soap.txt", _ FileMode.Append, FileAccess.write) DIM W AS New Streamwriter ("----- response at" DateTime.now.toString ()) w.flush () 'Compress Stream and Save It To a file Comp (newStream, fs) w.Close () newStream.Position = 0'Compress stream and send it to the wire Comp (newStream, networkStream) End Sub 'Write the SOAP request message out to a file at the server's file system . Public Sub BeforeDeserialize (ByVal message As SoapMessage) Copy (networkStream, newStream) Dim fs As New FileStream ( "c: /temp/server_soap.txt", _ FileMode.Create, FileAccess.Write) Dim w As New StreamWriter (fs) W.WriteLine ("---- Request AT" DateTime.now.toString () W.Flush () newstream.position = 0 Copy (NewStream, FS) w.close () newstream.position = 0 End Sub
Sub Copy (ByVal fromStream As Stream, ByVal toStream As Stream) Dim reader As New StreamReader (fromStream) Dim writer As New (toStream) StreamWriter writer.WriteLine (reader.ReadToEnd ()) writer.Flush () End Sub
Sub Comp (ByVal fromStream As Stream, ByVal toStream As Stream) Dim reader As New StreamReader (fromStream) Dim writer As New StreamWriter (toStream) Dim test1 As String Dim test2 As String test1 = reader.ReadToEnd'String compression using NZIPLIB test2 = zipper .CLASS1.COMPRESS (TEST1) Writer.writeline (TEST2) WRITER.FLUSH () End Sub
END CLASS
'Create a SoapExtensionAttribute for the SOAP extension that can be' applied to an XML Web service method.
Public overrides property priority () AS integer get return 1 End Get Set (Byval Value As Integer) End End Property
END CLASS
Second step
We increase the Serversoapextension.dll assembly as a reference, and declare the SOAP extension in Web.config:
XML Version = "1.0" encoding = "UTF-8"?>
... configuration> As you can see in your code, we use a temporary directory ("c: / temp") to capture SOAP requests and compressed SOAP responses to text. Document ("c: /TEMP/server_soap.txt").
Client SOAP extension
In the client, the SOAP response from the server is decompressed so that the original response content can be obtained. Let's take a step step by step to do:
first step
Using Visual Studio .NET, we create a new Visual Basic .NET class library project (using "ClientSoapextension as the project name) and add the following class:
Imports SystemImports System.Web.ServicesImports System.Web.Services.Protocolsimports System.Ioimports Zipper Public Class MyExtension Inherits SOAPEXTENSION INHERITS SOAPEXTENSISIM
Private NetworkStream As Stream Private NewsTream As Stream
Public overloads overrides function getinitializer (Byval_MethodInfo As LogicalMethodInfo, _ Byval Attribute as sopextensionattribute) as object returnus system.dbnull.value end function
Public Overloads Overrides Function GetInitializer (ByVal _WebServiceType As Type) As Object Return System.DBNull.Value End FunctionPublic Overrides Sub Initialize (ByVal initializer As Object) End Sub
Public overrides sub processmessage (byval message as soapMessage) Select Case Message.Stage
Case soapMessagestage.beforserialize
Case soapMessagestage.AfterSerialize AfTerSerize (Message)
Case SOAPMESSAGESTAGE.BEFOREDSERIALIZE BEFOREDESERIALIZE (MESSAGE)
Case SoapMessagestage.AfterDeserialize
Case Else Throw New Exception ("Invalid Stage") End Select End Sub
'Save the stream representing the SOAP request or SOAP response' into a local memory buffer. Public Overrides Function ChainStream (ByVal stream As Stream) _As Stream networkStream = stream newStream = New MemoryStream () Return newStream End Function
'Write the SOAP request message out to a file at' the client's file system Public Sub AfterSerialize (ByVal message As SoapMessage) newStream.Position = 0 Dim fs As New FileStream (. "C: /temp/client_soap.txt", _FileMode. Create, FileAccess.write) DIM W AS NEW Streamwriter ("---- Request AT" DateTime.now.tostring ()) W.Flush () Copy (NewStream, FS) W.Close () Newstream.position = 0 Copy (NewStream, NetworkStream) End Sub
'Write the uncompressed SOAP message out to a file' at the client's file system .. Public Sub BeforeDeserialize (ByVal message As SoapMessage) 'Decompress the stream from the wire DeComp (networkStream, newStream) Dim fs As New FileStream ( "c: / Temp / client_soap.txt ", _filemode.Append, fileaccess.write) DIM W AS NEW Streamwriter (" ----- response at " DateTime.now.tostring ()) w.flush () newStream.Position = 0 'Store the uncompressed stream to a file Copy (newStream, fs) w.Close () newStream.Position = 0 End SubSub Copy (ByVal fromStream As Stream, ByVal toStream As Stream) Dim reader As New StreamReader (fromStream ) DIM WRITER AS New Streamwriter (Reader.ReadToend ()) Writer.Flush () End Sub
Sub DeComp (ByVal fromStream As Stream, ByVal toStream As Stream) Dim reader As New StreamReader (fromStream) Dim writer As New StreamWriter (toStream) Dim test1 As String Dim test2 As String test1 = reader.ReadToEnd 'String decompression using NZIPLIB test2 = zipper .Class1.decompress (TEST1) Writer.writeline (TEST2) Writer.flush () End Sub
END CLASS
'Create a SoapExtensionAttribute for the SOAP extension that can be' applied to an XML Web service method.
Public Overrides Readonly Property ExtensionType () AS TYPE GET RETURN GETTYPE (MyExtension) End Get Property
Public overrides property priority () AS integer get return 1 End Get Set (Byval Value As Integer) End End Property
End Class is like you see in your code, we use a temporary directory ("c: / temp") to capture SOAP requests and decompression SOAP response to text files ("c: /TEMP/Client_Soap.txt" )in. Second step
We add ClientSoapextension.dll assembly as a reference, and declare the SOAP extension in our application's XML Web Service reference:
'------------------------------------- ------------------------ '
Imports systemimports system.componentmodelimports system.diagnosticsimports system.web.servicesimports system.web.services.protocolsimports system.xml.Serialization
'' This Source Code Was Auto-generated by Microsoft.vsdesigner, 'Version 1.0.3705.209.'Namespace WSTEST2
'
'
'
Return Me.BeginInvoke ("getProducts", new object (-1) {}, _callback, ask, asyncState) End Function
'
Here is the source code of the zipper class, which is implemented using the free NZIPLIB library:
using System; using NZlib.GZip; using NZlib.Compression; using NZlib.Streams; using System.IO; using System.Net; using System.Runtime.Serialization; using System.Xml; namespace zipper {public class Class1 {public static string Compress (string uncompressedString) {byte [] bytData = System.Text.Encoding.UTF8.GetBytes (uncompressedString); MemoryStream ms = new MemoryStream (); Stream s = new DeflaterOutputStream (ms); s.Write (bytData, 0, bytData .Length); s.Close (); byte [] compressedData = (byte []) ms.ToArray (); return System.Convert.ToBase64String (compressedData, 0, _compressedData.Length);} public static string DeCompress (string compressedString ) {string uncompressedString = ""; int totalLength = 0; byte [] bytInput = System.Convert.FromBase64String (compressedString) ;; byte [] writeData = new byte [4096]; Stream s2 = new InflaterInputStream (new MemoryStream (bytInput) WHILE (TRUE) {Int size = s2.read (WriteData, 0, WriteData.Length; if (size> 0) {TOTALLENGTH = Size; uncompressedString = system.text.encoding.utf8.getstring (writedata, _0, size);} else {Break;}} S2.Close () Return uncompressed 4TRING;}}}
analysis
Software & Hardware
· Client: Intel Pentium III 500 MHz, 512 MB RAM, Windows XP. · Server: Intel Pentium III 500 MHz, 512 MB RAM, Windows 2000 Server, Microsoft SQL Server 2000.
At the client, a Windows application calls an XML Web Service. This XML Web Service returns a dataset and populates DataGrid in the client application.
Figure 2. This is a sample program that we use and not using SOAP compression calls the same XML Web Service. This XML Web Service returns a large data set.
CPU use record
As shown in Figure 3, there is no use of compressed CPU usage time is 29903 MilliseConds. Figure 3. No use of compressed CPU usage records
In our example, the use of compressed CPU usage is displayed in Figure 4, which is 15182 MilliseConds.
Figure 4. Using a compressed CPU usage record
As you can see, when we get this dataset in the customer, use compression and non-use compression less than 50% of the CPU time, only a little impact on CPU loading. SOAP compression can significantly increase XML Web Services efficiency when the client and the server exchanged large data. In the Web, there are many solutions to improve efficiency. Our code is to get the biggest results but the cheapest solution. The SOAP extension is to improve XML Web Services performance by compression exchange data, which only has a little impact on the CPU loading time. And it is worth reminding that you can use more powerful and compressed algorithms that require smaller resources to get greater effects.