A view component supplies reusable content inside a parent Razor view. Its C# class obtains the data and chooses what to render, so a sidebar or cart summary need not be added to every action’s view model. Unlike a controller action or Razor Page, a view component cannot receive an HTTP request directly; its output is included in the parent view. section 24.2 section 9.2.2
Deriving from ViewComponent supplies view-component behavior and access to context such as RouteData and ViewBag. A component can also be discovered by a class name ending in ViewComponent with an Invoke or InvokeAsync method, or by the ViewComponent attribute. Components can live anywhere in the project; Components is the conventional folder. section 24.3 section 8.1.3
To build one, keep the data work in C# and the markup in Razor:
- Inject a service through the component constructor. In Invoke, prepare the data and return View(data) to select the component’s default Razor view; a simple component can instead return a string. section 8.1.3 section 24.3
- Put the markup in Views/Shared/Components/<component name>/Default.cshtml. The navigation view uses category names to generate links; the cart view uses a Cart to show item count and total value. section 8.1.3 section 9.2.2
- Invoke the component from a parent view or shared layout with a vc element, such as <vc:navigation-menu />. The component’s result is inserted into that view’s output. section 8.1.3
Listing 8.8 Adding categories in the NavigationMenuViewComponent.cs file in the SportsStore/Components folder
using Microsoft.AspNetCore.Mvc;
using SportsStore.Models;
namespace SportsStore.Components {
public class NavigationMenuViewComponent : ViewComponent {
private IStoreRepository repository;
public NavigationMenuViewComponent(IStoreRepository repo) {
repository = repo;
}
public IViewComponentResult Invoke() {
return View(repository.Products
.Select(x => x.Category)
.Distinct()
.OrderBy(x => x));
}
}
}
The navigation component injects IStoreRepository, selects distinct ordered categories in Invoke, and passes them to its Razor view. section 8.1.3
The parent view can pass values into Invoke or InvokeAsync. For a themeName parameter, supply theme-name on the vc element, or pass an object with a matching property to Component.InvokeAsync. Supply every required parameter: omitting one can leave the component absent without an error message. A default parameter value provides a fallback. section 24.5.1
Highlight the active category
Read RouteData.Values["category"] in Invoke, put the value in ViewBag.SelectedCategory, then let Default.cshtml give the matching link a different CSS class. A unit test can supply a ViewComponentContext with route data and inspect the returned view data. section 8.1.3
Use InvokeAsync when the data comes from an asynchronous API. Return a Task; Razor waits for it before inserting the result. A page-size component demonstrates this with an HttpClient request and a Default.cshtml view. It is applied the same way as a synchronous component. section 24.5.2

