【发布时间】:2018-10-21 09:10:02
【问题描述】:
我在这里查看了其他问题,但没有人回答我为什么不能使用现有的 MemoryStream 来创建 zip。
这是获取包含文件的压缩文件夹的有效 API 方法。这些文件已经存在于服务器上,该方法只是查找那里的位置,并在内存中检索所有文件,并向用户发送一个 HttpResponMessage 对象,其中包含所有文件的压缩文件夹。然而,下面有一行代码似乎没有意义。我必须将 MemoryStream 解析为字节数组,然后再解析回 MemoryStream,以便正确创建 Zip 并将其发送回。这似乎是错误的,但我不知道如何纠正它。 (见下文“//Works:”和“//Does Not work:”)
public HttpResponseMessage GetEvalByCompany([FromUri]Guid id, [FromUri] int year)
{
try
{
string companyName = _portalDB.Companies.FirstOrDefault(c => c.Id == id).FirmName;
//Get all evaluation file paths for a given company for a given year
var files = _evaluationDB.Evaluations.Where(j => j.CompanyId == id).Select(j => @"C:\Path\To\File" + j.RelativePath.Replace("~", @"").Replace(@"/", @"\")).Distinct().ToList<string>();
using (var outStream = new MemoryStream())
{
using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
{
foreach (var record in files)
{
var fileInArchive = archive.CreateEntryFromFile(record, Path.GetFileName(record), CompressionLevel.Optimal);
}
}
// Create a response
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
//Works:
response.Content = new StreamContent(new MemoryStream(outStream.ToArray())); //Why does this need to happen?
//Does Not work:
//response.Content = new StreamContent(outStream); //Why doesn't this work?
// Add appropriate headers to make browser recognize response as a download
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = "Evaluations for Company - " + companyName + ".zip";
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/zip");
return response;
}
}
catch (Exception ex)
{
return ErrorHandler.HandleException(ex, Request);
}
}
根据我收到的答案,我能够修复代码,因此它不必不必要地解析流。这是为未来开发人员简单地寻找解决方案的更新代码。删除 using 似乎也不会导致任何 GC 问题。我找到了一个链接来更好地解释这一点。 (MemoryStream.Close() or MemoryStream.Dispose())
public HttpResponseMessage GetEvalByCompany([FromUri]Guid id, [FromUri] int year)
{
try
{
string companyName = _portalDB.Companies.FirstOrDefault(c => c.Id == id).FirmName;
//Get all evaluation file paths for a given company for a given year
var files = _evaluationDB.Evaluations.Where(j => j.CompanyId == id).Select(j => @"C:\Path\To\File" + j.RelativePath.Replace("~", @"").Replace(@"/", @"\")).Distinct().ToList<string>();
var outStream = new MemoryStream();
using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
{
foreach (var record in files)
{
var fileInArchive = archive.CreateEntryFromFile(record, Path.GetFileName(record), CompressionLevel.Optimal);
}
}
// Create a response
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
//Updated code
outStream.Seek(0, SeekOrigin.Begin);
response.Content = new StreamContent(outStream); //works now because outStream isn't in a using block
// Add appropriate headers to make browser recognize response as a download
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = "Evaluations for Company - " + companyName + ".zip";
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/zip");
return response;
}
catch (Exception ex)
{
return ErrorHandler.HandleException(ex, Request);
}
}
【问题讨论】:
-
将流寻回零应该不够吗?
-
当我使用 .Seek(0, SeekOrigin.Begin) 或 .Position = 0 时,我得到与“不起作用”代码相同的结果。浏览器收到“成功”的 200 响应,标题确认内容中的文档但状态为失败且未下载 zip。