技术开发 频道

通过压缩SOAP改善XML Web service性能

  客户端的SOAP扩展

  在客户端,从服务器来的SOAP响应被解压缩,这样就可以获取原始的响应内容。下面就一步一步告诉你怎么做:

  第一步

  使用Visual Studio .NET, 我们创建一个新的Visual Basic .NET类库项目(使用 "ClientSoapExtension"作为项目名称),并且添加下面的类:

Imports System Imports System.Web.Services Imports System.Web.Services.Protocols Imports System.IO Imports zipper Public Class myextension Inherits SoapExtension Private networkStream As Stream Private newStream As Stream Public Overloads Overrides Function GetInitializer(ByVal _ methodInfo As LogicalMethodInfo, _ ByVal attribute As SoapExtensionAttribute) As Object Return System.DBNull.Value End Function Public Overloads Overrides Function GetInitializer(ByVal _ WebServiceType As Type) As Object Return System.DBNull.Value End Function Public Overrides Sub Initialize(ByVal initializer As Object) End Sub Public Overrides Sub ProcessMessage(ByVal message As SoapMessage) Select Case message.Stage Case SoapMessageStage.BeforeSerialize Case SoapMessageStage.AfterSerialize AfterSerialize(message) Case SoapMessageStage.BeforeDeserialize 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(fs) w.WriteLine("----- 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(fs) w.WriteLine("-----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 Sub Sub Copy(ByVal fromStream As Stream, ByVal toStream As Stream) Dim reader As New StreamReader(fromStream) Dim writer As New StreamWriter(toStream) writer.WriteLine(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. <AttributeUsage(AttributeTargets.Method)> _ Public Class myextensionattribute Inherits SoapExtensionAttribute Public 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 Set End Property End Class

  就象你在代码中看到的那样,我们使用了一个临时目录("c:\temp") 来捕获SOAP请求和解压缩的SOAP响应到文本文件(“c:\temp\client_soap.txt”)中。

  第二步

  我们添加ClientSoapExtension.dll程序集作为引用,并且在我们的应用程序的XML Web service引用中声明SOAP扩展:

''------------------------------------------------------------------------- '' <autogenerated> '' 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. '' </autogenerated> ''------------------------------------------------------------------------- Option Strict Off Option Explicit On Imports System Imports System.ComponentModel Imports System.Diagnostics Imports System.Web.Services Imports System.Web.Services.Protocols Imports System.Xml.Serialization '' ''This source code was auto-generated by Microsoft.VSDesigner, ''Version 1.0.3705.209. '' Namespace wstest2 ''<remarks/> <System.Diagnostics.DebuggerStepThroughAttribute(), _ System.ComponentModel.DesignerCategoryAttribute("code"), _ System.Web.Services.WebServiceBindingAttribute(Name:="Service1Soap", _ [Namespace]:="http://tempuri.org/")> _ Public Class Service1 Inherits System.Web.Services.Protocols.SoapHttpClientProtocol ''<remarks/> Public Sub New() MyBase.New Me.Url = "http://localhost/CompressionWS/Service1.asmx" End Sub ''<remarks/> <System.Web.Services.Protocols.SoapDocumentMethodAttribute _ ("http://tempuri.org/getproducts",RequestNamespace:= _ "http://tempuri.org/", ResponseNamespace:="http://tempuri.org/", _ Use:=System.Web.Services.Description.SoaPBindingUse.Literal,_ ParameterStyle:=System.Web.Services.Protocols.SoapParameterStyle _ .Wrapped), ClientSoapExtension.myextensionattribute()> _ 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, asyncState) End Function ''<remarks/> 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 Class End Namespace

  这里是zipper类的源代码,它是使用免费软件NZIPLIB库实现的:

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 uncompressedString; } } }

  分析

  我们在客户方获取这个数据集的时候,使用压缩与不使用压缩少用了近50%的CPU时间,仅仅在CPU加载时有一点影响。当客户端和服务端交换大的数据时,SOAP压缩能显著地增加XML Web Services效率。

  在Web中,有许多改善效率的解决方案。我们的代码是获取最大成果但是最便宜的解决方案。SOAP扩展是通过压缩交换数据来改善XML Web Services性能的,这仅仅对CPU加载时间造成了一点点影响。并且值得提醒的是,可以使用更强大的和需要更小资源的压缩算法来获取更大的效果。

0
相关文章