1

I am using TagBuilder to return HTML, what's happening is the HTML is rendering as text, this is part of the code:

private string RenderAlert()
{
    //<div class="alert-box">
    var wrapper = new TagBuilder("div");
    //merge attributes
    wrapper.MergeAttributes(htmlAttributes != null ? HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes) : null);

    if (alertStyle != AlertStyle.Default)
        wrapper.AddCssClass(alertStyle.ToString().ToLower());
    wrapper.AddCssClass("alert-box");


    //build html
    wrapper.InnerHtml.AppendHtml(text);

    //Add close button
    if (!hideCloseButton)
        wrapper.InnerHtml.AppendHtml(RenderCloseButton());


    var stringWriter = new System.IO.StringWriter();
    wrapper.WriteTo(stringWriter, HtmlEncoder.Default);
    var tagBuilderIsFinallyAStringNow = stringWriter.ToString();

    return tagBuilderIsFinallyAStringNow;
}

private static string RenderCloseButton()
{
    //<a href="" class="close">x</a>
    var closeButton = new TagBuilder("a");
    closeButton.AddCssClass("close");
    closeButton.Attributes.Add("href", "");
    closeButton.InnerHtml.AppendHtml("x");

    var stringWriter = new System.IO.StringWriter();
    closeButton.WriteTo(stringWriter, HtmlEncoder.Default);
    var tagBuilderIsFinallyAStringNow = stringWriter.ToString();

    return tagBuilderIsFinallyAStringNow;
}

public override string ToString()
{
    return RenderAlert(); <-- this is where the html finally gets rendered
}

This is the HTML page:

@using MyHelpers;
@{
    ViewBag.Title = "Alert Box Examples";
}

<h2>@ViewBag.Title</h2>

<h3>The markup</h3>

<div class="alert-box">
    This is a standard alert (div.alert-box).
    <a href="" class="close">×</a>
</div>

<div class="alert-box success">
    This is a success alert (div.alert-box.success).
    <a href="" class="close">×</a>
</div>

<div class="alert-box warning">
    This is an warning (div.alert-box.warning).
    <a href="" class="close">×</a>
</div>

<div class="alert-box info">
    This is a info alert (div.alert-box.info).
    <a href="" class="close">×</a>
</div>

<h3>Fluent API</h3>
<span>Html.Alert("Message")</span>
@Html.Alert("Message")

<span>Html.Alert("Message").Success()</span>
@Html.Alert("Message").Success()

<span>Html.Alert("Message").Warning()</span>
@Html.Alert("Message").Warning()

<span>Html.Alert("Message").Info()</span>
@Html.Alert("Message").Info()

<span>Html.Alert("No close button").Info().HideCloseButton().Attributes(new { data_special = "SpecialAttribute" })</span>
@Html.Alert("No close button").Info().HideCloseButton().Attributes(new { data_special = "SpecialAttribute" })

<h4>Standard API</h4>

<span>Html.Alert("Another message", hideCloseButton:true)</span>
@Html.Alert("Another message", hideCloseButton: true)

@section scripts
{
    <script>
        //On Page Load
        (function ($) {
            $(function () {
                //Attach plugins
                //Alerts plugin
                $(document).foundationAlerts();
            });
        })(jQuery);
    </script>
}

enter image description here

But I do not get the raw HTML, instead, the text gets rendered:

Alert Box Examples
The markup
This is a standard alert (div.alert-box).×
This is a success alert (div.alert-box.success).×
This is an warning (div.alert-box.warning).×
This is a info alert (div.alert-box.info).×
Fluent API
Html.Alert("Message") <div class="alert-box">Message<a class="close" href="">x</a></div> Html.Alert("Message").Success() <div class="success alert-box">Message<a class="close" href="">x</a></div> Html.Alert("Message").Warning() <div class="warning alert-box">Message<a class="close" href="">x</a></div> Html.Alert("Message").Info() <div class="info alert-box">Message<a class="close" href="">x</a></div> Html.Alert("No close button").Info().HideCloseButton().Attributes(new { data_special = "SpecialAttribute" }) <div class="info alert-box" data-special="SpecialAttribute">No close button</div>
Standard API
Html.Alert("Another message", hideCloseButton:true) <div class="alert-box">Another message</div>
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using System.Text.Encodings.Web;

namespace MyHelpers
{
    public class AlertBox : IAlertBox
    {
        private readonly string text;

        private AlertStyle alertStyle;

        private bool hideCloseButton;

        private object htmlAttributes;

        /// <summary>
        /// Returns a div alert box element with the options specified
        /// </summary>
        /// <param name="text">Sets the text to display</param>
        /// <param name="style">Sets style of alert box [Default | Success | Warning | Info ]</param>
        /// <param name="hideCloseButton">Sets the close button visibility</param>
        /// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.</param>
        public AlertBox(string text, AlertStyle style, bool hideCloseButton = false, object htmlAttributes = null)
        {
            this.text = text;
            this.alertStyle = style;
            this.hideCloseButton = hideCloseButton;
            this.htmlAttributes = htmlAttributes;
        }

        #region FluentAPI

        /// <summary>
        /// Sets the display style to Success
        /// </summary>
        public IAlertBoxFluentOptions Success()
        {
            alertStyle = AlertStyle.Success;
            return new AlertBoxFluentOptions(this);
        }

        /// <summary>
        /// Sets the display style to Warning
        /// </summary>
        /// <returns></returns>
        public IAlertBoxFluentOptions Warning()
        {
            alertStyle = AlertStyle.Warning;
            return new AlertBoxFluentOptions(this);
        }

        /// <summary>
        /// Sets the display style to Info
        /// </summary>
        /// <returns></returns>
        public IAlertBoxFluentOptions Info()
        {
            alertStyle = AlertStyle.Info;
            return new AlertBoxFluentOptions(this);
        }

        /// <summary>
        /// Sets the close button visibility
        /// </summary>
        /// <returns></returns>
        public IAlertBoxFluentOptions HideCloseButton(bool hideCloseButton = true)
        {
            this.hideCloseButton = hideCloseButton;
            return new AlertBoxFluentOptions(this);
        }

        /// <summary>
        /// An object that contains the HTML attributes to set for the element.
        /// </summary>
        /// <param name="htmlAttributes"></param>
        /// <returns></returns>
        public IAlertBoxFluentOptions Attributes(object htmlAttributes)
        {
            this.htmlAttributes = htmlAttributes;
            return new AlertBoxFluentOptions(this);
        }
        #endregion //FluentAPI

        private string RenderAlert()
        {
            //<div class="alert-box">
            var wrapper = new TagBuilder("div");
            //merge attributes
            wrapper.MergeAttributes(htmlAttributes != null ? HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes) : null);

            if (alertStyle != AlertStyle.Default)
                wrapper.AddCssClass(alertStyle.ToString().ToLower());
            wrapper.AddCssClass("alert-box");


            //build html
            wrapper.InnerHtml.AppendHtml(text);

            //Add close button
            if (!hideCloseButton)
                wrapper.InnerHtml.AppendHtml(RenderCloseButton());


            var stringWriter = new System.IO.StringWriter();
            wrapper.WriteTo(stringWriter, HtmlEncoder.Default);
            var tagBuilderIsFinallyAStringNow = stringWriter.ToString();

            return tagBuilderIsFinallyAStringNow;
        }

        private static string RenderCloseButton()
        {
            //<a href="" class="close">x</a>
            var closeButton = new TagBuilder("a");
            closeButton.AddCssClass("close");
            closeButton.Attributes.Add("href", "");
            closeButton.InnerHtml.AppendHtml("x");

            var stringWriter = new System.IO.StringWriter();
            closeButton.WriteTo(stringWriter, HtmlEncoder.Default);
            var tagBuilderIsFinallyAStringNow = stringWriter.ToString();

            return tagBuilderIsFinallyAStringNow;
        }


        //Render HTML
        public override string ToString()
        {
            return RenderAlert();
        }

        //Return ToString
        public string ToHtmlString()
        {
            return ToString();
        }
    }
}

This is the HtmlHelper:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc;

using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;

namespace MyHelpers
{
    /// <summary>
    /// Generates an Alert message
    /// </summary>
    public static class AlertHtmlHelper
    {
        /// <summary>
        /// Generates an Alert message
        /// </summary>
        public static AlertBox Alert(this IHtmlHelper html,
            string text,
            AlertStyle alertStyle = AlertStyle.Default,
            bool hideCloseButton = false,
            object htmlAttributes = null
            )
        {
            return new AlertBox(text, alertStyle, hideCloseButton, htmlAttributes);
        }

        // Strongly typed
        /// <summary>
        /// Generates an Alert message
        /// </summary>
        public static AlertBox AlertFor<TModel, TTextProperty>(this IHtmlHelper<TModel> html,
            Expression<Func<TModel, TTextProperty>> expression,
            AlertStyle alertStyle = AlertStyle.Default,
            bool hideCloseButton = false,
            object htmlAttributes = null
            )
        {
            var metadata = ExpressionMetadataProvider.FromLambdaExpression(expression, html.ViewData, html.MetadataProvider);
            return new AlertBox((string)metadata.Model, alertStyle, hideCloseButton, htmlAttributes);
        }

        /// <summary>
        /// Generates an Alert message
        /// </summary>
        public static AlertBox AlertFor<TModel, TTextProperty, TStyleProperty>(this IHtmlHelper<TModel> html,
            Expression<Func<TModel, TTextProperty>> textExpression,
            Expression<Func<TModel, TStyleProperty>> styleExpression,
            bool hideCloseButton = false,
            object htmlAttributes = null
            )
        {
            var text = (string)ExpressionMetadataProvider.FromLambdaExpression(textExpression, html.ViewData, html.MetadataProvider).Model;
            var alertStyle = (AlertStyle)ExpressionMetadataProvider.FromLambdaExpression(styleExpression, html.ViewData, html.MetadataProvider).Model;

            return new AlertBox(text, alertStyle,hideCloseButton, htmlAttributes);
        }


    }
}

AlertBoxFluentOptions.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace MyHelpers
{
    public class AlertBoxFluentOptions : IHtmlString, IAlertBoxFluentOptions
    {
        private readonly AlertBox parent;

        public AlertBoxFluentOptions(AlertBox parent)
        {
            this.parent = parent;
        }

        public IAlertBoxFluentOptions HideCloseButton(bool hideCloseButton = true)
        {
            return parent.HideCloseButton(hideCloseButton);
        }

        public IAlertBoxFluentOptions Attributes(object htmlAttributes)
        {
            return parent.Attributes(htmlAttributes);
        }

        public override string ToString()
        {
            return parent.ToString();
        }

        public string ToHtmlString()
        {
            return ToString();
        }
    }
}

AlertStyle.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyHelpers
{
    public enum AlertStyle
    {
        Default,
        Success,
        Warning,
        Info
    }
}

IAlertBox.cs:

using System.Web;

namespace MyHelpers
{
    public interface IAlertBox : IHtmlString, IAlertBoxFluentOptions
    {
        IAlertBoxFluentOptions Success();
        IAlertBoxFluentOptions Warning();
        IAlertBoxFluentOptions Info();
    }
}

IAlertBoxFluentOptions.cs:

using System.Web;

namespace MyHelpers
{
    public interface IAlertBoxFluentOptions : IHtmlString
    {
        IAlertBoxFluentOptions HideCloseButton(bool hideCloseButton = true);
        IAlertBoxFluentOptions Attributes(object htmlAttributes);
    }
}

I used this example on GitHub: Due to the project being outdated, I had to make a few changes.

https://github.com/EdCharbeneau/FluentHtmlHelpers/tree/master/FluentHtmlHelpers

3
  • 1
    Can you share the code how you are using the mentioned tag helper in the view?
    – Yong Shun
    Commented Jan 5 at 0:45
  • @YongShun: i have updated let me know if you require more information.
    – redoc01
    Commented Jan 5 at 0:54
  • @YongShun: i have added the html page of how im using the @Html.Alert()
    – redoc01
    Commented Jan 5 at 1:00

1 Answer 1

1

Refer to the built-in HTML Helper (HtmlHelperInputExtensions.TextBoxFor Method), the return types are IHtmlContent.

The idea is the same, to render the HTML, you need the value with IHtmlContent instead of string type.

using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;

public class AlertBox : IAlertBox
{
    ...

    //Return ToString
    public IHtmlContent ToHtmlString()
    {
        return new HtmlString(ToString());
    }
}

In your AlertBoxFluentOptions, you should have a method that returns IHtmlContent value.

public interface IAlertBoxFluentOptions
{
    IHtmlContent ToHtmlString();
}

public class AlertBoxFluentOptions : IAlertBoxFluentOptions
{
    ...

    public IHtmlContent ToHtmlString()
    {
        return new HtmlString(ToString());
    }
}

In your view, you should call ToHtmlString method for your HTML helper methods.

@Html.Alert("Message").ToHtmlString()
@Html.Alert("Message").Success().ToHtmlString()

Without calling .ToHtmlString() in the View, both classes should implement IHtmlContent.

public class AlertBox : IAlertBox, IHtmlContent
{
    ...

    public void WriteTo(TextWriter writer, HtmlEncoder encoder)
    {
       writer.Write(ToString());
    }
}
public class AlertBoxFluentOptions : IAlertBoxFluentOptions, IHtmlContent
{
    ...

    public void WriteTo(TextWriter writer, HtmlEncoder encoder)
    {
       writer.Write(ToString());
    }
}

And in the view,

@Html.Alert("Message")
@Html.Alert("Message").Success()
7
  • if i do that then i cant use @Html.Alert("Message").Success(), @Html.Alert("Message").Warning(), @Html.Alert("Message").Info() and the others as this is return an AlertBox() Object so that i can call Success, Warning and Info Methods.
    – redoc01
    Commented Jan 5 at 2:36
  • 1
    Updated my answer.
    – Yong Shun
    Commented Jan 5 at 3:43
  • still no luck when adding ToHtmlString(), the helper still returns text instead of html.
    – redoc01
    Commented Jan 5 at 3:59
  • 1
    Is it possible that to share your repository for this helper? For the code I provided, I am able to render the value as HTML element in my local.
    – Yong Shun
    Commented Jan 5 at 4:09
  • 1
    Hi, I updated my answer, you need to implement IHtmlContent and IHtmlContent.WriteTo method.
    – Yong Shun
    Commented Jan 5 at 5:23

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.