ViewComponents are not async

Jash picture Jash · Mar 16, 2016 · Viewed 10k times · Source

I am trying to use the ViewComponents.InvokeAsync() feature, but somehow this is not async at all. It is waiting for the component code to render. http://docs.asp.net/en/latest/mvc/views/view-components.html

My code is very much similar to the one explained in above example. I am using the layout page which comes when you create new application in MVC 6.

I thought that ViewComponent.InvokeAsync() method will render asynchronously with respect to the main page. But it does not. In order to achieve this, we need to use AJAX as explained here.

Answer

Shaun Luttin picture Shaun Luttin · Mar 16, 2016

Server Side Async is not Client Side Async

Server side async does not do partial page rendering in the web browser. The following code will block until GetItemsAsync returns.

public async Task<IViewComponentResult> InvokeAsync()
{
    var items = await GetItemsAsync();
    return View(items);
}

And this code will block until the itemsTask completes.

public async Task<IViewComponentResult> InvokeAsync()
{
    var itemsTask = GetItemsAsync(maxPriority, isDone);

    // We can do some other work here,
    // while the itemsTask is still running.

    var items = await itemsTask;
    return View(items);
}

Server side async lets us do additional work on the server while we wait for some other server side task to complete.

AJAX View Component

To partially render the page in the web browser, we need to use client side AJAX. In the following example, we use AJAX to call /Home/GetHelloWorld and render in in the body.

~/HelloWorldViewComponent.cs

public class HelloWorldViewComponent : ViewComponent
{
    public IViewComponentResult Invoke()
    {
        var model = new string[]
        {
            "Hello", "from", "the", "view", "component."  
        };

        return View("Default", model);
    }     
}

~/HomeController.cs

public class HomeController : Controller
{
    public IActionResult GetHelloWorld()
    {
        return ViewComponent("HelloWorld");
    }
}

~/Views/Shared/Components/HelloWorld/Default.cshtml

@model string[]

<ul>
    @foreach(var item in Model)
    {
        <li>@item</li>
    }
</ul>

~/wwwroot/index.html

<body>
<script src="js/jquery.min.js"></script>
<script>
    $.get("home/GetHelloWorld", function(data) {
        $("body").html(data);
    });
</script>
</body>

localhost:5000/index.html

A unordered list that shows the string array.