我需要一个调用webmethod的控制台应用程序。
它必须是异步的,没有超时(我们不知道这个方法需要花多少时间来处理任务。
这是好方法:
[WebMethod]
[SoapDocumentMethod(OneWay = true)]
...
答案 0 :(得分:5)
如果您需要结果,请勿单向使用
首先,如果您需要来自方法的回复,则不需要[SoapDocumentMethod(OneWay = true)]
。此属性创建一个“fire and forget”调用,该调用永远不会将响应返回给caler并且必须返回void
。相反,使用常规方法调用并将其称为异步。
一种或两种方法?
如果您正在使用ASMX,则有两种基本解决方案:一种具有超长超时的方法,或两种方法(如@Aaronaught suggested above):一种启动操作并返回一个ID操作,另一个传入ID并检索结果(如果可用)。
就个人而言,在大多数情况下我不会推荐这种双方法,因为涉及额外的复杂性,包括:
Request
和Response
这样的ASP.NET内部对象是not available when called from a background task launched with ThreadPool.QueueUserWorkItem
. 确实,在某些情况下,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
因此,您可以考虑调整 根据你的这两个值 应用程序的场景。这里有一个 前线程也提到了这个:
请注意,我强烈建议您将超时时间设置为足以包含最长时间的操作(加上足够的缓冲区以便在事情变慢时保持安全)但我不建议完全关闭超时。由于错误的客户端或服务器可以永久禁用另一个,因此允许无限制超时通常是错误的编程习惯。相反,只是让超时很长 - 并确保记录客户端或服务器超时的实例,以便在问题发生时检测并诊断问题!
最后,回应上面的评论者:对于新代码,最好使用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方法实施定期轮询系统。