0

I'm relatively new to .NET Core and trying to get my head around async/await usage to help speed up a slow-loading page.

My original controller method looked like this:

public IActionResult Index()
{
      //other code here

      regionVM.listEvents = getEvents(regionCatID);
      regionVM.listNews = getNews(regionCatID);
      regionVM.listLIA = getLIA(regionCatID);
      regionVM.listAwards = getAwards(regionCatID);

      return View("/Views/Regions/Index.cshtml", regionVM);
}

getEvents, getNews, getLIA, and getAwards are all other methods within the same controller. The corresponding lists they populate in the view model are used to display four different areas in the view. This all populates properly, but is slow.

I read a lot of different articles and posts, but tried to update my code following this one in particular: How can I run both of these methods 'at the same time' in .NET 4.5?

My new method looked like this:

public async Task<IActionResult> Index()
{
      //other code here

      var eTask = Task.Run(() => getEvents(regionCatID));
      var nTask = Task.Run(() => getNews(regionCatID));
      var lTask = Task.Run(() => getLIA(regionCatID));
      var aTask = Task.Run(() => getAwards(regionCatID));

      regionVM.listEvents = await eTask;
      regionVM.listNews = await nTask;
      regionVM.listLIA = await lTask;
      regionVM.listAwards = await aTask;

      return View("/Views/Regions/Index.cshtml", regionVM);
}

This seemed to work and compiled without any errors, but now when the regions pages load it's sort of hit or miss whether the four areas actually populate in the view. For instance, sometimes the news area will be blank, when I know there are news items that should be populated and were populating with the old synchronous method.

Is the view loading before the tasks are done executing? Or am I going about this completely the wrong way? Thanks for any suggestions.

user3562286
  • 151
  • 2
  • 13
  • you should include code for at least one of those methods. Someone can help you optimize your data calls. – pcalkins Jun 01 '22 at 23:01
  • 2
    .net 4.5 is old .net framework stuff. The advice in that thread is not relevant here. (MS's terminology is confusing but ASP.NET != .net4.x) You don't need threading so remove task.run() stuff. Your app pool/server will take care of threading. Async/Await is not threading but non-blocking calls to the thread(s). It's best to keep async all the way through, so make all those methods async too. If speed is an issue it's usually due to a large dataset being returned to the view... consider pagination if that's the case. – pcalkins Jun 01 '22 at 23:03
  • 1
    Per your description, I want to rasie another kind of idea that using Ajax query in your view to call your 4 methods separately. As you know Ajax query are async so you can write method to call them. It may make your website behaves like news part will be loaded first while Awards part may loaded at last, but all of them will be loaded finally except some exception happened, then the problematic part won't be loaded. And I agree with @pcalkins that "usually due to a large dataset being returned to the view" – Tiny Wang Jun 02 '22 at 03:08
  • And you may also have a look at [this document](https://learn.microsoft.com/en-us/aspnet/core/performance/performance-best-practices?view=aspnetcore-6.0)... – Tiny Wang Jun 02 '22 at 03:10
  • By the way, in asp.net core, we have async method and then we use await when calling async method. – Tiny Wang Jun 02 '22 at 05:40

1 Answers1

0

There are different ways to handle this, but firstly, I would make sure to understand async/await. Microsoft has great articles and videos on the topic.

Also, I have no idea what the methods you are calling (e.g. getEvents) look like so my answer is assuming they are true async methods.

I would avoid Task.Run within ASP.NET Core apps generally speaking. It only results in extra unnecessary Thread Pool scheduling.

    // Your new code can easily be rewritten as:
    public async Task<IActionResult> Index()
    {
          //other code here
          
          regionVM.listEvents = await getEvents(regionCatID);
          regionVM.listNews = await getNews(regionCatID);
          regionVM.listLIA = await getLIA(regionCatID);
          regionVM.listAwards = await getAwards(regionCatID);

          return View("/Views/Regions/Index.cshtml", regionVM);
    }

    // OR
    public async Task<IActionResult> Index()
    {
          //other code here
          
          var task1 = getEvents(regionCatID);
          var task2 = getNews(regionCatID);
          var task3 = getLIA(regionCatID);
          var task4 = getAwards(regionCatID);
       
          await Task.WhenAll(task1, task2, task3, task4);

          regionVM.listEvents = await task1;
          regionVM.listNews = await task2;
          regionVM.listLIA = await task3;
          regionVM.listAwards = await task4;

          return View("/Views/Regions/Index.cshtml", regionVM);
    }

Because the code in each of these examples is awaited, its guaranteed the when the regions page is rendered, the four areas will be populated because the line

return View("/Views/Regions/Index.cshtml", regionVM);

Is only executed once all the data has already been fetched.


There are others ways to also improve page performance if you want it to be rendered quickly. For example, I'm not sure how much data is actually being fetched in your controller action, however, instead of only loading the page when all the data is returned, you can use ajax calls to fetch all this data. This way, your controller 'Index' action wont fetch all the data and your page will render immediately, then you make ajax calls from your javascript code to get data for each area.

A common example for doing this is something like a Dashboard page.

Filipe
  • 163
  • 7