فشرده سازی پیام ها هنگام استفاده WebService ها
در این مقاله راه حلی را برای ZIP کردن اطلاعات قبل از ارسال و باز کردن آنها پس از دریافت را شرح می دهیم. امید است که مورد استفاده قرار گیرد.
پیش نیاز ها
http://www.icsharpcode.net/OpenSource/SharpZipLib/Default.aspx
در راه حل ارائه شده ، لازم نیست که تمام پیام فشرده شود و فقط محتویات پیام را فشرده شده و ارسال می شود و پس از دریافت، فقط محتویات پیام باز می شوند.
پیاده سازی
CompressionExtension
وقتی اطلاعات موجود در پیام فشرده می شود، اطلاعات به آرایه ای از اطلاعات دودویی تبدیل می شود. امکان نمایش اطلاعات دودویی در در پیام ارسالی ممکن نیست، و باید اطلاعات را با الگوریتم BASE64 تبدیل کنیم.
using System;
using System.IO;
using System.Text ;
using System.Web.Services;
using System.Web.Services.Protocols ;
using ICSharpCode.SharpZipLib.Checksums;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.GZip;
using System.Xml ;
namespace Radcom
{
///<summary>
/// Summary description for ConpressionExtension.
///</summary>
publicclass CompressionExtension : System.Web.Services.Protocols.SoapExtension
{
Stream oldStream;
Stream newStream;
publicoverrideobject GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
{
return attribute;
}
// Get the Type
publicoverrideobject GetInitializer(Type t)
{
returntypeof(CompressionExtension);
}
// Get the CompressionExtensionAttribute
publicoverridevoid Initialize(object initializer)
{
CompressionExtensionAttribute attribute = (CompressionExtensionAttribute) initializer;
return;
}
// Process the SOAP Message
publicoverridevoid ProcessMessage(SoapMessage message)
{
// Check for the various SOAP Message Stages
switch (message.Stage)
{
case SoapMessageStage.BeforeSerialize:
break;
case SoapMessageStage.AfterSerialize:
// ZIP the contents of the SOAP Body after it has
// been serialized
Zip();
break;
case SoapMessageStage.BeforeDeserialize:
// Unzip the contents of the SOAP Body before it is
// deserialized
Unzip();
break;
case SoapMessageStage.AfterDeserialize:
break;
default:
thrownew Exception("invalid stage");
}
1 }
// Gives us the ability to get hold of the RAW SOAP message
publicoverride Stream ChainStream( Stream stream )
{
oldStream = stream;
newStream = new MemoryStream();
return newStream;
}
// Utility method to copy streams
void Copy(Stream from, Stream to)
{
TextReader reader = new StreamReader(from);
TextWriter writer = new StreamWriter(to);
writer.WriteLine(reader.ReadToEnd());
writer.Flush();
}
// Zip the SOAP Body
privatevoid Zip()
{
newStream.Position = 0;
// Zip the SOAP Body
newStream = ZipSoap(newStream);
// Copy the streams
Copy(newStream, oldStream);
}
// The actual ZIP method
privatebyte[] Zip(string stringToZip)
{
byte[] inputByteArray = Encoding.UTF8.GetBytes(stringToZip);
MemoryStream ms = new MemoryStream();
// Check the #ziplib docs for more information
ZipOutputStream zipOut = new ZipOutputStream( ms ) ;
ZipEntry ZipEntry = new ZipEntry("ZippedFile");
zipOut.PutNextEntry(ZipEntry);
zipOut.SetLevel(9);
zipOut.Write(inputByteArray, 0 , inputByteArray.Length ) ;
zipOut.Finish();
zipOut.Close();
// Return the zipped contents
return ms.ToArray();
}
// Select and Zip the appropriate parts of the SOAP message
public MemoryStream ZipSoap(Stream streamToZip)
{
streamToZip.Position = 0;
// Load a XML Reader
XmlTextReader reader = new XmlTextReader(streamToZip);
XmlDocument dom = new XmlDocument();
dom.Load(reader);
// Load a NamespaceManager to enable XPath selection
XmlNamespaceManager nsmgr = new XmlNamespaceManager(dom.NameTable);
nsmgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
XmlNode node = dom.SelectSingleNode("//soap:Body", nsmgr);
// Select the contents within the method defined in the SOAP body
node = node.FirstChild.FirstChild;
// Check if there are any nodes selected
while( node != null )
{
if( node.InnerXml.Length > 0 )
{
// Zip the data
byte[] outData = Zip(node.InnerXml);
// Convert it to Base64 for transfer over the internet
node.InnerXml = Convert.ToBase64String(outData) ;
}
// Move to the next parameter
node = node.NextSibling ;
}
MemoryStream ms = new MemoryStream();
// Save the updated data
dom.Save(ms);
ms.Position = 0;
return ms;
}
// Unzip the SOAP Body
privatevoid Unzip()
{
MemoryStream unzipedStream = new MemoryStream();
TextReader reader = new StreamReader(oldStream);
TextWriter writer = new StreamWriter(unzipedStream);
writer.WriteLine(reader.ReadToEnd());
writer.Flush();
// Unzip the SOAP Body
unzipedStream = UnzipSoap(unzipedStream);
// Copy the streams
Copy(unzipedStream, newStream);
newStream.Position = 0;
}
// Actual Unzip logic
privatebyte[] Unzip(string stringToUnzip)
{
// Decode the Base64 encoding
byte[] inputByteArray = Convert.FromBase64String( stringToUnzip ) ;
MemoryStream ms = new MemoryStream(inputByteArray) ;
MemoryStream ret = new MemoryStream();
// Refer to #ziplib documentation for more info on this
ZipInputStream zipIn = new ZipInputStream(ms);
ZipEntry theEntry = zipIn.GetNextEntry();
Byte[] buffer = new Byte[2048] ;
int size = 2048;
while (true)
{
size = zipIn.Read(buffer, 0, buffer.Length);
if (size > 0)
{
ret.Write(buffer, 0, size);
}
else
{
break;
}
}
return ret.ToArray();
}
// Unzip the SOAP Body
public MemoryStream UnzipSoap(Stream streamToUnzip)
{
streamToUnzip.Position = 0;
// Load a XmlReader
XmlTextReader reader = new XmlTextReader(streamToUnzip);
XmlDocument dom = new XmlDocument();
dom.Load(reader);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(dom.NameTable);
nsmgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
// Select the SOAP Body node
XmlNode node = dom.SelectSingleNode("//soap:Body", nsmgr);
node = node.FirstChild.FirstChild;
// Check if node exists
while( node != null )
{
if( node.InnerXml.Length >0 )
{
// Send the node's contents to be unziped
byte[] outData = Unzip(node.InnerXml);
string sTmp = Encoding.UTF8.GetString(outData);
node.InnerXml = sTmp;
}
// Move to the next parameter
node = node.NextSibling ;
}
MemoryStream ms = new MemoryStream();
dom.Save(ms);
ms.Position = 0;
return ms;
}
}
این کلاس به شما اجازه می دهد تا توابعی که از خاصیت فشرده سازی استفاده می کنند را از دیگر توابع متمایز کنید. این کلاس از SoapExtensionAttribute ارث بری می کند و مشخصه های ExtensionType و Priority را تغییر می دهد.
using System; // Override the base class properties |
نحوه استفاده
البته بدیهی است که باید DLL های مربوطه (SharpZip , CompressionExtension) را نیز در اختیار داشته باشید تا بتوانید از کتابخانه های توسعه یافته استفاده کنید.
نکته ی مهم دیگر اینکه وقتی یک SOAP Call برای یک Web Method به وجود آید، توابع توسعه یافته فعال شده و کار می کنند و اگر برای مراجعه به توابع از HTTP GET / POST استفاده کنید، توابع شما فعال نخواهند شد. برای مثال اگر شما از تست های استانداردی که ASP.NET برای تست وب سرویس در اختیار شما می گذارد استفاده کنید، نتیجه فشرده سازی را نخواهید دید.
<%@ WebService Language="C#" Class="MyService" %> |
using System.Diagnostics; |
/خ