使用ASP.NET Web API,控制器如何返回使用DotNetZip Library压缩的流图像集合?

如何创建Web API控制器,生成并返回从内存中JPEG文件(MemoryStream对象)集合流式传输的压缩zip文件。 我正在尝试使用DotNetZip库。 我找到了这个例子: http : //www.4guysfromrolla.com/articles/092910-1.aspx#postadlink 。 但是,Response.OutputStream在Web API中不可用,因此该技术不能正常工作。 因此我尝试将zip文件保存到新的MemoryStream中; 但它扔了。 最后,我尝试使用PushStreamContent。 这是我的代码:

public HttpResponseMessage Get(string imageIDsList) { var imageIDs = imageIDsList.Split(',').Select(_ => int.Parse(_)); var any = _dataContext.DeepZoomImages.Select(_ => _.ImageID).Where(_ => imageIDs.Contains(_)).Any(); if (!any) { throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound)); } var dzImages = _dataContext.DeepZoomImages.Where(_ => imageIDs.Contains(_.ImageID)); using (var zipFile = new ZipFile()) { foreach (var dzImage in dzImages) { var bitmap = GetFullSizeBitmap(dzImage); var memoryStream = new MemoryStream(); bitmap.Save(memoryStream, ImageFormat.Jpeg); var fileName = string.Format("{0}.jpg", dzImage.ImageName); zipFile.AddEntry(fileName, memoryStream); } var response = new HttpResponseMessage(HttpStatusCode.OK); var memStream = new MemoryStream(); zipFile.Save(memStream); //Null Reference Exception response.Content = new ByteArrayContent(memStream.ToArray()); response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/zip"); response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = string.Format("{0}_images.zip", dzImages.Count()) }; return response; } } 

zipFile.Save(memStream)抛出null引用。 但是zipFile和memStream都不为null,并且没有内部exception。 所以我不确定是什么导致了null引用。 我对Web API,内存流的经验很少,而且之前我从未使用过DotNetZipLibrary。 这是对这个问题的跟进: 想要一个高效的ASP.NET Web API控制器,它可以可靠地返回30到50~3MB的JPEG

有任何想法吗? 谢谢!

更通用的方法可以这样工作:

 using Ionic.Zip; // from NUGET-Package "DotNetZip" public HttpResponseMessage Zipped() { using (var zipFile = new ZipFile()) { // add all files you need from disk, database or memory // zipFile.AddEntry(...); return ZipContentResult(zipFile); } } protected HttpResponseMessage ZipContentResult(ZipFile zipFile) { // inspired from http://sofzh.miximages.com/c%23/y { using (var zipFile = new ZipFile()) { foreach (var dzImage in dzImages) { var bitmap = GetFullSizeBitmap(dzImage); var memoryStream = new MemoryStream(); bitmap.Save(memoryStream, ImageFormat.Jpeg); memoryStream.Position = 0; var fileName = string.Format("{0}.jpg", dzImage.ImageName); zipFile.AddEntry(fileName, memoryStream); } zipFile.Save(outputStream); //Null Reference Exception } } finally { outputStream.Close(); } }); streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/zip"); streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = string.Format("{0}_images.zip", dzImages.Count()), }; var response = new HttpResponseMessage(HttpStatusCode.OK) { Content = streamContent }; return response; } 

理想情况下,使用ZipOutputStream类动态创建zip而不是使用ZipFile可以更加动态地创建它。 在这种情况下,不需要每个位图的MemoryStream。

 public HttpResponseMessage GetItemsInZip(int id) { var itemsToWrite = // return array of objects based on id; // create zip file stream MemoryStream archiveStream = new MemoryStream(); using (ZipArchive archiveFile = new ZipArchive(archiveStream, ZipArchiveMode.Create, true)) { foreach (var item in itemsToWrite) { // create file streams // add the stream to zip file var entry = archiveFile.CreateEntry(item.FileName); using (StreamWriter sw = new StreamWriter(entry.Open())) { sw.Write(item.Content); } } } // return the zip file stream to http response content HttpResponseMessage responseMsg = new HttpResponseMessage(HttpStatusCode.OK); responseMsg.Content = new ByteArrayContent(archiveStream.ToArray()); archiveStream.Dispose(); responseMsg.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = "test.zip" }; responseMsg.Content.Headers.ContentType = new MediaTypeHeaderValue("application/zip"); return responseMsg; } 

使用Framework .NET 4.6.1和MVC 5

我和你有同样的问题。

 zipFile.Save(outputStream); //I got Null Reference Exception here. 

问题是我正在从内存流中添加文件,如下所示:

 zip.AddEntry(fileName, ms); 

您所要做的就是将其更改为:

 zip.AddEntry(fileName, ms.ToArray()); 

似乎当作者决定实际写入文件并尝试读取流时,流被垃圾收集或者……

干杯!