- What are View Components?
- Constructing a View Component
- Using a View Component
- See Also
What are View Components?
Introduced with the advent of ASP.NET Core, View Components are a great tool for modularizing your MVC or Razor Pages site and empowering your Partial Views. A View Component is essentially a partial View with embeded business logic. If you prefer, you can think of them instead as a miniature Controller with a very specific purpose and associated partial View. Their versatility makes View Components a great addition to any MVC application, but they aren’t necessarily appropriate for every situation. If you’ve worked with MVC and partial Views before ASP.NET Core, View Components will seem familiar at best, or redundant at worst. They’re very simple in principle, and very powerful if leveraged appropriately.
Anatomy of a View Component
A View Component usually consists of two parts: a class which inherits from
ViewComponent and contains some kind of logic, and an associated partial View. The latter isn’t strictly required, but we will revisit that later in the article. Like a Partial View, View Components return a chunk of HTML, which is to say just its corresponding View.1 Like Controllers, they encapsulate potentially complex business logic, support constructor dependency injection, and are independently testable.
But View Components Aren’t Either
While these are convenient abstractions, there’s some critical differences:
- View Components are internal constructs which cannot be accessed by external requests directly. In other words, they cannot be reached by and do not handle HTTP requests.
- View Components do not participate in the Controller lifecycle. This means they cannot leverage the Filter pipeline2, nor do they use model binding.
- Rather than binding parameters from HTTP request values, View Component parameters are passed as an anonymous object during invocation.
What’s the point?
As with any other tool in your .NET Core arsenal, View Components are as useful as they are appropriate for the problem at hand. The name implies reusability and cohesion, and it’s best to think of a View Component as a module or widget that is part of one or more larger Views/Pages/Layouts within your ASP.NET Core project. Depending on your business requirements and design guidelines, your Views could be largely driven by multiple View Components which are fed parameters from the “parent” View’s View Model. With that in mind, View Components are most useful when you have chunks of a web page that require additional processing independent of the caller.
View Components supersede a simple Partial View, which usually has minimal or no logic, and even then only with respect to how the View Model is displayed. Developers can often run in to hang-ups when it comes to the
ViewDataDictionary and passing a View Model different than the parent View’s; this issue is sidestepped using a View Component. They also precede a full-blown dedicated Controller returning a Partial View, which has the same or greater capabilities; a Controller may be more overhead than necessary, or there may be no intention for the View Component to be accessible by external requests.
Whether or not it accepts input parameters from the calling View/Controller, a View Component should do something when invoked: whether that’s accessing another resource (such as a database or web API), validating inputs, or determining rendering logic and which Partial View should be returned. Be careful not to get overzealous about them, though: if a Partial View with some Razor markup is enough for your needs, stick with that. View Components do not replace any existing functionality, they bridge the gap between a pure Partial View and a Controller/View pair.
Constructing a View Component
The View Component Class
public class Sidebar : ViewComponent
public async Task IViewComponentResult InvokeAsync()
In this barebones example, our View Component
Sidebar derives from
ViewComponent and implements the required method
InvokeAsync() with no parameters, returning its Default View. However, as with most things in ASP.NET Core, there’s more than one correct way to create a working View Component.
They can also be defined by naming convention, applying “ViewComponent” as a suffix to the class name:
// I'm a View Component!
public class SidebarViewComponent
Or, by decoration:
// Me too!
public class Sidebar
By default, the ViewComponent’s name is the prefixed class name; the “ViewComponent” suffix is ignored. This can be overridden by setting the
ViewComponentAttribute.Name property of the base
I personally use a combination of the first two approaches
public class SidebarViewComponent : ViewComponent
While it may be redundant, it also makes class relationships abundantly obvious (at least to Future You), viz. a
Sidebar object class or View Model and a
SidebarViewComponent to dictate lookup/rendering. Ultimately, it’s down to preference and consistency; pick a format and stick with it!
The View() Method
This is really where View Components start to shine, but before we can dive into how
View() can be leveraged, we need to discuss what happens behind-the-scenes. One of the selling points for View Components is that the associated Partial View requires no special considerations; in fact, it isn’t even necessary. That said, for most use cases you’ll find
ViewComponent.View() sufficient. This is the bread-and-butter method for passing data or a View Model to a partial View from your View Component. If no view name is specified, this method returns a Partial View file named
Default.cshtml in a predefined directory.
When a ViewComponent is invoked and the
View() method returned, the following locations are checked for the Patial View, in order:
Simple, right? The last of these is recommended by Microsoft, and it makes sense: the first two locations are more specific, allowing the selected view to be overridden based on whether the component is called from a Razor Page or from a specific controller respectively.
In a Razor Pages only project, the “Pages/Components/” path is preferable to keep your project folder structure simple. To illustrate where this would be useful in an MVC or hybrid MVC/Razor Pages application, take our
- My Default view would be created in
- Suppose I need to adjust the layout on a particular page of my website that the component appears on, Catalog; perhaps I want it in a collapsed configuration to maximize horizontal space, and to remove some extraneous content.
- No problem, I just add my revised view to
Views/Catalog/Components/Default.cshtml, assuming the Controller for Catalog is also named
- If Catalog is instead a Razor Page, I can move my custom view to
Pages/Components/Default.cshtml, BUT this will apply to all Razor Pages calling the same component!
Like with our class naming, consider the project at hand and what makes the most sense to you and your team. However, there is another approach, which I prefer: using a named partial view (in this case
Mini.cshtml) and placing it in the recommended directory.
Now that we understand how
View() returns a partial View, we can take a closer look at how View Components utilize named Partial Views and View Models. The method has several overloads, accepting two optional parameters,
- As the parameter name implies,
viewNameallows you to change the targeted view from
Defaultto a specified file name; the file extension
.cshtmlis unnecessary in most cases.
- If only a view name is provided, the default paths are searched for it; if a full path is provided, it will be used exclusively.
viewNameis unspecified or null,
Defaultis used instead.
- The generic
modelparameter accepts an object to be passed to the invoked partial View; typically this should match the
modelof the partial View. If none is specified, the View’s model will be
The Content() Method
In some cases, you may not need or have a partial view to return from your View Component. Some examples include, but are not limited to:
- Returning HTML from an external source, such as a database, file, or web API.
- Returning a string response, where a separate View file and/or View Model is unnecessary overhead.
- Conditionally returning a default response, such as unauthorized access or invalid input parameters.
- Conditionally returning an empty response without dealing with a
nullView Model in the partial view.
In these cases, the View Component can return a
ContentViewComponentResult using the
Content() method, which will HTML encode any string passed to it. This can be sufficient when combined with database lookups, string interpolation, and other means of constructing meaningful return values without requiring the additional complexity of a dedicated View, such as a Message of the Day, or a user message if a particular Component is unavailable.
Using a View Component
Continue to Using a View Component
By default, a View Component’s
Layoutis null. Consequently,
sectionblocks will never be rendered, nor throw exceptions. While this can be overridden, it’s outside of the scope of this post. It will be covered more in-depth in a future submission. ↩
OnActionExecuted(). As will be covered later in this series, it is still possible to leverage some filters. ↩