我创建了一个自定义操作结果来发送从另一台服务器下载的多个文件的压缩存档。
抱歉,有大量代码,但它确实存在。
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;
}
}
}
一切正常,直到客户尝试从服务器所在的同一网络下载压缩存档。这很奇怪,因为出于某种原因下载对我来说很好。
唯一明显的区别是我和他的下载速度。他的下载速度约为 11 mbps,而我的下载速度为 0.4 mbps。
记录的异常:
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)