2
votes

I created a new ASP.NET Core web application project, now for simplicity let's say its root namespace is MyWeb.Mvc which is also the assembly name specified in the project properties.

In the same web application project I created a folder titled TagHelpers and in it I added a class like this:

namespace MyWeb.Mvc.TagHelpers {
   public abstract class JsonLdBase : TagHelper
   {
      protected string addKeyValue(string key, string value, bool noClosing = true)
      {
         return string.Format("\"{0}\": \"{1}\"{2}{3}", key, value, noClosing ? "," : "", Environment.NewLine);
      }
    }

    public class JsonLdWebsiteTagHelper : JsonLdBase
    {
      public string Name { get; set; }
      public string Alt { get; set; }
      public string Url { get; set; }

      public override void Process(TagHelperContext context, TagHelperOutput output) {
          output.TagName = "script";
          output.TagMode = TagMode.StartTagAndEndTag;
          output.Attributes.SetAttribute("type", new HtmlString("application/ld+json"));
          output.Content.SetContent(
              "{" + Environment.NewLine +
              addKeyValue("@context", "http://schema.org") + 
              addKeyValue("@type", "WebSite") +
              addKeyValue("name", Name) + 
                addKeyValue("alternateName", Alt) +
                addKeyValue("url", Url) +
            "}"
          );
      }
    }

}

Then in the _ViewImports.cshtml I have this:

@using MyWeb.Mvc.TagHelpers
@addTagHelper MyWeb.Mvc.TagHelpers.*, MyWeb.Mvc

And in the _Layout.cshtml I use it like this:

<jsonldwebsite name="Panama Vibes" alt="Panama Vibes" url="PanamaVibes.com"/>

Given it was placed in _Layout.cshtml it should appear in all pages. But when I compile and run the web application and view the source of the main page I see the custom tag has been rendered as a normal HTML tag without TagHelper processing.

Now, originally I was thinking of using the json-ld NuGet package but I desisted when I saw it was not updated since 2016 and that the programmer had not taken the time to document how it can be used or given any examples whatsoever.

UPDATE #1 As suggested I explicitely set the TagMode property. However the whole output becomes HTML encoded and therefore does not pass the JSON+LD validation.

I now use HtmlString("application/json+ld") and the type entry is now properly rendered without encoding of the "+" sign. However, I tried using the same approach for the Content but there

4

4 Answers

2
votes

By default, the name of the tag in the razor page is json-ld-website:

<json-ld-website name="Panama Vibes" alt="Panama Vibes" url="PanamaVibes.com" />

You can customize the name by using the HtmlTargetElementAttribute:

[HtmlTargetElement("jsonldwebsite")]
public class JsonLdWebsiteTagHelper : JsonLdBase
{
    public string Name { get; set; }
    public string Alt { get; set; }
    public string Url { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        output.TagName = "script";
        output.TagMode = TagMode.StartTagAndEndTag;
        output.Attributes.SetAttribute("type", "application/ld+json");
        output.Content.SetContent(
            "{" + Environment.NewLine +
            addKeyValue("@context", "http://schema.org") +
            addKeyValue("@type", "WebSite") +
            addKeyValue("name", Name) +
              addKeyValue("alternateName", Alt) +
              addKeyValue("url", Url) +
          "}"
        );
    }
}

Also, you should are changing the name of the tag to script, which is not a self closed tag. This means you should use output.TagMode = TagMode.StartTagAndEndTag; to ensure there is a close tag. This way your sample will generate the following html:

<script type="application/ld&#x2B;json">{&#xD;&#xA;&quot;@context&quot;: &quot;http://schema.org&quot;,&#xD;&#xA;&quot;@type&quot;: &quot;WebSite&quot;,&#xD;&#xA;&quot;name&quot;: &quot;Panama Vibes&quot;,&#xD;&#xA;&quot;alternateName&quot;: &quot;Panama Vibes&quot;,&#xD;&#xA;&quot;url&quot;: &quot;PanamaVibes.com&quot;,&#xD;&#xA;}</script>

EDIT

All values are encoded by default (for security reasons). You can write Raw html using the SetHtmlContent method. For attribute values, you'll have to provide a custom IHtmlContent which doesn't encode the value. However, any valid html parser should unencode the attribute value.

public class JsonLdWebsiteTagHelper : JsonLdBase
{
    public string Name { get; set; }
    public string Alt { get; set; }
    public string Url { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        output.TagName = "script";
        output.TagMode = TagMode.StartTagAndEndTag;
        output.Attributes.Add(new TagHelperAttribute("type", new HtmlContent("application/ld+json")));
        output.Content.SetHtmlContent(
            "{" + Environment.NewLine +
            addKeyValue("@context", "http://schema.org") +
            addKeyValue("@type", "WebSite") +
            addKeyValue("name", Name) +
              addKeyValue("alternateName", Alt) +
              addKeyValue("url", Url) +
          "}"
        );
    }

    private class HtmlContent : IHtmlContent
    {
        private string _value;
        public HtmlContent(string value)
        {
            _value = value;
        }
        public void WriteTo(TextWriter writer, HtmlEncoder encoder)
        {
            writer.Write(_value);
        }
    }
}
0
votes

Have you tried the HtmlTargetElement attribute ?

[HtmlTargetElement("jsonldwebsite")]
0
votes

@Meziantou got me on the right direction by fixing the TagMode and the tag naming blooper.

The encoded output however was making the JSON+LD to fail validation because it was misformed due to the HTML encoding applied in SetContent. Here I had to do two things to resolve it:

  • in SetAttribute() I simply wrapped "application/json+ld" with new HtmlString() so that the plus sign was outputted as such rather than encoded.
  • For the content however the HtmlString() could not be used. But after some investigation I changed it to replace the SetContent() call with call(s) to output.Content.AppendHtml()

Now the tag is processed, it has an end tag and all the JSON+LD is properly formatted so that it passes the validation tool.

0
votes

For Microsoft.AspNetCore Version 2.0 or above

  • Custom tag helper in cs files on self-project

To include a custom tag helper from your projects 'TagHelper' folder Use below code in '_ViewImports.cshtml' file

@using MyProjectNameSpaceInWeb
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, MyProjectNameSpaceInWeb



  • import Custom tag helper from another project

By including the last line it will include all tag helpers in your main project

If you create tag helpers as another project first include the project in dependency list and use below code in '_ViewImports.cshtml' file

@using MyProjectNameSpaceInWeb
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, MyCustomTagHelperProjectNameSpace



  • import Built-in in tag helpers

To include a built-in tag helper in your projects 'TagHelper' folder Use below code in '_ViewImports.cshtml' file

@using MyProjectNameSpaceInWeb
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers