客户端的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加载时间造成了一点点影响。并且值得提醒的是,可以使用更强大的和需要更小资源的压缩算法来获取更大的效果。
