DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Testing the Untestable and Other Anti-Patterns
  • The Anatomy of a Microservice, One Service, Multiple Servers
  • Understanding the Dependency Injection Lifecycle: Singleton, Scoped, and Transient With Detailed Examples
  • Secure Your Web Applications With Facial Authentication

Trending

  • AI Speaks for the World... But Whose Humanity Does It Learn From?
  • Orchestrating Microservices with Dapr: A Unified Approach
  • How to Ensure Cross-Time Zone Data Integrity and Consistency in Global Data Pipelines
  • Enhancing Business Decision-Making Through Advanced Data Visualization Techniques
  1. DZone
  2. Coding
  3. Languages
  4. View Component or Tag Helper?

View Component or Tag Helper?

View components and tag helpers are nice features of ASP.NET Core that allow us to encapsulate some UI logic and avoid repeating the same code in different views.

By 
Gunnar Peipman user avatar
Gunnar Peipman
·
May. 23, 19 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
11.6K Views

Join the DZone community and get the full member experience.

Join For Free

Suppose you are working on an ASP.NET Core web application. To avoid havingn the views and layouts grow massively, you plan to separate some parts of these to independent components. This way you don't repeat code you wrote once. You find view components and tag helpers, but which one should you use?

The Difference Between View Components and Tag Helpers

It's important to understand what is what before doing any work.

  • View components are like partial views with no model binding. View components have a backing component class with the InvokeAsync() method. They support dependency injection like controllers do. Similar to controllers, they support multiple views.
  • Tag helpers are classes that allow server-side code to participate in the rendering of HTML elements. The most famous tag helper is probablythe  anchor tag helper that makes it possible to create MVC links using the <a> tag. Tag helpers support dependency injection but there's no support for external views. All markup is produced in tag helper code.

View component or tag helper? If it's something small, related to just few tags and no customizations are needed, then it's a tag helper; otherwise, it's view component.

Example: Assembly Version Tag Helper

I recently built a simple assembly version tag helper that I can use in projects where I have to display a web application version in  thefooter of all pages. The implementation is simple — just write out the version and that's it.

[HtmlTargetElement("AssemblyVersion", TagStructure = TagStructure.NormalOrSelfClosing)]
public class AssemblyVersionTagHelper : TagHelper
{
    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        output.TagName = "";
        output.Content.Append(GetType().Assembly.GetName().Version.ToString());
    }
}

There's no point in going with a view component here, as there's no need for views.

Example: Pager View Component

A pager view component is a different beast and it comes with the need for custom markup. A pager may come with default markup but in different projects we may have different markup for a pager.

A tag helper doesn't have support for multiple views and wrapping markup inside C# code would be crazy. Just take a look at the following fragment of a view component view and think if you want to implement it in pure C# code.

<ul class="pagination">
    <li class="paginate_button page-item first" id="kt_table_1_first">
        <a tabindex="0" class="page-link" aria-controls="kt_table_1" href="@Html.Raw(urlTemplate + "1")">
            <i class="la la-angle-double-left"></i>
        </a>
    </li>
    <li class="paginate_button page-item previous" id="kt_table_1_previous">
        <a tabindex="0" class="page-link" aria-controls="kt_table_1" href="@Html.Raw(urlTemplate + (Model.CurrentPage-1))">
            <i class="la la-angle-left"></i>
        </a>
    </li>
    @for (var i = startIndex; i <= finishIndex; i++)
    {
        @if (i == Model.CurrentPage)
        {
            <li class="paginate_button page-item active">
                <a tabindex="0" class="page-link" aria-controls="kt_table_1" href="@Html.Raw(urlTemplate + i)">@i</a>
            </li>
        }
        else
        {
            <li class="paginate_button page-item ">
                <a tabindex="0" class="page-link" aria-controls="kt_table_1" href="@Html.Raw(urlTemplate + i)">@i</a>
            </li>
        }
    }
    <li class="paginate_button page-item next" id="kt_table_1_next">
        <a tabindex="0" class="page-link" aria-controls="kt_table_1" href="@Html.Raw(urlTemplate + (Math.Min(Model.CurrentPage + 1, Model.PageCount)))">
            <i class="la la-angle-right"></i>
        </a>
    </li>
    <li class="paginate_button page-item last" id="kt_table_1_last">
        <a tabindex="0" class="page-link" aria-controls="kt_table_1" href="@Html.Raw(urlTemplate + Model.PageCount)">
            <i class="la la-angle-double-right"></i>
        </a>
    </li>
</ul>

Of course we can come out with a base tag helper for pager, define protected virtual method to output markup, and create custom implementations based on it, but it's against the idea of why a tag helper was invented. Let's say it's anti-pattern.

Here is an example of a pager view component that supports custom views.

public class PagerViewComponent : ViewComponent
{
    public async Task<IViewComponentResult> InvokeAsync(PagedResultBase result, string viewName = "Default")
    {
        result.LinkTemplate = Url.Action(RouteData.Values["action"].ToString(), new { page = "{0}" });
 
        return await Task.FromResult(View(viewName, result));
    }
}

Compared to tag helpers, pager view components are easier to maintain as the view markup and view component code are separated.

Wrapping Up

View components and tag helpers are nice features of ASP.NET Core that allow us to encapsulate some UI logic and avoid repeating the same code in different views. We can use view components and tag helpers in shared projects and libraries. Tag helpers are for extending HTML elements with server-side logic. View components support custom views like controllers do and they are for cases when a component has more markup than just a few HTML tags.

Dependency injection Pager Web application ASP.NET Core IT Anti-pattern HTML Implementation Assembly (CLI)

Published at DZone with permission of Gunnar Peipman, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Testing the Untestable and Other Anti-Patterns
  • The Anatomy of a Microservice, One Service, Multiple Servers
  • Understanding the Dependency Injection Lifecycle: Singleton, Scoped, and Transient With Detailed Examples
  • Secure Your Web Applications With Facial Authentication

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!