假设我有一个类似下面的Action,我想尽快返回View并继续在后台线程中做一些工作。
public async Task<ActionResult> Index()
{
Debug.WriteLine("Inside Index");
var newCustomer = new Customer
{
Name = "Ibrahim"
};
Task.Run(() => SaveCustomer(newCustomer));
Debug.WriteLine("Exiting Index");
return View();
}
private async Task SaveCustomer(Customer NewCustomer)
{
Debug.WriteLine("Started Saving Customer");
await Task.Delay(2000);
Debug.WriteLine("Completed Saving Customer");
}
我确实得到了预期的输出:
Inside Index
Exiting Index
Started Saving Customer
Completed Saving Customer
但令我困扰的是,我收到警告,我的Index
操作将同步运行,我应该放置await
,但在SaveCustomer
完成后返回视图目的被打败了。
我怎么做错了?任何建议都表示赞赏。
答案 0 :(得分:2)
但令我困扰的是,我收到警告,我的Index动作将同步运行
我怎么做错了?
不要从上到下强制异步。相反,从最低级别的自然异步操作开始(例如,EF6数据库访问),并允许异步从最低级别的代码向上增长。
此外,在ASP.NET上,您应该强烈避免使用Task.Run
。
应用这两个原则会产生Index
这样的方法:
public async Task<ActionResult> Index()
{
Debug.WriteLine("Inside Index");
var newCustomer = new Customer
{
Name = "Ibrahim"
};
await SaveCustomer(newCustomer);
Debug.WriteLine("Exiting Index");
return View();
}
但是在SaveCustomer完成后返回视图并且目的被取消。
完全没有。异步ASP.NET代码的目的是 而不是 以尽早返回到客户端。 async
和await
不会更改HTTP协议。服务器端的await
产生线程池,而不是客户端。
如果您需要提前退货(并且大多数人不会 - 他们只是认为他们需要&#34;需要&#34;)应该使用one of the established patterns for returning early(正如我在博客中描述的那样)。请注意,唯一正确(即完全可靠)的解决方案需要使用独立的后台进程建立可靠的队列。
答案 1 :(得分:1)
您的Index
根本没有使用任何异步功能。你为什么标记它async
?你一定是误解了什么,不知道是什么。删除async Task
规范。
答案 2 :(得分:1)
您收到编译器警告,因为Index()
方法中没有任何异步。您的Task.Run(() => SaveCustomer(newCustomer));
行表示Fire和Forget(未等待的任务) - 这与异步代码非常不同。 Index()
完全同步,同时创建一个&#34; side Task&#34;在将来的某个时间执行。正如提到的另一个答案 - 您也可以从方法中删除异步标记 - 它不是异步。