【问题标题】:How: Web Service and handling Client Timeouts in the Web Service?如何:Web 服务和处理 Web 服务中的客户端超时?
【发布时间】:2010-11-18 22:33:25
【问题描述】:

我正在尝试记录客户端在 Web 服务调用中超时时发生的情况。

看看下面的 HelloWorld 代码。这是我想做的,但似乎 IsClientConnected 不起作用,因为它总是返回 true。

[WebMethod]
public string HelloWorld() {
    //.. Do the Webservice stuff
    if (!Context.Response.IsClientConnected) {
        //Log some vital info about this call that timed out...
    }
    return "The WebService Result";
}

有没有人知道另一种检查 Web 服务调用状态的方法?

当客户端与 Web 服务调用断开连接时,Web 服务中不会引发异常。代码继续运行,直到完成,然后将其结果返回到虚无中(因为连接已关闭)。

【问题讨论】:

  • IIS 版本对 IsClientConnected 的准确性有很大影响。我很想看看其他人想出什么来解决这个问题轮询。

标签: .net web-services timeout


【解决方案1】:

我创建了一个简单的测试客户端并将我的请求设置为在 100 毫秒内超时

        HttpWebRequest MakeRequest = (HttpWebRequest)WebRequest.Create("http://localhost:55959/ScanServer.asmx");
        if (MakeRequest == null)
        {
            throw new Exception();
        }
        HttpWebResponse PostResponse = null;

        MakeRequest.Method = "POST";
        MakeRequest.AuthenticationLevel = System.Net.Security.AuthenticationLevel.None;
        MakeRequest.UserAgent = "testing";
        MakeRequest.Timeout = 100;
        MakeRequest.ContentType = "application/soap+xml; charset=utf-8;";

        try
        {
            byte[] PostBytes = UTF8Encoding.UTF8.GetBytes(PostData);
            MakeRequest.ContentLength = PostBytes.Length;

            Stream RequestStream = MakeRequest.GetRequestStream();
            RequestStream.Write(PostBytes, 0, PostBytes.Length);

            PostResponse = (HttpWebResponse)MakeRequest.GetResponse();
        }
        catch
        {
            throw;
        }

在调试时在 SOAP WebService 调用中,我在断点处等待,直到客户端收到超时异常。然后将Context.Response.IsClientConnected 的值设置为false。我还使用 Fiddler 发送请求,并且在服务器断点时我中止了会话。再次将该值设置为 false。

我不知道为什么您在检查 IsClientConnected 时会看到超时而无法记录数据,除非超时是在与您的服务器的初始连接中。

【讨论】:

    【解决方案2】:

    我认为一般情况下不会有例外。即使服务发送回一个长响应,例如关闭传出传输窗口,并超时等待能够发送字节,所有这些都将在 Web 方法返回到 ASP.NET 之后发生。

    您应该了解哪些网络方法耗时过长。您可以通过打开跟踪来开始执行此操作,如“Enabling Tracing in ASP.NET Web Services”所示。然后,您可能需要更进一步,对服务进行概要分析以查看时间花费在何处。

    您还应该仔细查看事件日志。特别是,从“ASP.NET”事件源中查找警告事件。这些来自ASP.NET Health Monitoring。我建议您了解 Health Monitoring 系统,因为您可能会发现它为您做了很多您必须自己编写的事情,而只是以配置为代价。

    【讨论】:

    • 我将研究健康监测。恐怕追踪会是致命的。来自几种不同类型的客户端的这些服务有很多流量。糟糕的是,似乎没有办法从 web 服务端检测客户端和 web 服务之间的断开连接。如果有,我希望有人能启发这个线程。
    • 您运行的是哪个操作系统版本? Vista 和 Server 2008 有一个 EtwTraceListener,它记录到“Windows 事件跟踪”子系统,它的速度足以让设备驱动程序使用它。
    • 是的,那就没有 EtwTraceListener。
    【解决方案3】:

    我认为,为了让 IsClientConnected 返回 false,Web 服务代码中“//.. Do the Webservice stuff”的部分执行时间必须比客户端的超时设置长。您可以通过将客户端的超时设置为 60 秒并在 IsClientConnected 调用之前在您的 Web 服务代码中放置一个 Thread.Sleep(70000) 来模拟这一点。

    但是,我认为即使这样也不会导致 IsClientConnected 返回 false。 Web 服务请求超时和重置与服务器的连接是两种不同的野兽。如果 Response 有一个名为 IsClientStillWaitingForThisWebServiceCallToReturn 的方法,那可能会满足您的要求。

    我认为,如果您在 Web 服务方法仍在 IsClientConnected 检查之前的部分中物理断开客户端与网络的连接时,您可以让 IsClientConnected 返回 false,但我猜这不是您想要的。

    【讨论】:

    • 我的概念测试只是一个 web 服务应用程序,正如你提到的那样运行睡眠,另一个应用程序以 100 毫秒的超时时间调用该 web 服务。应用程序因错误而终止 = 连接已关闭。然后应用程序来到 IsClientConnected,它仍然是 True 并返回没有错误的退出。
    • 正如我所说,客户端在 Web 服务请求上超时和客户端重置与服务器的连接不是一回事,因此您的结果正是我所期望的。 IsClientConnected 返回 True,因为客户端仍连接到服务器(即使 Web 服务调用已超时)。
    • Web 服务调用超时仅在客户端发生,服务器对此一无所知。
    • 好的。那么这里有两件事可以解决问题。客户端仍然在其端打开连接,即使它没有监听,或者客户端关闭它的端(没有向服务器发送关于它的信号)。但是如果是后者,服务器应该仍然能够向客户端发送一个“你还活着”的回调来检查套接字上的状态。如果可行,我可以通过试用来检查这是否是使用 WS 调用和客户端超时的客户端的行为方式(断开客户端连接)。
    • 从我刚刚阅读的内容来看,IsClientConnected 仅在用户单击停止或刷新按钮或将其浏览器重定向到新服务器时才返回 false。这意味着用户的浏览器实际上向服务器发送了一些东西,告诉服务器它不再连接。我的猜测是调用 Web 服务的客户端应用程序在发生超时时根本不会发送此信号,因此 IsClientConnected 始终返回 true。我还猜想如果您的客户端中止 Web 服务调用(而不是超时),IsClientConnected 将返回 False。
    【解决方案4】:

    HTTP 协议没有规范服务器如何 ping 客户端。 IsClientConnected 的意义 - 检查是否存在渲染 HttpResponse 的一些“不满意”查询。 如果客户端支持keep-connection-alive,可能(我不确定)。

    考虑拉架构 - 你是否有单向方法,以及来自客户端的一些看门狗定期检查方法是否完成。

    【讨论】:

    • 是的。这将在轮询解决方案上失败,但到目前为止,当我嗅探有关 web 服务的网络流量时,有一个请求和一个响应。从来没有建立新的 HTTP 连接来接收结果,因为这会在服务器的新 HTTP 标头中显示出来。所以我假设有一个连接保持活跃。此连接在某种程度上将是一个 .Net 套接字。可能是隐藏的,但最坏的情况可以通过一点反思来理解。套接字有一个我可以检查的状态。
    • 是的,你是对的。 IsClientConnected 完全返回您所描述的内容。 Keep-alive 只是优化标志,而不是规则。这就是为什么它谈论可能性(!仅)通过同一个套接字传输其他东西。
    【解决方案5】:

    这将取决于您使用的 Web 服务框架的详细信息。从你展示的内容来看,如果你没有检测到这一点的机制,我不会感到惊讶。

    考虑到通常 Web 服务甚至不需要使用 HTTP 等传输,您可以通过队列甚至电子邮件进行响应。一般来说,作为简单 Web 服务的服务器实现,您不能确保您的客户端已经看到了答案。如果您的测试有效,您会推断出什么?在你进行测试的那一刻,他就在那里,在你决定不登录之后的一纳秒,但在你回来之前,他已经走了。在简单的 SOAP/HTTP 中,Client 和 Server 之间没有事务关系。

    有额外的 Web 服务标准来解决其中的一些问题,但通常您需要在假设调用者可能看不到答案的情况下设计 Web 服务。 (也许您还提供状态服务,因此客户可以下车然后回来询问“您是否处理订单“345”)。

    请告诉我们您希望通过此日志记录实现什么目标,也许有人有设计方法可以提供帮助。

    【讨论】:

    • 集群中的服务出现问题,但我们不知道哪个集群服务是超时的,因为客户端连接到集群 URL 而不是物理服务器 URL。这里的目标通常是在我的 web 服务中添加一个 log-to-the-windows-event 在客户端和该服务器之间发生超时或过早断开连接的情况下。
    • 我这样做的假设如下:当客户端对服务器进行 WS 调用时,会建立一个 TCP 套接字连接。此连接保持活动状态,等待回复。一旦服务完成了对代码的处理,数据就会在这个连接上返回。只要服务正在执行其代码,只要建立的连接仍然有效,就应该有一种方法可以获取该 TCP 连接的状态。
    • 所以我只想要一个通用的“故障转移”记录器,用于客户端断开连接的各种 Web 服务,我可以轻松地将其添加到代码中。
    • -1:看看他的问题。很明显他使用的是 ASMX Web 服务,而不是 WCF。
    • @Wolf5:TCP/IP 不能以这种方式工作。服务器至少在开始发送响应之前不会知道连接已断开;可能直到整个响应都发送完毕并且它正在等待确认。
    【解决方案6】:

    订阅某种事件比检查某个标志更好。基本上,ASP.NET 正在终止请求,因为它花费的时间超过了配置的超时值(httpRuntime 元素中的executionTimeout 设置)。但是,我不太确定 ASP.NET 运行时是否存在这样的事件。显然,它也没有引发任何异常。因此,在这种特殊情况下,您的服务和 ASP.NET 运行时之间似乎存在脱节。我很想知道是否有办法/技巧来完成你所追求的。

    与此同时,您可以查看 ASP.NET 性能计数器。有一个称为“请求超时”。它可能包括在队列中等待或执行期间超时的请求。您可以在 Web 方法的开始和结束时读取 Web 服务的性能计数器。如果数字跳跃,这意味着请求只是超时。这可能并不一定意味着跳转对应于该特定请求,但在任何情况下,您仍然可以记录一些可能有用的信息,例如传递给 Web 方法的参数、经过的时间等。如果您的客户需要即时解决方案,您还可以增加 web.config 中的 executionTimeout 值,以便在尝试优化 Web 方法以更快地运行时留出更多时间。

    如果这是一个 asmx Web 服务,您可能需要查看 global.asax 中的 Session_End 事件。当 ASP.NET 终止请求时,它可能会被调用。

    只是一些想法。

    【讨论】:

    • -1:是什么让你认为请求被“杀死”了?他只知道客户端超时。
    • 是什么让你认为他不是?也许您应该开始更多地专注于提供答案,而不是试图找出其他人的帖子的错误。我们试图给 OP 一些方向和提示。最后,他需要决定哪一个适用于或最适合他/她的问题。我们只有有限的信息可供使用和做出假设。
    • “他”?他假设如果客户端“断开连接”,服务将被通知。事实并非如此。他还假设客户端断开连接。所有这些都是从客户端超时的事实推断出来的。事实上,我们只知道客户端超时。
    • 对不起,我的意思是“请求”而不是“他”。是什么让您认为“请求没有被杀死?”
    【解决方案7】:

    我希望每个 Web 服务调用都是请求/响应。如果出现服务不可用或超时等错误,我希望会引发异常。

    那么可以用 try catch 包围调用吗?

    【讨论】:

    • 客户端超时时Web服务内部不会抛出异常。它只是完成并将结果“发送”到虚无中。
    • 啊哈,所以您说的是服务器端,而不是客户端。抱歉,我不清楚。
    猜你喜欢
    • 2012-10-30
    • 2012-11-24
    • 1970-01-01
    • 2014-09-04
    • 2014-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多