View Components with ASP.NET Core 1.1

View Components allow creating functionality similar to a controller action method independent to a controller. Thus, view components can be used from different controllers, and they can also be created in a library, and used from multiple Web applications. Thus, view components can be used for a login panel, a shopping cart, a tag cloud – just anything you want to use across multiple controllers, and maybe also across multiple web applications.

This article shows how you can create and use view components. View Components are new with ASP.NET MVC Core 1.0, and got a new feature with version 1.1 in that they can be used with tag helpers.

Look at

Creating the View Component

A view component can be created in a library. With the sample application, I’ve created a .NET Core library. For view components, the NuGet package Microsoft.AspNetCore.Mvc.ViewFeatures need to be added:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp1.0</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Mvc.ViewFeatures" Version="1.1.1" >
  </ItemGroup>
</Project>

The sample view component shows a list of books based on a publisher. For this, the immutable Book class is defined with properties BookId, Title, and Publisher:

    public class Book
    {
        public Book(int bookId, string title, string publisher)
        {
            BookId = bookId;
            Title = title;
            Publisher = publisher;
        }
        public int BookId { get; }
        public string Title { get; }
        public string Publisher { get; }
        public override string ToString() => Title;
    }

The view component makes use of dependency injection. The contract that is used by the view component is defined by the interface IBooksService:

    public interface IBooksService
    {
        Task<IEnumerable<Book>> GetBooksAsync();
    }

A view component needs to derive from the base class ViewComponent. Using the attribute ViewComponent, a name can be assigned to the view component. This is the name the view components can be referenced. Without this attribute, the class name is used to reference the view component. With the constructor of the BooksViewComponent class, the previously created IBooksService interface needs to be injected. The heart of the view component is the InvokeAsync method. A view component can either define a synchronous method Invoke, or the asynchronous variant InvokeAsync. With the parameters, just define the parameters you need. The type and number of parameters is not fixed. With the sample code, a parameter of type string is used to return books only from the publisher passed. The return type of the method needs to be IViewComponentResult. The View method of the base class returns ViewViewComponentResult which in turn implements IViewComponentResult. The View method is very similar to the View method in the controller as overloads are available where you can pass the name of a view, and/or the model. With the sample code just the model is assigned, and the default view will be chosen:

    [ViewComponent(Name = &quot;BooksList&quot;)]
    public class BooksViewComponent : ViewComponent
    {
        private readonly IBooksService _booksService;

        public BooksViewComponent(IBooksService booksService) =&gt;
            _booksService = booksService;

        // InvokeAsync
        public async Task<IViewComponentResult> InvokeAsync(string publisher)
        {
            var books = await _booksService.GetBooksAsync();
            return View(books.Where(b => b.Publisher == publisher));
        }
    }

A view component implements the synchronous method Invoke or the asynchronous method InvokeAsync. With the parameters you can define the parameters you need.

Implementing the Service

The service that is used by the view component is implemented in the class BooksSampleService:

    public class BooksSampleService : IBooksService
    {
        private List<Book> _books = new List<Book>
        {
            new Book(1, "Professional C# 6 and .NET Core 1.0", "Wrox Press"),
            new Book(2, "Professional C# 5.0 and .NET 4.5.1", "Wrox Press"),
            new Book(3, "Enterprise Services with the .NET Framework", "Addison Wesley")
        };

        public Task<IEnumerable<Book>> GetBooksAsync() => 
            Task.FromResult<IEnumerabl<Book>>(_books);
    }

With the Startup class, the service is registered with the DI container:

        public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddMvc();
            services.AddSingleton<IBooksService, BooksSampleService>();
        }

Creating a view for the View Component

The view component is independent of the controller, so it’s best to define the view shared. This requires a specific directory structure. With the view component named BooksList, the directory for the view is Views\Shared\Components\BooksList. The default view has the file name Default.cshtml. With the sample code, just an unordered list containing the book titles is created:

@using ComponentsLibrary.Models
@model IEnumerable<Book>;

<h2>Books View Component</h2>

<ul>
    @foreach (var book in Model)
    {
        <li>@book.Title</li>
    }
</ul>

Using the View Component from the Controller

Now it’s possible to use the view component directly from the controller. In the HomeController, the method Books1 invokes the method ViewComponent which is defined as virtual method in the Controller base class. This method is overloaded, so you can pass the name or type of the view component and the parameters as an object:

        public IActionResult Books1() =>
            ViewComponent("BooksList", "Wrox Press");

The method ViewComponent defines an object parameter where you can pass the values to the InvokeAsync method of the view component. If you have multiple parameters, you can pass these using an anonymous object where the property names match the parameter names:

        public IActionResult Books1a() =>
            ViewComponent("BooksList", new { publisher = "Wrox Press" });

Opening the view, the result from the view component is shown:

View Component with Controller

Using the View Component from a View

You can invoke the view component from a view – which likely is more used than invoking it from the controller. With the Home controller, the method Books2 returns a default view:

        public IActionResult Books2() => View();

In the view Books2.cshtml, the view component is invoked using the InvokeAsync method. Component is a property of the page that returns an object IViewComponentHelper. With the IViewComponentHelper, overloaded versions of the InvokeAsync method are defined to pass the view component as type or with the name:

<h2>Books 2</h2>

@await Component.InvokeAsync("BooksList", new { publisher = "Wrox Press" })

The result now shows the view with the shared layout and the view component:

View Component with Component.InvokeAsync

Using a Tag Helper for the View Component

New with ASP.NET Core 1.1 is the option to invoke the view component with a tag helper. To enable tag helpers, the namespace of the view component needs to be added with @addTagHelper directive:

@using ViewComponentsSample
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, ComponentsLibrary

With this in place, the view-component can be written using the vc prefix and the name of the view component. The view component name changes with the tag helper: uppercase letters change to lowercase with an . Parameters can be written using simple HTML attributes:

<h2>Books 3</h2>

<vc:books-list publisher="Wrox Press" />

<hr />
<vc:books-list publisher="Addison Wesley" />

This is the result running the application and showing both Wrox Press and Addison Wesley books:

View Component with Tag Helper

Using ASP.NET Core 1.1, view components can be used with tag helpers

Summary

View components belong to the ASP.NET MVC Core extension that didn’t exist with previous ASP.NET MVC versions. They allow creating functionality independent of the controller, and a shared view. The ASP.NET Core 1.1 functionality with tag helpers for view components offer a nice use.

Sample Code

The sample code is available at GitHub.

To run the sample code you need Visual Studio 2017.

Have fun with programming and learning!
Christian

More Information

More information about ASP.NET Core is available in my new book and my workshops:

Professional C# 6 and .NET Core 1.0

Christian Nagel’s Workshops

Image from © Wavebreakmedia Ltd | Dreamstime.com Green and yellow eye on blue face

5 thoughts on “View Components with ASP.NET Core 1.1

  1. An error occurred during the compilation of a resource required to process this request. Please review the following specific error details and modify your source code appropriately.

    /Views/_ViewImports.cshtml

    Cannot resolve TagHelper containing assembly ‘MyAssembly.MyComponentNamespace. Error: Could not load file or assembly ‘MyAssembly.MyComponentNamespace’ or one of its dependencies. The system cannot find the file specified.

    @using MyAssembly
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    @addTagHelper *, MyAssembly.MyComponentNamespace

    It seems, @addTagHelper accepts an assembly and not a namespace. So my view components cannot be used as tag helpers.

    Like

  2. Your example doesn’t show any difference between View Component and Partial View. So what’s the point? If you’re boring to write Partial Views you can try View Components???

    Like

  3. Pingback: .NET Blog

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.