HOW TO dynamically generate a Word document with custom header & footer

Way back in 2004, a project I was working on required a web page to be exported as a Word document (.DOC). Without relying on any components, I utilized the Office XML & HTML technique to implement this feature. I posted my sample on CodeProject to seek feedback. Over the years, I've received some generous comments & feature requests. Many wanted to know how to add a header & footer to the dynamically generated Word document.

With the help of the Microsoft Office HTML and XML Reference, I devised a hack to add a lacklustre header and/or footer. Some folks wanted to customize the contents of the header & footer but when they tried with my hack that offered limited functionality, the header/footer text showed up in the document body to their annoyance. This July, an ingenious developer posted a hack that can overcome this problem, in the Comments section of my CodeProject article. His practical workaround was to pack the duplicating header/footer text inside a table & push it off the page's dimensions with CSS.



For those interested, I adapted his VB.NET snippet into a complete sample in C#. Instead of using a ASP.NET webform as I did in the original code sample in the article, I have used a Generic Handler (.ASHX) to dynamically generate a Word document as it is more suitable for this purpose.

<%@ WebHandler Language="C#" Class="Handler" %>


using System;
using System.Web;
using System.Text;

public class Handler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
StringBuilder sbTop = new System.Text.StringBuilder();
sbTop.Append(@"
<html
xmlns:o='urn:schemas-microsoft-com:office:office'
xmlns:w='urn:schemas-microsoft-com:office:word'
xmlns='http://www.w3.org/TR/REC-html40'>
<head><title></title>

<!--[if gte mso 9]>
<xml>
<w:WordDocument>
<w:View>Print</w:View>
<w:Zoom>90</w:Zoom>
<w:DoNotOptimizeForBrowser/>
</w:WordDocument>
</xml>
<![endif]-->


<style>
p.MsoFooter, li.MsoFooter, div.MsoFooter
{
margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
tab-stops:center 3.0in right 6.0in;
font-size:12.0pt;
}
<style>

<!-- /* Style Definitions */

@page Section1
{
size:8.5in 11.0in;
margin:1.0in 1.25in 1.0in 1.25in ;
mso-header-margin:.5in;
mso-header:h1;
mso-footer: f1;
mso-footer-margin:.5in;
}


div.Section1
{
page:Section1;
}

table#hrdftrtbl
{
margin:0in 0in 0in 9in;
}
-->
</style></head>

<body lang=EN-US style='tab-interval:.5in'>
<div class=Section1>
<h1>Time and tide wait for none</h1>
The quick brown fox jumps over the lazy dog
...
...


<table id='hrdftrtbl' border='1' cellspacing='0' cellpadding='0'>
<tr><td>
<div style='mso-element:header' id=h1 >
<p class=MsoHeader style='text-align:center'>Confidential</p>
</div>
</td>
<td>
<div style='mso-element:footer' id=f1>
<p class=MsoFooter>Draft
<span style=mso-tab-count:2'></span><span style='mso-field-code:"" PAGE ""'></span>
of <span style='mso-field-code:"" NUMPAGES ""'></span></p></div>
/td></tr>
</table>
</body></html>
");

string strBody = sbTop.ToString();
context.Response.AppendHeader("Content-Type", "application/msword");
context.Response.AppendHeader("Content-disposition", "attachment; filename=HeaderFooter.doc");
context.Response.Write(strBody);
}


public bool IsReusable
{
get
{
return false;
}
}
}

To clearly understand the code you would have to download the Microsoft Office HTML and XML Reference which is in .CHM format (as there is no online version of it) & look up the exact meanings of custom CSS properties.

Related links:

HOW TO implement "Download as Word/Excel" functionality through a web page
HOW TO send an email with a Word or Excel file attachment built on the fly
HOW TO generate a Word document dynamically with user submitted text formatted with Free Text Box

Comments

  1. Interesting topic. I have a problem inserting images as these are not shown. Can you help me please.

    ReplyDelete
  2. I applied this code but when we set the margins of the table it stops showing header and footer on the page..Please suggest

    ReplyDelete
  3. Hi!

    The thing that you should do so that the header and the footer will not appear on the body is that create again another table. for the body..



    I do have a question, how can i insert a logo in the header? thanks!

    ReplyDelete
  4. Its really helpful for me.


    Avneesh Pandey,
    Software Engg.
    Xcino Inc

    ReplyDelete
  5. Thank you very much Anil
    you save my day :)
    Nanthini

    ReplyDelete
  6. Great post! excellent point of refrence though my header and footers are doubling up e.g. one shown in the header and one in the content

    ReplyDelete
  7. Tried the same concept in ColdFusion. Just wrapped my header and footer in a div and gave it the style with the 9in left margin. It works, as the header and footer don't appear in the body of my document, however it adds 2 extra blank pages. Any way to prevent that??

    ReplyDelete
  8. How to set background image in word file using c# code??

    ReplyDelete
  9. Is there a way to do this with your method but skip the first page, meaning have the numbering start on the second page?

    ReplyDelete
  10. Any setting that is possible in MS Word can also be accomplished by code. Starting page numbering on page 2 can be done - http://office.microsoft.com/en-001/word-help/start-page-numbering-on-page-2-HP001227657.aspx Create a sample Word document with that setting and then save that document as a Webpage. A HTML page is created along with dependent files in a folder with the same name as the web page. Identify the HTML, CSS code that is causing the page number to show up and modify the above code. This will require some experimenting. Due to time constraints, I cannot do it myself but let me know if you run into any issues and I'll jump in then.

    ReplyDelete
  11. Thank you! That tricked worked.

    ReplyDelete
  12. Heyyy..thats help me alot..but having a problem in image..how to set image height width because it shows original image height width..and width height style doesn't effect on it..any suggestion please

    ReplyDelete

Post a Comment