前幾天介紹過在 Visual Studio 寫 Markdown 文件的好用擴充套件 - Markdown Editor,我有個大膽的想法:既然在 VS 寫 Markdown 這麼方便,我何不在 ASP.NET Core 網站開個專屬資料夾直接寫線上使用手冊,像這樣:

像上面這樣,Markdown 文件、圖檔、下載 PDF 都放在同一個資料夾,還可以區分子資料夾。

文件可加入連結串接其他 Markdown 文件(例如本案中的 other、SubFolder/ 對映 other.md 及 SubFolder/index.md)或下載檔案(demo.pdf):

這樣的架構彈性夠,寫作上應該蠻順手的。至於要放到網站上使用,除了靠 Hugo 之類的軟體批次轉換,若能讓 ASP.NET Core 直接將 .md 轉成 HTML,其餘圖檔、PDF、子資料夾結構都能 100% 沿用,感覺上更直覺簡單了。

首先我們需要一個 Markdown 轉 HTML 的程式庫,Markdown Editor 用的是 MarkDig,從 NuGet 安裝 MarkDig 程式庫,寫個 HelpController 呼叫 Markdown.ToHtml(File.ReadAllText(md_path));,我們便能產生 Markdown Editor 預覽一致的 HTML 內容。

但 HelpController 只負責處理 .md,HelpDoc 資料夾的 png、pdf 靜態檔案可交給 ASP.NET Core 底層處理,讓 URL /help/folder/name.png 對映到 /HelpDoc/folder/name.png 即可,之前研究過用 UseStaticFiles() 自訂靜態檔案來源,現在便派上用場了。

有了構想,簡單拼裝一下。Program.cs 加入 UseStaticFiles() 及 MapControllerRoute():

//... 省略
app.UseHttpsRedirection();

// 將 /HelpDoc 目錄檔案對映到 /help URL
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(app.Environment.ContentRootPath, "HelpDoc")),
    RequestPath = "/help"
});
// 將 /help/** 非靜檔案路徑對映到 HelpController,{*path} 可涵蓋包含多層 / 的網址
app.MapControllerRoute(
    name: "Help",
    pattern: "help/{*path}",
    defaults: new { controller = "Help", action = "Index" }
);

app.UseStaticFiles();

//... 省略

HelpController.cs 內做簡單的路徑對映轉換,這種依使用者指定路徑讀檔的程式,一定要嚴防路徑參數被插入特殊字元偷檔案,我採用的檢核方式是用 Regex.IsMatch(path, "^[A-Za-z/]*$") 限定路徑只能包含英文字母及 / 符號,其餘一律視為不合法。

using Microsoft.AspNetCore.Mvc;
using System.Text.RegularExpressions;

namespace MarkdownDistrictAspNetCore.Controllers
{
    public class HelpController : Controller
    {
        string MarkdownPath;
        public HelpController(IHostEnvironment env)
        {
            MarkdownPath = Path.Combine(env.ContentRootPath, "HelpDoc");
        }

        public IActionResult Index(string path)
        {
            // Path validation
            path = path ?? string.Empty;
            if (!Regex.IsMatch(path, "^[A-Za-z/]*$"))
                return Content($"Ivalid Path - {path}");
            var mdPath = Path.Combine(MarkdownPath, path.Replace("/", "\\"));
            if (!System.IO.File.Exists(mdPath + ".md"))
            {
                mdPath = mdPath.TrimEnd('/') + "/index";
                if (!System.IO.File.Exists(mdPath + ".md"))
                    return NotFound();
                else
                {
                    if (!string.IsNullOrEmpty(path)) 
                        path = path.TrimEnd('/') + "/";
                    return Redirect($"~/Help/{path}index");
                }
            }
            ViewBag.HtmlContent = Markdig.Markdown.ToHtml(System.IO.File.ReadAllText(mdPath + ".md"));
            return View();
        }
    }
}

就醬,插電、開機,輕鬆秒殺~

相同的檔案結構,.md 直接變成網頁,很酷吧?

範例程式已上傳 Github,需要者請自取。

Tips of showing Markdown documents in ASP.NET Core web sites.


Comments

# by Toolman

黑大好 如果想用 markdown 產說明文件,或許可以用一些 document generator ? 像是 Vuepress 只要用這些靜態產生器產出靜態檔,就可以直接掛載到 IIS 上當成說明文件了 另外想請問一下黑大,您的部落格網站是架在什麼機器上呢? 部落格中的圖檔等等靜態檔,是否有存在什麼額外的 static file server 呢?

# by Jeffrey

to Toolman,這個解決方案我打算用在簡單的線上輔助說明,若是完整手冊,我偏好用 Hugo 來做。Vuepress 挺吃前端技能的,完全沒摸過 npm、yarn 的生手看到會怕,Hugo 相對簡單一些。 我的 Blog 是以 Miniblog.Core 為基礎修改的,在 Linux Docker 容器執行,圖檔就放在 wwwroot 下,沒用特殊儲存做法,但有沿用 Miniblog.Core 內建的圖片延遲載入機制。

# by Toolman

了解,感謝回答 不好意思想再請問,您的 Linux Docker 是架在自己的機器上嗎? 還是是放在第3方的機器上呢?

# by Jeffrey

to Toolman,放雲端,但 ASP.NET Core 跑 Docker 蠻省資源的,試過放在迷你主機 ( https://blog.darkthread.net/blog/minipc-as-centos-server/ ) 跑也沒什麼問題

# by Toolman

挺有趣的XD 感謝黑大的分享

Post a comment