Muhammad Rehan Saeed
Muhammad Rehan Saeed

Reputation: 38497

Named Tag Helpers in ASP.NET 5 MVC 6

I have built two-dozen HTML helpers I am converting to tag helpers for ASP.NET 5 MVC 6 to generate Facebook Open Graph meta tags. Here is an example of the 'website' type:

Index.cshtml

<open-graph-website title="Page Title" 
                    main-image="new OpenGraphImage(
                        "~/img/open-graph-1200x630.png", 
                        "image/png", 
                        1200, 
                        630)"
                  determiner="Blank"
                  site-name="Site Title">

Each Open Graph object type has a special namespace which has to be added to the head tag e.g.

_Layout.cshtml

<html>
<head prefix="website: http://ogp.me/ns/website#">
</head>
<body>
    <!-- ...Omitted -->
</body>
</html>

I managed to do this using HTML Helpers in the past by using the ViewBag and the Namespace getter property on the OpenGraphWebsite class like so:

Index.cshtml

ViewBag.OpenGraph = new OpenGraphWebsite(
    "Page Title",
    new OpenGraphImage("/img/open-graph-1200x630.png", "image/png", 1200, 630)
    {
        Determiner = OpenGraphDeterminer.Blank,
        SiteName = "Site Title"
    };

_Layout.cshtml

<html>
<head @(ViewBag.OpenGraph == null ? null : ViewBag.OpenGraph.Namespace)>
    @Html.OpenGraph((OpenGraphMetadata)ViewBag.OpenGraph);
</head>
<body>
    <!-- ...Omitted -->
</body>
</html>

Is there a way to achieve a similar result with tag helpers? Some way of naming a tag helper or referring to it?

Upvotes: 0

Views: 822

Answers (2)

Muhammad Rehan Saeed
Muhammad Rehan Saeed

Reputation: 38497

This is the answer from the question I asked on GitHub. Note that this tag helper runs automatically because it only targets the head element.

[TargetElement("open-graph-website", Attributes = nameof(Title) + "," + nameof(MainImage), TagStructure = TagStructure.WithoutEndTag)]
public class OpenGraphWebsiteTagHelper : OpenGraphMetadataTagHelper // Inherits from TagHelper
{
    // ... Omitted
    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        context.Items[typeof(OpenGraphMetadata)] = this.GetNamespaces();
        output.Content.SetContent(this.ToString());
    }
}

[TargetElement("head")]
public class OpenGraphNamespacePrefixTagHelper : TagHelper
{
     private const string PrefixAttributeName = "prefix";

    public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        context.Items.Add(typeof(OpenGraphMetadata), null);

        await context.GetChildContentAsync();

        string namespaces = context.Items[typeof(OpenGraphMetadata)] as string;
        if (namespaces != null)
        {
            output.Attributes.Add(PrefixAttributeName, namespaces);
        }
    }
}

I am still going to experiment with adding a dummy required property. This would force users to opt-in to using the tag helper, rather than it running automatically just because they added the tag helper DLL. It would be nice if value-less attributes could be added to tag helpers to facilitate this feature for bool properties:

<head asp-open-graph-prefix>
Rather than:
<head asp-open-graph-prefix="true">

[TargetElement("head", Attributes = OpenGraphPrefixAttributeName)]
public class OpenGraphNamespacePrefixTagHelper : TagHelper
{
    private const string OpenGraphPrefixAttributeName = "asp-open-graph-prefix";

    [HtmlAttributeName(OpenGraphPrefixAttributeName)]
    public bool DUMMY { get; set; }

    // ..Omitted
}

Upvotes: 0

N. Taylor Mullen
N. Taylor Mullen

Reputation: 18301

Looks like this was discussed/answered in the corresponding GitHub issue.

Upvotes: 1

Related Questions