惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

月光博客
月光博客
罗磊的独立博客
The GitHub Blog
The GitHub Blog
V
V2EX
Last Week in AI
Last Week in AI
博客园 - 聂微东
MyScale Blog
MyScale Blog
美团技术团队
L
LangChain Blog
博客园 - Franky
腾讯CDC
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园_首页
S
SegmentFault 最新的问题
爱范儿
爱范儿
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Stack Overflow Blog
Stack Overflow Blog
量子位
小众软件
小众软件
宝玉的分享
宝玉的分享
J
Java Code Geeks
Google DeepMind News
Google DeepMind News
D
Docker
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报

博客园_首页

Plist 二进制格式 Milvus 和 PGVector,哪个更好? OpenClaw 已过时?在 VS Code 中运行 Hermes Agent! 第30篇文章:一个大三计科生的自白 Manim如何在数学公式中完美显示中文? Docker 部署 RocketMQ 5 并发编程核心概念辨析 C#事务处理最佳实践:别再让“主表存了、明细丢了”的破事发生 CLI 是什么?为什么大厂突然集体卷命令行? 【从0到1构建一个ClaudeAgent】协作-自主Agent UIImageView 设置图片不生效的原因排查 最小二乘问题详解20:无先验约束下的增量式SFM自由网平差 痞子衡嵌入式:大话双核i.MXRT1180之XIP应用里借助MU实现可靠Flash IAP的方法 AI Chat 封装, SemanticKerne.AiProvider.Unified 已发布 Windows下右键编辑js文件无法打开记事本——在注册表中使用环境变量 在后台服务中使用 Scoped 服务,为什么总是报错? H200 安装驱动并使用sglang启动模型 wireshark 抓包Trap上报告警内容 我用 AI 辅助开发了一系列小工具(2):图片压缩工具 [A Primer On MC and CC] 2.1 Memory Consistency 1 - 指令重排序和 SC 模型 Oracle数据库SCN推进技术详解与实践指南 玩转控件:封装个带图片的Label控件 Claude Code 4.7 真正该升级的不是模型,而是你的工作流 前端小白一句话,AI 帮我做了个颜值拉满的桌面媒体播放器。当代码不再是门槛,一句话编程就是现实。 5. WorkBuddy: 小龙虾的灵魂三件套,让你的小龙虾不只是工具 SQLite 分片方案实战:三种分片策略的深度对比 告别简陋 UI!一款基于 Fluent Design 和基于 WinUI 的开源免费、现代化的 Avalonia UI 控件库 关于二进制排列组合枚举的总结 AI开发-python-LangGraph框架(3-27-LangGraph从零实现大模型智能决策工作流) ElasticSearch主分片和副本分片概念详解
Jasmine.Format - 一个高性能、线程安全的 .NET HTML 生成库
丁双磊 · 2026-06-14 · via 博客园_首页

引言

在 .NET 开发中,生成 HTML 内容是一个常见的需求。无论是构建邮件模板、生成报表、还是创建动态网页内容,我们都需要一种简洁、安全且高效的方式来构建 HTML。今天,我想向大家介绍 Jasmine.Format —— 一个专为高性能场景设计的 .NET HTML 生成库。

为什么需要 Jasmine.Format?

传统的 HTML 字符串拼接方式存在以下问题:

  1. 安全隐患:手动拼接容易忘记 HTML 编码,导致 XSS 攻击风险
  2. 代码冗长:字符串拼接代码难以阅读和维护
  3. 性能问题:频繁的字符串分配造成 GC 压力
  4. 线程安全:可变对象在多线程环境下需要额外同步

Jasmine.Format 旨在解决这些问题,提供一个流畅、安全、高效的 HTML 生成解决方案。

核心特性

1. 自动 HTML 编码,防止 XSS 攻击

var p = new HtmlP().Add("<script>alert('XSS')</script>");
// 输出: <p>&lt;script&gt;alert(&#39;XSS&#39;)&lt;/script&gt;</p>

所有通过 Add() 方法添加的文本都会自动进行 HTML 编码,有效防止 XSS 攻击。只有在明确信任内容时,才使用 AddRaw() 方法。

2. 流畅的 API 设计

var html = new HtmlP()
    .Add("您好,")
    .Add(new HtmlSpan("张三", "#0066cc"))
    .Add("!欢迎使用系统。")
    .WithStyle("font-size: 14px; line-height: 1.5;")
    .ToHtml();

// 输出: <p style="font-size: 14px; line-height: 1.5;">您好,<span style="color:#0066cc;">张三</span>!欢迎使用系统。</p>

链式方法调用让代码简洁直观,易于阅读和维护。

3. 不可变模式,天然线程安全

var original = new HtmlP().Add("原始内容");
var modified = original.Add("新增内容");

// original 保持不变
Console.WriteLine(original.ToHtml());  // <p>原始内容</p>
Console.WriteLine(modified.ToHtml());  // <p>原始内容新增内容</p>

每次操作返回新实例,原始实例保持不变。这种不可变设计使得对象可以在多线程环境下安全共享,无需任何同步机制。

4. 高性能优化

  • 对象池:复用 List 对象,减少 GC 压力
  • StringBuilder 缓存:线程本地缓存,提高字符串构建效率
  • 容量预估:预先分配 StringBuilder 容量,避免重新分配
// 对象池配置
private static readonly ObjectPool<List<object>> _listPool = 
    new ObjectPool<List<object>>(() => new List<object>(), 32);

5. 多框架支持

支持 .NET Standard 2.0、.NET 6/7/8/9/10,可在各种 .NET 项目中使用。

快速入门

安装

dotnet add package Jasmine.Format

基础用法

创建段落

using Jasmine.Format;
using Jasmine.Format.Elements.Text;
using Jasmine.Format.Elements.Basic;

// 简单段落
var p = new HtmlP().Add("Hello, World!");

// 带样式的段落
var p = new HtmlP().Add("内容").WithStyle("text-align: center;");

// 混合内容
var p = new HtmlP()
    .Add("访问 ")
    .Add(new HtmlA("示例网站", "https://example.com", "_blank"))
    .Add(" 了解更多");

创建列表

using Jasmine.Format.Elements.List;

// 无序列表
var ul = new HtmlList(ListType.Unordered)
    .AddItem("项目一")
    .AddItem("项目二")
    .AddItem("项目三");

// 有序列表(从 5 开始)
var ol = new HtmlList(ListType.Ordered, 5)
    .AddItem("第五步")
    .AddItem("第六步");

// 批量添加
var items = new[] { "A", "B", "C" };
var ul = new HtmlList(ListType.Unordered).AddRange(items);

创建容器

using Jasmine.Format.Elements.Container;

var div = new HtmlDiv("border: 1px solid #ccc; padding: 10px;")
    .Add(new HtmlP().Add("标题"))
    .Add(new HtmlP().Add(new HtmlSpan("高亮文本", "#ff6600")));

高级用法

条件渲染

var isAdmin = true;
var p = new HtmlP()
    .Add("用户:")
    .Add(userName)
    .Add(isAdmin ? " (管理员)" : "");

批量操作

var trains = new[] {
    new { Station = "北京", TrainNo = "G123", Status = "正常" },
    new { Station = "上海", TrainNo = "G456", Status = "晚点" }
};

var p = new HtmlP()
    .Add("列车信息:")
    .AddSpanRange(trains, t => new HtmlSpan(
        $"{t.Station}开{t.TrainNo}次",
        t.Status == "正常" ? "green" : "red"
    ));

模板格式化

using Jasmine.Format.Utilities;

// 位置参数
var html = HtmlFormatHelper.Format(
    "欢迎 {0}, 年龄: {1}",
    "张三", "25"
);

// 命名参数
var dict = new Dictionary<string, string>
{
    { "name", "李四" },
    { "age", "30" }
};
var html = HtmlFormatHelper.FormatTemplate(
    "姓名: {name}, 年龄: {age}",
    dict
);

性能测试

在内部测试中,Jasmine.Format 在高并发场景下表现优异:

测试场景 传统字符串拼接 Jasmine.Format
1000 次循环生成 ~15ms ~8ms
内存分配次数 ~2000 次 ~500 次
多线程并发 需要同步 无需同步

实际应用场景

1. 邮件模板生成

var emailBody = new HtmlDiv("font-family: Arial;")
    .Add(new HtmlP().Add($"尊敬的 {userName}:"))
    .Add(new HtmlP().Add("您的订单已发货,详情如下:"))
    .Add(new HtmlList(ListType.Unordered)
        .AddRange(orderItems.Select(i => $"{i.Name} - {i.Price}元")))
    .ToHtml();

2. 报表生成

var report = new HtmlDiv()
    .Add(new HtmlP($"报告日期:{DateTime.Now:yyyy-MM-dd}").WithStyle("font-weight: bold;"))
    .Add(new HtmlList(ListType.Ordered)
        .AddRange(summaryItems))
    .ToHtml();

3. 动态通知内容

var notification = new HtmlP()
    .Add(new HtmlSpan("系统通知", "#ff6600", "font-weight: bold;"))
    .AddRaw("<br/>")
    .Add(messageContent)
    .ToHtml();

最佳实践

  1. 始终使用 Add() 方法:除非内容完全可信,否则不要使用 AddRaw()
  2. 利用不可变性:在多线程环境下,放心共享 HtmlP、HtmlDiv 等对象
  3. 批量操作:使用 AddSpanRangeAddRange 等方法处理集合数据
  4. 样式分离:将样式集中管理,便于维护

开源与贡献

Jasmine.Format 是一个开源项目,欢迎社区贡献:

  • GitHub: [项目地址]
  • MIT 许可证
  • 129+ 单元测试覆盖

总结

Jasmine.Format 提供了一种简洁、安全、高效的方式来生成 HTML 内容。它的不可变设计确保了线程安全,自动编码防止了 XSS 攻击,对象池优化提升了性能。如果你在 .NET 项目中需要生成 HTML,不妨试试 Jasmine.Format!


相关链接:

技术栈:

  • .NET Standard 2.0 / .NET 6/7/8/9/10
  • C# 不可变设计模式
  • 对象池优化
  • StringBuilder 缓存