异步webmethod没有超时

时间:2010-03-16 12:46:59

标签: c# web-services

我需要一个调用webmethod的控制台应用程序。

它必须是异步的,没有超时(我们不知道这个方法需要花多少时间来处理任务。

这是好方法:

[WebMethod]
[SoapDocumentMethod(OneWay = true)]

...

2 个答案:

答案 0 :(得分:5)

如果您需要结果,请勿单向使用

首先,如果您需要来自方法的回复,则不需要[SoapDocumentMethod(OneWay = true)]。此属性创建一个“fire and forget”调用,该调用永远不会将响应返回给caler并且必须返回void。相反,使用常规方法调用并将其称为异步。

一种或两种方法?

如果您正在使用ASMX,则有两种基本解决方案:一种具有超长超时的方法,或两种方法(如@Aaronaught suggested above):一种启动操作并返回一个ID操作,另一个传入ID并检索结果(如果可用)。

就个人而言,在大多数情况下我不会推荐这种双方法,因为涉及额外的复杂性,包括:

  • 需要更改客户端和服务器代码以支持两步调用
  • RequestResponse这样的ASP.NET内部对象是not available when called from a background task launched with ThreadPool.QueueUserWorkItem.
  • 如果每个请求涉及多个线程,
  • 在繁忙的服务器上进行限制会更加困难。
  • 服务器必须挂起结果,直到客户端选择它们(或者你决定将它们丢弃),如果结果很大,可能会占用RAM。
  • 您无法将大型中间结果流式传输回客户端

确实,在某些情况下,2方法方法可能会更好地扩展,并且对客户端和服务器之间断开的网络连接更具弹性。如果您需要在几小时后获取结果,则需要考虑这一点。但是你的操作只需要几分钟,你可以保证客户端将保持连接,考虑到2方法方法的附加开发复杂性,我认为只有当单方法解决方案不能使用时,它才是最后的选择。符合您的需求。

无论如何,解决方案需要两件。首先,您需要从客户端异步调用该方法。其次,您需要延长客户端和服务器上的超时。我在下面报道。

异步调用ASMX Web服务

要从命令行应用程序异步调用ASMX Web服务,请从第2页开始查看this article。它显示了如何使用较新的{cn .NET .NET静态应用程序异步调用Web服务{ {3}}。请注意,由于Visual Studio的代理生成器不创建这些方法,因此不再推荐使用较早的.NET 1.0方法Event-Based Async Pattern,它依赖于代理上的BeginXXX / EndXXX方法。最好使用上面链接的基于事件的模式。

以上是上述文章的摘录/改编,因此您可以了解所涉及的代码:

void KickOffAsyncWebServiceCall(object sender, EventArgs e)
{
    HelloService service = new HelloService();
    //Hookup async event handler
    service.HelloWorldCompleted += new 
        HelloWorldCompletedEventHandler(this.HelloWorldCompleted);
    service.HelloWorldAsync();
}

void HelloWorldCompleted(object sender,
                         HelloWorldCompletedEventArgs args)
{
    //Display the return value
    Console.WriteLine (args.Result);
}

延长服务器和客户端超时

为防止超时,here总结了如何调整客户端和服务器超时。您没有在问题中指明您是拥有服务器端方法还是仅拥有客户端调用,因此下面的摘录涵盖了这两种情况:

  

有两个会议   影响webservice调用超时   行为:

     

** ASP.NET webservice的服务器端httpruntime超时   设置,这是通过配置   以下元素:

     

httpRuntime元素(ASP.NET设置架构)
  http://www.dotnetmonster.com/Uwe/Forum.aspx/asp-net-web-services/5202/Web-Method-TimeOut

     

<结构> <&的System.Web GT;
  < httpRuntime .............
  executionTimeout = “45”
  ............... /> < /system.web>   < /结构>

     

另外,请确保您已设置   < compilation debug =“false”/>为了   使超时工作正常。

     

**如果您正在使用wsdl.exe或VS IDE生成“添加webreference”   代理调用webservice方法,   还有一个超时设置   客户端代理类(派生自   SoapHttpClientProtocol类)。这是   “Timeout”属性派生自   “WebClientProtocol”类:

     

WebClientProtocol.Timeout属性http://msdn2.microsoft.com/en-us/library/e1f13641.aspx

     

因此,您可以考虑调整   根据你的这两个值   应用程序的场景。这里有一个   前线程也提到了这个:

     

http://msdn2.microsoft.com/en-us/library/system.web.services.protocols.webclientprotocol.timeout.aspx

请注意,我强烈建议您将超时时间设置为足以包含最长时间的操作(加上足够的缓冲区以便在事情变慢时保持安全)但我不建议完全关闭超时。由于错误的客户端或服务器可以永久禁用另一个,因此允许无限制超时通常是错误的编程习惯。相反,只是让超时很长 - 并确保记录客户端或服务器超时的实例,以便在问题发生时检测并诊断问题!

最后,回应上面的评论者:对于新代码,最好使用WCF。但是,如果您使用ASMX Web服务时,上述解决方案应该可以正常工作。

答案 1 :(得分:3)

如果方法实际单向,并且您不关心结果或需要跟进请求的状态,那就足够了。

如果您确实需要结果(最终),或者需要检查操作的状态,那么这将无法正常工作。在这种情况下,您的方法应该做的是在后台线程中开始工作,然后立即返回可以在其他Web方法中使用的ID以查找状态。

这样的事情:

public enum JobStatus { Running, Completed, Failed };

public class MyService : WebService
{
    [WebMethod]
    public int BeginJob()
    {
        int id = GetJobID();
        // Save to a database or persistent data source
        SaveJobStatus(id, JobStatus.Running);
        ThreadPool.QueueUserWorkItem(s =>
        {
            // Do the work here
            SaveJobStatus(id, JobStatus.Completed);
        }
        return id;
    }

    [WebMethod]
    public JobStatus GetJobStatus(int id)
    {
        // Load the status from database or other persistent data source
        return ( ... )
    }
}

这是启动工作的一种方法,另一种检查其状态的方法。由客户定期轮询。它不是一个非常好的系统,但是ASMX没有很多选择。

当然,如果您确实需要此操作的响应,则更好方式是使用WCF。 WCF为您提供callback contracts,您可以使用它来开始单向操作,并在该操作完成时订阅通知,这样就无需进行上述轮询。

所以,总结一切:

  • 如果您不需要任何回复或状态更新,请使用IsOneWay = true

  • 如果您确实需要更新,并且可以在服务端使用WCF,请将其与回调合同一起使用。无论如何,您应该将WCF用于新的Web服务项目。

  • 如果您需要更新且无法使用WCF,请在后台线程中进行工作,并使用其他状态检查Web方法实施定期轮询系统。