升级到 3.0:默认资源限额会拒绝部分此前可处理的超大输入;公开入口和库目标框架保留。升级前请阅读 迁移指南。
中文 · English
一个"模板 ⇄ 数据"契约引擎:导出和导入是同一个契约的两个方向——
- 导出(Fill) = 模板 + 强类型数据 → 文件
- 导入(Parse) = 文件 → 按契约解析 → 强类型数据
模板由代码生成、用户只改样式;上传时校验模板与契约匹配(缺什么、多什么、哪里错,一行行列得清清楚楚)。
| 你的需求 | 安装 | 说明 |
|---|---|---|
| 列表数据导入 / 导出(标题行 + 数据行) | TemplateFrame.Excel.Simple |
一个 List<T> 进出 xlsx,最简路径 |
| Word 单据打印(页眉页脚 / 表格 / 图片 / A5 横版) | TemplateFrame.Word |
内容控件(SDT)定位,改样式时须保留控件与表格结构 |
| Excel 复杂表单(合并单元格 / 图片 / 自由版式) | TemplateFrame.Excel |
命名区域定位,网格规整型版式 |
三个插件都依赖基础包 TemplateFrame(契约模型 + 强类型服务基类),装插件即自动引入。只想手写 Excel 表格、不要契约?TemplateFrame.Excel.Simple 里的 SimpleExcel.Write / Read 静态类可以单独用。
四包统一 netstandard2.0 / net462 / net8.0 多目标,NuGet 按运行时自动选择:
| 你的运行时 | 命中资产 |
|---|---|
| .NET Framework 4.6.2+ | net462 |
| .NET 5 – 7 | netstandard2.0 |
| .NET 8+ | net8.0(net9 / net10 向下兼容消费) |
插件直接依赖 DocumentFormat.OpenXml,net462 资产另引用 System.ValueTuple;核心包不引用 OpenXML。
以物料清单为例(TemplateFrame.Excel.Simple):
dotnet add package TemplateFrame.Excel.Simple① 定义数据与服务——声明契约(有哪些列),版式与映射全部省掉:
using TemplateFrame.Contract;
using TemplateFrame.Excel.Simple;
public sealed record MaterialLine
{
public string Code { get; init; } = string.Empty;
public string Name { get; init; } = string.Empty;
public string? Unit { get; init; }
}
public sealed record MaterialsData
{
public IReadOnlyList<MaterialLine> Items { get; init; } = [];
}
public sealed class MaterialsService : SimpleExcelTemplateService<MaterialsData>
{
protected override TemplateContract DefineContract() => new()
{
Name = "Materials",
Version = "1.0",
Elements =
[
new TableElement
{
Key = "Materials",
DataPath = "Items", // 指向 MaterialsData.Items,自动映射
Columns =
[
new TextElement { Key = "Code", DisplayName = "编码", DataPath = "Code", Required = true },
new TextElement { Key = "Name", DisplayName = "名称", DataPath = "Name", Required = true },
new TextElement { Key = "Unit", DisplayName = "基本单位", DataPath = "Unit" },
],
},
],
};
}② 四个操作(先准备示例输入):
var data = new MaterialsData { Items = [new MaterialLine { Code = "M001", Name = "螺栓", Unit = "个" }] };var service = new MaterialsService();
using var template = service.BuildTemplate(); // 生成模板(仅表头的 xlsx,发给用户)
using var filled = service.Fill(data); // 强类型数据 → 填充后的 xlsx(导出)
var validation = service.Validate(template); // 校验上传的模板与契约匹配(缺列/错位列清单)
var parsed = service.Parse(filled); // 读回文件 → 强类型 MaterialsData(导入)
// BuildTemplate / Fill 返回内存流,需要落盘时:
using var file = File.Create("filled.xlsx");
filled.CopyTo(file);TData 甚至可以直接是 List<MaterialLine>(根集合,契约表格的 DataPath 留空)——Fill(list) / Parse(stream) 不用包一层容器对象。
- 契约 = 元素清单:
TemplateContract描述场景有哪些元素(TextElement/ImageElement/TableElement),可序列化、可版本化。表头列名、校验规则、导入导出的键,都从这一份声明来。 - 模板归业务应用:契约不产出版式。业务服务在
BuildInitialTemplate()里用插件的类型化构建器组装版式(标题、表格、图片占位、页眉页脚);也可以让设计师直接用 Word 做,Validate统一兜底。 - 数据形状
FillData:与插件无关的弱类型容器。契约元素声明DataPath后由DataPathMapper自动映射(默认),或手写MapToData/MapFromData完全掌控。 - 校验与诊断:Word/Excel 用
FillDetailed/ParseDetailed获取告警;引擎转换失败保留原文,默认强类型映射保留属性默认值。完整说明见校验与解析规则。Simple 使用独立的Validate/Parse,见格式差异。 - 服务生命周期:Word/Excel 模板生成按实例串行,不代表整个服务线程安全;共享实例前请阅读生命周期规则。
单据打印这类复杂版式用 TemplateService<TData, TBuilder>——继承时声明插件构建器类型,版式能力就是构建器的方法。以下为结构片段,省略 DTO、契约与页眉回调;可运行项目见下方示例:
public sealed class DeliveryOrderService : TemplateService<DeliveryOrderData, WordTemplateBuilder>
{
public DeliveryOrderService() : base(new WordTemplateEngine()) { }
protected override TemplateContract DefineContract() => /* 元素清单 */;
protected override void BuildInitialTemplate()
{
Builder.SetPageSetup(new PageSetup { Size = PageSize.A5, Orientation = PageOrientation.Landscape });
Builder.AddHeader(BuildHeader);
Builder.AddTable("Lines", ["序号", "物料名称", "数量"],
new TableFormat { ColumnWidthsCm = [1.8, 8.5, 3.2] });
Builder.AddImage("QrCode", widthInches: 1.0, heightInches: 1.0);
}
}WordTemplateBuilder:SetPageSetup/AddHeader/AddFooter/AddParagraph/AddText/AddElement/AddTable/AddImage/AddPageNumber/AddLayoutTable/AddCell……ExcelTemplateBuilder:SetSheetName/AddText(单元格, 文本)/AddElement/AddTable/AddImage/MergeCells/SetColumnWidth……- Word 用 SDT tag,Excel 用命名区域(
TF_<Key>);编辑时须保留标记、有效引用与表格结构,每次填充都从未填充的原始模板开始。详见格式规则。
多语言:版式文本 / 表头可用 i18n 键方法(AddParagraphKey / AddTableKeys 等),BuildInitialTemplateFile(CultureInfo?) 按语言出模板;运行时消息(校验 / 异常)中英双语按 CurrentUICulture 自动。详见设计文档。
samples/ 提供 8 个控制台 Demo(Word / Excel / Excel.Simple × 手写映射 / 自动映射 / i18n),运行命令与输出说明见 docs/DEMOS.md。比如送货单 Word 版:
dotnet run --project samples/TemplateFrame.Demo.Word| 文档 | 内容 |
|---|---|
| docs/DESIGN.md | 架构与设计决策(三层拆分、定位机制、校验模型、决策记录) |
| docs/DEMOS.md | 8 个 Demo 的运行命令与输出说明 |
| docs/ROADMAP.md | 迭代路线图(已归档 + 规划) |
| docs/PUBLISHING.md | 发布流程(打 v* tag 自动发 GitHub Release + nuget.org) |
| docs/PERFORMANCE.md | 性能快照(三插件吞吐/分配实测 + 基准复现) |
| CHANGELOG.md | 变更日志 |
| 插件 README | Word · Excel · Excel.Simple |
开发使用 global.json 固定的 .NET 10 SDK;测试覆盖 net8.0 / net472 / net10.0,样例运行于 .NET 10。输入文档默认启用可配置资源限额,部署补丁、调用示例和审计命令见 安全与开发环境说明。直接使用系统级 dotnet 命令。
dotnet build TemplateFrame.slnx
dotnet test TemplateFrame.slnxdotnet pack src/TemplateFrame/TemplateFrame.csproj -c Release -o artifacts
dotnet pack src/TemplateFrame.Word/TemplateFrame.Word.csproj -c Release -o artifacts
dotnet pack src/TemplateFrame.Excel/TemplateFrame.Excel.csproj -c Release -o artifacts
dotnet pack src/TemplateFrame.Excel.Simple/TemplateFrame.Excel.Simple.csproj -c Release -o artifacts包内置 XML 文档与 README,符号包(snupkg)一并输出;版本号统一写在 src/Directory.Build.props,发布流程见 docs/PUBLISHING.md。