Reputation: 391
I am trying to implement an async Component in MVC 6 and I am struggling with it.
View Code:
@await Component.InvokeAsync("GetTextA")
@Component.Invoke("GetTextB")
Compnent A Code:
public class GetTextAViewComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync()
{
await Task.Delay(12000);
return View("Default","from code");
}
}
Component B Code:
public class GetTextBViewComponent : ViewComponent
{
public IViewComponentResult Invoke()
{
return View("Default");
}
}
It takes more than 12000 milliseconds to load the view. Which means the async component is loaded synchronously.
How do I make it load asynchronously so that all the contents in the view should load without waiting for the async component.
Upvotes: 1
Views: 2729
Reputation: 2024
In the following example you can see despite both the components have delay of 6 seconds each, it does NOT take 12 seconds to render the response. That proves, view components can be invoked asynchronously, which effectively saves the CPU clock cycle and makes it serve more simultaneous requests than ever before.
AViewComponent
public async Task<IViewComponentResult> InvokeAsync()
{
await Task.Delay(6000);
return View<string>("Hello World A!");
}
BViewComponent
public async Task<IViewComponentResult> InvokeAsync()
{
await Task.Delay(6000);
return View<string>("Hello World B!");
}
Views\Shared\Components\A\Default.cshtml
@model string
<h1>@Model</h1>
Views\Shared\Components\B\Default.cshtml
@model string
<h1>@Model</h1>
index.cshtml
@DateTime.Now
@{
var taskA = Component.InvokeAsync("A");
var taskB = Component.InvokeAsync("B");
taskA.Wait();
taskB.Wait();
}
@taskA.Result
@taskB.Result
@DateTime.Now
Output (See the time difference of 6 seconds)
6/14/2016 6:09:04 PM
Hello World A!
Hello World B!
6/14/2016 6:09:10 PM
Upvotes: 1
Reputation: 8862
If you want the view to render and have the async code run later you basically have to use Ajax. Running the component async means it doesn't block the thread and it can be reused by other requests.
Edit:
If you want to render the top of a page, and have the rest show up later you can use the new @Flush
feature. Add a call to @await FlushAsync()
before the long running task, and the top of the view will be flushed to the client. If you are using layouts it becomes a little more complex, follow this test for more examples:
Upvotes: 3