0

I'm trying to create an HTTP triggered function that will pull down a blob out of Azure storage, zip it, and then reupload the zip to blob storage. Somewhere along the way this is going wrong. It successfully zips and re-uploads but the zip file has 0KB content and cannot be opened. Any help would be appreciated. Find code below.

 public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
    {
        log.Info("C# HTTP trigger function processed a request.");
        try
        {
          string fileName = req.GetQueryNameValuePairs()
                .FirstOrDefault(q => string.Compare(q.Key, "fileName", true) == 0)
                .Value;

            log.Info($"fileName: {fileName}");

            dynamic request = await req.Content.ReadAsAsync<object>();
            var container = (string)request.body;

            string connectionString = Environment.GetEnvironmentVariable("blobstorageconnectionstring");
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);
            CloudBlobClient client = storageAccount.CreateCloudBlobClient();

            MemoryStream outputStream = new MemoryStream();

            using (ZipFile zip = new ZipFile())
            {
                zip.AddEntry($"{fileName}.xlsx", DownloadFromBlobStorage(fileName, connectionString, container));
                zip.CompressionMethod = CompressionMethod.Deflate;
                zip.Save(outputStream);
            }


            UploadToBlobStorage(fileName + "ZIP", outputStream, connectionString, container);

            return req.CreateResponse(HttpStatusCode.OK, "OK");
        }
        catch (Exception ex)
        {
            log.Error("error", ex: ex);

            return req.CreateResponse(HttpStatusCode.BadRequest);
        }

    }
    private static void UploadToBlobStorage(string name, MemoryStream dataStream, string storageConnectionString, string blobContainerName)
    {

        CloudStorageAccount account = CloudStorageAccount.Parse(storageConnectionString);
        CloudBlobClient client = account.CreateCloudBlobClient();

        CloudBlobContainer container = client.GetContainerReference(blobContainerName);
        container.CreateIfNotExists();

        CloudBlockBlob blob = container.GetBlockBlobReference(name);
        blob.Properties.ContentType = "application/x-zip-compressed";

        dataStream.Position = 0;
        blob.UploadFromStream(dataStream);
    }
    private static MemoryStream DownloadFromBlobStorage(string fileName, string storageConnectionString, string blobContainerName)
    {

        CloudStorageAccount account = CloudStorageAccount.Parse(storageConnectionString);
        CloudBlobClient client = account.CreateCloudBlobClient();

        CloudBlobContainer container = client.GetContainerReference(blobContainerName);
        container.CreateIfNotExists();

        CloudBlockBlob blob = container.GetBlockBlobReference(fileName);

        MemoryStream memStream = new MemoryStream();

        blob.DownloadToStream(memStream);

        return memStream;
    }
Abifail
  • 23
  • 4

1 Answers1

0

It seems that you should position the MemoryStream object returned from DownloadFromBlobStorage() to zero too (you already do it with outputStream/dataStream on UploadToBlobStorage()), before passing it to zip.AddEntry():

   MemoryStream inputStream = DownloadFromBlobStorage(fileName, connectionString, container);
   inputStream.Position = 0;
   zip.AddEntry($"{fileName}.xlsx", inputStream);

Take a look at this answer:

Creating Zip file from stream and downloading it - Stack Overflow

After some more research I found that generally you should always position a stream before passing it for a function:

Who is responsible for stream positioning? - Software Engineering Stack Exchange

Pedro Gaspar
  • 777
  • 8
  • 35
  • That fixed it. I feel dumb. Thank you!! – Abifail Nov 29 '18 at 17:34
  • As an alternative: `inputStream.Seek(0, SeekOrigin.Begin);` – JohnyL Nov 29 '18 at 19:23
  • @JohnyL, yeah, that's how it's used on the answer I've linked, so I researched about the differences, but in that case there are no differences between both methods: [Stream.Seek(0, SeekOrigin.Begin) or Position = 0](https://stackoverflow.com/q/7238929/8133067) – Pedro Gaspar Nov 29 '18 at 19:26