From shesha-enterprise
Generates Shesha document generation artifacts for producing PDFs or Word documents from Word templates via Aspose mail merge. Creates DTOs, item classes, AutoMapper profiles, application services, controllers, Word template guidance, and sample Word document templates with proper merge fields. Use when the user asks to create, scaffold, or implement document generation, mail merge, Word-to-PDF conversion, Word document generation, document processing, or Word document templates in a Shesha project.
How this skill is triggered — by the user, by Claude, or both
Slash command
/shesha-enterprise:shesha-document-generationThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Generate document generation artifacts for a Shesha/.NET application that uses `Shesha.Enterprise.DocumentProcessing` to produce PDFs or Word documents from Word templates via Aspose mail merge, based on $ARGUMENTS.
Generate document generation artifacts for a Shesha/.NET application that uses Shesha.Enterprise.DocumentProcessing to produce PDFs or Word documents from Word templates via Aspose mail merge, based on $ARGUMENTS.
AsposeBuilderBase.GetTemplate()StoredFile on the entityStoredFile property on an entity (e.g., a config entity's template field), uses IStoredFileService.GetStreamAsync() to load and Aspose directly for mail mergedocument.Save(stream, SaveFormat.Pdf)document.Save(stream, SaveFormat.Docx), preserving editabilitySheshaAppServiceBase, auto-registered as API endpointControllerBase, manual [Route]/[HttpGet] attributesControllerBase, uses Dictionary<string, object> instead of a typed DTODocumentDto instead of PdfDto in class names and Documents instead of PdfDocuments in folder names. When PDF or Both, keep PdfDto/PdfDocuments.string (pre-formatted) unless they are byte[] (signatures/images) or DataTable/DataSet (regions).{Placeholder} tokens throughout generated code so the user can replace them with project-specific values..docx) with the correct merge fields for easy testing and subsequent modification?" If yes, generate the template using word-template-generator.md.w:fldChar begin/separate/end) — never w:fldSimple. See word-template-generator.md for the full reference.When generating sample .docx templates:
w:fldChar complex field characters (begin → instrText → separate → display → end). The w:fldSimple element does NOT produce real merge fields recognized by Word or Aspose.TableStart:RegionName and TableEnd:RegionName merge fields. Place them in separate table rows around the data row. The data row (containing field merge fields) is the one that repeats. Aspose removes the marker rows during mail merge.TableStart/TableEnd must be physically nested inside the parent's start/end markers.P0, P1, ..., P7).node_modules, package-lock.json, and the generator script after template generation.| # | Artifact | Layer | Template |
|---|---|---|---|
| 1 | PDF DTO | Application | dto-and-items.md SS1 |
| 2 | Item Class (for regions) | Application | dto-and-items.md SS2 |
| 3 | AutoMapper Profile | Application | dto-and-items.md SS3 |
| 4 | Application Service | Application | document-service.md SS1 |
| 5 | Controller | Application | document-service.md SS2 |
| 6 | Dictionary-based Controller | Application | document-service.md SS3 |
| 7 | Word Document Output (no PDF) | Application | document-service.md SS5 |
| 8 | Embedded Resource variant | Application | document-service.md SS4 |
| 9 | StoredFile template source | Application | document-service.md SS6 |
| 10 | Module/NuGet setup | Domain/Application | setup-and-templates.md SS1 |
| 11 | Word template design guide | N/A | setup-and-templates.md SS2 |
| 12 | Sample Word template (.docx) | N/A | word-template-generator.md |
{ModuleName}.Application/
PdfDocuments/{DocumentName}/
{DocumentName}AppService.cs -- or {DocumentName}Controller.cs
Dtos/
{DocumentName}PdfDto.cs
{ItemName}Section.cs -- one per repeating region
{DocumentName}MappingProfile.cs -- if using typed DTO + AutoMapper
Shesha.Enterprise.DocumentProcessing| Type | Purpose |
|---|---|
DocumentProcessManager | Main service — GenerateAsync<T>(dto, templateName) returns Stream, GetDataTable<T>(list, tableName) returns DataTable |
FileTemplateConfiguration | Maps a template name (string) to a StoredFile in the database |
AsposeBuilderBase | Base class with GetTemplate(), AddPersonSignature(), ReplaceRichTextField(), embedded resource support |
BaseDocumentProcessor | Extended base with field settings parsing, cleanup options, rich text items |
// Generate PDF stream from typed DTO + template name
Stream stream = await _documentProcessManager.GenerateAsync(pdfDto, "TemplateName");
// Convert a list of items to a DataTable for mail merge regions
DataTable table = _documentProcessManager.GetDataTable(items, "RegionName");
// Save generated PDF as a StoredFile
StoredFile file = await _documentProcessManager.SaveFileAsync(stream, ownerType, ownerId, "TemplateName");
Important: MailMergeCleanupOptions requires using Aspose.Words.MailMerging; — this is a separate namespace from Aspose.Words.
using Aspose.Words.MailMerging; // Required for MailMergeCleanupOptions
builder.Document.MailMerge.CleanupOptions =
MailMergeCleanupOptions.RemoveEmptyParagraphs |
MailMergeCleanupOptions.RemoveUnusedFields |
MailMergeCleanupOptions.RemoveUnusedRegions;
// DTO property — byte[] rendered as image in merge field
public byte[] {Role}Signature { get; set; }
// Loading signature bytes from a Person's StoredFile
using var sigStream = await _storedFileService.GetStreamAsync(person.SignatureFile);
using var ms = new MemoryStream();
await sigStream.CopyToAsync(ms);
dto.{Role}Signature = ms.ToArray();
// DTO property
public DataTable {RegionName} { get; set; }
// Building the table
var items = entities.Select(e => new {RegionItem}
{
Name = e.Name,
Value = e.Value?.ToString() ?? ""
}).ToList();
dto.{RegionName} = _documentProcessManager.GetDataTable(items, "{RegionName}");
// Create parent and child tables
var parentTable = _documentProcessManager.GetDataTable(parentItems, "ParentRegion");
var childTable = _documentProcessManager.GetDataTable(childItems, "ChildRegion");
// Build DataSet with relationship
var dataSet = new DataSet();
dataSet.Tables.Add(parentTable.Copy());
dataSet.Tables.Add(childTable.Copy());
dataSet.Relations.Add(new DataRelation("ParentChildRelation",
dataSet.Tables["ParentRegion"].Columns["ParentId"],
dataSet.Tables["ChildRegion"].Columns["ParentId"]));
// Store in DTO
dto.ParentRegion = dataSet.Tables["ParentRegion"];
dto.ChildRegion = dataSet.Tables["ChildRegion"];
dto.ParentChildDataSet = dataSet;
using System.Text.RegularExpressions;
private static string StripHtml(string html)
{
if (string.IsNullOrEmpty(html)) return "";
return Regex.Replace(html, "<.*?>", string.Empty).Trim();
}
Return PDF as download:
using var documentStream = await _documentProcessManager.GenerateAsync(pdfDto, templateName);
using var memoryStream = new MemoryStream();
await documentStream.CopyToAsync(memoryStream);
var bytes = memoryStream.ToArray();
return File(bytes, "application/pdf", fileName);
Return Word document as download (no PDF conversion):
// Use Aspose directly — DocumentProcessManager.GenerateAsync() always returns PDF
var document = new Document(templateStream); // load from FileTemplateConfiguration or embedded resource
document.MailMerge.Execute(fieldNames, fieldValues);
using var memoryStream = new MemoryStream();
document.Save(memoryStream, SaveFormat.Docx);
var bytes = memoryStream.ToArray();
var fileName = $"{DocumentName}_{DateTime.Now:yyyyMMdd}.docx";
return File(bytes, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", fileName);
See document-service.md SS5 for the full application service and controller templates.
Save PDF to entity StoredFile property:
using var documentStream = await _documentProcessManager.GenerateAsync(pdfDto, templateName);
using var memoryStream = new MemoryStream();
await documentStream.CopyToAsync(memoryStream);
memoryStream.Position = 0;
var storedFile = await _storedFileService.SaveFileAsync(
memoryStream,
fileName,
file => { file.FileType = "application/pdf"; });
entity.PdfDocument = storedFile;
await _repository.UpdateAsync(entity);
Generate safe file name:
private static string GenerateFileName(string prefix, string identifier)
{
var fileName = $"{prefix}_{identifier}_{DateTime.Now:yyyyMMdd}.pdf";
return string.Join("_", fileName.Split(Path.GetInvalidFileNameChars()));
}
Now generate the requested artifact(s) based on: $ARGUMENTS
npx claudepluginhub boxfusion/boxfusion-plugins --plugin shesha-enterpriseGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.