Search code examples
c#razorasp.net-core-mvcbootstrap-5

Section header not displaying correctly in ASP.NET Core view


I am migrating an application from ASP.NET MVC 5 running on .NET 4.8 to ASP.NET Core 6 MVC.

The MVC 5 application has the following in an Index.cshtml file:

@section header
{
    @Html.Partial("~/Views/Shared/DisplayTemplates/_ModeHeader.cshtml", Model.Mode, new ViewDataDictionary { { "text", "Salaries" }, { "icon", "fa-money-check" } })
}

I updated it to the following in the new application:

@section header {
    @await Html.PartialAsync("~/Views/Shared/DisplayTemplates/_ModeHeader.cshtml", Model.Mode, new ViewDataDictionary(ViewData) { { "text", "Salaries" }, { "icon", "fa-money-check" } })
}

_ModeHeader.cshtml:

@using Project.Extensions.MVC
@using Project.Models

@model Enums.Mode

@{
    if (!ViewData.ContainsKey("icon"))
    {
        ViewData["icon"] = "fa-list-alt";
    }
}

<div class="border-bottom row">
    <div class="col">
        <span class="h1">
            @switch (Model)
            {
                case Enums.Mode.None:
                    break;
                case Enums.Mode.Browse:
                    @IconExtensions.BuildColoredIconTag(ViewData["icon"].ToString(), "text-info")
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
            @ViewData["text"]
        </span>
    </div>
</div>

The expected result is an icon, a space, and the text Salaries.

The current result is the text Normal, a space, and the text Salaries.

UPDATE:

The text "Normal" is the result of updating the line var finalHtml = icon.ToString(TagRenderMode.Normal); from the old application to var finalHtml = icon.TagRenderMode.ToString();. Since TagRenderMode is "Normal" by default, that is where the value comes from.

IconExtensions.cs:

public static class IconExtensions
{
    public static HtmlString BuildIconTag(string iconName)
    {
        var icon = BuildInternalIconTag(iconName);

        var htmlBuilder = new StringBuilder();

        htmlBuilder.Append(icon);

        var finalHtml = icon.TagRenderMode.ToString();

        return new HtmlString(finalHtml);
    }

    public static HtmlString BuildColoredIconTag(string iconName, string color)
    {
        var icon = BuildInternalColoredIconTag(iconName, color);

        var htmlBuilder = new StringBuilder();

        htmlBuilder.Append(icon);

        var finalHtml = icon.TagRenderMode.ToString();

        return new HtmlString(finalHtml);
    }

    public static TagBuilder BuildInternalIconTag(string iconName)
    {
        var icon = new TagBuilder("i");

        icon.AddCssClass("fas");
        icon.AddCssClass("fa-fw");
        icon.AddCssClass(iconName);
        icon.MergeAttribute("aria-hidden", "true");

        return icon;
    }

    public static TagBuilder BuildInternalColoredIconTag(string iconName, string color)
    {
        var icon = new TagBuilder("i");

        icon.AddCssClass("fas");
        icon.AddCssClass("fa-fw");
        icon.AddCssClass(iconName);
        icon.AddCssClass(color);
        icon.MergeAttribute("aria-hidden", "true");

        return icon;
    }
}

Solution

  • This line is just setting finalHtml to "Normal"

    var finalHtml = icon.TagRenderMode.ToString();
    

    This line is using just "Normal" to make the HtmlString

    return new HtmlString(finalHtml);
    

    You are not using your icon object at all at this point.

    You probably want something more like:

    public static HtmlString BuildColoredIconTag(string iconName, string color)
    {
        var icon = BuildInternalColoredIconTag(iconName, color);
        var writer = new StringWriter();
        icon.WriteTo(writer, HtmlEncoder.Default);
    
        return new HtmlString(writer.ToString());
    }