Generating a Word Document on the fly using .NET Core

Here, we have a web application with a .NET core backend running on Azure. Using Office SDK for this purpose was ruled out for this reason. We needed something free, open-source, and supported on.
Generating a Word Document
Share
In this article

We had an interesting requirement in one of our projects wherein we needed to generate a Word document on the fly. Here, we have a web application with a .NET core backend running on Azure. Using Office SDK for this purpose was ruled out for this reason. We needed something free, open-source, and supported on .Net core. We zeroed in on the .NET version of the Apache POI project (simplified as NPOI).

NPOI is a .NET library that can read or write in office formats without Microsoft Office installed. It doesn’t need COM+ or interop. Yes, not only Word but other Office documents as well. For our use case, we will just focus on generating a simple Word document to demonstrate the features of NPOI.

Let’s see a quick example of how we can utilize NPOI to create a Word document.

The first step is to create a new .NET core project. Here, I’m using .NET 8. Next, add the NPOI Nuget package. And now, it all begins…

Create a new Word document in memory

 XWPFDocument wordDoc = new XWPFDocument();

We can create a Header and Footer:

XWPFHeaderFooterPolicy headerFooterPolicy = wordDoc.GetHeaderFooterPolicy();
if (headerFooterPolicy == null) headerFooterPolicy = wordDoc.CreateHeaderFooterPolicy();
// create header and add a test header
XWPFHeader header = headerFooterPolicy.CreateHeader(XWPFHeaderFooterPolicy.DEFAULT);
XWPFParagraph paragraph1 = header.CreateParagraph();
paragraph1.Alignment = (ParagraphAlignment.LEFT);
XWPFRun run1 = paragraph1.CreateRun();
run1.SetText("Header Test");
// create footer
XWPFFooter footer = headerFooterPolicy.CreateFooter(XWPFHeaderFooterPolicy.DEFAULT);

Now, we add a simple copyright in the footer

// add copyright
var paragraph2 = footer.CreateParagraph();
paragraph2.Alignment = (ParagraphAlignment.CENTER);
XWPFRun run2 = paragraph2.CreateRun();
run2.SetText("© 2024 Devon Software & Services Pvt. Ltd.");

Next step, we can add an image to the header

// Add an image in the header
const string imageName = "sampleImage.png";
XWPFRun run = AddImage(paragraph1.CreateRun(), imageName, 50, 50);

Add Image Method looks like this:

public static XWPFRun AddImage(XWPFRun run, string imageName, int width, int height)
{
    var widthEmus = (int)(width * 9525 * 0.75);
    var heightEmus = (int)(height * 9525 * 0.75);
    using (FileStream picData = new FileStream(imageName, FileMode.Open, FileAccess.Read))
    {
        run.AddPicture(picData, (int)NPOI.XWPF.UserModel.PictureType.PNG, imageName, widthEmus, heightEmus);
    }
    return run;
}

Configure page margins:

// Add Page Margins
CT_SectPr sectPr = wordDoc.Document.body.sectPr;
CT_PageMar pageMar = sectPr.AddPageMar();
pageMar.left = 720; //720 Twentieths of an Inch Point (Twips) = 720/20 = 36 pt = 36/72 = 0.5"
pageMar.right = 720;
pageMar.top = 720; //1440 Twips = 1440/20 = 72 pt = 72/72 = 1"
pageMar.bottom = 720;
pageMar.header = 72; //45.4 pt * 20 = 908 = 45.4 pt header from top
pageMar.footer = 72; //28.4 pt * 20 = 568 = 28.4 pt footer from bottom

 

Create a table and set its layout to fixed

// Create a table
 XWPFTable exampleTable = wordDoc.CreateTable(3, 2);
 exampleTable.SetColumnWidth(0, 3500);
 exampleTable.SetColumnWidth(1, 7000);
 // Set Table Layout to fixed
 SetTableLayoutToFixed(exampleTable);

Hide table borders

// Hide table borders
exampleTable = HideBorders(exampleTable);
public static XWPFTable HideBorders(XWPFTable table)
{
    // Vanish borders
    table.SetBottomBorder(XWPFTable.XWPFBorderType.NONE, 0, 0, "WHITE");
    table.SetTopBorder(XWPFTable.XWPFBorderType.NONE, 0, 0, "WHITE");
    table.SetLeftBorder(XWPFTable.XWPFBorderType.NONE, 0, 0, "WHITE");
    table.SetRightBorder(XWPFTable.XWPFBorderType.NONE, 0, 0, "WHITE");
    table.SetInsideHBorder(XWPFTable.XWPFBorderType.NONE, 0, 0, "WHITE");
    table.SetInsideVBorder(XWPFTable.XWPFBorderType.NONE, 0, 0, "WHITE");
    return table;
}

Add some content to a table cell

// Add contents to a cell
XWPFTableCell cell1 = exampleTable.GetRow(0).GetCell(0);
XWPFParagraph paragraph4 = cell1.AddParagraph();
paragraph4.Alignment = ParagraphAlignment.CENTER;
XWPFRun run4 = paragraph4.CreateRun();
run4.SetText(" Some random text...");
run4.SetColor("FF5000");
run4.FontFamily = "Josefin Sans";
run4.FontSize = 14;
run4.IsBold = true;

Some Bullet examples:

A simple bullet example

public void SimpleBulletExample(XWPFDocument doc, XWPFTableCell cell)
 {
     XWPFNumbering numbering = doc.CreateNumbering();
     string abstractNumId = numbering.AddAbstractNum();
     string numId = numbering.AddNum(abstractNumId);
     XWPFParagraph p0 = cell.AddParagraph();
     XWPFRun r0 = p0.CreateRun();
     r0.SetText(fillerText2);
     r0.FontFamily = "Josefin Sans";
     r0.FontSize = 10;
     p0.SetNumID(numId);
     XWPFParagraph p1 = cell.AddParagraph();
     XWPFRun r1 = p1.CreateRun();
     r1.SetText(fillerText2);
     r1.FontFamily = "Josefin Sans";
     r1.FontSize = 10;
     p1.SetNumID(numId);
     XWPFParagraph p2 = cell.AddParagraph();
     XWPFRun r2 = p2.CreateRun();
     r2.SetText(fillerText2);
     r2.FontFamily = "Josefin Sans";
     r2.FontSize = 10;
     p2.SetNumID(numId);
 }

A multi-level bullet example

 public void MultiLevelBulletExample(XWPFDocument doc)
 {
     XWPFNumbering numbering = doc.CreateNumbering();
     var abstractNumId = numbering.AddAbstractNum();
     var numId = numbering.AddNum(abstractNumId);
     doc.CreateParagraph();
     doc.CreateParagraph();
     var p1 = doc.CreateParagraph();
     var r1 = p1.CreateRun();
     r1.SetText("multi level bullet");
     r1.IsBold = true;
     r1.FontFamily = "Courier";
     r1.FontSize = 12;
     p1 = doc.CreateParagraph();
     r1 = p1.CreateRun();
     r1.SetText("first");
     p1.SetNumID(numId, "0");
     p1 = doc.CreateParagraph();
     r1 = p1.CreateRun();
     r1.SetText("first-first");
     p1.SetNumID(numId, "1");
     p1 = doc.CreateParagraph();
     r1 = p1.CreateRun();
     r1.SetText("first-second");
     p1.SetNumID(numId, "1");
     p1 = doc.CreateParagraph();
     r1 = p1.CreateRun();
     r1.SetText("first-third");
     p1.SetNumID(numId, "1");
     p1 = doc.CreateParagraph();
     r1 = p1.CreateRun();
     r1.SetText("second");
     p1.SetNumID(numId, "0");
     p1 = doc.CreateParagraph();
     r1 = p1.CreateRun();
     r1.SetText("second-first");
     p1.SetNumID(numId, "1");
     p1 = doc.CreateParagraph();
     r1 = p1.CreateRun();
     r1.SetText("second-second");
     p1.SetNumID(numId, "1");
     p1 = doc.CreateParagraph();
     r1 = p1.CreateRun();
     r1.SetText("second-third");
     p1.SetNumID(numId, "1");
     p1 = doc.CreateParagraph();
     r1 = p1.CreateRun();
     r1.SetText("second-third-first");
     p1.SetNumID(numId, "2");
     p1 = doc.CreateParagraph();
     r1 = p1.CreateRun();
     r1.SetText("second-third-second");
     p1.SetNumID(numId, "2");
     p1 = doc.CreateParagraph();
     r1 = p1.CreateRun();
     r1.SetText("third");
     p1.SetNumID(numId, "0");
 }

 

Write the in-memory built Word document to a file

string outputFile = AppDomain.CurrentDomain.BaseDirectory + "TestWord" + ".docx";
FileStream resumeOutputFile = new FileStream(outputFile, FileMode.Create);
wordDoc.Write(resumeOutputFile);

 

The generated Word document looks like below

generated Word document
generated Word document

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

These are just a few examples. We have only scratched the tip of the iceberg here.  You can find the example code here https://github.com/ravindrank/NPOI-Word-Demo

Download, build, and run the project yourself to see the code in action.

Applications and Advantages

The applications and advantages are numerous.

  • Being a platform-agnostic library, we can use this on any platform where the .NET core runs (Windows, Linux, MacOS).
  • Open Source code and community supported – Feel free to contribute
  • Totally free to use
  • Support multiple office formats
  • Read as well as Write to office documents
  • Some very good examples

Visit https://github.com/nissl-lab/npoi to know more about NPOI

Available freely on GitHub: nissl-lab/npoi: a .NET library that can read/write Office formats without Microsoft Office installed. No COM+, no interop. (github.com)

Of course, we have a NuGet package available as well: NuGet Gallery | NPOI 2.6.2

Let me know if you are interested in learning more. Glad to hear back if this has helped you. Any feedback/suggestions are welcome!

Share