如何生成将运行完成并立即返回客户端的任务?

时间:2014-09-29 22:11:48

标签: c# asp.net-web-api task-parallel-library

所以我尝试使用HTTP 202代码创建服务器端异步的概念证明(服务器接受任务,立即返回端点进行轮询,然后创建/更新资源)

Rick Strahl has a description如何在普通的ASP.NET中执行此操作。该技术取决于能否Response.End然后继续执行代码。 Response对象似乎在Web API控制器的上下文中似乎不可用。

如果以下方法按计划运行,则不会阻止返回http 202,并且仍然保证数据库任务将运行完成。

//Insert or Update Asych. 
public Task<HttpResponseMessage> Post(bool asynch, [FromBody]DatedValue value) //Insert Value
{
    Guid key = Guid.NewGuid();

    //Want this to run to completion, even if response associated with parent thread is done.
    Task toWait = Task.Factory.StartNew(() =>
    {
        queue.Add(key, 0);
        DatedValue justCreated = Insert(value);
        queue[key] = justCreated.Id;
    });

    //Return address to resource just created.
    Task<HttpResponseMessage> sender = Task.Factory.StartNew(() =>
    {
        HttpResponseMessage message = Request.CreateResponse(HttpStatusCode.Accepted);
        message.Headers.Location = new Uri("/ValueQueue/" + key);
        return message;
    });

    Task.WaitAll((new[] { toWait, sender }));

    return sender;
}

1 个答案:

答案 0 :(得分:3)

Task.WaitAll阻止执行,并且在两个任务完成之前不会返回响应。如果您更改类似下面的代码,则应该能够在运行任务时返回响应。

public HttpResponseMessage Post(bool asynch, [FromBody]DatedValue value)
{
    Guid key = Guid.NewGuid();

    Task.Factory.StartNew(() =>
    {
        queue.Add(key, 0);
        DatedValue justCreated = Insert(value);
        queue[key] = justCreated.Id;
    });

    HttpResponseMessage message = Request.CreateResponse(HttpStatusCode.Accepted);
    message.Headers.Location = new Uri("/ValueQueue/" + key);
    return message;
}

但是,您应该意识到这样的方法存在问题。如果您在IIS上托管Web API,则您的工作进程可以在任务运行时回收。由于您已经返回了响应,因此就ASP.NET而言,它已经完成了它的工作。因此,如果出于某种原因,IIS决定回收工作进程,无论您的任务在执行方面的位置如何,它都会继续运行,因此您最终可能会损坏数据。

使用.NET 4.5.2,您可以使用QueueBackgroundWorkItem。阅读本文 - http://blogs.msdn.com/b/webdev/archive/2014/06/04/queuebackgroundworkitem-to-reliably-schedule-and-run-long-background-process-in-asp-net.aspx