我正在使用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永远不会被调用。如何实现后台任务调度?
答案 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();
}