ViewComponent InvokeAsync方法和非异步操作

时间:2018-06-19 18:00:34

标签: asp.net-core async-await asp.net-core-mvc asp.net-core-2.0

在asp.net核心ViewComponent中,我们必须在返回InvokeAsync的{​​{1}}方法中实现逻辑。但是,我没有任何IViewComponentResult逻辑可以在invoke方法内执行。因此,基于SO post here,我删除了async限定词,只返回了async

Task.FromResult

然后在View中(由于我没有public Task<IViewComponentResult> InvokeAsync(MyBaseModel model) { var name = MyFactory.GetViewComponent(model.DocumentTypeID); return Task.FromResult<IViewComponentResult>(View(name, model)); } ,所以我不在这里使用async

await

但是视图呈现了这一点:

@Component.InvokeAsync("MyViewComponent", new { model = Model }) 1 [Microsoft.AspNetCore.Html.IHtmlContent]`

2 个答案:

答案 0 :(得分:2)

您必须await Component.InvokeAsync。您的方法不执行任何异步操作这一事实无关紧要。该方法本身是异步的。

但是,这有点过分简化了。坦率地说,async / await关键字的易用性掩盖了这一切实际上是多么复杂。准确地说,与其将这些类型的方法称为“异步”,不如将它们称为“任务返回”。任务本质上是某些操作的句柄。该操作可以是异步同步。它与异步关系最密切,只是因为在大多数情况下将同步操作包装在任务中是毫无意义的。但是,关键是仅仅因为某些东西必须返回任务并不意味着它必须是异步的。

所有异步所做的就是允许线程切换的可能性。在某些操作(通常涉及I / O)会导致工作线程空闲一段时间的情况下,该线程可用于其他工作,并且原始工作 在其他线程上完成。注意此处使用被动语言。异步操作可以不涉及线程切换。该任务可以在同一线程上完成,就好像它是同步的一样。如果基础操作已经完成,则该任务甚至可以立即完成。

在这里的情况下,您没有做任何异步工作,这很好。但是,方法定义要求使用Task<T>作为返回值,因此您必须使用Task.FromResult返回实际结果。这些都是非常标准的东西,似乎已经为您所理解。我想,您所缺少的是,您在考虑的是,由于您实际上并未在进行任何异步工作,因此使用await是错误的。 await关键字没有什么神奇之处;它基本上只是意味着一直待在这里直到任务完成。如果没有要完成的异步工作(例如此处的情况),则同步代码将正常运行,并在完成后返回到调用代码。不过,为方便起见,await还执行了另一个重要功能:它解开了任务。

这就是您的问题所在。由于您不等待,因此任务本身将返回到Razor视图处理管道中。它不知道该怎么做,因此默认情况下它会执行它的操作,并且仅在其上调用ToString,因此您将返回该文本。展开后,您只需要IViewComponentResult,而Razor 确实知道该怎么做。

答案 1 :(得分:1)

如果您在invoke方法内执行的逻辑是同步的,即您没有任何await,则有2个选项:

  1. 您可以定义不带async关键字的invoke方法,并且应该返回Task.FromResult<T>
  2. 改为使用public IViewComponentResult Invoke()

我认为async关键字启用了await关键字,这很重要。 async关键字没什么特别的。

由于标记帮助程序方法,在呈现视图的主线程上  要等待调用视图组件Component.InvokeAsync(),您确实需要在此处放置await关键字以启动任务。 await检查视图组件渲染以查看其是否已经完成。如果有,那么主线程将继续运行。否则,主线程将告诉ViewComponent运行。