43

I am using the following code to stream pptx which is in a MemoryStream object but when I open it I get Repair message in PowerPoint, what is the correct way of writing MemoryStream to Response Object?

HttpResponse response = HttpContext.Current.Response;
response.Clear();
response.AppendHeader("Content-Type", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
response.AppendHeader("Content-Disposition", string.Format("attachment;filename={0}.pptx;", getLegalFileName(CurrentPresentation.Presentation_NM)));                
response.BinaryWrite(masterPresentation.ToArray());
response.End();
Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
Ali
  • 1,648
  • 2
  • 26
  • 48

8 Answers8

76

I had the same problem and the only solution that worked was:

Response.Clear();
Response.ContentType = "Application/msword";
Response.AddHeader("Content-Disposition", "attachment; filename=myfile.docx");
Response.BinaryWrite(myMemoryStream.ToArray());
// myMemoryStream.WriteTo(Response.OutputStream); //works too
Response.Flush();
Response.Close();
Response.End();
Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
playful
  • 1,744
  • 15
  • 14
  • 3
    According to [this article](https://support.microsoft.com/en-us/help/312629/prb-threadabortexception-occurs-if-you-use-response.end,-response.redirect,-or-server.transfer) `Response.End()` throws an exception, which isn't really what you want. Use `HttpContext.Current.ApplicationInstance.CompleteRequest();` – jimboweb Jun 09 '17 at 20:38
16

Assuming you can get a Stream, FileStream or MemoryStream for instance, you can do this:

Stream file = [Some Code that Gets you a stream];
var filename = [The name of the file you want to user to download/see];

if (file != null && file.CanRead)
{
    context.Response.AddHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
    context.Response.ContentType = "application/octet-stream";
    context.Response.ClearContent();
    file.CopyTo(context.Response.OutputStream);
}

Thats a copy and paste from some of my working code, so the content type might not be what youre looking for, but writing the stream to the response is the trick on the last line.

Ian Robertson
  • 2,652
  • 3
  • 28
  • 36
7

Instead of creating the PowerPoint presentation in a MemoryStream write it directly to the Response.OutputStream. This way you don't need to be wasting any memory on the sever as the component will be directly streaming the output to the network socket stream. So instead of passing a MemoryStream to the function that is generating this presentation simply pass the Response.OutputStream.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • The implementation operates on MemoryStream can you please give a code example where I can copy this MemoryStream to Response.OutputStream in order to get "Repair Free" pptx file? I've tried MemoryStream.WriteTo(Response.OutputStream) but didn't help. – Ali Dec 08 '12 at 16:24
  • Are you sure that the implementation generates valid PowerPoint file? What happens if you write this MemoryStream to a file on the server and attempt to open it afterwards: `File.WriteAllBytes(@"c:\test.pptx", masterPresentation.ToArray())`. Are you able to successfully open the file? Also you should definitely fix the implementation of the control that works with a Stream and not MemoryStream which is hugely inefficient, especially in a server side application such as ASP.NET. – Darin Dimitrov Dec 08 '12 at 16:28
  • I don't have permission to write the file on Server but It's a valid file since OpenXML SDK open it to apply the theme perfectly fine. – Ali Dec 08 '12 at 16:29
  • 1
    How do you know that it is a valid file? You haven't even stored it into a file yet. – Darin Dimitrov Dec 08 '12 at 16:29
  • The problem actually occurs when the presentation has more than 30 slides and since the way we stream affects the size of the file this is my best guess. – Ali Dec 08 '12 at 16:34
  • @Ali, unless you set Response.BufferOutput = false, you need to do Response.flush() after you write to the Response buffer. Then using open MemoryStream object, stream.WriteTo(Response.OutputStream) works as advertised. – Dan Randolph Feb 22 '16 at 22:14
  • Also, if your MemoryStream object is not created in a "Using(...)" statement, be sure to do stream.Close() after the WriteTo call. – Dan Randolph Feb 22 '16 at 22:44
4

Try with this

Response.Clear();
Response.AppendHeader("Content-Type", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
Response.AppendHeader("Content-Disposition", string.Format("attachment;filename={0}.pptx;", getLegalFileName(CurrentPresentation.Presentation_NM)));
Response.Flush();                
Response.BinaryWrite(masterPresentation.ToArray());
Response.End();
Nudier Mena
  • 3,254
  • 2
  • 22
  • 22
4

First We Need To Write into our Memory Stream and then with the help of Memory Stream method "WriteTo" we can write to the Response of the Page as shown in the below code.

   MemoryStream filecontent = null;
   filecontent =//CommonUtility.ExportToPdf(inputXMLtoXSLT);(This will be your MemeoryStream Content)
   Response.ContentType = "image/pdf";
   string headerValue = string.Format("attachment; filename={0}", formName.ToUpper() + ".pdf");
   Response.AppendHeader("Content-Disposition", headerValue);

   filecontent.WriteTo(Response.OutputStream);

   Response.End();

FormName is the fileName given,This code will make the generated PDF file downloadable by invoking a PopUp.

Deepak Kothari
  • 1,601
  • 24
  • 31
3

The problem for me was that my stream was not set to the origin before download.

Response.Clear();
Response.ContentType = "Application/msword";
Response.AddHeader("Content-Disposition", "attachment; filename=myfile.docx");

//ADDED THIS LINE
myMemoryStream.Seek(0,SeekOrigin.Begin);

myMemoryStream.WriteTo(Response.OutputStream); 
Response.Flush();
Response.Close();
Ryan Bennett
  • 3,404
  • 19
  • 32
1

I tried all variants of end, close, flush, and System.Web.HttpContext.Current.ApplicationInstance.CompleteRequest() and none of them worked.

Then I added the content length to the header: Response.AddHeader("Content-Length", asset.File_Size.ToString());

In this example asset is a class that has a Int32 called File_Size

This worked for me and nothing else did.

Norwood
  • 41
  • 2
0

I had the same issue. try this: copy to MemoryStream -> delete file -> download.

string absolutePath = "~/your path";
try {
    //copy to MemoryStream
    MemoryStream ms = new MemoryStream();
    using (FileStream fs = File.OpenRead(Server.MapPath(absolutePath))) 
    { 
        fs.CopyTo(ms); 
    }

    //Delete file
    if(File.Exists(Server.MapPath(absolutePath)))
       File.Delete(Server.MapPath(absolutePath))

    //Download file
    Response.Clear()
    Response.ContentType = "image/jpg";
    Response.AddHeader("Content-Disposition", "attachment;filename=\"" + absolutePath + "\"");
    Response.BinaryWrite(ms.ToArray())
}
catch {}

Response.End();