Markdown是一种非常流行的富文本格式,特别是在技术人员中应用广泛,Markdown文件的扩展名是.md。
由于Markdown并不是Web的标准,因此目前大部分浏览器并不支持直接显示Markdown文件。
在这里我们将编写一个在服务器端把Markdown转换为HTML的中间件。
我们开发的中间件是构建在ASP.NET Core内置的StaticFiles中间件之上的,并且在它之前运行。
所有的*.md文件都被放到wwwroot文件夹下,当我们请求wwwroot下其他的静态文件的时候,StaticFiles中间件会把它们返回给浏览器。
而当我们请求wwwroot下的*.md的时候,我们编写的中间件会读取对应的*.md文件并且把它们转换为HTML格式返回给浏览器。
*.md文件是文本文件,存在不同编码格式的问题,因此我们调用Ude.NetStandard这个NuGet包中的CharsetDetector类来探测流的编码,并且从流中读取文本,如以下代码:
C#
/// <summary>
/// 探测流的编码
/// </summary>
/// <param name="stream"></param>
/// <returns></returns>
private static string DetectCharset(Stream stream)
{
CharsetDetector detector = new();
detector.Feed(stream);
detector.DataEnd();
string charset = detector.Charset ?? "UTF-8";
stream.Position = 0;
return charset;
}
/// <summary>
/// 从流中读取文本
/// </summary>
/// <param name="stream"></param>
/// <returns></returns>
private static async Task<string> ReadTextAsync(Stream stream)
{
string charset = DetectCharset(stream);
using var reader = new StreamReader(stream,Encoding.GetEncoding(charset));
return await reader.ReadToEndAsync();
}
}
DetectCharset方法用来探测流的编码,ReadText方法则调用DetectCharset探测流的编码,然后使用这个编码读取文本内容。
接下来,我们创建一个中间件读取*.md文件并且将其转换为HTML格式,如下面代码:
C#
public class MarkDownViewerMiddleware(RequestDelegate _next, IWebHostEnvironment _environment, IMemoryCache _cache)
{
public async Task InvokeAsync(HttpContext context)
{
string path = context.Request.Path.Value ?? string.Empty;
if (!path.EndsWith(".md"))
{
await _next(context);
return;
}
//获取静态文件夹下的指定文件
var file = _environment.WebRootFileProvider.GetFileInfo(path);
if (!file.Exists)
{
await _next(context);
return;
}
context.Response.ContentType = $"text/html;charset=UTF-8";
context.Response.StatusCode = 200;
//为了实现文件修改后用户能够立即获得最新文件,把文件的修改时间作为缓存键的一部分
string cacheKey = nameof(MarkDownViewerMiddleware) + path + file.LastModified;
//为了避免每次用户请求都读取和分析*.md文件,启用内存缓存来保存转换后的HTML内容
var html = await _cache.GetOrCreateAsync(cacheKey, async ce =>
{
ce.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1);
using var stearm = file.CreateReadStream();
string text = await ReadContext.ReadTextAsync(stearm);
//MarkdownSharp 转换为HTML
Markdown markdown = new();
return markdown.Transform(text);
});
await context.Response.WriteAsync(html);
}
}
编写完成中间件代码后,我们在wwwroot文件夹下放置若干个*.md文件,然后在Progarm.cs中注册这个中间件,如如下代码:
C#
app.UseMiddleware<MarkDownViewerMiddleware>();
app.UseStaticFiles();
MarkDownViewerMiddleware一定要放到StaticFiles之前。完成上面的代码后,运行项目,并且访问MD文件,我们就可以看到MD文件被转换为HTML格式,如图所示:
