Razor Pages has Components too don't you know!
March 2, 2021 · 4 minute read · Tags: razor pages
It’s become very fashionable to build web applications as a series of smaller components, which can be composed together to form a fully-featured UI.
In fact this is probably the single biggest shift when moving from Razor Pages or MVC to Blazor, where instead of thinking about views or pages, you’re free to create as many components as you like, and use them wherever you like.
Components can really speed up your web development. Once you get used to the idea of breaking complex UI down into smaller pieces it quickly becomes second nature.
But what about MVC and Razor Pages? What if you’re using those frameworks and want a piece of the component action?
View Components?
Turns out there is a handy (but oft overlooked) feature in ASP.NET Core called View Components.
Here’s an example which uses one View Component to show “Hello World” to three different people.
@page
<vc:greeting name="Boris"/>
@await Component.InvokeAsync("Greeting", new
{
name = "Jon"
})
@await Component.InvokeAsync("Greeting", new
{
name = "Steve"
})
We’ll come to why the first instance is different from the other two in a moment, but already we can see some advantages of this approach.
With our Greeting
component we have a re-usable piece of UI which we can call with different parameters from anywhere in our Razor Pages application.
Here’s the Greeting
View Component itself…
GreetingViewComponent.cs
using Microsoft.AspNetCore.Mvc;
namespace RazorPageExamples.Pages.Components.Greeting
{
public class GreetingViewComponent : ViewComponent
{
public GreetingViewComponent()
{
}
public IViewComponentResult Invoke(string name)
{
return View("Default", name);
}
}
}
We’re free to use Dependency Injection in a ViewComponent (for example to inject a service, or something like MediatR to handle retrieving data).
The Invoke
method will be, well… invoked, when the component is rendered.
We then return a view called Default
, passing a string name
as the model for that View.
Default.cshtml
@model string
<p>
Hello @Model
</p>
I have a ViewComponent and I’m not afraid to use it!
Finally, to render this component we can use a couple of approaches.
The first is to use Component.InvokeAsync
:
@await Component.InvokeAsync("Greeting", new
{
name = "Steve"
})
Where we pass the arguments (name
in this case) via an anonymous object as the second argument to InvokeAsync
.
But you might prefer a more declarative approach which you can achieve using the vc
tag helper…
<vc:greeting name="Boris"/>
Here we use the vc
tag helper, specify the component name and parameters using kebab case.
Components All The Way Down
As we move inexorably towards a web built on components, this feels like a handy way to step in that direction within your existing Razor Pages and MVC applications.
Here’s the source code for this example.
Just before you ride off into the sunset to replace all your pages with components, it’s worth noting you can render Blazor WASM Components in your existing applications, and in fact Blazor Server Components too.
Although broadly similar there are some key differences between using ViewComponents and Blazor Components in your applications so make sure to check out this excellent summary of the key differences by Andrew Lock.