为什么我们必须为每个操作方法调用await _userManager.GetUserAsync(User)?

问题描述:

说实话,我不明白基于asp.net-core的web应用程序是如何工作的。现在我正试图一点一点地弄清楚它是如何在幕后工作的。为什么我们必须为每个操作方法调用await _userManager.GetUserAsync(User)?

让我们考虑选择Individual User Account的默认模板。更确切地说,在ManageController类中如下所示。

namespace StackOverflow.Controllers 
{ 
    [Authorize] 
    [Route("[controller]/[action]")] 
    public class ManageController : Controller 
    { 
     // others are trimmed for the sake of simplicity 

     [HttpPost] 
     [ValidateAntiForgeryToken] 
     public async Task<IActionResult> EnableAuthenticator(EnableAuthenticatorViewModel model) 
     { 
      // .......... 

      var user = await _userManager.GetUserAsync(User); 
      // ........ 
     } 

     [HttpPost] 
     [ValidateAntiForgeryToken] 
     public async Task<IActionResult> ResetAuthenticator() 
     { 
      var user = await _userManager.GetUserAsync(User); 
      //....... 
     } 

     [HttpGet] 
     public async Task<IActionResult> GenerateRecoveryCodes() 
     { 
      var user = await _userManager.GetUserAsync(User); 
      // .......... 
     }   
} 

问题

声明

var user = await _userManager.GetUserAsync(User); 

几乎每个动作方法时发生。

为什么我们必须调用await _userManager.GetUserAsync(User)每个操作方法?为什么我们不把它作为一个类的财产?

为了使用类属性,您需要一个异步属性。这在C#中是不可能的 - 斯蒂芬·克莱瑞在这个主题here上进行了大量的细节。

这是一个有意义的设计决策,因为“异步属性”是一个矛盾。属性获取器应返回当前值;他们不应该开展后台操作。另外,“异步setter”背后的语义并不完全清楚。

虽然你可能块上的异步代码,它不建议。 Stephen Cleary还有另一篇文章here

但是,你不应该。因为当你阻止异步代码时,你首先放弃了异步代码的所有好处。只要阻塞线程,异步处理程序的增强可伸缩性就会失效。

+1

除了异步问题,还有其他原因吗?在我的思维模型中,一个asp.net web应用程序在许多用户之间共享,因此用户请求对应于一个操作方法调用,因此,全局定义的用户没有意义。这是对的吗? –

+1

'用户'分配到'GetUserAsync'是控制器的一个属性 - 对于每个单独的请求,都有一个控制器的新实例,因此它有自己的'User'。如果'GetUser'作为同步操作是一个选项,您可以根据需要使用属性来包装该呼叫。 –

+2

是的,一个HTTP请求通常映射到控制器的* new *实例上的一个'ActionMethod'调用。存储在控制器级别的任何“全局”状态将在请求之间丢失。因此,当你*可以*存储它时,将它作为局部变量存储在'ActionMethod'中是没有好处的。 –