C#.NET Web服务异步

我正在尝试使用Web服务实现一个执行一些非常冗长的任务的API。 我基本上希望Web服务启动执行冗长任务的线程,并使其保持运行直到完成。 问题是因为它是一个API,我希望它是跨平台的。 所以我的问题如下:

  • 是否可以进行不需要客户端在.NET Framework上的异步调用? (看起来初始/结束框架需要我返回.NET IASyncResult对象)如果是这样,怎么办呢? 完全明确的示例代码将非常有用。
  • 因为Web服务中没有状态保留,以后可以恢复该线程吗? 如果客户想要取消该过程,这将非常重要。

这是一个很好的起点:

http://msdn.microsoft.com/en-us/library/aa480516.aspx

如果您实现此模式,从客户端的角度来看,没有任何变化。 您可以实现第二个Web方法来检查在异步方法中排队的任何正在运行的作业的状态。

从示例代码中进行了一些修改,以便您了解需要执行的操作(我不希望这会编译):

[WebService] public class AsyncWebService : System.Web.Services.WebService { public delegate string LengthyProcedureAsyncStub( int milliseconds, MyState state); public string LengthyProcedure(int milliseconds, MyState state) { while(state.Abort == false) { //Do your work. Check periodically for an abort } return state.Abort ? "Aborted" : "Success"; } //This state object is what you can use to track invocations of your method //You'll need to store it in a thread safe container. Add it to the container in the Begin method and remove it in the end method. While it's in the container other web methods can find it and use it to monitor or stop the executing job. public class MyState { public Guid JobID = Guid.NewGuid(); public object previousState; public LengthyProcedureAsyncStub asyncStub; public bool Abort = false; } [ System.Web.Services.WebMethod ] public IAsyncResult BeginLengthyProcedure(int milliseconds, AsyncCallback cb, object s) { LengthyProcedureAsyncStub stub = new LengthyProcedureAsyncStub(LengthyProcedure); MyState ms = new MyState(); ms.previousState = s; ms.asyncStub = stub; //Add to service wide container return stub.BeginInvoke(milliseconds, cb, ms); } [ System.Web.Services.WebMethod ] public string EndLengthyProcedure(IAsyncResult call) { //Remove from service wide container MyState ms = (MyState)call.AsyncState; return ms.asyncStub.EndInvoke(call); } [WebMethod] public void StopJob(Guid jobID) { //Look for the job in the service wide container MyState state = GetStateFromServiceWideContainer(jobID); state.Abort = true; } } 

就客户而言,他们正在调用名为LenghtyProcedure的web方法,该方法在作业完成之前不会返回。

好的,备份一秒钟。

如果你希望人们能够打电话给asynch,那么他们就会控制你,你只需要回应。 如果你想在你身边完成异步工作,那么你需要建立一个不同的模式。 一种模式是设置调用工作的方法,然后设置另一种方法来查看工作状态。 第一种方法返回某种类型的令牌/ id,可用于检查另一个调用的状态。 然后,您有第三种方法来获取结果。 这都是客户驱动的。

理论上,您可以建立一个回调机制,但客户端需要有一种获得答案的方法,这是他们自己的服务。 这更复杂,本质上更少“公共API”,但它可以与客户合作。

系统的异质性不应该是一个因素。 并且,您可以建立这两种模式,因此拥有可以接受答案的Web服务的客户可以触发并忘记,而其他人则进行轮询。

轮询的一个缺点是你增加了更多的重量,所以设定适当的期望,并准备扼杀这样做的人:

 while(thread.NoComplete()) { pollTheCrapOutofService(); } 

如果你可以绕过异构环境(开放标准等),并且可以强制使用.NET,那么就像克雷格所提到的那样,你还有其他选择。

我们为此使用AppFabric Workflow服务。

它们作为WCF服务公开,因此任何可以进行SOAP调用的东西 – 或任何其他受支持的WCF传输 – 都可以调用它们。

免费提供持久性(如果您设置了SQL Server),监视和管理也是如此,并且自动生成.NET客户端。

一个潜在的缺点:您需要IIS 7+和.NET 4。

是否可以进行不需要客户端在.NET Framework上的异步调用? (看起来初始/结束框架需要我返回.NET IASyncResult对象)如果是这样,怎么办呢?

向您的客户公开REST API。 然后,您只需要一层代码,用于在.NET异步对象和REST服务之间进行转换。

因为Web服务中没有状态保留,以后可以恢复该线程吗?

您可以公开一个返回操作状态的REST方法,以及另一个取消异步操作的REST方法。

对于长时间运行的操作,我通常使用ThreadPool设置Windows服务。 您可以在那里公开您的IAsync API。

在IIS服务器上公开REST API的最简单方法是使用简单的ASP.NET MVC应用程序。 您可以直接从控制器方法执行长时间运行的异步进程。