This guide will help you generate Word Documents using MS OpenXML library in .NET core with the help of an OutputFormatter
The projec tuses .NET Core 2.0 and OpenXml 2.8.1 and creates Word Documents (Docx) using Microsoft OpenXml library. The solution relies on .NET OutputFormatter to create a file using a template (DataExport folder).
Here's a quick setup:
- Add DocumentFormat.OpenXml 2.8.1 NuGet package as dependency
public class DemoDto
{
public string Welcome { get; set; }
public string HelloWorld { get; set; }
}
public class WordOutputFormatter : OutputFormatter
{
public string ContentType { get; }
public WordOutputFormatter()
{
ContentType = "application/ms-word";
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse(ContentType));
}
public override bool CanWriteResult(OutputFormatterCanWriteContext context)
{
return context.Object is DemoDto;
}
// this needs to be overwritten
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context)
{
var response = context.HttpContext.Response;
var filePath = string.Format("./DataExport/myfile-{0}.docx", DateTime.Now.Ticks);
var templatePath = string.Format("./DataExport/my-template.docx");
var viewModel = context.Object as DemoDto;
//open the template then save it as another file (while also stream it to the user)
byte[] byteArray = File.ReadAllBytes(templatePath);
using (MemoryStream mem = new MemoryStream())
{
mem.Write(byteArray, 0, (int)byteArray.Length);
//to create a new document
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(mem, true))
{
var body = wordDoc.MainDocumentPart.Document.Body;
var paras = body.Elements<Paragraph>();
//append some stuff to the document
Paragraph p = new Paragraph();
Run r = new Run();
Text t = new Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent quam augue, tempus id metus in, laoreet viverra quam. Sed vulputate risus lacus, et dapibus orci porttitor non.");
r.Append(t);
p.Append(r);
body.Append(p);
p = new Paragraph();
r = new Run();
t = new Text(viewModel.HelloWorld);
r.Append(t);
p.Append(r);
body.Append(p);
wordDoc.Close();
}
using (FileStream fileStream = new FileStream(filePath, System.IO.FileMode.CreateNew))
{
mem.WriteTo(fileStream);
mem.Close();
fileStream.Close();
}
response.Headers.Add("Content-Disposition", "inline;filename=MyFile.docx");
response.ContentType = "application/ms-word";
await response.SendFileAsync(filePath);
}
}
In the Startup.cs
services.AddMvc(config =>
{
config.OutputFormatters.Add(new WordOutputFormatter());
config.FormatterMappings.SetMediaTypeMappingForFormat(
"docx", MediaTypeHeaderValue.Parse("application/ms-word"));
});
[Route("api/[controller]")]
[Produces("application/ms-word")]
public class DemoController : Controller
{
[HttpGet("Export")]
[Produces("application/ms-word")]
public async Task<IActionResult> Export()
{
try
{
var demoDto = new DemoDto() { Welcome = "Lorem Ipsum", HelloWorld = "Hello World!!!" };
return Ok(demoDto);
}
catch (Exception ex)
{
//log the exception
return BadRequest();
}
}
}
Add Swashbuckle.AspNetCore (2.3+) as a dependency In your startup file (Startup.cs) ConfigureServices method, after the MVC configuration:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info { Title = "My App!", Version = "v1" });
});
In the Startup.cs Configure method, add the following
app.UseSwagger(c => { c.RouteTemplate = "api/swagger/{documentName}/swagger.json"; });
app.UseSwaggerUI(c => { c.SwaggerEndpoint("v1/swagger.json", "My App Api"); c.RoutePrefix = "api/swagger"; });
Swagger: http://localhost:5000/api/swagger/index.html
Directly navigate: http://localhost:5000/api/export/demo