async
cshtml
web development
razor pages
performance optimization

Async loading inside cshtml page

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

When people ask about async loading inside a .cshtml page, they usually mean one of two things. They either want the server to fetch data asynchronously before rendering the page, or they want part of the page to load later in the browser without blocking the initial render.

Those are different problems, and the clean solution depends on which one you actually need. In ASP.NET Core, the important rule is that asynchronous work should usually happen in the controller, page model, or a view component, not deep inside the Razor markup itself.

Do Server-Side Async Before Rendering

If the page needs data before it can render, fetch that data asynchronously in the controller or page model. Then pass the completed model to the view.

csharp
1public class ProductsController : Controller
2{
3    private readonly AppDbContext db;
4
5    public ProductsController(AppDbContext db)
6    {
7        this.db = db;
8    }
9
10    public async Task<IActionResult> Index()
11    {
12        var products = await db.Products
13            .OrderBy(p => p.Name)
14            .ToListAsync();
15
16        return View(products);
17    }
18}

Then the .cshtml page stays simple and focused on display:

cshtml
1@model List<Product>
2
3<ul>
4@foreach (var product in Model)
5{
6    <li>@product.Name</li>
7}
8</ul>

This gives you the scalability benefits of asynchronous I/O without turning the Razor file into a place that mixes rendering and data access.

Load Part Of The Page Later With JavaScript

If you want the page shell to appear immediately and load one section later, use a separate endpoint and fetch it from the browser. That is true asynchronous loading from the user's perspective.

csharp
1public class DashboardController : Controller
2{
3    private readonly ReportService reports;
4
5    public DashboardController(ReportService reports)
6    {
7        this.reports = reports;
8    }
9
10    public IActionResult Index() => View();
11
12    public async Task<IActionResult> LatestSales()
13    {
14        var data = await reports.GetLatestSalesAsync();
15        return PartialView("_LatestSales", data);
16    }
17}
cshtml
1<div id="sales-panel">Loading...</div>
2
3<script>
4fetch('/Dashboard/LatestSales')
5  .then(response => response.text())
6  .then(html => {
7    document.getElementById('sales-panel').innerHTML = html;
8  });
9</script>

This pattern improves perceived performance because the initial page can render while the expensive section loads afterward.

Use View Components For Reusable Async Sections

If the async content is part of the server-rendered page and you want to keep the logic modular, a view component is a good fit. View components support async methods naturally and keep data loading out of the main view.

csharp
1public class CartSummaryViewComponent : ViewComponent
2{
3    private readonly CartService cartService;
4
5    public CartSummaryViewComponent(CartService cartService)
6    {
7        this.cartService = cartService;
8    }
9
10    public async Task<IViewComponentResult> InvokeAsync()
11    {
12        var summary = await cartService.GetSummaryAsync();
13        return View(summary);
14    }
15}
cshtml
@await Component.InvokeAsync("CartSummary")

That keeps the Razor page readable while still allowing asynchronous data retrieval for a reusable fragment.

Common Pitfalls

The biggest mistake is doing data access directly in the .cshtml file. That makes the view hard to test, hard to cache, and easy to break. Another common issue is assuming that async on the server automatically creates progressive loading in the browser. It does not. Server-side async frees threads while waiting on I/O, but the browser still receives the rendered response when the server sends it. If you want part of the page to appear later, you need a separate HTTP request from the browser or a streaming strategy. Developers also sometimes block async code with .Result or .Wait(), which defeats the purpose and can cause thread starvation or deadlocks in older patterns.

Summary

  • Put asynchronous data access in the controller, page model, or view component, not directly in Razor markup.
  • Use server-side async when the page must have the data before it renders.
  • Use JavaScript plus a separate endpoint when part of the page should load after the initial render.
  • View components are a clean way to render reusable async fragments.
  • Avoid blocking calls such as .Result and avoid mixing heavy data access with view templates.

Course illustration
Course illustration

All Rights Reserved.