我怎样才能创建生成并返回一个zip压缩文件从内存JPEG文件(MemoryStream的对象)的集合流在Web API控制器。 我试图用DotNetZip库。 我发现这个例子: http://www.4guysfromrolla.com/articles/092910-1.aspx#postadlink 。 但Response.OutputStream是不是在网络API可用,所以该技术不做得比较工作。 因此,我试图保存压缩文件到一个新的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)抛出空引用。 但无论是zip文件,也不memStream是空的,没有内部异常。 所以,我不知道是什么导致空引用。 我已经使用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://stackoverflow.com/a/16171977/92756
var pushStreamContent = new PushStreamContent((stream, content, context) =>
{
zipFile.Save(stream);
stream.Close(); // After save we close the stream to signal that we are done writing.
}, "application/zip");
return new HttpResponseMessage(HttpStatusCode.OK) {Content = pushStreamContent};
}
该ZipContentResult
方法还可以住在一个基类,从在任何API控制器的任何其他动作使用。
该PushStreamContent类可以在这种情况下使用,以消除对MemoryStream的需要,至少在整个压缩文件。 它可以实现这样的:
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));
var streamContent = new PushStreamContent((outputStream, httpContext, transportContent) =>
{
try
{
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;
}
使用.NET框架4.6.1与MVC 5
我有同样的问题,因为你。
zipFile.Save(outputStream); //I got Null Reference Exception here.
问题是,我是从像这样一个内存流添加文件:
zip.AddEntry(fileName, ms);
所有你需要做的就是它改成这样:
zip.AddEntry(fileName, ms.ToArray());
看来,当笔者决定实际编写的文件,并试图读取数据流,数据流是垃圾收集或某事...
干杯!
文章来源: Using ASP.NET Web API, how can a controller return a collection of streamed images compressed using DotNetZip Library?