فشرده سازی پیام ها در وب سرویس ها

فشرده سازی پیام ها هنگام استفاده WebService ها

یکی از مشکلاتی که در هنگام استفاده از وب سرویس ها ممکن است به آن بر بخورید، حجم زیاد اطلاعاتی است که باید رد و بدل شود و گهگاه کاربر را در استفاده از متدهای یک WebService، دچار مشکل می کند. از آنجایی که XML  زبان خلاصه گویی نیست و برای بیان اطلاعات Tag های فراوان دارد، حجم اطلاعات رد و بدل شده زیاد است.

در این مقاله راه حلی را برای ZIP کردن اطلاعات قبل از ارسال و باز کردن آنها پس از دریافت را شرح می‏ دهیم. امید است که مورد استفاده قرار گیرد.

پیش نیاز ها

اولین سؤالی که ممکن است پیش آید این است که از کدام الگوریتم برای ZIP کردن استفاده شود؟ با توجه به اینکه C# هیچ کلاسی برای این کار ندارد می ‏توانید از توابع و کتابخانه های آماده، استفاده کنید. یکی از کتابخانه‏ های معروف #ZipLib است که به صورت OpenSource موجود است و می ‏توانید آن از آدرس زیر Download کنید.

http://www.icsharpcode.net/OpenSource/SharpZipLib/Default.aspx

در راه حل ارائه شده ، لازم نیست که تمام پیام فشرده شود و فقط محتویات پیام را فشرده شده و ارسال می شود و پس از دریافت، فقط محتویات پیام باز می شوند.

پیاده سازی

دو کلاس باید پیاده سازی شوند، یکی باید SoapExtention را توسعه دهد و کلاس دیگر SoapExtensionAttribute.

CompressionExtension

در کلاس CompressionExtension دو مرحله وجود دارد. یکی AfterSerialize و دیگر BeforeDeserialize. در AfterSerialize اطلاعات Zip می شوند و اطلاعات فشرده شده در پیام قرار داده شده و ارسال می شود. در مرحله BeforeDeserialize برعکس مرحله بالا انجام می ‏شود، بدین صورت که اطلاعات بررسی شده، UnZip می ‏شوند و اطلاعات بازشده در پیام قرار داده می شود تا آماده استفاده باشد.

وقتی اطلاعات موجود در پیام فشرده می شود، اطلاعات به آرایه ای از اطلاعات دودویی تبدیل می شود. امکان نمایش اطلاعات دودویی در در پیام ارسالی ممکن نیست، و باید اطلاعات را با الگوریتم 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>

      public class CompressionExtension : System.Web.Services.Protocols.SoapExtension

      {

            Stream oldStream;

            Stream newStream;

   

 

            public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)

            {

                  return attribute;

            }

 

            // Get the Type

            public override object GetInitializer(Type t)

            {

                  return typeof(CompressionExtension);

            }

   

            // Get the CompressionExtensionAttribute

            public override void Initialize(object initializer)

            {

                  CompressionExtensionAttribute attribute = (CompressionExtensionAttribute) initializer;

 

                  return;

            }

 

            // Process the SOAP Message

            public override void 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:

                              throw new Exception("invalid stage");

                  }

            }

 

            // Gives us the ability to get hold of the RAW SOAP message

            public override 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

            private void Zip()

            {

                  newStream.Position = 0;

                  // Zip the SOAP Body

                  newStream = ZipSoap(newStream);

                  // Copy the streams

                  Copy(newStream, oldStream);

            }

 

            // The actual ZIP method

            private byte[] 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

    &bbsp;       private void 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

            private byte[] 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;

            }

 

      }

}

CompressionExtensionAttribute

این کلاس به شما اجازه می دهد تا توابعی که از خاصیت فشرده سازی استفاده می‏ کنند را از دیگر توابع متمایز کنید. این کلاس از SoapExtensionAttribute ارث بری می کند و مشخصه های  ExtensionType و Priority را تغییر می دهد.

 

using System;

using System.Web.Services;

using System.Web.Services.Protocols;

 

namespace Radcom

{

      /// <summary>

      /// Summary description for CompressionExtensionAttribute.

      /// </summary>

     

      // Make the Attribute only Applicable to Methods

      [AttributeUsage(AttributeTargets.Method)]

      public class CompressionExtensionAttribute : System.Web.Services.Protocols.SoapExtensionAttribute

      {

   

            private int priority;

 

            // Override the base class properties

            public override Type ExtensionType

            {

                  get { return typeof(CompressionExtension); }

            }

 

            public override int Priority

            {

                  get

                  {

                        return priority;

                  }

                  set

                  {

                        priority = value;

                  }

            }

 

      }

}

نحوه استفاده

پس از کامپایل کردن، کتابخانه شما آماده است. برای استفاده در بخش سرویس دهنده، کافی است Namespace ی که برای پروژه خود درنظرگرفته اید، در قسمت using بیاورید و بعد از تعریف تابع موردنظر خود (پس از [WebMethod]) عبارت [CompressionExtension] را اضافه کنید و تابع موردنظر خود را به صورت عادی و معمول بنویسید.

 البته بدیهی است که باید DLL های مربوطه  (SharpZip , CompressionExtension)  را نیز در اختیار داشته باشید تا بتوانید از کتابخانه های توسعه یافته استفاده کنید.

نکته ی مهم دیگر اینکه وقتی یک SOAP Call برای یک Web Method به وجود آید، توابع توسعه یافته فعال شده و کار می کنند و اگر برای مراجعه به توابع از HTTP GET / POST استفاده کنید، توابع شما فعال نخواهند شد. برای مثال اگر شما از تست های استانداردی که ASP.NET برای تست وب سرویس در اختیار شما می گذارد استفاده کنید، نتیجه فشرده سازی را نخواهید دید.

<%@ WebService Language="C#" Class="MyService" %>

 

using System.Web.Services;

using MasterCSharp.WebServices ;

using System.Data ;

using System.Data.SqlClient ;

 

public class MyService

{

 

      [WebMethod]

      [CompressionExtension]

      public string MyMethod()

      {

 

            // Replace with the connection string to connect to your database

            DataSet ds = new DataSet();

            /*

            Fill Dataset

            */

            return ds.GetXml() ;

      }

 

}

برای استفاده از توابع در قسمت سرویس گیرنده ، پس از افزودن وب سرویس به عنوان Web Reference باید DLL های موجود را به پروژه خود بیفزایید (هر دو DLL) و سپس در فایل reference.cs در webreference مربوطه قبل از هر تابع عبارت [CompressionExtension] را بیفزایید، چون به طور استاندارد وقتی مرجع را به پروژه خود می افزایید، این مورد وجود ندارد.

using System.Diagnostics;

using System.Xml.Serialization;

using System;

using System.Web.Services.Protocols;

using System.ComponentModel;

using System.Web.Services;

using Radcom;

 

 

[System.Diagnostics.DebuggerStepThroughAttribute()]

[System.ComponentModel.DesignerCategoryAttribute("code")]

[System.Web.Services.WebServiceBindingAttribute

(Name="MyServiceSoap", Namespace="http://tempuri.org/")]

public class MyService :

System.Web.Services.Protocols.SoapHttpClientProtocol {

   

    public MyService() {

        this.Url = "http://localhost/TestPages/Service.asmx";

    }

   

    /// <remarks/>

    // Add our Custom SOAP Extension

    [CompressionExtension]

[System.Web.Services.Protocols.SoapDocumentMethodAttribute

("http://tempuri.org/MyMethod",

RequestNamespace="http://tempuri.org/",

ResponseNamespace="http://tempuri.org/",

Use=System.Web.Services.Description.SoapBindingUse.Literal,

ParameterStyle=

System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]

 

    public string MyMethod() {

        object[] results = this.Invoke("MyMethod", new object[0]);

        return ((string)(results[0]));

    }

   

    /// <remarks/>

    public System.IAsyncResult BeginMyMethod(System.AsyncCallback callback, object asyncState) {

        return this.BeginInvoke("MyMethod", new object[0], callback, asyncState);

    }

   

    /// <remarks/>

    public string EndMyMethod(System.IAsyncResult asyncResult) {

        object[] results = this.EndInvoke(asyncResult);

        return ((string)(results[0]));

    }

}


آخرین بروزرسانی
۲۳ بهمن ۱۴۰۲ 
تعداد کلیک
۴,۵۲۲

فهرست نظرها و ارسال نظر جدید

نام را وارد کنید
ایمیل را وارد کنید
تعداد کاراکتر باقیمانده: 1000
نظر خود را وارد کنید