异步Web方法无超时

4
我需要一个控制台应用程序,它将调用 WebMethod。
它必须是异步的,并且没有超时(我们不知道这个方法处理任务需要多长时间)。
这是一个好的方式吗?
[WebMethod]
[SoapDocumentMethod(OneWay = true)]

??


1
你的web方法需要返回一个响应吗? - lajuette
5
除非你被限制使用.NET 2.0,否则使用 ASMX web服务并不是一种“好的方式”。微软现在认为ASMX web服务是“遗留技术”,所有新的web服务开发应该使用WCF。请注意,这里不做任何解释。 - John Saunders
2
一篇在MSDN上标有关于ASMX“遗留”的注释的文章(而MSDN上关于ASMX的新文章则没有携带该注释)并不会突然使ASMX在其所做的事情上变得更糟。整个争论最多只是与phenevo的问题无关。 - Dave Ward
2
ASMX在.NET 4中得到支持,并将在可预见的未来继续得到支持(根据微软的说法;只需问问他们)。如果您不得不诉诸恐吓策略来销售WCF,那么这就充分说明了WCF的问题。 - Dave Ward
1
如果你需要响应,那么你不想使用OneWay,因为它排除了获取响应-它是“发送并忘记”。有关更多详细信息,请参见下面的答案。 - Justin Grant
显示剩余2条评论
2个回答

5

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

首先,如果您需要从方法中获得响应,则不要使用[SoapDocumentMethod(OneWay = true)]。此属性创建了一个“发出请求并忘记”的调用,它不会将响应返回给调用方,必须返回void。相反,使用常规方法调用并异步调用它。

一个方法还是两个方法?

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

个人而言,在大多数情况下,我不建议使用这种两个方法的方法,因为其中涉及的额外复杂性包括:

  • 需要更改客户端和服务器代码以支持两步调用
  • 当使用ThreadPool.QueueUserWorkItem启动的后台任务时,像RequestResponse这样的ASP.NET内置对象是不可用的。
  • 如果每个请求都涉及多个线程,则繁忙服务器上的限流会变得更加困难。
  • 服务器必须保留结果,直到客户端接收它们(或您决定将其丢弃),如果结果很大,则可能会占用RAM。
  • 无法将大型中间结果流式传输回客户端

确实,在某些情况下,两种方法的方法可能更好地扩展,并且对于客户端和服务器之间的网络连接断开更具有韧性。如果您需要几个小时后再获取结果,则应考虑此选项。但是,如果您的操作只需要几分钟,并且可以保证客户端保持连接,则考虑到两种方法的额外开发复杂性,我认为这是最后的选择,仅在单方法解决方案无法满足您的需求时使用。

无论如何,解决方案需要两个部分。首先,您需要从客户端异步调用该方法。其次,您需要延长客户端和服务器上的超时时间。我在下面介绍这两个部分。 异步调用 ASMX Web 服务 要从命令行应用程序异步调用 ASMX Web 服务,请参阅本文第2页开始的内容。它展示了如何使用较新的基于事件的异步模式从 .NET 客户端应用程序异步调用 Web 服务。请注意,旧的 .NET 1.0 方法在此处所描述的依赖于代理上的 BeginXXX/EndXXX 方法不再建议使用,因为 Visual Studio 的代理生成器不会创建这些方法。最好使用以上链接中提供的基于事件的模式。
以下是来自上述文章的摘录/改编,以便您了解所涉及的代码:
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);
}

延长服务器和客户端超时时间

为了防止超时,http://www.dotnetmonster.com/Uwe/Forum.aspx/asp-net-web-services/5202/Web-Method-TimeOut 提供了一个很好的总结,介绍如何调整客户端和服务器端的超时时间。您在问题中没有说明您是否拥有服务器端方法或只是客户端调用,因此以下摘录涵盖了这两种情况:

有两个设置会影响 WebService 调用超时行为:
1. ASP.NET WebService 的服务端 httpruntime 超时设置,可以通过以下元素进行配置:
httpRuntime 元素 (ASP.NET 设置架构) http://msdn2.microsoft.com/en-us/library/e1f13641.aspx 另外,请确保已经设置了 ,以便正确运行超时。
2. 如果您使用 wsdl.exe 或 VS IDE "添加 Web 引用" 生成的代理来调用 WebService 方法,则客户端代理类(派生自 SoapHttpClientProtocol 类)也有一个超时设置。这是从 WebClientProtocol 类派生的 "Timeout" 属性:
WebClientProtocol.Timeout 属性 http://msdn2.microsoft.com/en-us/library/system.web.services.protocols.webclientprotocol.timeout.aspx 因此,您可以根据应用程序的场景考虑调整这两个值。这里还有一个旧帖子提到了这个问题: http://groups.google.com/group/microsoft.public.dotnet.framework.webservices/browse_thread/thread/73548848d0544bc9/bbf6737586ca3901 请注意,我强烈建议将超时时间设置得足够长,以包含最长的操作时间(再加上足够的缓冲时间以确保安全),但是我不建议完全关闭超时时间。允许无限制的超时时间通常是不好的编程实践,因为一个错误的客户端或服务器可能会永久性地禁用另一个。相反,只需将超时时间设置得非常长,并确保记录客户端或服务器超时的情况,以便在发生问题时进行检测和诊断!
最后,为了echo上面的评论者:对于新代码最好使用WCF。但如果你被困在使用ASMX web服务中,上述解决方案应该可以工作。

3
如果该方法实际上是单向的,并且您不关心结果或永远不需要跟进请求的状态,那么这就足够了。
如果您确实需要结果(最终),或者需要检查操作的状态,则这种方法效果不佳。在这种情况下,您的方法应该在后台线程中开始工作,然后立即返回一个 ID,该 ID 可以在不同的 Web 方法中使用以查找状态。
所以类似于这样:
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提供回调协议,您可以使用它来开始单向操作并订阅通知,以便在完成该操作时接收到通知,从而消除了上面轮询的需要。
因此,总结所有内容如下:
  • 如果您不需要任何响应或状态更新,请使用IsOneWay = true
  • 如果您需要更新,并且服务端可以使用WCF,请使用带有回调协议的WCF。无论如何,您都应该在新的Web服务项目中使用WCF。
  • 如果您需要更新并且无法使用WCF,则在后台线程中执行工作,并使用额外的状态检查Web方法实现定期轮询系统。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接