我目前正在运营一个电子商务网站。
因此,当用户结帐时,我有一个银行回拨页面...
但由于我必须在付款发生后执行冗长的任务(目前同步完成),因此用户必须等待很长时间才能将其重定向回我的网站。
我试图用thread.start创建一个后台线程,但问题是我松开了会话,这是不可理解的。
那么,基于这个描述,你将如何进行?你会去异步还是多线程?
如果你去Async,会怎么样?
所以我们有类似的东西:
public ActionResult CallBack()
{
if (AcceptPayment() == "OK")
{
LenghtyTask();
}
return RedirectToUrl("MyWebSite");
}
答案 0 :(得分:3)
首先,在ASP.NET站点中运行后台线程是一个很大的禁忌,因为您无法控制应用程序的生命周期。应用程序池可以关闭或回收,这意味着您丢失了数据。
您可以使用数据库来存储任务(并在作业进行时更新其状态),或者只是创建一个执行作业的Windows服务或类似服务。
由于您无法控制正在运行的作业,因此询问您是否应使用Async或线程是毫无意义的,因为它们都不会释放任何资源(即使您的应用程序运行得更快)。
只需选择您知道的那个并让HTTP请求完成即可。告诉用户该作业正在后台处理,让他刷新浏览器以查看其进展情况。另一种方法是使用Ajax或ASP.NET SignalR来检查后台进度。
答案 1 :(得分:0)
可能会像这样
public ActionResult CallBack()
{
if (AcceptPayment() == "OK")
{
// simply launches the task and moves on
Task.Run(LenghtyTask());
}
return RedirectToUrl("MyWebSite");
}
现在在您的页面上:RedirectToUrl(“MyWebSite”)
你必须设置像Tejs指出的ajax请求,它可以在任务完成时通知用户
public ActionResult IsTaskFinished()
{
// No clue where your transaction is, but your gonna need to know it to check it's state
return JSON(SomeClass.Current.IsTaskFinished(ContextBoundObject.Transaction.Id));
}
在实际启动ajax之前,您可能想在/ MyWebSite上调用SomeClass.Current.IsTaskFinished(ContextBoundObject.Transaction.Id)
..如果转换已经完成。
function isTaskFinished() {
$.post("/IsTaskFinished").always(function(data) {
if (!!data) {
setTimout(isTaskFinished, 3000);
}
else {
// yay i'm done, inform user !
}
});
}
当然,您必须考虑重试限制,错误处理等。
答案 2 :(得分:-1)
我会将冗长的操作放在队列中(MSMQ,RabbitMQ等),并让工作进程(最好是Windows服务器)将作业出列并执行那些冗长的操作。
就如何通知用户而言,有几种选择,但我的选择是实时更新,您可以将服务器推送到客户端浏览器。只需在应用程序上有一个SignalR端点,然后通过工作进程上的SignalR .NET客户端连接它。完成冗长的操作后,您可以通过SignalR端点通知连接的客户端。
无论你做什么,都要避免在ASP.NET下进行任何数据关键操作的后台操作,如@jgauffin指出的那样。原因如下:http://haacked.com/archive/2011/10/16/the-dangers-of-implementing-recurring-background-tasks-in-asp-net.aspx