Category / Section
How to perform mail merge in ASP.NET MVC?
4 mins read
You can insert fields into the Document Editor and perform mail merge using the Syncfusion® DocIO library on the server side, and then view the merged document in the Document Editor control.
CSHTML
<div> <div style="margin-bottom:12px"> <button onclick="mergeDocument()" class="e-control e-btn e-primary">Merge Document</button> </div> <div style="display:flex"> <div style="width:15%;border:1px solid #e0e0e0"> <b><label style="display:block;margin:10px">Select Field to Insert</label></b> @Html.EJS().ListView("listview").Enable(true).Select("onFieldSelect").DataSource((IEnumerable<object>)ViewBag.dataSource).Render() </div> <div style="width:85%;border:1px solid #e0e0e0"> @Html.EJS().DocumentEditor("container").IsReadOnly(false).EnableSelection(true).EnableEditor(true).EnableEditorHistory(true).EnableWordExport(true).Created("onCreated").Render() </div> </div> <div class="overlay" id="popup-overlay" style="display: none;"></div> <div id='waiting-popup' style="display: none;"> <svg class="circular" height="40" width="40"> <circle class="circle-path" cx="25" cy="25" r="20" fill="none" stroke-width="6" stroke-miterlimit="10" /> </svg> </div> </div>
JS
var documenteditor; var listView; function onCreated() { documenteditor = document.getElementById("container").ej2_instances[0]; JS documenteditor.pageOutline ="#e0e0e0" listView = document.getElementById("listview").ej2_instances[0]; documenteditor.resize(); } function onFieldSelect(args) { let fieldName = args.data.text; listView.selectItem(undefined) insertField(fieldName); } function insertField(fieldName) { fileName = fieldName.replace(/\n/g, '').replace(/\r/g, '').replace(/\r\n/g, ''); var fieldCode = 'MERGEFIELD ' + fileName + " \\* MERGEFORMAT "; documenteditor.editor.insertField(fieldCode, '«' + fieldName + '»'); documenteditor.focusIn(); } function mergeDocument() { documenteditor.saveAsBlob("Docx").then(function (blob) { var fileReader = new FileReader(); fileReader.onload = function () { var base64String = fileReader.result; var data = { fileName: documenteditor.documentName + '.docx', documentData: base64String } showHideWaitingIndicator(true) var httpRequest = new XMLHttpRequest(); httpRequest.open('Post', '/api/DocumentEditor/MailMerge', true); httpRequest.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); httpRequest.onreadystatechange = function () { if (httpRequest.readyState === 4) { if (httpRequest.status === 200 || httpRequest.status === 304) { documenteditor.open(httpRequest.responseText); } else { // Failed to merge document } showHideWaitingIndicator(false); } }; httpRequest.send(JSON.stringify(data)); } fileReader.readAsDataURL(blob); }); } function showHideWaitingIndicator(show) { document.getElementById("popup-overlay").style.display = show ? 'block' : 'none'; document.getElementById("waiting-popup").style.display = show ? 'block' : 'none'; }
Controller
public ActionResult Index() { List<object> listdata = new List<object>(); listdata.Add(new { text = "FirstName", id = "_firstname", }); listdata.Add(new { text = "LastName", id = "_lastname", }); listdata.Add(new { text = "CustomerID", id = "_customerid", }); listdata.Add(new { text = "EmailID", id = "_emailid", }); listdata.Add(new { text = "MobileNo", id = "_mobileno", }); ViewBag.dataSource = listdata; return View(); }
Web API
[HttpPost] public HttpResponseMessage MailMerge([FromBody]ExportData exportData) { Byte[] data = Convert.FromBase64String(exportData.documentData.Split(',')[1]); MemoryStream stream = new MemoryStream(); stream.Write(data, 0, data.Length); stream.Position = 0; try { Syncfusion.DocIO.DLS.WordDocument document = new Syncfusion.DocIO.DLS.WordDocument(stream, Syncfusion.DocIO.FormatType.Docx); document.MailMerge.RemoveEmptyGroup = true; document.MailMerge.RemoveEmptyParagraphs = true; document.MailMerge.ClearFields = true; document.MailMerge.Execute(CustomerDataModel.GetAllRecords()); SplitEachRecords(document); document.Save(stream, Syncfusion.DocIO.FormatType.Docx); } catch (Exception ex) { } // Write Pdf stream here. return new HttpResponseMessage() { Content = new StringContent(ImportWordDocument(stream)) }; } public string ImportWordDocument(Stream stream) { string sfdtText = ""; Syncfusion.EJ2.DocumentEditor.WordDocument document = Syncfusion.EJ2.DocumentEditor.WordDocument.Load(stream, Syncfusion.EJ2.DocumentEditor.FormatType.Docx); sfdtText = Newtonsoft.Json.JsonConvert.SerializeObject(document); document.Dispose(); return sfdtText; } private void SplitEachRecords(Syncfusion.DocIO.DLS.WordDocument document) { TextSelection[] textSelections = document.FindAll("#PageBreak", true, true); if (textSelections != null) { foreach (TextSelection selection in textSelections) { WParagraph paragraph = selection.GetAsOneRange().OwnerParagraph; paragraph.Text = string.Empty; paragraph.InsertSectionBreak(SectionBreakCode.NewPage); } } } private void ApplyBoldFormatting(object sender, MergeFieldEventArgs args) { if (args.FieldName == "IsDefault") { if (args.FieldValue.ToString() == "Yes") isApplyBold = true; else isApplyBold = false; } else if (args.FieldName == "FirstName") { if (isInsertBreak) { bool isInCell = args.CurrentMergeField.OwnerParagraph.Owner is WTableCell; bool isInTextBox = args.CurrentMergeField.OwnerParagraph.Owner is WTextBox; bool isInContentControl = args.CurrentMergeField.OwnerParagraph.Owner is BlockContentControl; WParagraph paragraph; if (isInCell) { WTableCell ownerCell = args.CurrentMergeField.OwnerParagraph.Owner as WTableCell; paragraph = ownerCell != null ? (ownerCell.OwnerRow.Owner as WTable).PreviousSibling.PreviousSibling as WParagraph : args.CurrentMergeField.OwnerParagraph.PreviousSibling as WParagraph; } else if (isInTextBox) { WTextBox textBox = args.CurrentMergeField.OwnerParagraph.Owner as WTextBox; paragraph = textBox.OwnerParagraph.PreviousSibling.PreviousSibling is WParagraph ? textBox.OwnerParagraph.PreviousSibling.PreviousSibling as WParagraph : args.CurrentMergeField.OwnerParagraph; } else if (isInContentControl) { BlockContentControl contentControl = args.CurrentMergeField.OwnerParagraph.Owner as BlockContentControl; paragraph = contentControl.PreviousSibling.PreviousSibling as WParagraph; } else paragraph = args.CurrentMergeField.OwnerParagraph.PreviousSibling.PreviousSibling as WParagraph; paragraph.Text = "#PageBreak"; } else isInsertBreak = true; } if (isApplyBold) { foreach (Entity entity in args.CurrentMergeField.OwnerParagraph.Items) { if (entity is WTextRange) (entity as WTextRange).CharacterFormat.Bold = true; } // Apply the bold formatting to the adjacent cell. WTableCell cell = args.CurrentMergeField.OwnerParagraph.Owner.PreviousSibling as WTableCell; ApplyBoldFormattingForCell(cell); } } private void ApplyBoldFormattingForCell(WTableCell cell) { foreach (WParagraph paragraph in cell.Paragraphs) { foreach (Entity entity in paragraph.Items) { if (entity is WTextRange) (entity as WTextRange).CharacterFormat.Bold = true; } } }
Sample: https://www.syncfusion.com/downloads/support/directtrac/general/ze/Mail_Merge_Sample1301778016
In the previous sample, a list view has been added in the left pane, which shows a list of fields that can be inserted into the Document Editor.
On selecting the list item, the corresponding field will be inserted into the Document Editor. After inserting the field, you can perform mail merge on the server side and view the merged document by clicking the merge document button.