[
  {
    "Id": "260274",
    "ThreadId": "76104",
    "Html": "<p>This code offers a ZIP file for download that can then not be opened by Windows Explorer (but by 7zip).</p>\r\n<p>Does anyone see anything wrong with this code?</p>\r\n<div style=\"color:Black;background-color:White\">\r\n<pre>\r\n    <span style=\"color:Blue\">protected</span> <span style=\"color:Blue\">void</span> Page_Load(<span style=\"color:Blue\">object</span> sender, EventArgs e)\r\n    {\r\n        <span style=\"color:Blue\">var</span> fileInfos = <span style=\"color:Blue\">new</span> List&lt;<span style=\"color:Blue\">string</span>&gt; { \r\n        <span style=\"color:#A31515\">@&quot;C:\\Temp\\sub1\\file1.pdf&quot;</span>, <span style=\"color:#A31515\">@&quot;C:\\Temp\\sub1\\file2.gz&quot;</span>\r\n        };\r\n        streamZipToClient2(Response, <span style=\"color:#A31515\">&quot;test.zip&quot;</span>, <span style=\"color:#A31515\">&quot;myzip&quot;</span>, <span style=\"color:#A31515\">@&quot;C:\\Temp\\&quot;</span>, fileInfos);\r\n    }\r\n\r\n\r\n    <span style=\"color:Blue\">static</span> <span style=\"color:Blue\">void</span> streamZipToClient2(HttpResponse response, <span style=\"color:Blue\">string</span> zipFileName, <span style=\"color:Blue\">string</span> zipFileBaseDirectory, <span style=\"color:Blue\">string</span> physicalBasePath, IEnumerable&lt;<span style=\"color:Blue\">string</span>&gt; physicalFilePaths)\r\n    {        \r\n        response.Clear();\r\n        response.Buffer = <span style=\"color:Blue\">false</span>;\r\n\r\n        <span style=\"color:Blue\">long</span> approximateZipFileSize = 0;\r\n\r\n        <span style=\"color:Blue\">foreach</span> (<span style=\"color:Blue\">var</span> filePath <span style=\"color:Blue\">in</span> physicalFilePaths)\r\n        {\r\n            approximateZipFileSize += (<span style=\"color:Blue\">new</span> FileInfo(filePath)).Length;\r\n        }\r\n\r\n        response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);\r\n        response.Cache.SetNoStore();\r\n        response.Cache.SetExpires(DateTime.UtcNow.AddYears(-1));\r\n\r\n        response.ContentType = <span style=\"color:#A31515\">&quot;application/zip&quot;</span>;\r\n        response.AddHeader(<span style=\"color:#A31515\">&quot;content-disposition&quot;</span>, <span style=\"color:#A31515\">&quot;filename=&quot;</span> + zipFileName);   \r\n        response.AddHeader(<span style=\"color:#A31515\">&quot;content-length&quot;</span>, (approximateZipFileSize * 1.2).ToString());\r\n        \r\n        <span style=\"color:Blue\">using</span> (<span style=\"color:Blue\">var</span> zipFile = <span style=\"color:Blue\">new</span> Ionic.Zip.ZipFile())\r\n        {\r\n            zipFile.CompressionLevel = Ionic.Zlib.CompressionLevel.None;            \r\n            <span style=\"color:Blue\">foreach</span> (<span style=\"color:Blue\">var</span> physicalFilePath <span style=\"color:Blue\">in</span> physicalFilePaths)\r\n            {\r\n                <span style=\"color:Blue\">var</span> fileBytes = File.ReadAllBytes(physicalFilePath);\r\n\r\n                <span style=\"color:Blue\">string</span> relativeFilePath = physicalFilePath.Replace(physicalBasePath, <span style=\"color:#A31515\">&quot;&quot;</span>);                \r\n                <span style=\"color:Blue\">string</span> fileName = Path.GetFileName(physicalFilePath);\r\n                <span style=\"color:Blue\">string</span> directoryInZipFile = Path.Combine(zipFileBaseDirectory, relativeFilePath.Replace(fileName, <span style=\"color:#A31515\">&quot;&quot;</span>));                \r\n                zipFile.AddEntry(fileName, directoryInZipFile, fileBytes);                \r\n                zipFile.Save(response.OutputStream);                \r\n            }\r\n        }\r\n        HttpContext.Current.ApplicationInstance.CompleteRequest();\r\n    }\r\n</pre>\r\n</div>\r\n<p>The content length and caching code is not responsible (omitting it doesn't help).<br>All the files exist (and the resulting structure of the zip&nbsp;file is fine, as evidenced by 7zips handling).</p>\r\n<p>I tried this code with the current 1.8 release and the current 1.9-dev release&nbsp;(with some differing semantics).</p>\r\n<p>Any help would be much appreciated!</p>\r\n<p>Thanks</p>",
    "PostedDate": "2009-11-24T09:17:52.717-08:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  },
  {
    "Id": "260276",
    "ThreadId": "76104",
    "Html": "<p>Moving the call to Save(...) out of the loop solved this problem.</p>",
    "PostedDate": "2009-11-24T09:30:35.947-08:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  },
  {
    "Id": "260323",
    "ThreadId": "76104",
    "Html": "<p>That sounds right.&nbsp; If you keep the Save() in the loop, then it saves multiple independent ZIPs, one after the other, to the output stream, and I'm sure the results would be unpredictable in that case.</p>\r\n<p>Also, think about Response.Close() instead of HttpContext.Current.ApplicationInstance.CompleteRequest();</p>",
    "PostedDate": "2009-11-24T11:33:20.947-08:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  },
  {
    "Id": "263908",
    "ThreadId": "76104",
    "Html": "<p>ps, I think you should use Response.Close() instead of HttpContext.Current.ApplicationInstance.CompleteRequest();</p>",
    "PostedDate": "2009-12-05T05:01:51.817-08:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  },
  {
    "Id": "263932",
    "ThreadId": "76104",
    "Html": "<p>Yes, a call to Response.Close() is necessary for the streaming to work if the size is not given correctly.</p>",
    "PostedDate": "2009-12-05T07:07:06.327-08:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  }
]