Building an ASP.NET Web Application that Displays DOCX as HTML
Return to the
WmlToHtmlConverter
Developer CenterThere are four basic operations that developers need to do when building an ASP.NET Web application with Open XML functionality:
- Upload a document
- Modify the document using the Open XML SDK
- Convert the document to HTML/CSS and display the converted HTML
- Download the modified document
In this screen-cast, I demonstrate how to start from nothing and build such an application using Visual Studio 2013. Note that there is nothing about this application that is specific to VS 2013. The approach and the code will work as well with VS 2012 or 2010. Below the screen-cast, I list the interesting code so that it is as easy as possible for you to cut and paste the code and build your own similar application.
Here is the source for the Web form:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApplication1.WebForm1" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <div> <asp:FileUpload ID="FileUploadControl" runat="server" /> <p style="line-height: .5em;" /> <asp:Label ID="lblMessage" runat="server" Text=""></asp:Label> <p style="line-height: .5em;" /> <asp:Button ID="btnUpload" runat="server" Text="Upload" OnClick="btnUpload_Click" /> <p style="line-height: .5em;" /> <asp:Button ID="btnModify" runat="server" Text="Modify" OnClick="btnModify_Click" /> <p style="line-height: .5em;" /> <asp:Button ID="btnDisplay" runat="server" Text="Display" OnClick="btnDisplay_Click" /> <p style="line-height: .5em;" /> <asp:Button ID="btnDownload" runat="server" Text="Download" OnClick="btnDownload_Click" /> </div> </form> <lt;/body> </html>
Here is the listing, in its entirety, for the code behind the Web page:
using System; using System.Collections.Generic; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Text; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Xml.Linq; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; using OpenXmlPowerTools; namespace WebApplication1 { public partial class WebForm1 : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } protected void btnUpload_Click(object sender, EventArgs e) { if (FileUploadControl.HasFile) try { string fileNameFromUser = FileUploadControl.FileName; var fiFileName = new FileInfo(fileNameFromUser); if (Util.IsWordprocessingML(fiFileName.Extension)) { using (MemoryStream memoryStream = new MemoryStream()) { memoryStream.Write(FileUploadControl.FileBytes, 0, FileUploadControl.FileBytes.Length); // Open and close the WordprocessingML document to make sure // that the SDK can open it. using (WordprocessingDocument wDoc = WordprocessingDocument.Open(memoryStream, true)) { } lblMessage.Text = "File uploaded successfully"; Session["ByteArray"] = FileUploadControl.FileBytes; Session["FileNameFromUser"] = fileNameFromUser; } } else { lblMessage.Text = "ERROR: Not a WordprocessingML document"; Session["ByteArray"] = null; Session["FileNameFromUser"] = null; } } catch (Exception ex) { lblMessage.Text = "ERROR: " + ex.Message.ToString(); Session["ByteArray"] = null; Session["FileNameFromUser"] = null; } else { lblMessage.Text = "You have not specified a file."; Session["ByteArray"] = null; Session["FileNameFromUser"] = null; } } protected void btnModify_Click(object sender, EventArgs e) { byte[] byteArray = (byte[])(Session["ByteArray"]); if (byteArray != null) { try { using (MemoryStream memoryStream = new MemoryStream()) { memoryStream.Write(byteArray, 0, byteArray.Length); using (WordprocessingDocument wDoc = WordprocessingDocument.Open(memoryStream, true)) { var body = wDoc.MainDocumentPart.Document.Body; var lastPara = body.Elements<Paragraph>().LastOrDefault(); var newPara = new Paragraph( new Run( new Text("Hello World!"))); lastPara.InsertAfterSelf(newPara); } Session["ByteArray"] = memoryStream.ToArray(); lblMessage.Text = "Paragraph added to DOCX"; } } catch (Exception ex) { lblMessage.Text = "ERROR: "quot; + ex.Message.ToString(); } } else { lblMessage.Text = "You have not specified a file."; } } static string DocxConvertedToHtmlDirectory = "DocxConvertedToHtml/"; protected void btnDisplay_Click(object sender, EventArgs e) { byte[] byteArray = (byte[])(Session["ByteArray"]); if (byteArray != null) { try { DirectoryInfo convertedDocsDirectory = new DirectoryInfo(Server.MapPath(DocxConvertedToHtmlDirectory)); if (!convertedDocsDirectory.Exists) convertedDocsDirectory.Create(); Guid g = Guid.NewGuid(); var htmlFileName = g.ToString() + ".html"; ConvertToHtml(byteArray, convertedDocsDirectory, htmlFileName); Response.Redirect(DocxConvertedToHtmlDirectory + htmlFileName); } catch (Exception ex) { lblMessage.Text = "ERROR: " + ex.Message.ToString(); } } else { lblMessage.Text = "You have not specified a file."; } } public static void ConvertToHtml(byte[] byteArray, DirectoryInfo destDirectory, string htmlFileName) { FileInfo fiHtml = new FileInfo(Path.Combine(destDirectory.FullName, htmlFileName)); using (MemoryStream memoryStream = new MemoryStream()) { memoryStream.Write(byteArray, 0, byteArray.Length); using (WordprocessingDocument wDoc = WordprocessingDocument.Open(memoryStream, true)) { var imageDirectoryFullName = fiHtml.FullName.Substring(0, fiHtml.FullName.Length - fiHtml.Extension.Length) + "_files"; var imageDirectoryRelativeName = fiHtml.Name.Substring(0, fiHtml.Name.Length - fiHtml.Extension.Length) + "_files"; int imageCounter = 0; var pageTitle = (string)wDoc .CoreFilePropertiesPart .GetXDocument() .Descendants(DC.title) .FirstOrDefault(); HtmlConverterSettings settings = new HtmlConverterSettings() { PageTitle = pageTitle, FabricateCssClasses = true, CssClassPrefix = "pt-", RestrictToSupportedLanguages = false, RestrictToSupportedNumberingFormats = false, ImageHandler = imageInfo => { DirectoryInfo localDirInfo = new DirectoryInfo(imageDirectoryFullName); if (!localDirInfo.Exists) localDirInfo.Create(); ++imageCounter; string extension = imageInfo.ContentType.Split('/')[1].ToLower(); ImageFormat imageFormat = null; if (extension == "png") { // Convert png to jpeg. extension = "gif"; imageFormat = ImageFormat.Gif; } else if (extension == "gif") imageFormat = ImageFormat.Gif; else if (extension == "bmp") imageFormat = ImageFormat.Bmp; else if (extension == "jpeg") imageFormat = ImageFormat.Jpeg; else if (extension == "tiff") { // Convert tiff to gif. extension = "gif"; imageFormat = ImageFormat.Gif; } else if (extension == "x-wmf") { extension = "wmf"; imageFormat = ImageFormat.Wmf; } // If the image format isn't one that we expect, ignore it, // and don't return markup for the link. if (imageFormat == null) return null; FileInfo imageFileName = new FileInfo(imageDirectoryFullName + "/image" + imageCounter.ToString() + "." + extension); try { imageInfo.Bitmap.Save(imageFileName.FullName, imageFormat); } catch (System.Runtime.InteropServices.ExternalException) { return null; } XElement img = new XElement(Xhtml.img, new XAttribute(NoNamespace.src, imageDirectoryRelativeName + "/" + imageFileName.Name), imageInfo.ImgStyleAttribute, imageInfo.AltText != null ? new XAttribute(NoNamespace.alt, imageInfo.AltText) : null); return img; } }; XElement html = HtmlConverter.ConvertToHtml(wDoc, settings); // Note: the xhtml returned by ConvertToHtmlTransform contains objects of type // XEntity. PtOpenXmlUtil.cs define the XEntity class. See // http://blogs.msdn.com/ericwhite/archive/2010/01/21/writing-entity-references-using-linq-to-xml.aspx // for detailed explanation. // // If you further transform the XML tree returned by ConvertToHtmlTransform, you // must do it correctly, or entities will not be serialized properly. var body = html.Descendants(Xhtml.body).First(); body.AddFirst( new XElement(Xhtml.p, new XElement(Xhtml.A, new XAttribute("href", "/WebForm1.aspx"), "Go back to Upload Page"))); var htmlString = html.ToString(SaveOptions.DisableFormatting); File.WriteAllText(fiHtml.FullName, htmlString, Encoding.UTF8); } } } protected void btnDownload_Click(object sender, EventArgs e) { byte[] byteArray = (byte[])(Session["ByteArray"]); if (byteArray != null) { Response.Clear(); Response.ContentType = "application/octet-stream"; string fileName = (string)(Session["FileNameFromUser"]); Response.AddHeader("Content-Disposition", String.Format("attachment; filename={0}", fileName)); Response.BinaryWrite(byteArray); Response.Flush(); Response.End(); } else { lblMessage.Text = "You have not specified a file."; } } } }
Cheers, Eric