我有一个web api GET方法,它返回一个zip文件供下载。这是创建zip存档的代码:
var resultStream = new MemoryStream();
using (var zipArchive = new ZipArchive(resultStream, ZipArchiveMode.Create, leaveOpen: true))
{
foreach (var file in files)
{
zipArchive.CreateEntryFromFile(file.Path, file.Name, CompressionLevel.Optimal);
}
}
以下是响应如何填充:
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new ByteArrayContent(resultStream.ToArray());
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/zip");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = "export_" + DateTime.Now.ToString("dd-MM-yyyy_HH-mm-ss") + ".zip";
response.Content.Headers.ContentDisposition.CreationDate = DateTime.Now;
response.Content.Headers.ContentDisposition.Size = resultStream.Length;
response.Content.Headers.ContentLength = resultStream.Length;
上面的代码工作得很好,问题是它在服务器上消耗了大量内存,当然这取决于文件大小。我已经尝试将结果更改为StreamContent
,但这不起作用,因为响应只返回标题并最终超时。
所以这是我的问题:
IHostBufferPolicySelector
来禁用缓冲,但它似乎没有任何效果。答案 0 :(得分:3)
改编自Kudu
项目,该方法使用PushStreamContent
与特定DelegatingStream
包装器组合来流式传输zip存档:
public static class ZipStreamContent
{
public static PushStreamContent Create(string fileName, Action<ZipArchive> onZip)
{
var content = new PushStreamContent((outputStream, httpContent, transportContext) =>
{
using (var zip = new ZipArchive(new StreamWrapper(outputStream), ZipArchiveMode.Create, leaveOpen: false))
{
onZip(zip);
}
});
content.Headers.ContentType = new MediaTypeHeaderValue("application/zip");
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
content.Headers.ContentDisposition.FileName = fileName;
return content;
}
// this wraps the read-only HttpResponseStream to support ZipArchive Position getter.
public class StreamWrapper : DelegatingStream
{
private long _position = 0;
public StreamWrapper(Stream stream)
: base(stream)
{
}
public override long Position
{
get { return _position; }
set { throw new NotSupportedException(); }
}
public override void Write(byte[] buffer, int offset, int count)
{
_position += count;
base.Write(buffer, offset, count);
}
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
_position += count;
return base.BeginWrite(buffer, offset, count, callback, state);
}
}
}
根据您的情况,您可以使用:
var response = new HttpResponseMessage(HttpStatusCode.OK);
var response.Content = ZipStreamContent.Create(
"export_" + DateTime.Now.ToString("dd-MM-yyyy_HH-mm-ss") + ".zip",
zipArchive => {
foreach (var file in files)
{
zipArchive.CreateEntryFromFile(file.Path, file.Name, CompressionLevel.Optimal);
}
});