Perfect: Display Markdown and Add Syntax Highlighting in C# Blazor

Perfect: Display Markdown and Add Syntax Highlighting in C# Blazor

I think it's fairly perfect now. Below is how it was done.

Last updated 2/27/2022 5:46 PM
沙漠尽头的狼
5 min read
Category
Blazor
Tags
.NET C# Blazor Markdown

Yesterday, I published an article introducing this library: Displaying Markdown Files in C# Blazor, which explains how to display Markdown content in Blazor. The code in that article had no syntax highlighting. After much deliberation, I decided to improve it, so I searched online and found this article: .NET C# Blazor Server-Side Rendering Markdown. The current rendering effect is as follows:

I think it's quite satisfactory now. Let me explain how it's done.

1. Preparation

1.1 Add Markdown to HTML package: Markdig

Markdig: Markdig is a fast, powerful, CommonMark compliant, extensible .NET Markdown processor.

<PackageReference Include="Markdig" Version="0.27.0" />

1.2 Introduce Prism Plugin

This Prism is not the other Prism. It's a JS plugin: Prism is a lightweight, robust, and elegant syntax highlighting library. It's a derivative project of Dabblet.

Include it in the head of _Layout.cshtml:

<head>
  ....
  <!--Reset browser styles-->
  <link
    rel="stylesheet"
    href="https://cdn.jsdelivr.net/npm/normalize.css@8.0.1/normalize.css"
  />
  <!--Code block theme-->
  <link
    rel="stylesheet"
    href="https://cdn.jsdelivr.net/npm/prismjs@1.27.0/themes/prism-coy.min.css"
  />
  <!--Toolbar plugin-->
  <link
    rel="stylesheet"
    href="https://cdn.jsdelivr.net/npm/prismjs@1.27.0/plugins/toolbar/prism-toolbar.min.css"
  />
  <!--Line numbers plugin-->
  <link
    rel="stylesheet"
    href="https://cdn.jsdelivr.net/npm/prismjs@1.27.0/plugins/line-numbers/prism-line-numbers.min.css"
  />
  ...
</head>
<body>
  ...
  <!--Prism core JS (for rendering code blocks)-->
  <script src="https://cdn.jsdelivr.net/npm/prismjs@1.27.0/prism.min.js"></script>
  <!--Display code block line numbers-->
  <script src="https://cdn.jsdelivr.net/npm/prismjs@1.27.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
  <!--Toolbar (prerequisite for some plugins)-->
  <script src="https://cdn.jsdelivr.net/npm/prismjs@1.27.0/plugins/toolbar/prism-toolbar.min.js"></script>
  <!--Display language name on code blocks-->
  <script src="https://cdn.jsdelivr.net/npm/prismjs@1.27.0/plugins/show-language/prism-show-language.min.js"></script>
  <!--Copy code-->
  <script src="https://cdn.jsdelivr.net/npm/prismjs@1.27.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"></script>
  <!--Automatically load language-specific syntax highlighting JS from CDN-->
  <script src="https://cdn.jsdelivr.net/npm/prismjs@1.27.0/plugins/autoloader/prism-autoloader.min.js"></script>
</body>

2. Usage

I extracted the Markdown display into a separate component MarkdownComponent.razor, using the relative path of the loaded Markdown file, the article link, and the source code link as parameters for reuse in other tools. The code snippets below are mainly from this file.

Component parameter definition:

@code {
    [Parameter]
    public string LocalPostFilePath { get; set; } = null!;

    [Parameter]
    public string RemotePostUrl { get; set; } = null!;

    [Parameter]
    public string SourceCodeUrl { get; set; } = null!;
}

Markdown content reading and conversion from Markdown format to HTML are defined in the OnInitializedAsync() method:

protected override async Task OnInitializedAsync()
{
    var markdownData = await File.ReadAllTextAsync(LocalPostFilePath);

    // Convert markdown to html
    var htmlData = Markdown.ToHtml(markdownData);

    // Convert to Prism-supported language tags (optional, can be removed)
    htmlData = htmlData.Replace("language-golang", "language-go");

    // TODO: Use https://github.com/mganss/HtmlSanitizer to sanitize XSS in HTML
    if (htmlData.Contains("<script") || htmlData.Contains("<link"))
    {
        _hasXss = true;
    }

    // Convert plain text to renderable HTML type
    _postHtmlContent = (MarkupString) htmlData;
}

The final step is to call the Prism plugin method after the component is rendered, written in the method OnAfterRenderAsync(bool firstRender). This is the key code for syntax highlighting:

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    await _jsRuntime.InvokeVoidAsync("Prism.highlightAll");
}

Rendering is relatively simple (for our usage). See the code below:

<div class="line-numbers">
  @{ if (_hasXss) { @_postHtmlContent.ToString() } else { @_postHtmlContent } }
</div>

Call the component in IcoTool.razor:

<MarkdownComponent
  LocalPostFilePath="wwwroot/2022/02/2022-02-22_02.md"
  RemotePostUrl="https://dotnet9.com/2022/02/Perfect-Display-Markdown-in-Csharp-Blazor-and-add-code-highlighting"
  SourceCodeUrl="https://github.com/dotnet9/dotnet9.com/blob/develop/src/Dotnet9.Tools.Web/Pages/Public/ImageTools/IcoTool.razor"
/>

Of course, component encapsulation depends on individual needs. The above gives the general idea. I won't post the detailed code. If you're interested, check out the Dotnet9 Toolbox source code.

Reference article:

Keep Exploring

Related Reading

More Articles
Same category / Same tag 11/6/2024

Why My Blog Website Returned to Blazor

The development of the blog website has gone through many hardships, with nearly 10 versions including MVC, Vue, Go, etc. Now it has returned to Blazor and adopted static SSR, resulting in a significant speed increase and successful launch.

Continue Reading
Same category / Same tag 2/29/2024

Data Display Can Also Be Done Like This in Winform

In the process of developing Winform, data display functionality is often required. Previously, the gridcontrol control was commonly used. Today, through an example, I would like to introduce how to use the table component from Ant Design Blazor for data display in a Winform Blazor Hybrid application.

Continue Reading
Same category / Same tag 2/29/2024

Can the Winform interface also look good?

A few days ago, I introduced using Blazor Hybrid in Winform, and mentioned that with the Blazor UI, our Winform programs can be designed to look better. Next, I will illustrate with an example of drawing in Winform Blazor Hybrid, hoping it helps you.

Continue Reading