Создание Zip-архива в памяти и возврат его из веб-интерфейса - PullRequest
0 голосов
/ 06 июня 2018

Итак, я пытаюсь создать zip-архив и вернуть его из моего веб-интерфейса.Контроллер вызывается с углового 2 сайта.В настоящее время zip-файл создается, но когда я его открываю, я получаю неверное сообщение.Первоначально у меня были потоки в использовании операторов, но я должен был изменить их по мере их удаления до завершения запроса.

Мне нужно создать zip-файл, добавить файл csv к его содержимому.А затем верните почтовый файл.Но почтовый файл всегда недействителен.Я прочитал, что zip-архив необходимо утилизировать, чтобы он записал его содержимое, однако я не уверен, каков наилучший способ реализовать это.Спасибо за любые рекомендации.

public async Task<IHttpActionResult> ExportReport(int id, ReportModel report)
    {
        try
        {
            var result = await ReportGenerationService.ExportReportForId(id, report.Page, report.PageSize, report.SortField, report.SortDir, report.SearchTerm, report.StartDate, report.EndDate, report.UserId, report.TeamId, report.SelectedDateItem);
            if (result != null)
            {

                var compressedFileStream = new MemoryStream();

                var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Update, false);

                var zipEntry = zipArchive.CreateEntry("textExport.csv");
                var origionalFileSteam = new MemoryStream(result.ExportToBytes());
                var zipEntryStream = zipEntry.Open();
                origionalFileSteam.CopyTo(zipEntryStream);


                var response = new HttpResponseMessage(HttpStatusCode.OK) {Content = new StreamContent(compressedFileStream)};
                response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
                response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
                {
                    FileName = "Export.zip"
                };

                var t = compressedFileStream.CanRead;
                return ResponseMessage(response);

            }

            return NotFound();
        }
        catch (Exception ex)
        {
            return InternalServerError(ex);
        }
    }

В ответ на операторы using:

В какой-то момент у меня было все, что связано с использованием операторов, но ответ не удался, потому что поток уже был удален.Вы можете увидеть это ниже.

public async Task<IHttpActionResult> ExportReport(int id, ReportModel report)
    {
        try
        {
            var result = await ReportGenerationService.ExportReportForId(id, report.Page, report.PageSize, report.SortField, report.SortDir, report.SearchTerm, report.StartDate, report.EndDate, report.UserId, report.TeamId, report.SelectedDateItem);
            if (result != null)
            {

                var compressedFileStream = new MemoryStream();
                var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Update, false);

                        //Create a zip entry for each attachment
                    var zipEntry = zipArchive.CreateEntry("textExport.csv");

                    //Get the stream of the attachment
                    using (var originalFileStream = new MemoryStream(result.ExportToBytes()))
                    using (var zipEntryStream = zipEntry.Open()) {
                        //Copy the attachment stream to the zip entry stream
                        originalFileStream.CopyTo(zipEntryStream);
                    }
                    compressedFileStream.Position = 0;

                    var response = new HttpResponseMessage(HttpStatusCode.OK) {Content = new StreamContent(compressedFileStream)};
                    response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
                    response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
                    {
                        FileName = "Export.zip"
                    };

                    return ResponseMessage(response);
            }

            return NotFound();
        }
        catch (Exception ex)
        {
            return InternalServerError(ex);
        }
    }

Ответы [ 2 ]

0 голосов
/ 06 июня 2018

Поток памяти удаляется при удалении zip-архива.

Вы должны утилизировать архив, чтобы заставить его записать содержимое в основной поток памяти, но обратите внимание на следующее

ZipArchive.Dispose ()

Если вы не сконструируете объект с помощью перегрузки конструктора ZipArchive(Stream, ZipArchiveMode, Boolean) и установите для его параметра leaveOpen значениеtrue, все базовые потоки закрыты и больше не доступны для последующих операций записи.

Когда вы закончите использовать этот экземпляр ZipArchive, вызовите Dispose(), чтобы высвободить все ресурсы, используемые этим экземпляром.Вам следует исключить дальнейшие ссылки на этот экземпляр ZipArchive, чтобы сборщик мусора мог восстановить память экземпляра, а не сохранять ее для завершения.

И так как вы хотите продолжить использовать поток памятизатем вам нужно убедиться, что он остается открытым и указатель потока сброшен, чтобы его можно было прочитать с самого начала.

public async Task<IHttpActionResult> ExportReport(int id, ReportModel report) {
    try {
        var result = await ReportGenerationService.ExportReportForId(id, report.Page, report.PageSize, report.SortField, report.SortDir, report.SearchTerm, report.StartDate, report.EndDate, report.UserId, report.TeamId, report.SelectedDateItem);
        if (result != null) {
            var compressedFileStream = new MemoryStream();
            using(var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Create, 
                leaveOpen: true)) { //<--This is important to keep stream open
                //Create a zip entry for each attachment
                var zipEntry = zipArchive.CreateEntry("textExport.csv");
                //Get the stream of the attachment
                using (var originalFileStream = new MemoryStream(result.ExportToBytes()))
                using (var zipEntryStream = zipEntry.Open()) {
                    //Copy the attachment stream to the zip entry stream
                    await originalFileStream.CopyToAsync(zipEntryStream);
                }
            }// disposal of archive will force data to be written/flushed to memory stream.
            compressedFileStream.Position = 0;//reset memory stream position.

            var response = new HttpResponseMessage(HttpStatusCode.OK) {
                Content = new StreamContent(compressedFileStream)
            };
            response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") {
                FileName = "Export.zip"
            };
            return ResponseMessage(response);
        }
        return NotFound();
    } catch (Exception ex) {
        return InternalServerError(ex);
    }
}
0 голосов
/ 06 июня 2018

Вам не хватает горстки using(){} блоков.

Убедитесь, что вы закрыли originalFileSteam, zipEntryStream и zipArchive в правильном порядке.

И просто чтобы быть уверенным, сбросьте memoryStream.Я не знаю, нужно ли это, но это не повредит.

//using (var compressedFileStream = new MemoryStream())
var compressedFileStream = new MemoryStream();

using (var zipArchive = new ZipArchive(...)) 
{
        //Create a zip entry for each attachment
        var zipEntry = zipArchive.CreateEntry("textExport.csv");

        //Get the stream of the attachment
        using (var originalFileStream = new MemoryStream(result.ExportToBytes()))
        using (var zipEntryStream = zipEntry.Open()) 
        {
            //Copy the attachment stream to the zip entry stream
            originalFileStream.CopyTo(zipEntryStream);
        }
}

//compressedFileStream .Position = 0;
var responseBytes =new MemoryStream(compressedFileStream.ToArray());

var response = new HttpResponseMessage(HttpStatusCode.OK) {Content = new StreamContent(responseBytes )};
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

return ResponseMessage(response);
...