我正在编写一个MVC5应用程序,其控制器的函数为Method1
我有一个async Task
的第三方功能,让我们称之为DoMethodAsync
(它本质上是一个POST呼叫)。
我想在从Method1
返回之前调用它,但我并不真正关心异步任务的结果,如果失败,则失败。如何触发并忘记并让它在后台执行,以便它不会阻止控制器响应其他请求?
如何确保DoMethodAsync
仅在Method1
返回后执行?
答案 0 :(得分:10)
我真的不关心异步任务的结果,如果失败,它就会失败。
真的?只是问,因为这是一个非常罕见的用例。
如何触发并忘记并让它在后台执行,以便它不会阻止控制器响应其他请求?
我有一个blog post,可以查看各种方法来解雇和忘记" ASP.NET上的任务。
您不想要只调用该方法并忽略返回的任务,因为该方法将继承启动请求的请求上下文。然后在请求完成之后,处理请求上下文,并且该方法可以最终在有趣的"地方 - 有些东西会起作用,但有些东西不会。
因此,最小可行解决方案是将其包装在Task.Run
:
var _ignored = Task.Run(() => DoMethodAsync());
但请注意,ASP.NET完全没有意识到这个"额外的操作"。如果您希望DoMethodAsync
有更多机会实际执行完成,那么您将要使用HostingEnvironment.QueueBackgroundWorkItem
(4.5.2+)向ASP.NET运行时注册它或my own BackgroundTaskManager.Run
(4.5.0 / 4.5.1)。
另请注意,这些选项的 none 将保证DoMethodAsync
将完成运行;他们只是给你最好的努力。"对于真正可靠的系统,您需要一个适当的分布式架构,即具有独立处理器的可靠存储。
答案 1 :(得分:1)
我知道这很古老,但是经过数小时的搜索和尝试其他事情,我遇到了这个问题。将此处的一些信息与其他资源结合起来,我能够实现我想要的东西,我认为这与OP想要的东西一样。
我想调用/ API / Start之类的URL,并且希望该URL立即返回一个视图,该视图显示“感谢您启动,请稍后再回来查看”。但是,它只需要简单地启动后台工作即可。
这是与MVC 5一起使用的,因此不确定是否会有所作为,但是...
侧面注:要查看实际效果,请使用2个网址 /默认/索引<-将报告约5秒 / Default / IndexAsync <-会报告约0秒(有点..您会看到)
public class DefaultController : Controller
{
// GET: Sync
public ActionResult Index()
{
System.Diagnostics.Stopwatch myStopwatch = new System.Diagnostics.Stopwatch();
myStopwatch.Start();
DoTask();
myStopwatch.Stop();
ViewBag.Message = ($"Process took {myStopwatch.Elapsed.TotalSeconds.ToString()}");
return View("Index");
}
// GET: Async
public ActionResult IndexAsync()
{
System.Diagnostics.Stopwatch myStopwatch = new System.Diagnostics.Stopwatch();
myStopwatch.Start();
Task.Factory.StartNew(DoTaskAsync);
myStopwatch.Stop();
ViewBag.Message = ($"Process took {myStopwatch.Elapsed.TotalSeconds.ToString()}");
return View("Index");
}
// "the Sync Task"
private void DoTask()
{
System.Diagnostics.Debug.Print($"DoTask Started at {DateTime.Now.ToString()}");
System.Threading.Thread.Sleep(5000);
System.Diagnostics.Debug.Print($"DoTask Finished at {DateTime.Now.ToString()}");
}
// "the Async Task"
private async Task DoTaskAsync()
{
System.Diagnostics.Debug.Print($"DoTaskAsync Started at {DateTime.Now.ToString()}");
System.Threading.Thread.Sleep(5000);
System.Diagnostics.Debug.Print($"DoTaskAsync Finished at {DateTime.Now.ToString()}");
}
}
答案 2 :(得分:0)
调用异步方法意味着在异步方法执行时,不将阻止调用方法(您的代码),至少在默认情况下不会被阻止(您可以通过&#进行代码阻止) 39;等待关键字或通过调用任务的阻止方法之一,例如&#39;结果&#39;或等等...等。)。
这意味着如果您只是调用该方法,该方法将异步运行,您的代码将不会等待它结束。我认为这正是你想要的。
答案 3 :(得分:0)
public ActionResult Index()
{
DoMethodAsync(); // if you do not await and simple call this task it will run in backround as you want
return View();
}
async Task DoMethodAsync()
{
// calculate something
}