Sunday, January 26, 2014

Load a Word document into Internet Explorer and set Response.ContentType

About two years ago I wrote some code to construct a PDF document on the fly and display it in the browser. Yesterday I was trying to do the same thing for a Word document. If you've seen earlier posts this month you will see I am using Aspose Words for .Net to perform a mail merge.  I wanted the ability to preview the result before saving the output. 
Now when I did this previously for a PDF file I had a web service that returned a memory stream and I was able to load that into the Response.OutputStream object without difficulty. But I immediately ran into a problem with my web service which is built with .Net FW 4.0.  The memory stream I returned became a marshalled object which does not have the same properties for WriteTo() or ToArray() which meant I could not easily load it into Response.OutputStream.
I suppose I could have found a solution but instead I thought I would return it as a string instead. Alas that gave a new set of problems which I suspect was down to encoding when converting between the stream and the string.  This morning I tried converting to a base base64 string and that did the trick. 
So firstly here is the code in the web service that converts the memory stream to base64.

public string PreviewMerge(DataMergeRequest req)
{   // code to do mailmerge goes here
   MemoryStream msRawData = merge.MergeDataSet(ds, templatelocation);

   string base64;
   base64 = Convert.ToBase64String(msRawData.GetBuffer(), 0, (int)msRawData.Length);

    return base64;

On the ASPX page you need to remove everything below the Page directive.
In the Page_Load event you need this code. Note you should NOT use Response.End - there is a known issue with it creating a Threading exception.  Use HttpContext.Current.ApplicationInstance.CompleteRequest() instead. 

Response.Charset = "";

// get results of merge as base 64 encoded stream
string strBase64 = ds.PreviewMerge(req);

// DECODE into memory stream
byte[] raw = Convert.FromBase64String(strBase64);

using (MemoryStream decoded = new MemoryStream(raw))
   // load the stream into the Response Output stream
// set the content type for docx
Response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";


No comments: