ViewComponents in ASP.NET 5 and ASP.NET MVC 6

Let’s have a quick look at another new feature in ASP.NET MVC 6, and that is the ViewComponent feature. View components are intended to be replacements to ChildActions and, to some extent, of partial views.

Traditionally in ASP.NET MVC (and in general in the textbook MVC pattern), you had to compose the entire model in the controller and pass it along to the view, which simply rendered the entire page based on the data from the model. The consequence of this is that the view does not need to explicitly ask for any data – as its sole purpose is to just act upon the model it received.

While this sounds very nice in theory, it has traditionally posed a number of practical difficulties. There are a number of reusable components on pretty much every website – think a menu, a shopping cart, lists of all kinds, breadcrumbs, metadata and so on – so things that appear on multiple pages.

Let’s have a look at how this is solved in MVC 6.

The reusable component problem

Having to compose and gather the data required to create these components in multiple controllers over and over can be really painful, and has often led developers to create a all kinds of model builders and inherited models (have you ever created a BaseModel containing things like menu or page metadata?).

One way to easy that pain was to try to use child actions – which were actions that could only be called from the view (not publicly by the client). I have seen plenty of MVC projects that used child actions to render such reusable components. Another alternative has always been to create elaborate HtmlHelpers. Unfortunately since the helpers were static, you couldn’t do dependency injection into them, so trying to load any extra data for the purpose of such helper, would require you to use service locator – the MVC global DependencyResolver.

View components are really a mesh of both HtmlHelper and child actions.

ViewComponents example

Consider the following sample service:

It’s not unreasonable to think that you might have code resembling something that in your projects. Imagine that we need to display a list of these promoted products in multiple places on the website.

Typically in MVC 5 and earlier, you would have a child action, an HtmlHelper or a base model builder to handle this. With view component you can simply add a view component class:

That class can use ASP.NET 5 dependency injection – which is very convenient. It can return something primitive like a JSON or a string, but it can also have its own partial view; in the above example the partial exists under /Views/Shared/Components/{componentname}/Default.cshtml. The Default.cshtml is the default convenion for all views of view component. You can also pass the name of the view returning i.e. return View(“_Products”, products)

In our case the Razor view would look like you would expect any partial view to look:

In order to embed this view component into a proper, main view, you use the Component property of the Razor pages – in the form of the following syntax:

There is also a sync version, if your component is synchronous. And that’s about it – a bit against the textbook MVC pattern, but very convenient and much cleaner than the old approaches or workarounds we had to use.

Some background info

In order for a class to be recognized as a view component, it needs to be:

  • public
  • non-abstract
  • non generic
  • end with ViewComponent suffix or be decorated with ViewComponentAttribute

As you can see, just like the rest of MVC 6, it heavily relies on conventions. To build a view component you do not need to inherit from any specific class or implement any interface.

As far as the actual functionality inside your view component, it is also defined by convention – it should be wrapped in one of the following methods (the method name and return type are important):

The default view component invoker (which could be changed if you wish) will first try to look for the async method, and if it’s not found, then it will try to fallback to the sync version. Afterwards, if it’s still not found, you’ll get a runtime error. This is important to note, because given the above mentioned requirements for a class to be considered a valid view component, it is still possible to get a runtime error if you misspell or misname the actual Invoke method.

Depending on what you need to do, there is a base class ViewComponent, which you can choose to inherit from for your own convenience. It will give you – through it’s expose properties – access to all contextual information about the view such as user principal information, current HttpContext, ViewData and all other information you typically would have inside a view. It will also allow you to easily attach a Razor view to the view component – which you can do by calling the base View() method when returning from your view component.

As far as discovery of view components goes, all assemblies that reference ASP.NET MVC packages will be considered valid to search. This is particularly important for developers of reusable, CMS-like components that are intended to be used cross-project. The discovery is controlled by a type called DefaultViewComponentDescriptorProvider, which allows you to extend itself with additional source to look at or provide different rules for the class to be recognized as view component.

Finally, it is also possible to pass data to the components. Then you add the relevant parameters to the signature, for example:

In order to invoke such a component from a view, you use an overload of the Component.InvokeAsync which takes param of object[]: