65.9K
CodeProject 正在变化。 阅读更多。
Home

Web 服务优化

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.40/5 (13投票s)

2006年1月31日

4分钟阅读

viewsIcon

92402

客户端 Web Service 优化和网络流量最小化。

引言

大多数关于优化 ASP.NET Web Services 的文章都只关注优化服务器端代码(这些代码大部分运行在拥有两吉字节内存和快速 SCSI 硬盘的强大多处理器机器上)。但我们不应忘记,客户端优化和网络流量优化同样需要应用,否则它们可能成为瓶颈。本文将介绍如何优化对 Web Services 方法的客户端调用。

1. 异步调用 Web 方法

首先,请异步调用您的 Web 方法。异步调用意味着被调用的成员将在另一个线程上执行其工作。当所有工作完成后,该成员必须通知主线程,并可选择地将其返回值传递给主线程。这能显著提高性能。如果一个复杂且耗时的 Web 方法在一个单独的线程中执行,主应用程序就可以继续执行其任务,而不必等待 Web 方法完成。

互联网上有大量关于此主题的文章,因此我只做简要介绍。当 VS.NET 为 Web Service 生成代理类时,它会自动为每个 Web 方法生成 `Begin<webmethodname>` 和 `End<webmethodname>` 方法。这个简短的示例演示了如何使用它们。

假设我们有一个 Web Service `MyWebService` 和一个 Web 方法 int Sum(int a, int b),它返回 `a+b`。代理类将包含两个自动生成的方法:

public System.IAsyncResult BeginSum(int a, int b, 
       System.AsyncCallback callback, object asyncState)
{
    return this.BeginInvoke("Sum", new object[] {a, b}, 
                                 callback, asyncState);
}

public int EndSum(System.IAsyncResult asyncResult)
{
    object[] results = this.EndInvoke(asyncResult);
    return ((int)(results[0]));
}

以下是从我们的应用程序异步调用 `Sum` Web 方法的方法:

//webservice instance
private MyWebService webService = new MyWebService();

private int result = 0;

public void InvokeSum(int a, int b)
{
    //delegating
    AsyncCallback asyncCallback = 
            new AsyncCallback(FinishSum);

    //start executing a web method 
    //Sum in a separate thread
    webService.BeginSum(a, b, asyncCallback, null);
}

//this callback method is invoked 
//when a web method has finished working
public void FinishSum(IAsyncResult iAsyncResult)
{
    //get the result
    this.result = webService.EndSum(iAsyncResult);
}

2. 提前创建实例以在最开始预加载所有引用的程序集

每个人都会注意到,第一次调用 Web Service 的时间比后续调用要长。这是为什么?尝试在 Debug 模式下运行您的应用程序,并查看 Visual Studio 的“输出”窗口。一旦调用 Web 方法,应用程序就会加载许多库,如 *System.Web.dll*、*System.Web.Services.dll*、*System.XML.dll* 等。也许还有您自己用于与 Web Service 交互的类的其他程序集。加载这些程序集自然需要时间。因此,在应用程序启动时,请提前创建 Web Service 的实例。这将把所有需要的库加载到内存中,从而节省时间。

3. 使用预身份验证

此部分仅适用于使用“匿名”以外的身份验证机制的 Web Services。

类 `SoapHttpClientProtocol` 是所有 Web Service 代理类的基类。该类有一个 `PreAuthenticate` 属性。以下是从 MSDN 引用的一段描述该属性的内容:

当 `PreAuthenticate` 为 true 时,如果身份验证机制支持,则会在第一个请求中发送 WWW-authenticate 标头。当 `PreAuthenticate` 为 false 时,会在不最初尝试验证用户的情况下,向 XML Web Service 方法发出请求。如果 XML Web Service 允许匿名访问,则会执行 XML Web Service 方法。如果不允许匿名访问,则会将 401 HTTP 返回码发送回客户端。作为响应,`WebClientProtocol` 类会将身份验证凭据返回给 Web 服务器。如果客户端已成功通过身份验证并获得访问 XML Web Service 的权限,则会执行 XML Web Service 方法;否则,客户端将被拒绝访问。

换句话说:**任何对 Web Service 方法的调用都会至少产生一个 401 错误**(如果您使用“集成 Windows 身份验证”,则可能产生两个或三个 401 错误!)。为避免这种情况,请将 `PreAuthenticate` 设置为 true

但请记住,并非所有托管 Web 服务器使用的身份验证方法都支持预身份验证。同样,请参阅 此 MSDN 文章。如果您的托管 IIS 服务器使用“Windows 集成身份验证”,则无法进行预身份验证。为加快 Web Service 调用速度,请使用“基本”身份验证方案。但请记住,“基本”身份验证存在漏洞。仅与 SSL 保护的 Web Services 和网站一起使用。

4. 编辑 IIS 自定义错误消息

当发生错误时,Web 服务器会显示错误消息。包含这些消息的 *htm* 文件位于服务器文件夹 *c:\WINDOWS\Help\iisHelp\common\* (如果不在那里,请查看您的 IIS 设置)。**编辑这些文件**以最小化流量!摆脱样式表、表格和其他“花哨”的东西!

您可能会问,为什么?正如我在第 3 部分(预身份验证)中提到的,访问 Web Service 时总会有 401 错误。即使将 `PreAuthenticate` 设置为 true,首次访问 Web Service 时仍然会生成 401 错误。因此,请最小化 401 文件的内容。

例如,这是我的 *401-2.htm* 文件:

Error 401.2 - Unauthorized: Access is denied due to server configuration.

我的 *401-2.htm* 文件仅 73 字节。而 IIS 的默认 *401-2.htm* 文件为 5KB(感受一下区别)。

5. 使用压缩

使用 SOAPExtensions 机制和任何压缩算法来压缩客户端和服务器之间的 XML 流量。您可以使用 ZIP 压缩来处理您的数据。C# 有许多开源的压缩库。例如,您可以使用一个名为 SharpZipLib 的免费库来压缩您的 Web 方法。请阅读 这篇文章下载“CompressionExtension”项目。为您的 Web Service 添加压缩非常简单:将下载的项目包含在您的解决方案中,在 Web Service 中引用它,并在代理类代码中用 `[CompressionExtension]` 标记您的 Web 方法。另外,在 *.asmx* 组件中添加 `[CompressionExtension]` 标志。就这样。

© . All rights reserved.