Representación de HTML sin formato en Blazor con MarkupString

· 3 min de lectura

El otro día estaba creando un componente que necesitaba representar HTML procedente de un CMS. Tenía la cadena HTML en una variable y la solté en la plantilla como @myHtml. Y, por supuesto, Blazor escapó de todo y representó las etiquetas reales como texto en la página. No es lo que quería.

El problema

De forma predeterminada, Blazor codifica cualquier cadena que represente en una plantilla. Entonces si tienes:

@code {
    private string content = "<strong>Hello</strong> <em>world</em>";
}

Y haces esto:

<div>@content</div>

Verás el texto literal <strong>Hello</strong> <em>world</em> en la página en lugar de Hola mundo. Blazor hace esto a propósito para evitar ataques XSS, que es el comportamiento predeterminado correcto.

La solución: MarkupString

Si realmente necesita representar HTML sin formato, envuelva su cadena en un MarkupString:

<div>@((MarkupString)content)</div>

¡Y eso es todo! Ahora Blazor representará el HTML como marcado real. También puedes asignarlo a una variable:

@code {
    private string rawHtml = "<strong>Hello</strong> <em>world</em>";
    private MarkupString HtmlContent => (MarkupString)rawHtml;
}
<div>@HtmlContent</div>

Un ejemplo del mundo real

Estaba extrayendo contenido del blog desde una API y necesitaba representarlo en un componente de vista previa. El contenido tenía todo tipo de HTML: encabezados, bloques de código, enlaces, imágenes. Esto es aproximadamente cómo se veía:

@inject HttpClient Http

@if (article is not null)
{
    <article>
        <h1>@article.Title</h1>
        <div class="content">
            @((MarkupString)article.HtmlBody)
        </div>
    </article>
}

@code {
    [Parameter]
    public int ArticleId { get; set; }

    private ArticleDto? article;

    protected override async Task OnInitializedAsync()
    {
        article = await Http.GetFromJsonAsync<ArticleDto>($"api/articles/{ArticleId}");
    }
}

Funciona perfectamente. El HTML de la API se representa como marcado real.

Tenga cuidado con el contenido que no es de confianza

Esto es importante: MarkupString no desinfecta el HTML. Representa todo lo que le das, incluidas las etiquetas <script>. Entonces, si el contenido proviene de la entrada del usuario o de una fuente que no es confiable, primero debe desinfectarlo.

No hay un desinfectante HTML integrado en Blazor, pero puedes usar una biblioteca como HtmlSanitizer:

using Ganss.Xss;

@code {
    private HtmlSanitizer sanitizer = new();

    private MarkupString SafeHtml(string html)
    {
        var clean = sanitizer.Sanitize(html);
        return (MarkupString)clean;
    }
}
<div>@SafeHtml(untrustedContent)</div>

Esto elimina elementos peligrosos como <script>, onclick controladores y otras cosas que no quieres que se muestren en el contenido proporcionado por el usuario.

Cuando usarlo

Utilizo MarkupString para:

  • Contenido CMS o rebajas que se han convertido a HTML del lado del servidor
  • Salida del editor de texto enriquecido
  • Vista previa de plantillas de correo electrónico
  • Cualquier HTML prediseñado de fuentes confiables

Para cualquier cosa que provenga de la entrada del usuario, siempre desinfecte primero. Más vale prevenir que lamentar.

Espero que os haya gustado el post! No dudes en contactarme en cualquier red social en @emimontesdeoca.

Recursos