网络服务数据压缩:优化Web服务通信

在开发Web服务时,客户端与服务器之间的数据传输成本逐渐成为一个问题,这不仅影响响应速度,还增加了网络负载。本文介绍一种在服务器端压缩SOAP信封体,客户端解压缩的方法,通过SOAP过滤器实现,无需更改任何代码,也无需额外开销。

在编写此类应用程序时,有一些常见的建议需要遵循,其中包括但不限于以下几点:

  • 尽量在每个页面只调用服务器一次,因为实际的成本在于来回访问服务器,而不是传输数据本身。
  • 在客户端缓存数据,以减少访问服务器的需要。
  • 设计应用程序时只传递必要的信息,例如不要创建“所有供应商”的屏幕,而是创建“搜索特定供应商”的屏幕。

尽管如此,有时确实需要通过Web传输大量数据,例如包含数千行数据的DataSet。这就是代码发挥作用的地方。

代码描述

代码是一个DLL,需要在客户端和服务器两个项目中引用,包含3个简单的类:

  1. ZipWrapper:这是一个包装类,使用ICSharpZipLib库(一个用于Zip功能的免费代码库),可以选择所需的压缩方法(如BZ2、GZip、tar等),同时使用相同的接口。
  2. ZipFilter:这是一个SoapOutputFilter类,负责压缩SOAP信封的主体。它还公开了两个属性:MinFilterSizeKB(开始压缩的最小主体大小)和Enabled(过滤器是否启用)。
  3. UnZipFilter:这是一个SoapInputFilter类,将压缩的主体还原成原始形式。如果Zip过滤器在信封上做了标记,Unzip过滤器将自动工作,不需要任何配置参数。

代码片段

必须重写ProcessMessage方法来通过SOAP机制的管道改变信封的主体。首先,验证过滤器是否启用,消息是否足够大以进行压缩。然后,创建一个自定义头部,通知客户端该消息应该被解压缩。接下来,创建信封主体元素的压缩流。最后,用新的压缩对象替换主体。

public override void ProcessMessage(SoapEnvelope envelope) { if (!m_bEnabled) return; XmlElement soapHeader = envelope.CreateHeader(); if (envelope.Body.InnerText.Length < (m_MinFilterSize)) return; else soapHeader.AppendChild(CreateCustomHeader(soapHeader, "1")); MemoryStream result = new MemoryStream(ZipWrapper.Compress(Encoding.UTF8.GetBytes(envelope.Body.InnerXml))); Microsoft.Web.Services2.Attachments.Attachment attch = new Microsoft.Web.Services2.Attachments.Attachment("APPLICATION/OCTET-STREAM", result); envelope.Context.Attachments.Add(attch); XmlElement newBody = envelope.CreateBody(); newBody.RemoveAll(); envelope.SetBodyObject(newBody); }

使用方法

创建一个Web服务项目。在解决方案资源管理器中右键单击项目,选择WSE 2.0设置。在常规选项卡中,启用两个复选框。添加对WebServiceZipFilter.dll的引用。在web.config文件中,添加以下内容:

<microsoft.web.services2> <filters> <output> <add type="WebServiceZipFilter.ZipFilter, WebServiceZipFilter" /> </output> </filters> </microsoft.web.services2>

为了配置过滤器,应该设置其属性:

WebServiceZipFilter.ZipFilter.MinFilterSizeKB = 10; WebServiceZipFilter.ZipFilter.Enabled = true;

注意:强烈建议通过web.config中的可配置部分设置这些值,以便根据调整需求动态更改。

创建一个WinForms客户端项目。在解决方案资源管理器中右键单击项目,选择WSE 2.0设置。在常规选项卡中,启用第一个复选框。添加服务器的Web引用。创建服务器代理(实例化ServerNameWSE代理类)。在代理服务器创建后添加以下代码:

TestServer.Service1Wse myServer = new TestClient.TestServer.Service1Wse(); myServer.Pipeline.InputFilters.Add(new WebServiceZipFilter.UnZipFilter());

实验结果

在本地的一个专用服务器上进行了测试,该服务器位于家乡的Web农场中,提供5MB的下载速度和1MB的上传速度,使用ADSL 750KB的连接,在周末中午放松的时候,条件非常适合非压缩测试,但即使如此,差异仍然相当明显:

  • 发送570条不同数据的记录大约需要2.281秒,而压缩后大约需要1.843秒(减少了20%)。
  • 发送10570条记录(570条不同数据+10000条相似但不同的虚拟记录)大约需要29.43秒,而压缩后大约需要6.04秒(减少了80%!!!)。如果数据完全异构,差异将变得微不足道。

还会有新版本吗?显然不会。这是好消息吗?是的!为什么?因为Redmond的人们意识到缺少压缩功能,一些优秀的人发布了WCF实现,这些人还发布了WSE 3.0的版本,所以任务已经完成了。每个人都很高兴。

资源

  • 压缩帮助类。
  • ICSharpZipLib。
  • 下载WSE 2.0。
  • WSE 3.0实现的Zip过滤器。
  • WCF实现的Zip过滤器。
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485