如何优化WebService进行大批量数据传送(WSE3.0应用技巧)
在網上找了一下資料,用WebService進行大量數據傳送的人并不多,主要原因是因為傳送速度慢,因為WebService是以XML文件流的方式來傳送的,寫過XML的人都知道,XML中會有很多冗余的內容,比說字段名,他是每一行就要寫一次,如果有約束,還要附加很多描述語句,而且從WebService返回數據時,還要進行64位編碼,所以用WebService進行通迅效率很低.找了好久終于找到了一位高手的文章,原來WebService可以通過三步瘦身,但他用的方法是VS2003+wse2.0,而我用的是Vs2008+Wse3.0寫法有所不同,于是寫下此日志,幫助自己記錄,也希望幫到有相關需求的人.
正文:
1.將DataSet設置為用于遠程傳送的精簡二進制模式
2.用壓縮程序對數據進行壓縮(此處使用微軟提供的ICSharpCode.SharpZipLib.dll)
3.使用WSE3.0的MTOM技術優化SOAP.
WSE3.0配置:
安裝完WSE3.0后,你會發現安裝目錄下會有一個WebService3.dll,要將其引入到WebService項目中(不能像VS2005中可以直接創建一個WSE3.0的項目),然后要配置Web.config,置于具體的配置寫法可以用Wse3.0安裝目錄下的WseConfigEditor3.exe進行配置,例如要開通MTOM,則先在General頁中勾選Enable this project for Web Service Enhancements,再在Messaging頁中Client Mode選擇on 然后關閉程序,會提示生成配置文件,打開文件,將相關項目填回Web.config中就可以使用了.
具體Web.config內容如下
<?xml version="1.0" encoding="utf-8"?> <configuration><configSections><section name="microsoft.web.services3" type="Microsoft.Web.Services3.Configuration.WebServicesConfiguration, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /></configSections><system.web><webServices><soapExtensionImporterTypes><add type="Microsoft.Web.Services3.Description.WseExtensionImporter, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /></soapExtensionImporterTypes><soapServerProtocolFactory type="Microsoft.Web.Services3.WseProtocolFactory, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /></webServices><compilation><assemblies><add assembly="Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /></assemblies></compilation></system.web><microsoft.web.services3><messaging><mtom clientMode="On" /></messaging></microsoft.web.services3> </configuration>
具體代碼:
一.壓縮類:
using System; using System.IO; using System.Text; using ICSharpCode.SharpZipLib.Zip.Compression; using ICSharpCode.SharpZipLib.Zip.Compression.Streams;namespace ClassLb1 {/// <summary>/// 壓縮強度。/// </summary>public enum CompressionLevel{/// <summary>/// 采用最好的壓縮率。/// </summary>BestCompression,/// <summary>/// 采用默認的壓縮率。/// </summary>DefaultCompression,/// <summary>/// 采用最快的壓縮速度。/// </summary>BestSpeed,/// <summary>/// 不采用任何壓縮。/// </summary>NoCompression}/// <summary>/// CompressionHelper 的摘要說明。/// </summary>public class CompressionHelper{/// <summary>/// 獲取和設置壓縮強度。/// </summary>public CompressionLevel Level;public CompressionHelper(){Level = CompressionLevel.DefaultCompression;}public CompressionHelper(CompressionLevel level){Level = level;}#region Public Methods/// <summary>/// 從原始字節數組生成已壓縮的字節數組。/// </summary>/// <param name="bytesToCompress">原始字節數組。</param>/// <returns>返回已壓縮的字節數組</returns>public byte[] CompressToBytes(byte[] bytesToCompress){MemoryStream ms = new MemoryStream();Stream s = GetOutputStream(ms);s.Write(bytesToCompress, 0, bytesToCompress.Length);s.Close();return ms.ToArray();}/// <summary>/// 從已壓縮的字節數組生成原始字節數組。/// </summary>/// <param name="bytesToDecompress">已壓縮的字節數組。</param>/// <returns>返回原始字節數組。</returns>public byte[] DecompressToBytes(byte[] bytesToDecompress){byte[] writeData = new byte[4096]; //設置緩沖區Stream s2 = GetInputStream(new MemoryStream(bytesToDecompress)); //解壓縮數組MemoryStream outStream = new MemoryStream(); //由于Stream類型不能直接轉換為byte[]只能通過MemoryStream做中間變換while (true) //循環讀取數據流到outStream,直至讀取完畢{int size = s2.Read(writeData, 0, writeData.Length);if (size > 0){outStream.Write(writeData, 0, size);}else{break;}}s2.Close();byte[] outArr = outStream.ToArray();outStream.Close();return outArr;}#endregion#region Private Methods/// <summary>/// 根據壓縮強度返回使用了不用壓縮算法的 Deflate 對象。/// </summary>/// <param name="level">壓縮強度。</param>/// <returns>返回使用了不用壓縮算法的 Deflate 對象。</returns>private Deflater GetDeflater(CompressionLevel level){switch (level){case CompressionLevel.DefaultCompression:return new Deflater(Deflater.DEFAULT_COMPRESSION);case CompressionLevel.BestCompression:return new Deflater(Deflater.BEST_COMPRESSION);case CompressionLevel.BestSpeed:return new Deflater(Deflater.BEST_SPEED);case CompressionLevel.NoCompression:return new Deflater(Deflater.NO_COMPRESSION);default:return new Deflater(Deflater.DEFAULT_COMPRESSION);}}/// <summary>/// 從給定的流生成壓縮輸出流。/// </summary>/// <param name="inputStream">原始流。</param>/// <returns>返回壓縮輸出流。</returns>private DeflaterOutputStream GetOutputStream(Stream inputStream){return new DeflaterOutputStream(inputStream, GetDeflater(Level));}/// <summary>/// 從給定的流生成壓縮輸入流。/// </summary>/// <param name="inputStream">原始流。</param>/// <returns>返回壓縮輸入流。</returns>private InflaterInputStream GetInputStream(Stream inputStream){return new InflaterInputStream(inputStream);}#endregion} }
?
二.客戶端:
Thread thread1;private void button1_Click(object sender, EventArgs e){//try//{label1.Text = "整理數據......";thread1 = new Thread(new ThreadStart(UpLoad));thread1.Start();//}//catch (Exception e1)//{// MessageBox.Show("上傳數據失敗!錯誤代碼如下:/r/n" + e1.ToString());//}}/// <summary>/// 上傳數據/// </summary>private void UpLoad() {int LinLimit = 10;string ZDDB1 = "ZD";string Prsta = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;//Prsta = Prsta.Substring(0, Prsta.LastIndexOf("//", Prsta.Length - 2)); //截取Prsta的路徑SqlConn sqlConn = new SqlConn();SqlConnection Conn2 = sqlConn.Sqlc2(Prsta, ZDDB1);Conn2.Open();string sqlse1 = "select top 100 * from SqlLogOut";SqlDataAdapter sqlDa = new SqlDataAdapter(sqlse1, Conn2);SqlCommandBuilder scb = new SqlCommandBuilder(sqlDa);DataSet Ds = new DataSet();sqlDa.Fill(Ds, "SqlLogOut");label1.Text = "共有" + Ds.Tables[0].Rows.Count.ToString() + "條記錄 開始上傳..........";int Loop1 = Ds.Tables[0].Rows.Count / LinLimit; //分包數if (Ds.Tables[0].Rows.Count % LinLimit > 0)Loop1++;for (int i = 1; i <= Loop1; i++){DataSet DsPack = PackDs(Ds, LinLimit);DsPack.RemotingFormat = SerializationFormat.Binary; //將DS設置為用于遠程序傳送的精簡二進制模式BinaryFormatter BinForm = new BinaryFormatter();MemoryStream ms = new MemoryStream();BinForm.Serialize(ms, DsPack);byte[] buffer = ms.ToArray();byte[] byUpload = new CompressionHelper(CompressionLevel.BestSpeed).CompressToBytes(buffer); //將byte數組再進行加壓localhost.DataTransport daTr = new DataTransport.localhost.DataTransport();string Res = daTr.DataUpload(byUpload);if (Res == "#1"){progressBar1.Value =Convert.ToInt16( Convert.ToDouble(i) / Loop1 * 100);sqlDa.Update(Ds, "SqlLogOut"); //刪除數據庫上對應記錄}}label1.Text = "上傳完成.";Conn2.Close();thread1.Abort();}
三.WebService
public string DataUpload(byte[] byUpload,string UpBm){try{byte[] byData = new CompressionHelper().DecompressToBytes(byUpload);BinaryFormatter binForm = new BinaryFormatter();DataSet dsUpload = binForm.Deserialize(new MemoryStream(byData)) as DataSet;Bz1= "#1";}catch (Exception e1){Bz1 = e1.Message.ToString();}return Bz1;}
?
經此方法可以將原數據量大大壓縮2/3以上,只是原來的1/3左右
?
qingyou0405 發表于2009年5月25日
PackDs(Ds, LinLimit), 能提供此方法的源代碼嗎?我現在在做一個功能,涉及到webservice遠程數據傳輸, 我的email 33353405@163.com , 希望你能答復 。
turejackon 發表于2009年6月6日
回復 qingyou0405:PackDs(Ds, LinLimit)是用于裝上傳數據劃分為若干個數據包,程序好簡單,用一個同構DataSet每次取上傳數據中的若干數據后清除相關行就可以了
malingxian 發表于2010年1月23日
ICSharpCode.SharpZipLib.dll是微軟提供的?你很強啊turejackon
回復 malingxian:嚇....不是嗎,因為我也是看一個例子改過來的..他那里說是微軟提供的.
malingxian 發表于2010年3月3日 10:57:51
回復 turejackon:呵呵,確實不是。如果用.NET 2.0以上的話,可以用MS內置的ZIP工具壓縮。 很不幸,我也用WebService進行大數據量傳輸,也用SOAP進行壓縮,但是Dataset的壓縮應該單獨拿出來進行優化。我的做法是 Dataset->XML->Byte[]進行壓縮這樣做的好處是要比Dataset單獨進行壓縮數據量小更多,速度上也沒有什么影響。 你可以比較一下Dataset經SOAP后跟XML的大小,數據量越大,XML相對越小——因為二者結構不一樣。
chen_chen121212 發表于2010年1月25日 19:08:13
c++做的服務器,用.net引用wsdl后找不到方法了,為啥啊???
你好,我按照你上面的方法,配置Web.config時,老是提示未能找到元素“****”的架構信息,網上相關資料比較少,能不能在線指導一下,我的email是xmlttys0@163.com
出處:http://blog.csdn.net/turejackon/archive/2009/03/05/3958962.aspx
?
?
?
總結
以上是生活随笔為你收集整理的如何优化WebService进行大批量数据传送(WSE3.0应用技巧)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 10 款优雅的 Go 语言开发工具
- 下一篇: 日语在线翻译网站大全