GetAsByteArray() method ?

May 21, 2010 at 1:52 PM

Hello,

I am looking for a way to return the docx file as array of byte without saving the file to server disk.

I could return the output stream from Api assembly then write-it to the Response object as follows:

                using (DocBuilder builder = new DocBuilder(strTemplateFilePath))
                {
                    objStream = builder.Build(strDataPath, nsPrefix, ns, strOutputDocument, Thread.CurrentThread.CurrentUICulture, true);                   
                }

                Response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
                Response.AddHeader("content-disposition", "attachment;  filename=client.docx");
                Response.BinaryWrite(GetBytes(objStream));
                Response.End();

Unfortunately, the output docx file contains the famous corrupted file popup when opening-it which is a bug in office 2007. Is there a method that returns the correct array of byte[] from the word package?

Thank you for your cooperation.

Coordinator
May 21, 2010 at 1:57 PM

The output stream by the Build-method on DocBuilder is actually a MemoryStream (just cast it). A memorystream supports a method called ToArray. This gives you a byte[] of the data.

I'm unaware of any 'corrupted file' popup-bug that exists in Word. Is your template ok? If you enable validation on fleXdoc, do you get validation errors as well? If so, it's probably your template which causes the error.

Robert

May 21, 2010 at 2:46 PM

I tried-it with the OrderTemplate.docx which exists in the sample project. The corrupted file popup is still occurring. Try-it by yourself please and you will find the same result if you have office 2007 installed.

Houssam

 

May 25, 2010 at 7:11 AM

Hi Robert,

               using (DocBuilder builder = new DocBuilder(strTemplateFilePath))
                {
                    objStream = builder.Build(strDataPath, nsPrefix, ns, strOutputDocument, Thread.CurrentThread.CurrentUICulture, true);                   
                }
                Response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
                Response.AddHeader("content-disposition", "attachment;  filename=client.docx");
                Response.BinaryWrite(objStream.ToArray());
                Response.End();

As you suggested, i used the ToArray() method of the MemoryStream object to write binaries inside the Response as per the aforementioned code.

Unfortunately, the result docx document pop-ups the following message when opening-it :
"The office open xml file xxx.docx cannot be opened because there are problems with the contents."

Could you please help in this? i need the user to Save/Open the docx generated in memory.

Thank you and best regards,

Houssam

Coordinator
May 25, 2010 at 7:50 AM
Edited May 25, 2010 at 7:53 AM

Houssam, this should definately work. Did you check the file contents yourself? Especially the first few bytes are interesting: maybe ASP.Net or your app already wrote some data to the response stream. Maybe it helps to add a Response.Clear before writing to the stream. And how about buffering? Make sure you don't write too much data at once. Normally you cannot send more than 4MB at once using BinaryWrite, so you may need to call it multiple times. Also, maybe a Response.Flush (or something like that) is required before you call Response.End.

Also, if the file is ok when you write it to a filestream, it should also work when writing to the asp.net response stream. And the other way around: what if you write a correct docx to the response stream, does that work or do you get the same error?

Good luck,
Robert

May 25, 2010 at 8:44 AM

string strOutputDocument = Server.MapPath(@"\client.docx");
Response.ContentType = "application/vnd.openxmlformats officedocument.wordprocessingml.document";
Response.AddHeader("content-disposition", "attachment; filename=document.docx");                
Response.Clear();
Response.WriteFile(strOutputDocument);
Response.Flush();
Response.End();                  

client.docx has been created using the builder.build(...) method and it is OK.

The result document from the above code is still corrupted even though the file is OK.

What do you think about that?

Houssam

Coordinator
May 25, 2010 at 9:05 AM

Hmm, that's very odd. Does it help if you change the content-type to a regular binary file? Also, the content-type now contains a space, which doesn;t seem correct.

May 25, 2010 at 9:48 AM

Yes very odd. I tried all the available content-types. Still nothing is working.

Can i send you a sample project or could you give it a try please?

Thank you for your help.

Houssam

May 25, 2010 at 11:21 AM

Hello again,

As you said: "Make sure you don't write too much data at once" :)

Ultimate Solution:

long dataLengthToRead = objStream.Length;
int blockSize = dataLengthToRead >= 5000 ? 5000 : (int)dataLengthToRead;
byte[] buffer = new byte[dataLengthToRead];
Response.Clear();
Response.ClearContent();
Response.ClearHeaders();
Response.BufferOutput = true;
Response.AddHeader("Content-Disposition", "attachment; filename=document.docx");
Response.AddHeader("Content-Length", objStream.Length.ToString());
Response.ContentType = "application/vnd.openxmlformatsofficedocument.wordprocessingml.document";
while (dataLengthToRead > 0 && Response.IsClientConnected)
{
Int32 lengthRead = objStream.Read(buffer, 0, blockSize);
Response.OutputStream.Write(buffer, 0, lengthRead);
dataLengthToRead = dataLengthToRead - lengthRead;
}
Response.Flush();
Response.Close();                
Response.End();

Thank you for your patience.

Cheers,
Houssam