在异步任务完成之前返回

时间:2013-02-27 23:29:13

标签: c# asp.net-mvc-4 .net-4.5 async-await

我正在使用ASP.NET MVC 4 Web应用程序。我正在使用.NET 4.5,并且正在尝试利用新的异步API。

我有几种情况,我希望安排一个异步任务以便稍后运行,同时立即返回一个立即重要的值。例如,这是一个"登录"我希望尽快返回一个新的SessionID的方法,但是一旦我返回了SessionID,我想要清除过期的SessionID'

public async Task<Guid> LogIn(string UserName, string Password)
{
    //Asynchronously get ClientID from DB using UserName and Password

    Session NewSession = new Session()
    {
        ClientID = ClientID,
        TimeStamp = DateTime.Now
    };
    DB.Sessions.Add(NewSession);
    await DB.SaveChangesAsync();    //NewSession.ID is autopopulated by DB

    CleanSessions(ClientID);    //Async method which I want to execute later

    return NewSession.ID;
}

private async void CleanSessions(int ClientID)
{
    //Asynchronously get expired sessions from DB based on ClientID and mark them for removal
    await DB.SaveChangesAsync();
}

我尝试了很多不同的东西,包括Task.Run()和Parallel.Invoke()的组合,但是CleanSessions永远不会被调用。如何实现后台任务调度?

2 个答案:

答案 0 :(得分:14)

不建议在没有请求的情况下在ASP.NET中运行任务。 It's dangerous.

也就是说,将CleanSessions更改为Task,您可以这样做:

Task.Run(() => CleanSessions());

在你的情况下,我认为没关系,因为如果CleanSessions在执行过程中没有执行或被终止,那就没有长期问题(这可能发生在ASP.NET中,因为回收)。如果您想通知ASP.NET您有一些与请求无关的正在进行的工作,您可以使用BackgroundTaskManager from my blog,如下所示:

BackgroundTaskManager.Run(() => CleanSessions());

答案 1 :(得分:0)

如果,正如已经指出的那样,你试图做一些“火与忘记”,但在ASP.NET中 - 那么你可能想看看ConfigureAwait;您可以将其用作await的一部分,告诉它忽略同步上下文。将sync-context连接回ASP.NET执行管道是同步上下文,但如果没有必要,您可以避免它。例如:

public async Task<Guid> LogIn(string UserName, string Password)
{
    //Asynchronously get ClientID from DB using UserName and Password

    Session NewSession = new Session()
    {
        ClientID = ClientID,
        TimeStamp = DateTime.Now
    };
    DB.Sessions.Add(NewSession);
    await DB.SaveChangesAsync().ConfigureAwait(false);    //NewSession.ID is autopopulated by DB

    await CleanSessions(ClientID).ConfigureAwait(false);    //Async method which I want to execute later

    return NewSession.ID;
}
// simplified: no need for this to be full "async"
private Task CleanSessions(int ClientID)
{
    //Asynchronously get expired sessions from DB based on ClientID
    return DB.SaveChangesAsync();
}