ASP.NET Core で Markdown を活用してみる

GitHub やQiita など、さまざまなサービスで使われている形式になってきた Markdown 。この便利(?)なものを ASP.NET でも使ってみようというのがこの記事の趣旨です。

CommonMark.NET

Markdown を処理するライブラリを探してみると、その一つとして CommonMark.NET が見つかります。この説明によると、フル .NET ライブラリにも関わらずネイティブライブラリのラッパーと同じくらい速く、さらに PCL や .NET Core の上でも動くそうです。これは Markdown で書くときには使わない手はないですよね。

ちなみに CommonMark とは、 Markdown に数ある方言を解決するために、その仕様化を目指したプロジェクトです。というわけで、正確には Markdown を使っている…というわけではないですが、大抵は問題なく使えるでしょう。

使い方

基本の使い方は簡単で、 using CommonMark; と書いた状態で、 CommonMarkConverter.Convert メソッドを使って変換します。他にも Parse メソッドや ProcessStage メソッドなどもありますが、自分の Markdown 拡張を作ったりしない分には使わないと思います。出力される HTML の形式を切り替えたいときは、 CommonMarkSettings.Default.Clone() をして自分で設定していくことになります。

1
2
3
4
5
6
7
8
9
10
11
            var setting = CommonMarkSettings.Default;
var md = @"
# Hello!
This is CommonMark.NET test.
Simple library.
1. foo
2. bar
";

// settingはオプション引数
Console.WriteLine(CommonMarkConverter.Convert(md, setting))
1
2
3
4
5
6
7
<h1>Hello!</h1>
<p>This is CommonMark.NET test.<br />
Simple library.</p>
<ol>
<li>foo</li>
<li>bar</li>
</ol>

ファイル(ストリーム)から読んで別ファイルに出力するというオーバーロードも存在します。

1
2
3
4
5
6
7
using (var input = File.OpenRead("Hoge.md"))
using (var reader = new StreamReader(input))
using (var output = File.OpenWrite("Piyo.html"))
using (var writer = new StreamWriter(output))
{
CommonMarkConverter.Convert(reader, writer, setting);
}

ASP.NET Core と絡めたサンプル

ライブラリの紹介が終わったところで、いよいよ ASP.NET Core で使ってみます。全体のソースコードはこちらから

まずは ASP.NET Core プロジェクトを作成し、 ‘project.json’ に依存関係を書き加えます。 Microsoft.AspNetCore.StaticFilesCommonMark.NET を追加しました。

テンプレートとして、下のような簡単なものを用意しました。 ‘style.css’ は別途用意しています。

Startup.cs
15
16
17
18
19
20
21
22
23
24
25
26
		const string ContentTemplate = @"
<!DOCTYPE html>
<html>
<head>
<title>{0}</title>
<link href=""/style.css"" rel=""stylesheet"" />
</head>
<body>
{1}
</body>
</html>
";

処理コードの中では、用意している CommonMark と同じ名前のリクエストがあれば、それを HTML に変換して表示しています。 CommonMark の実際の処理は CommonMarkConverter.Convert メソッドだけです。

Configure()
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
var contnetDir = env.ContentRootFileProvider.GetDirectoryContents(@"content");
if (!contnetDir.Exists)
{
throw new Exception("\"content\" directory does not exist.");
}

app.UseStaticFiles();

loggerFactory.AddConsole();

if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

app.Run(async (context) =>
{
var pathElements = context.Request.Path.Value.Split('/');
if (pathElements.Length != 2)
{
return;
}

var requestName = pathElements[1];
if (string.IsNullOrEmpty(requestName))
{
requestName = "index";
}

var file = contnetDir.SingleOrDefault(x => x.Name == requestName + ".md");
if (file != null)
{
using (var stream = file.CreateReadStream())
using (var reader = new StreamReader(stream))
{
var pageContent = await reader.ReadToEndAsync();
var htmlPart = CommonMarkConverter.Convert(pageContent);
await context.Response.WriteAsync(string.Format(
ContentTemplate, requestName, htmlPart));
}
}
});

このプロジェクトを実行すると、次のようなページが表示されます。元の CommonMark ファイル

例1例1
例2例2

まとめ

Markdown を処理するためのライブラリである CommonMark.NET を紹介し、それを ASP.NET で利用してみました。

データベースやブラウザエディタを含めてプロジェクトを作れば、 Markdown の CMS っぽいのを構築できるかもしれません。