C#异步Web服务

本文关键字:服务 Web 异步 | 更新日期: 2023-09-27 17:58:20

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

  • 是否可以进行不需要客户端在.NET Framework上的异步调用?(Begin/End框架似乎需要我返回.NET IASyncResult对象)如果是这样,该怎么做?完全明确的示例代码会非常有用
  • 因为web服务中没有状态保存,所以这个线程以后可以恢复吗?如果客户想要取消流程,这将是非常重要的

C#异步Web服务

好的,后退一秒钟。

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

理论上,你可以设置一个回调机制,但客户端需要有一种方法来获得答案,那就是为他们提供服务。这更复杂,本质上更少的"公共API",但它可以与客户端一起工作。

系统的异质性不应成为一个因素。而且,你可以建立这两种模式,这样拥有可以接受答案的网络服务的客户就可以解雇并忘记,而其他人则进行投票。

民意调查的一个缺点是,你会给自己的一方增加更多的权重,所以设定适当的期望值,并准备好阻止做这种事情的人:

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

如果您可以绕过异构环境(开放标准等),并且可以强制使用.NET,那么您还有其他选择,正如Craig所提到的。

这是一个很好的起点:

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方法,该方法在作业完成之前不会返回。

我们为此使用AppFabric工作流服务。

它们被公开为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应用程序。您可以直接从控制器方法执行长时间运行的异步进程。