向 Web 服务添加 zip 过滤器






4.88/5 (71投票s)
2004 年 7 月 17 日
5分钟阅读

416389

1007
通过 Web 服务传递大量数据可能会成为 WAN 应用程序架构(例如,服务器位于 Web 上)中的巨大瓶颈,并且无论如何都会给网络流量带来实际负载。这是降低网络成本的一种解决方案。
引言
请稍等,我知道这里没有图片,但还是请您看看,特别是如果您是 Web 服务开发人员 ;-)
在编写 Web 服务时,当客户端和服务器需要通过 Web 进行通信时,通过网络传输数据的成本正成为一个问题,这既消耗响应能力,又增加网络负载。
此库通过使用 SOAP 过滤器,在服务器端压缩 SOAP 信封正文,并在客户端将其解压缩回来,这一切都在后台进行。
背景
编写此类应用程序时,有一些通用建议应遵循,其中包括以下列表:
- 尽量每页调用一次服务器 - 通常,实际成本是与服务器的往返访问,而不是传递实际数据。
- 在客户端缓存数据,以尽可能减少访问服务器的需求。
- 设计应用程序,仅传递必需的信息(即,不要创建“所有供应商”屏幕,而是创建“搜索特定供应商”屏幕)。
话虽如此,有时您确实需要通过 Web 传递大量数据,通常是一个包含数千行等内容的庞大的 DataSet
。我的代码就在这里派上用场。
我编写了一个 Zip 过滤器和相应的 Unzip 过滤器,您可以非常简单地将其添加到您的 Web 服务(添加引用并在 web.config 文件中声明过滤器)和 WinForms 客户端(同样,添加引用和一行代码),然后即可完成。
完全无需更改代码,也没有其他开销。
代码描述
该代码是一个 DLL,客户端和服务器项目都应引用它,它由 3 个简单的类组成。
ZipWrapper
ZipWrapper
是 ICSharpZipLib 库(一个免费的 Zip 工具代码库,来自此处)的包装类,通过它可以选择所需的压缩方法(BZ2、GZip、tar 等),同时使用相同的接口。(此类代码来自此链接,并根据我的需要进行了轻微修改。)
我使用的 Zip 类型是 GZip;虽然不是最好的压缩,但它比 BZip2 快得多,并且在我们的情况下被证明更受青睐。
ZipFilter
ZipFilter
是一个 SoapOutputFilter
类,负责压缩 SOAP 信封的正文。它还公开了两个属性:
MinFilterSizeKB
:开始压缩的最小正文大小,并非所有消息都值得压缩。Enabled
:过滤器是否已启用。
此类还可以确定压缩方法。
UnZipFilter
UnZipFilter
是一个 SoapInputFilter
类,它将压缩的正文恢复为其原始形式。只有当 Zip 过滤器在信封上生效时,unzip 过滤器才会运行,因此不需要任何配置参数。
代码片段
我们必须重写 ProcessMessage
方法,通过 SOAP 机制的管道更改信封的正文。首先,我们验证过滤器是否已启用以及消息是否足够大以进行压缩。然后,我们创建一个自定义标头,通知客户端应解压缩消息。接下来,我们创建一个压缩的信封正文元素的流。最后,我们将正文替换为新的压缩对象。
public override void ProcessMessage(SoapEnvelope envelope)
{
if ( !m_bEnabled )
return;
//adding an attribute to specify that the filter has been
//applied on this envelope.
XmlElement soapHeader = envelope.CreateHeader();
if ( envelope.Body.InnerText.Length < ( m_MinFilterSize ) )
return;
else
soapHeader.AppendChild(CreateCustomHeader(soapHeader, "1" ));
//compress the body element.
MemoryStream result = new
MemoryStream( ZipWrapper.Compress(
Encoding.UTF8.GetBytes( envelope.Body.InnerXml ) ) );
//Attach zipped result to the envelope.
Microsoft.Web.Services2.Attachments.Attachment attch =
new Microsoft.Web.Services2.Attachments.Attachment(
"APPLICATION/OCTET-STREAM",result );
envelope.Context.Attachments.Add( attch );
//remove old body.
XmlElement newBody = envelope.CreateBody();
newBody.RemoveAll();
envelope.SetBodyObject( newBody );
}
使用该库
必备组件
- ICSharpZipLib.dll - 在“资源”部分查找链接,WSE 2.0 - Microsoft 的 Web 服务增强包。
服务器端用法
- 创建一个 Web 服务项目。
- 在解决方案资源管理器中右键单击项目,然后选择 WSE 2.0 设置。
- 在“常规”选项卡中,同时选中两个复选框。
- 添加对 WebServiceZipFilter.dll 的引用。
- 在 web.config 文件中,在
<microsoft.web.services2>
标签下添加<filters> <output> <add type="WebServiceZipFilter.ZipFilter, WebServiceZipFilter" /> </output> </filters>
为了配置过滤器,您应该设置其属性。
// setting minimum zip size requirement to 10KB.
WebServiceZipFilter.ZipFilter.MinFilterSizeKB = 10;
// enabling the filter
WebServiceZipFilter.ZipFilter.Enabled = true;
请注意:强烈建议通过 web.config 中的可配置部分设置这些值,以便根据调整需求动态更改它们。
客户端用法
重要提示:许多用户一再问我是否可以在双工模式下工作,以及客户端是否可以像服务器一样配置。答案是肯定的,而且都可以。下面的列表是添加到管道的过滤器的替代代码,但您可以将必要的部分添加到 app.config 文件中,无需编码即可完成(请参阅上面的“服务器端用法”部分)。关于双工模式,双方都可以随意压缩和解压缩!
- 创建一个 WinForms 客户端项目。
- 在解决方案资源管理器中右键单击项目,然后选择 WSE 2.0 设置。
- 在“常规”选项卡中,选中第一个复选框。
- 添加服务器的 Web 引用。
- 创建一个服务器代理(实例化
ServerNameWSE
代理类)。 - 在创建服务器代理后立即添加以下代码:
// creating the server TestServer.Service1Wse myServer = new TestClient.TestServer.Service1Wse(); // Adding the unzip filter myServer.Pipeline.InputFilters.Add( new WebServiceZipFilter.UnZipFilter() );
一些实证结果
我在一个专属于我的服务器上进行了测试,该服务器位于我们当地的 Web 农场,提供 5MB 的下载和 1MB 的上传,使用 750 KB 的 ADSL 连接,时间是周日下午,因此非压缩测试条件非常理想,但差异仍然非常显著。
发送 570 条异构数据记录,未压缩时耗时约 2.281 秒,压缩后耗时 1.843 秒(减少 20%)。
发送 10570 条记录(570 条异构数据 + 10000 条不同但相似的虚拟记录),未压缩时耗时约 29.43 秒,压缩后耗时 6.04 秒(减少 80%!!!)。如果数据完全异构,差异会微乎其微。
未来版本
会有什么变化吗?显然不会。这是好消息吗?是的!为什么?因为 Redmond 的人们意识到压缩功能缺失了,并且有几位优秀的人发布了WCF 实现,并且这些人还发布了 WSE 3.0 的版本在此处,所以我的任务基本完成了。每个人都很高兴。
资源
历史
- 2004-7-18 v.1.0 - 首次发布。
- 2006-5-12 v.1.1 - 修复了 tl11 报告的错误,根据字节数而不是文本长度进行压缩。
强烈建议您审阅并评论。
祝您编码愉快。