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

یکی از مشکلاتی که در هنگام استفاده از وب سرویس ها ممکن است به آن بر بخورید، حجم زیاد اطلاعاتی است که باید رد و بدل شود و گهگاه کاربر را در استفاده از متدهای یک WebService، دچار مشکل می کند. از آنجایی که XML زبان خلاصه گویی نیست و برای بیان اطلاعات Tag های فراوان دارد، حجم اطلاعات رد و بدل شده زیاد است. در این مقاله راه حلی را برای ZIP کردن اطلاعات قبل از ارسال و باز کردن آنها پس از دریافت را شرح می‏ دهیم. امید است که مورد استفاده قرار گیرد.
سه‌شنبه، 24 شهريور 1388
تخمین زمان مطالعه:
موارد بیشتر برای شما
فشرده سازی پیام ها هنگام استفاده WebService ها
فشرده سازی پیام ها هنگام استفاده WebService ها
فشرده سازی پیام ها هنگام استفاده 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>
      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;
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]));
    }
}

منبع:www.radcom.ir




ارسال نظر
با تشکر، نظر شما پس از بررسی و تایید در سایت قرار خواهد گرفت.
متاسفانه در برقراری ارتباط خطایی رخ داده. لطفاً دوباره تلاش کنید.
مقالات مرتبط