Improve XML Web Service Performance by Compress SOAP

xiaoxiao2021-03-06  50

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:

Public Function Add (Byval A as Integer, Byval B AS _INTEGER) AS Integer Add = A Bend Function

When this method is called when the XML Web Service consumer is called, it does send a SOAP request to the server:

> 10 20

The server responds to this SOAP request with a SOAP response:

30 This is the actual information transmitted on the network after calling XML Web Service. In more complex XML Web services, the SOAP response may be a large data set. For example, when the content in the table in Northwind is serialized to XML, the data may reach 454KB. If we create an app to get this dataset via XML Web Service, the SOAP response will contain all the data.

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 _public class service1 inherits system.web.services.Webservice

Public Function getorders () As DataSet Dim OleDbConnection1 = New System.Data.OleDb.OleDbConnection () OleDbConnection1.ConnectionString = "Provider = SQLOLEDB.1; _Integrated Security = SSPI; Initial Catalog = Northwind; _Data Source =. ; Workstation ID = T-MNIKIT; "Dim OleDbCommand1 = New System.Data.OleDb.OleDbCommand () OleDbCommand1.Connection = OleDbConnection1 OleDbConnection1.Open () Dim OleDbDataAdapter1 = New System.Data.OleDb.OleDbDataAdapter () OleDbDataAdapter1.SelectCommand = OleDbCommand1 OleDbCommand1.CommandText = "Select * from orders" Dim objsampleset As New DataSet () OleDbDataAdapter1.Fill (objsampleset, "Orders") OleDbConnection1.Close () Return objsampleset End FunctionEnd Class

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 Class myextensionattribute Inherits SoapExtensionAttributePublic Overrides ReadOnly Property ExtensionType () As Type Get Return GetType (myextension) End Get End Property

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:

... 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 Class myextensionattribute Inherits SoapExtensionAttribute

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:

'------------------------------------- ------------------------ '' this code was generated by a Tool. 'Runtime Version: 1.0.3705.209' Changes to this file May Cause INCORRECT Behavior and Will Be Lost If 'The Code Is Regenerated.' '----------------------------- ------------------------------------------ Option Strictness Offoption Explicit ON

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

' _ public class service1 inherits system.web.services.protocols.soaphtpClientProtocol

' public sub new () mybase.new me.url = "http://localhost/compressionws/service1.asmx" End Sub

' _ Public Function getproducts () As system.data.dataset Dim Results () as object = me.invoke ("getProducts", _new object (-1) {} Return CType (Results (0), System.Data.DataSet) End Function ' Remarks /> Public Function BegingeTProducts (Byval Callback As _System.asyncCallback, Byval AsyncState As Object) as system.iasyncResult_

Return Me.BeginInvoke ("getProducts", new object (-1) {}, _callback, ask, asyncState) End Function

' Public Function Endgetproducts (ByVal asyncResult As _ System.IAsyncResult) As System.Data.DataSet Dim results () As Object = Me.EndInvoke (asyncResult) Return CType (results (0), System.Data.DataSet) END FUNCTION END CLASSEND NAMESPACE

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.

转载请注明原文地址:https://www.9cbs.com/read-81906.html

New Post(0)