HTL.Aspose.MergeTemplate
1.0.5
dotnet add package HTL.Aspose.MergeTemplate --version 1.0.5
NuGet\Install-Package HTL.Aspose.MergeTemplate -Version 1.0.5
<PackageReference Include="HTL.Aspose.MergeTemplate" Version="1.0.5" />
<PackageVersion Include="HTL.Aspose.MergeTemplate" Version="1.0.5" />
<PackageReference Include="HTL.Aspose.MergeTemplate" />
paket add HTL.Aspose.MergeTemplate --version 1.0.5
#r "nuget: HTL.Aspose.MergeTemplate, 1.0.5"
#:package HTL.Aspose.MergeTemplate@1.0.5
#addin nuget:?package=HTL.Aspose.MergeTemplate&version=1.0.5
#tool nuget:?package=HTL.Aspose.MergeTemplate&version=1.0.5
Aspose.MergeTemplate
Thư viện trộn dữ liệu vào mẫu Excel hoặc Word (lưu trên MinIO thông qua IStorageService) và xuất ra Excel/Word/PDF bằng Aspose.
MergeAsync tự nhận diện đuôi template:
.xls/.xlsx→ logic Excel (Aspose.Cells).doc/.docx→ logic Word (Aspose.Words)
Đăng ký DI
services.AddAsposeMergeTemplate(configuration);
AppSettings ví dụ:
{
"AsposeMergeTemplate": {
"TemplateStorageType": 2,
"OutputStorageType": 0,
"TemplatePrefix": ""
}
}
Cách dùng
var svc = serviceProvider.GetRequiredService<IMergeTemplateService>();
var result = await svc.MergeAsync(new MergeTemplateRequest
{
AppCode = "System",
TenantCode = tenantCode,
TemplateName = "mau-in/phieu-thu.xlsx", // hoặc .docx
Data = mergeData, // MergeTemplateData (contracts thuần), không phụ thuộc HTL.Domain.Core
ExportExcel = true, // với Word: xuất file .doc/.docx
ExportPdf = true,
// (Tuỳ chọn)
// CellValueHandle = new MyCustomCellValueHandle(), // Excel
// WordCellValueHandle = new MyWordCellValueHandle(), // Word
// NumberFormatter = new AppMergeNumberFormatter() // Excel + Word
// ExcelAfterMergeHandle = new MyExcelAfterMerge(), // sau khi trộn Excel
// WordAfterMergeHandle = new MyWordAfterMerge() // sau khi trộn Word
});
// Excel: result.OutputExcelPath / result.OutputPdfPath
// Word: result.OutputWordPath / result.OutputPdfPath
Format giá trị (Excel + Word)
MergeTemplateService ủy quyền format qua BaseMergeNumberFormatter (request → DI → DefaultMergeNumberFormatter).
MergeDataType built-in
| DataType | Default |
|---|---|
| Integer | N0 |
| Decimal | N2 |
| UnitPrice | N2 |
| Currency | N0 |
| Percent | N2 + % (không ×100) |
| ConvertToWords | số → chữ tiếng Việt (MergeNumberToWords) |
| Date | dd/MM/yyyy |
| DateTime | dd/MM/yyyy HH:mm:ss |
| Time | HH:mm:ss |
| ConvertDateVn | Ngày dd tháng MM năm yyyy |
| Boolean / Year | như tên |
Meta tùy chọn: MergeMetaKeys.DecimalPlaces, MergeMetaKeys.FormatKey.
Mở rộng kiểu mới (không sửa library)
public class AppMergeNumberFormatter : BaseMergeNumberFormatter
{
protected override void RegisterFormatters()
{
Register("SoKm", (cell, value, ct) =>
{
if (TryParseDecimal(value, out var n))
return Task.FromResult<string?>(FormatWithPlaces(n, GetDecimalPlaces(cell, 1)));
return Task.FromResult(value.ToString());
});
}
public override string FormatCurrency(decimal value, MergeCellValue? cell = null)
=> NumberFormatter.FormatNumber(value, 0, ",");
}
// DI: services.AddScoped<BaseMergeNumberFormatter, AppMergeNumberFormatter>();
// hoặc request.NumberFormatter = new AppMergeNumberFormatter();
cell.DataType = MergeDataType.Custom;
cell.Meta[MergeMetaKeys.FormatKey] = "SoKm";
Custom AfterMerge (sau khi trộn xong)
Hook gọi sau khi trộn master / detail / print options (Excel), trước khi xóa placeholder ##...## còn lại và Save. Caller tự chỉnh header, bảng (merge hàng/cột), footer trên Workbook / Document.
Ưu tiên resolve: request → DI → bỏ qua nếu không có.
public class MyExcelAfterMerge : IExcelAfterMergeHandle
{
public Task AfterMergeAsync(MergeAfterContext context, Workbook workbook, CancellationToken ct)
{
var sheet = workbook.Worksheets[0];
// Header / Table / Footer — thao tác trực tiếp Aspose.Cells
// context.Data.PrintOptions, Details, ColumnInfoDetails...
return Task.CompletedTask;
}
}
public class MyWordAfterMerge : IWordAfterMergeHandle
{
public Task AfterMergeAsync(MergeAfterContext context, Document document, CancellationToken ct)
{
// HeaderFooter, Table, ... — thao tác trực tiếp Aspose.Words
return Task.CompletedTask;
}
}
// Per-request
request.ExcelAfterMergeHandle = new MyExcelAfterMerge();
request.WordAfterMergeHandle = new MyWordAfterMerge();
// hoặc DI
// services.AddScoped<IExcelAfterMergeHandle, MyExcelAfterMerge>();
// services.AddScoped<IWordAfterMergeHandle, MyWordAfterMerge>();
Custom handle Word
Tương đương ICellValueHandle của Excel — gọi trước replace:
// request.WordCellValueHandle = new MyWordHandle();
// hoặc services.AddScoped<IWordCellValueHandle, MyWordHandle>();
Có thể set cellValue.StringValue trong handle để bỏ qua formatter.
Style font khi replace Word
Khi MergeCellValue.Meta có style, thư viện gắn IReplacingCallback (DocumentBuilder) để set Bold/Italic/màu/cỡ chữ.
cell.Meta[MergeMetaKeys.StyleJson] = new CustomStyleCell
{
sFontName = "Arial",
iFontSize = 14,
sFontStyle = "Bold", // Bold | Italic | Strikeout | Underline
sColor = "#FF0000"
};
// hoặc Meta["sFontStyle"] / Meta["iFontSize"] / Meta["sColor"] / Meta["sFontName"]
Override style nâng cao:
public class MyWordHandle : BaseWordCellValueHandle
{
protected override void ApplyFont(DocumentBuilder builder, CustomStyleCell style)
{
base.ApplyFont(builder, style);
builder.Font.Italic = true;
}
// hoặc override CreateFindReplaceOptions / CreateReplacingCallback
}
Tùy chọn xuất PDF (Excel)
Cấu hình qua MergeTemplateData.PrintOptions:
sPdfPresetId |
FitWide | FitTall | OnePagePerSheet |
|---|---|---|---|
table (mặc định) |
true | false | false |
dashboard |
true | true | true |
original |
false | false | false |
custom |
theo bFitToPagesWide / bFitToPagesTall / bOnePagePerSheet |
mergeData.PrintOptions = new MergePrintOptions
{
sPdfPresetId = "table",
// Font fallback (Excel + Word): chủ yếu tên font; KHÔNG set iFontSize để giữ size trên mẫu.
// Size chỉ đổi khi Meta/CustomStyleCell ô chỉ định. Ưu tiên: Meta ô → template → DefaultFont.
DefaultFont = new CustomStyleCell
{
sFontName = "Times New Roman",
sColor = "#000000"
},
// Border cả bảng (Excel + Word); ô có thể ghi đè qua CustomStyleCell
TableBorder = new MergeTableBorderOptions
{
Enabled = true,
sBorderStyle = "Thin", // None | Thin | Medium | Thick | Dashed | Dotted
sBorderColor = "#000000",
bBorderTop = true,
bBorderBottom = true,
bBorderLeft = true,
bBorderRight = true
}
};
// Border theo ô (ghi đè TableBorder)
cell.Meta[MergeMetaKeys.StyleJson] = new CustomStyleCell
{
sBorderStyle = "Medium",
sBorderColor = "#333333",
bBorderTop = true,
bBorderBottom = true,
bBorderLeft = false,
bBorderRight = false
};
Quy ước mẫu Word
- Master:
##TenTruong## - Detail: đặt Bookmark trùng key trong
Details(vdChiTiet); trong bảng có 1 dòng mẫu chứa##ChiTiet.TenCot## - Sau merge, placeholder
##...##còn lại sẽ bị xóa
Cột động Word (giống Excel)
Dùng cùng Metadata.DynamicColumnRules + ColumnInfoDetails. Trong bảng Word (bookmark = tableName), bố cục 3 hàng quanh ô neo:
| Hàng | Nội dung |
|---|---|
| Hàng trên ô neo | ParentName (group header, tùy chọn) |
| Hàng ô neo | ##{tableName}.{key}## (vd ##ChiTiet.SoLuong##) |
| Hàng dưới ô neo | được gán ##{tableName}.{FieldName}## cho từng cột động |
Thư viện insert thêm ô theo số cột, gán Text/ParentName, merge ngang group cùng ParentName, rồi mới clone dòng detail.
Hướng dẫn merge cột động (Dynamic Columns)
1) Quy ước trong file Excel template
- Ô neo (anchor cell): đặt 1 ô chứa placeholder theo dạng:
##{tableName}.{key}##- Ví dụ:
##ChiTiet.SoLuong##
- Thư viện sẽ dùng ô neo này để xác định vị trí bắt đầu sinh cột động.
- Nếu template của bạn có header 2 tầng (group header):
- Tầng group nằm ở hàng trên của ô neo (rowIndex - 1)
- Tầng tên cột nằm ở đúng hàng của ô neo (rowIndex)
- Dòng template để binding detail nằm ở hàng dưới (rowIndex + 1) và sẽ được set thành
##{tableName}.{FieldName}##
2) Khai báo rule sinh cột động (Metadata.DynamicColumnRules)
Bạn khai báo các rule để “bật” cột động tại các anchor key trong template:
mergeData.Metadata.DynamicColumnRules.Add(new MergeDynamicColumnRule
{
Id = 1,
TableName = "ChiTiet",
Key = "SoLuong", // khớp với ##ChiTiet.SoLuong##
IsDynamic = true,
ResultIndex = 0 // sẽ map với ColumnInfoDetails["ChiTiet"]["0"]
});
3) Truyền danh sách cột động thực tế (ColumnInfoDetails)
MergeTemplateData.ColumnInfoDetails có cấu trúc:
tableName→resultIndex(string)→List<MergeColumnDynamicInfo>
Trong đó mỗi MergeColumnDynamicInfo mô tả 1 cột được sinh:
GroupIndex: phải bằngDynamicColumnRule.Idđể rule biết cột nào thuộc anchor nàoText: tiêu đề cộtFieldName: tên field để sinh placeholder ở dòng template:##{tableName}.{FieldName}##ParentName(tuỳ chọn): nếu có sẽ tạo group header và tự merge theo nhóm cùngParentNameWidth: độ rộng cộtDataType: kiểu dữ liệu để format mặc định
Ví dụ:
mergeData.ColumnInfoDetails["ChiTiet"] = new Dictionary<string, List<MergeColumnDynamicInfo>>
{
["0"] = new List<MergeColumnDynamicInfo>
{
new()
{
GroupIndex = 1,
Text = "Kỳ 1",
FieldName = "SoLuongKy1",
ParentName = "Số lượng",
Width = 12,
DataType = MergeDataType.Decimal
},
new()
{
GroupIndex = 1,
Text = "Kỳ 2",
FieldName = "SoLuongKy2",
ParentName = "Số lượng",
Width = 12,
DataType = MergeDataType.Decimal
}
}
};
4) Lưu ý quan trọng
- Nếu số cột động lớn hơn số cột đang merge trong template, thư viện sẽ Insert thêm cột và tự gán header/template.
- Nếu anchor cell đang merge, thư viện sẽ tự unmerge/merge lại để khớp số lượng cột động.
- Dữ liệu detail thật khi merge vẫn lấy theo
Details[tableName]và placeholder##{tableName}.{field}##ở dòng template.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Aspose.Cells (>= 21.10.0)
- Aspose.Words (>= 21.6.0)
- HTL.Infrastructure.Storage (>= 1.0.7)
- Microsoft.Extensions.DependencyInjection (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 8.0.0)
- PDFsharp (>= 6.1.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.