We use cookies to provide you with a great user experience, analyze traffic and serve targeted promotions.   Learn More   Accept
Card image cap

Exploring ASP.NET Core Fundamentals - Understanding ViewComponents

ASP.NET Core  • Posted one month ago

In a typical Model-View-Controller template, we have a View which is bound to a Controller endpoint with the Model being the bridge for passing data in between the Controller and the View. In contrast, a ViewComponent works as an individual entity with its own encapsulated responsibility and a View to bind the model data. It is much more powerful, runs independently without being dependent on a Controller endpoint or a Route and is invoked by the Layout rather than the view itself. You can assume a ViewComponent like a HTML Tag that serves a purpose within a HTML document with a user defined business logic and view logic, and which can be reused as many times as required.

In real-world scenarios, a ViewComponent can be used for the following use-cases:

  • Dynamic navigation menus
  • Tags (where it queries the database)
  • Login panel
  • Cart widgets
  • Recently published articles
  • Sidebar content on a blog
  • A login panel which can be rendered on every page and show either the links to log out or log in, depending on the log in state of the user

Developing a ViewComponent:

A ViewComponent is typically a C# Class which:

  1. Extends Microsoft.AspNetCore.Mvc.ViewComponent base class
  2. Comes with an optional constructor and an InvokeAsync() method that receives parameters
  3. Returns an IViewComponentResult which contains the model data to be bound on its View Partial.

"The parameters which are defined in the InvokeAsync() method must exactly match the attributes specified while calling the ViewComponent tag in the View Layout. If the attributes and the parameters don't match, then the ViewComponent shall not be invoked."

A ViewComponent is created by the following ways:

  1. By deriving any class from the ViewComponent class (extending the class using inheritance)
  2. By decorating any class using the ViewComponent Attribute
  3. By naming any class such that the name ends with ViewComponent (eg. MyViewComponent)
  4. By applying all the above

The constructor of the ViewComponent can be used to inject any dependencies which need to be used within the ViewComponent class. Since the ViewComponents run independent of the Controller, We can't apply ActionFilters on a ViewComponent.

The Invoke method:

The Invoke() or InvokeAsync() method contains the business logic through which the resultant model is generated, which is then applied onto the View. When a ViewComponent is called, the constructor is executed like as in all other classes followed by the Invoke (or the asynchronous InvokeAsync) method call. It is fired when the ViewComponent is executed for rendering by the layout.

The Invoke method can be a parameter less method or takes the parameters which are passed to the ViewComponent as attributes. The Invoke method can contain all the processing logic and returns an IViewComponentResult (or the asynchronous Task) response.

A ViewComponent possesses a view for itself which is rendered in the layout when called. The aspnetcore runtime looks for the views under the following directories:

  • /Views/Shared/Components/{ViewComponentName}/{ViewName}
  • /Views/{Controller Name}/Components/{ViewComponentName}/{ViewName}
  • /Pages/Shared/Components/{ViewComponentName}/{ViewName}

If no view name is passed from the Invoke method, the control searches for Default.cshtml in the above locations.

Example:


#ViewComponent class#

public class MyModel 
{
    public string MyText {get; set;}
}

public class MyViewComponent : ViewComponent 
{
    IConfiguration configuration;

    public MyViewComponent(IConfiguration configuration) 
    {
      this.configuration = configuration;
    }
    public IViewComponentResult Invoke(string myText) 
    {
      var myModel = new MyModel { MyText = myText };
        return View(myModel)	
    }
}

#Default.cshtml#

@model MyModel
<span>@Model.MyText</span>

Invoking a ViewComponent:

A ViewComponent can be invoked in two ways:

  1. Component.InvokeAsync() method
  2. Using a TagHelper

Razor approach:

Within a Layout file, we can embed a ViewComponent directly by calling the below method at the required place using the razor syntax.

@await Component.InvokeAsync("My", new { myText = "Hello World"})

Tag approach:

The easier approach is by embedding the ViewComponent as a HTML tag in the format <vc:VIEWCOMPONENTNAME attrName="attrValue"></vc:VIEWCOMPONENTNAME>

For the tag helper approach to work, the prerequisite is to register the assembly containing the view component using the @addTagHelper directive under the ViewImports.cshtml file.

#ViewImports.cshtml#

@addTagHelper *, MyWebApp

For Example, the ViewComponent "Hello" can be embedded in a Layout file as if adding a HTML tag as below:

#Some View#

<vc:hello my-text="hello world"></vc:hello>

Where the corresponding ViewComponent class shall be as:


public class HelloViewComponent : ViewComponent 
{
    IConfiguration configuration;

    public HelloViewComponent(IConfiguration configuration) 
    {
        this.configuration = configuration;
    }

    public IViewComponentResult Invoke(string myText) 
    {
        var myModel = new MyModel { MyText = myText };
        return View(myModel)	
    }
}

Observe that the attribute names MUST match the parameters of the Invoke() method. During execution, the aspnetcore looks for a ViewComponent that matches with the Tag with the parameters.

"If there are any changes in the ViewComponent definition, one can just do a PROJECT BUILD for the Tag registry to update the ViewComponent tags"

Limitations of ViewComponents:

Like all features, ViewComponents too have a few shortcomings like:

  • ViewComponents are strictly view renderers, and hence we can POST data to any method in it. Instead we can make use of a Controller endpoint to POST data from a ViewComponent View.
  • ViewComponents can't hold section blocks like Scripts etc., with in the View.

Summary:

  • ViewComponents can be defined as an extension of a Partial View, with much more capabilities. They work outside of a Controller's boundary and are invoked by the Layout.
  • A ViewComponent can be created by decorating a class with ViewComponent attribute, or by extending the ViewComponent class or by naming the class ending with ViewComponent or all the three.
  • It typically contains a constructor which can be used for injecting dependencies, and an Invoke method with parameters which turn out as the attributes of the tag.
  • They can be invoked in a view using the typical InvokeAsync method or by using a Tag Helper.
  • A general application of ViewComponents include a PostList block or a Login panel which runs independent and asynchronous of the remaining page.
  • A ViewComponent cannot hold a controller endpoint, but can post data to another controller using a form submit.