Mvc: Facility for rendering a partial template from a tag helper

Created on 5 Nov 2016  路  2Comments  路  Source: aspnet/Mvc

Proposal

When creating a custom TagHelper it would be convenient to be able to render an existing partial view programatically and capture the rendered result in a string or an HtmlContent object inside the TagHelper.Process method.

For example, consider the following hypothetical custom TagHelper

`   
    public class CustomTagHelper : TemplateRenderingTagHelper
    {

        [HtmlAttributeName("asp-for")]
        public ModelExpression DataModel { get; set; }

        public override Task Process(TagHelperContext context, TagHelperOutput output)
        {
            output.TagName = "div";
            var renderedContent = HtmlHelper.Partial("~/Views/Shared/path/to/Template.cshtml");
            output.Content.SetHtmlContent(renderedContent);
        }
    }`

This tag helper inherits from the hypothetical TemplateRenderingTagHelper abstract class, this class would look like this:

`public abstract TemplateRenderingTagHelper : TagHelper
{
      protected IHtmlHelper HtmlHelper { get; set; }
      public TemplateRenderingTagHelper()
      {
            //Get a IHtmlHelper instance
            HtmlHelper = BuildAnIHtmlHelper();
      }
}
 `

As you can see this class makes available the HtmlHelper property for its sub classes, the HtmlHelper.Partial (or PartialAsync) can then be used to generate a template.

Motivation

Even if it is possible to call @Html.RenderPartial directly from the view, it is cleaner to factor the rendering inside the TagHelper.Process method especially if the rendering requires some preprocessing.
Consider the following TagHelper.Process example:

`
...
[HtmlAttributeName("asp-for")]
public ModelExpression DataModel { get; set; }
...
public override Task Process(TagHelperContext context, TagHelperOutput output)
{
      // Preprocessing on the model
      var model = SomeProcessingOn(DataModel.Model);
      // Building a Custom ViewData Dictionary
      var ViewData = BuildCustomViewDataDictWithCustomizedMetadata();

      output.TagName = "div";
      var renderedContent = HtmlHelper.Partial("~/Views/Shared/path/to/Template.cshtml", model, ViewData)
      output.Content.SetHtmlContent(renderedContent);
}`

Most helpful comment

@MissaouiChedy ,
Actually, you can use an HtmlHelper from within a TagHelper also now, with no need for further features:

  1. Add an IHtmlHelperargument to the constructor of your TagHelper, say: IHtmlHelper html, so that a fresh Html instance is injected when your TagHelper is created.
  2. Store it in a private variable, say html. The injected TagHlper is "neutral", not specific for your View, so you have to "contextualize" it for the current View Viecontext as explained in the steps below
  3. Add a property:
        [HtmlAttributeNotBound]
        [ViewContext]
        public ViewContext ViewContext { get; set; }

It will be automatically bound to your View ViewContext

  1. In the TagHelper ProcessAsync method contextualize the HtmlHelper:
(html as IViewContextAware).Contextualize(ViewContext );

Done! Now you have a working HtmlHelper.

All 2 comments

@MissaouiChedy ,
Actually, you can use an HtmlHelper from within a TagHelper also now, with no need for further features:

  1. Add an IHtmlHelperargument to the constructor of your TagHelper, say: IHtmlHelper html, so that a fresh Html instance is injected when your TagHelper is created.
  2. Store it in a private variable, say html. The injected TagHlper is "neutral", not specific for your View, so you have to "contextualize" it for the current View Viecontext as explained in the steps below
  3. Add a property:
        [HtmlAttributeNotBound]
        [ViewContext]
        public ViewContext ViewContext { get; set; }

It will be automatically bound to your View ViewContext

  1. In the TagHelper ProcessAsync method contextualize the HtmlHelper:
(html as IViewContextAware).Contextualize(ViewContext );

Done! Now you have a working HtmlHelper.

@frankabbruzzese
Yes in fact it works.
I tried previously to get an IHtmlHelper by using dependency injection, but I got an exception whenever I called one of its methods.
It turned out that I missed the contextualization part.

Was this page helpful?
0 / 5 - 0 ratings