Rad
Rad

Reputation: 391

Async Component not working in MVC 6

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

Answers (2)

Mukesh Bhojwani
Mukesh Bhojwani

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

Yishai Galatzer
Yishai Galatzer

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:

https://github.com/aspnet/Mvc/tree/9ea535027153094d547c2c001999b16a2598fbac/test/WebSites/RazorWebSite/Views/FlushPoint

Upvotes: 3

Related Questions