13

MVC 6 introduces Tag Helpers as a better alternative to @Html.EditorFor. It is possible to create custom Editor Template. It's also possible to create a custom Tag Helper.

However, when creating the Tag Helper, the HTML needs to be created by C# code (using TagBuilder, etc.). For complex Tag Helpers it's not as convenient as using a Razor syntax.

Is there any way I'm missing that would allow me to create an custom Tag Helper from a Razor page?

1 Answer 1

15

The beauty of TagHelpers is that you can intermingle C# and Razor in many different ways. So lets say you have a custom Razor template such as:

CustomTagHelperTemplate.cshtml

@model User

<p>User name: @Model.Name</p>
<p>User id: @Model.Id</p>

And you have the model:

namespace WebApplication1
{
    public class User
    {
        public string Name { get; set; }
        public int Id { get; set; }
    }
}

And the TagHelper:

using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Microsoft.Framework.WebEncoders;

namespace WebApplication1
{
    public class UserTagHelper : TagHelper
    {
        private readonly HtmlHelper _htmlHelper;
        private readonly IHtmlEncoder _htmlEncoder;

        public UserTagHelper(IHtmlHelper htmlHelper, IHtmlEncoder htmlEncoder)
        {
            _htmlHelper = htmlHelper as HtmlHelper;
            _htmlEncoder = htmlEncoder;
        }

        [ViewContext]
        public ViewContext ViewContext
        {
            set
            {
                _htmlHelper.Contextualize(value);
            }
        }

        public string Name { get; set; }

        public int Id { get; set; }

        public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
        {
            output.TagName = null;
            output.SelfClosing = false;

            var partial = await _htmlHelper.PartialAsync(
                "CustomTagHelperTemplate",
                new User
                {
                    Name = Name,
                    Id = Id
                });

            var writer = new StringWriter();
            partial.WriteTo(writer, _htmlEncoder);

            output.Content.SetContent(writer.ToString());
        }
    }
}

You can then write the following page:

@addTagHelper "*, WebApplication1"

<user id="1234" name="John Doe" />

Which generates:

<p>User name: John Doe</p>
<p>User id: 1234</p>
Sign up to request clarification or add additional context in comments.

6 Comments

So HTML Helpers are not actually being deprecated, but rather are supplemented by Tag Helpers?
Couldn't have put it better myself! Yes :)
is it possible to provide the model (User) from my page, let's say the sub-model of my main model, rather than instantiating it in the ProcessAsync method in tag helper class?
This does not work in ASP.NET Core 1.1. I get an error in line where you say partial.WriteTo(writer, _htmlEncoder) because WriteTo expects System.Text.Encodings.Web.HtmlEncoder not Microsoft.Extensions.WebEncoders.IHTMLEncoder. If you comment that out and try to run it - you then get InvalidOperationException: Unable to resolve service for type 'Microsoft.Extensions.WebEncoders.IHtmlEncoder' while attempting to activate 'UserTagHelper'.
This reminds me of the ASP .NET Web Forms days, with the <asp: controls (like asp:TextBox etc) came into play, and you would read one thing in the HTML markup and then get something completely different in the HTML response stream. Bad vibes. Of course I could have it completely wrong.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.