I created a custom action result to send zipped archive of multiple files downloaded from another server.
Sorry for a ton of code, but there it is.
using ICSharpCode.SharpZipLib.Zip;
/// <summary>
/// Downloads the files using specified URLs and continuously streams zipped result to the client
/// </summary>
public class MultipleFileZipResult : ActionResult
{
private readonly ILog log;
private const int BufferSize = 32 * 1024;
/// <summary>
/// Initializes a new instance of the <see cref="MultipleFileZipResult"/> class.
/// </summary>
/// <param name="urls">The URLs to download.</param>
/// <param name="resultFileName">Name of the result file.</param>
/// <param name="log">The logger.</param>
public MultipleFileZipResult(IEnumerable<DownloadableZipDescriptor> urls, string resultFileName, ILog log)
{
this.log = log;
this.Urls = urls;
this.ResultFileName = resultFileName;
}
/// <summary>
/// Gets or sets the list of URLs to download.
/// </summary>
public IEnumerable<DownloadableZipDescriptor> Urls { get; set; }
/// <summary>
/// Gets or sets the name of the zip result file.
/// </summary>
public string ResultFileName { get; set; }
/// <summary>
/// Enables processing of the result of an action method by a custom type that inherits from the <see cref="T:System.Web.Mvc.ActionResult"/> class.
/// </summary>
/// <param name="context">The context in which the result is executed. The context information includes the controller, HTTP content, request context, and route data.</param>
public override void ExecuteResult(ControllerContext context)
{
try
{
context.HttpContext.Response.ContentType = "application/zip";
context.HttpContext.Response.CacheControl = "private";
context.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
context.HttpContext.Response.AddHeader("content-disposition", string.Format("attachment; filename=\"{0}\"", this.ResultFileName));
context.HttpContext.Response.Flush();
var buffer = new byte[BufferSize];
using (var zippedUploadStream = new ZipOutputStream(context.HttpContext.Response.OutputStream))
{
zippedUploadStream.SetLevel(0);
foreach (var url in this.Urls)
{
Stream downloadStream = null;
WebResponse response = null;
try
{
var request = WebRequest.Create(url.DownloadUrl);
request.Proxy = null;
response = request.GetResponse();
downloadStream = response.GetResponseStream();
if (downloadStream != null)
{
var zipEntry = new ZipEntry(url.SaveFileName);
zippedUploadStream.PutNextEntry(zipEntry);
int read;
while ((read = downloadStream.Read(buffer, 0, buffer.Length)) > 0)
{
zippedUploadStream.Write(buffer, 0, read);
context.HttpContext.Response.Flush();
}
}
}
catch (Exception exception)
{
this.log.Error(exception);
}
finally
{
if (response != null)
{
response.Close();
}
if (downloadStream != null)
{
downloadStream.Close();
}
}
if (!context.HttpContext.Response.IsClientConnected)
{
break;
}
}
zippedUploadStream.Finish();
}
if (context.HttpContext.Response.IsClientConnected)
{
context.HttpContext.Response.Flush();
context.HttpContext.Response.End();
}
}
catch (Exception exception)
{
this.log.Error(exception);
throw;
}
}
}
Everything worked fine, untill customer tried to download zipped archive from the same network where servers are located. It is strange, becaues by some reason download works fine for me.
Only noticable difference is the download speed for me and he. His download speed is ~11 mbps, while mine is 0.4 mbps.
The exceptions being logged:
System.Web.HttpException (0x800704CD): The remote host closed the connection. The error code is 0x800704CD.
at System.Web.Hosting.IIS7WorkerRequest.RaiseCommunicationError(Int32 result, Boolean throwOnDisconnect)
at System.Web.Hosting.IIS7WorkerRequest.ExplicitFlush()
at System.Web.HttpResponse.Flush(Boolean finalFlush)
at System.Web.HttpResponseWrapper.Flush()
System.Web.HttpException (0x80004005): An error occurred while communicating with the remote host. The error code is 0x800703E3. ---> System.Runtime.InteropServices.COMException (0x800703E3): The I/O operation has been aborted because of either a thread exit or an application request. (Exception from HRESULT: 0x800703E3)
at System.Web.Hosting.IIS7WorkerRequest.RaiseCommunicationError(Int32 result, Boolean throwOnDisconnect)
at System.Web.Hosting.IIS7WorkerRequest.ExplicitFlush()
at System.Web.HttpResponse.Flush(Boolean finalFlush)
at System.Web.HttpResponseWrapper.Flush()
at Infrastructure.MultipleFileZipResult.ExecuteResult(ControllerContext context)
User contributions licensed under CC BY-SA 3.0