In the first blog post, we created a Google Docs like web app that has the following features:
- Rich Text Editing (change text font, size, colour, style (boldface, italic), alignment etc.).
- Real-time collaborative editing of the same document. Multiple users can access the document at the same time and modify it.
- Upload content of an existing Word Document into an editor.
In this blog post, we will extend our web‑application to include the following features:
- Download content of the editor as MS Word, PDF, TXT or HTML document.
- Share the URL with friends so that they can edit the document at the same time.
The final product will look as follows:

- Download Content of the Editor As
- Share URL of an Editor with friends
Download Content of the Editor as Microsoft Word Document
First, add a <input> of type submit to the form to display the “Download Document” button. We use the asp-page-handler attribute to specify the button’s handler. The form now looks like this:
<form method="post" enctype="multipart/form-data" id="uploadForm">
<input asp-for="UploadedDocument" />
<input type="submit" value="Upload Document" class="btn btn-primary" asp-page-handler="UploadDocument" />
<input type="submit" value="Download Document" class="btn btn-primary" asp-page-handler="DownloadDocument" />
<input asp-for="DocumentContent" type="hidden" />
</form>
We also added a hidden <input> bound to the DocumentContent property in Index.cshtml.cs. This property stores the editor’s HTML content.
[BindProperty]
public string DocumentContent { get; set; }
Firepad provides a synced event that fires when the local client edits the document and the changes are saved to Firebase. Attach a callback to set DocumentContent to firepad.getHtml(). Add this code to the init() function in Index.cshtml.
firepad.on('synced', function (isSynced) {
// isSynced will be false immediately after the user edits
// the pad, and true when their edit has been saved to Firebase.
if (isSynced) {
document.getElementById("DocumentContent").value = firepad.getHtml();
}
});
Now implement the OnPostDownloadDocument() handler. We use the GroupDocs.Editor library to convert the HTML stored in DocumentContent to a Microsoft Word file and return it to the user.
public FileResult OnPostDownloadDocument()
{
// Editor object is referencing to the document initially uploaded for editing.
WordProcessingLoadOptions loadOptions = new WordProcessingLoadOptions();
Editor editor = new Editor(UploadedDocumentPath, delegate { return loadOptions; });
// <html>, <head> and <body> tags are missing in the HTML string stored in DocumentContent, so we are adding them manually.
string completeHTML = "<!DOCTYPE html><html><head><title></title></head><body>" + DocumentContent + "</body></html>";
EditableDocument document = EditableDocument.FromMarkup(completeHTML, null);
// Path to the output document
var projectRootPath = Path.Combine(_hostingEnvironment.ContentRootPath, "DownloadedDocuments");
var outputPath = Path.Combine(projectRootPath, Path.GetFileName(UploadedDocumentPath));
// Save the Word Document at the outputPath
WordProcessingSaveOptions saveOptions = new WordProcessingSaveOptions(WordProcessingFormats.Docx);
editor.Save(document, outputPath, saveOptions);
// Return the Word Document as response to the User
var bytes = System.IO.File.ReadAllBytes(outputPath);
return new FileContentResult(bytes, new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.wordprocessingml.document"))
{
FileDownloadName = Path.GetFileName(UploadedDocumentPath)
};
}
UploadedDocumentPath is declared as a volatile string to keep the uploaded document path between sessions.
static volatile string UploadedDocumentPath;
public void OnPostUploadDocument()
{
var projectRootPath = Path.Combine(_hostingEnvironment.ContentRootPath, "UploadedDocuments");
var filePath = Path.Combine(projectRootPath, UploadedDocument.FileName);
UploadedDocument.CopyTo(new FileStream(filePath, FileMode.Create));
// Retain the path of uploaded document between sessions.
UploadedDocumentPath = filePath;
ShowDocumentContentInTextEditor();
}
Please check Save Document and Create EditableDocument from file or markup articles to learn more about GroupDocs.Editor classes.
Run the project and test the following steps:
- Upload an existing Word document by clicking Upload Document.
- Edit the content as needed.
- Click Download Document to receive the updated Word file.
Download Content of the Editor as PDF Document
Modify the OnPostDownloadDocument() handler to return a PDF file. Use PdfSaveOptions instead of WordProcessingSaveOptions and set the MIME type to application/pdf.
public FileResult OnPostDownloadDocument()
{
WordProcessingLoadOptions loadOptions = new WordProcessingLoadOptions();
Editor editor = new Editor(UploadedDocumentPath, delegate { return loadOptions; });
string completeHTML = "<!DOCTYPE html><html><head><title></title></head><body>" + DocumentContent + "</body></html>";
EditableDocument document = EditableDocument.FromMarkup(completeHTML, null);
var projectRootPath = Path.Combine(_hostingEnvironment.ContentRootPath, "DownloadedDocuments");
var outputPath = Path.Combine(projectRootPath, Path.GetFileNameWithoutExtension(UploadedDocumentPath) + ".pdf");
PdfSaveOptions saveOptions = new PdfSaveOptions();
editor.Save(document, outputPath, saveOptions);
var bytes = System.IO.File.ReadAllBytes(outputPath);
return new FileContentResult(bytes, new MediaTypeHeaderValue("application/pdf"))
{
FileDownloadName = Path.GetFileNameWithoutExtension(UploadedDocumentPath) + ".pdf"
};
}
Download Content of the Editor as Plain Text Document
To return a plain‑text file, use the TextSaveOptions class and set the MIME type to text/plain.
public FileResult OnPostDownloadDocument()
{
WordProcessingLoadOptions loadOptions = new WordProcessingLoadOptions();
Editor editor = new Editor(UploadedDocumentPath, delegate { return loadOptions; });
string completeHTML = "<!DOCTYPE html><html><head><title></title></head><body>" + DocumentContent + "</body></html>";
EditableDocument document = EditableDocument.FromMarkup(completeHTML, null);
var projectRootPath = Path.Combine(_hostingEnvironment.ContentRootPath, "DownloadedDocuments");
var outputPath = Path.Combine(projectRootPath, Path.GetFileNameWithoutExtension(UploadedDocumentPath) + ".txt");
TextSaveOptions saveOptions = new TextSaveOptions();
editor.Save(document, outputPath, saveOptions);
var bytes = System.IO.File.ReadAllBytes(outputPath);
return new FileContentResult(bytes, new MediaTypeHeaderValue("text/plain"))
{
FileDownloadName = Path.GetFileNameWithoutExtension(UploadedDocumentPath) + ".txt"
};
}
Share URL of an Editor with friends
Provide a simple way for users to copy the editor’s URL. Add a text input to Index.cshtml.
<div>
<strong>
<label for="shareURL">Edit with Friends: </label>
</strong>
<input type="text" name="shareURL" id="shareURL" size="50">
</div>
Place this <div> before the <div id="userlist"> tag. Set its value with the following line in the init() function.
document.getElementById("shareURL").value = window.location.origin + window.location.pathname + window.location.hash;
Adjust the CSS so the input displays correctly. Set the top position of firepad and userlist to 100px, and add a left margin to the input field.
#userlist {
position: absolute;
left: 0;
top: 100px;
bottom: 0;
height: auto;
width: 175px;
}
#firepad {
position: absolute;
left: 175px;
top: 100px;
bottom: 0;
right: 0;
height: auto;
}
#uploadForm {
margin: 16px 2px;
}
#shareURL {
margin-left: 123px;
}
Run the project. You will see a text field that lets you copy the editor’s URL. Share it with friends to edit the document together in real time.
Complete source code of the project is available on GitHub.