save the document created by docX into response and send it to user for downloading

LocustHorde picture LocustHorde · Jan 24, 2012 · Viewed 18.9k times · Source

I am trying to use the amazing DocX library on codeplex to create a word document.

when the user clicks a button, the document is created and I want to be able to send it to the user immediately via response.. I am doing something similar to this now:

Edited code based on suggestions

using (DocX Report = DocX.Create(string.Format("Report-{0}.doc", DateTime.Now.Ticks)))
{
    Paragraph p = Report.InsertParagraph();
    p.Append("Title").FontSize(30).Bold()
    .Append("Sub title").FontSize(28)
        .AppendLine()
        .Append(DateTime.Now.Date) 
    ;

    MemoryStream ms = new MemoryStream();
    Report.SaveAs(ms);


    Response.Clear();
    Response.AddHeader("content-disposition", "attachment; filename=\"" + fileName + ".docx\"");
    Response.ContentType = "application/msword";

    Response.Write(ms);
    Response.End();
}

I have tried a few variations of this.. but I am not able to achieve what I want.. Looking at this answer I can possibly save the document on the server and open with io stream.. but I want to avoid that extra step (and then I need to delete the file too)

I don't see the point of creating a file for few milli seconds.. there has to be a way to save the contents and send them to response stream.. right?

How'd I go about it? thanks..

EDIT: my current code either throws up cannot open file (Access denied) error If I am using file stream, OR downloads an empty document file without any content (sometimes, type of response is written to document)


This code gets me an MS word document with System.IO.MemoryStream as it's content..


Okay, here is the final working solution:

For some reason, DocX library doesn't want to save to Response.OutputStream directly, so I had to save it to memory stream and write the memory stream to response, like Neil & Daniel suggested. Here's what worked for me:

MemoryStream ms = new MemoryStream()
Report.SaveAs(ms);

Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=\"" + fileName + ".doc\");
Response.ContentType = "application/msword";

ms.WriteTo(Response.OutputStream);
Response.End();

Answer

Chris W picture Chris W · Apr 21, 2013

This might be a bit late, but I found a way to get this working with FileStreamResult:

    public FileStreamResult DownloadDocument()
    {
        using (DocX document = DocX.Create(@"Test.docx"))
        {
            // Insert a new Paragraphs.
            Paragraph p = document.InsertParagraph();

            p.Append("I am ").Append("bold").Bold()
            .Append(" and I am ")
            .Append("italic").Italic().Append(".")
            .AppendLine("I am ")
            .Append("Arial Black")
            .Font(new FontFamily("Arial Black"))
            .Append(" and I am not.")
            .AppendLine("I am ")
            .Append("BLUE").Color(Color.Blue)
            .Append(" and I am")
            .Append("Red").Color(Color.Red).Append(".");

            var ms = new MemoryStream();
            document.SaveAs(ms);
            ms.Position = 0;

            var file = new FileStreamResult(ms, "application/vnd.openxmlformats-officedocument.wordprocessingml.document")
            {
                FileDownloadName = string.Format("test_{0}.docx", DateTime.Now.ToString("ddMMyyyyHHmmss"))
            };

            return file;

        }
    }

The important bit is setting the Position of the memorystream back to 0, otherwise it appeared to be at the end, and the file was returning empty.