1

Currently I'm sending a file from Angular as a blob using formdata like so

  uploadFiles(file) {
    let testData: FormData = new FormData();
    testData.append('file_upload', file, file.name);
    console.log("TESTDATA", file);
    console.log(file);
    return this.http
      .post<{ message: string; listingId: string; creator: string }>(
        environment.azure_function_url + `/UploadFilesTest`,
        testData
      );
  }

I'm able to receive it in the azure function by following this answer in my azure function, but I'm not sure how to get from here to azure blob. I'm not sure what I would pass into blobService.createBlockBlobFromLocalFile to get the file to blob storage. I tried passing the parts and image variables but it keeps saying Parameter blob for function _createBlobFromLocalFile should be a non-empty string If I return the commented out code at the bottom then the frontend returns

enter image description here

which seems promising to me that I'm on the right track, butI just don't know how to get this to play nice with createBlockBlobFromLocalFile() function. I appreciate any help!

var multipart = require("parse-multipart");
var azure = require('azure-storage');
var blobService = azure.createBlobService(process.env.AZURE_STORAGE_AUCTIONIMAGESACCOUNT, process.env.AZURE_STORAGE_AZURE_STORAGE_AUCTIONIMAGESACCOUNT_ACCESS_KEY);

module.exports = function (context, req) {

  // encode body to base64 string
  var bodyBuffer = Buffer.from(req.body);

  var boundary = multipart.getBoundary(req.headers['content-type']);
  // parse the body
  var parts = multipart.Parse(bodyBuffer, boundary);
  console.log(parts)
  let image = [{ name: parts[0].filename, type: parts[0].type, data: parts[0].data.length }];
  // context.res = { body: { name: parts[0].filename, type: parts[0].type, data: parts[0].data.length, "TEST": "TEST" } };
  // context.done();
  // return;

  blobService.createBlockBlobFromLocalFile('auctionimages', image, 'image.png', function (error, result, response) {
    if (!error) {
      // file uploaded
    }
  });


};
user6680
  • 79
  • 6
  • 34
  • 78
  • Is using `formidable` an option? I answered a similar question a few days ago where I used that package. – Gaurav Mantri May 18 '20 at 16:00
  • As long as I can get it working, I don't care how it's done lol. I did read that azure functions are a little tricky when dealing with files so I'm not sure if formidable will work, but I'm no expert – user6680 May 18 '20 at 16:06
  • See if this helps: https://stackoverflow.com/questions/61423408/images-uploaded-with-node-corrupted. – Gaurav Mantri May 18 '20 at 16:16
  • Azure functions are setup a little different. The person in that answer also mentions this ```I had to tune it for Azure functions``` so I need an azure function focused solution. I'm not sure this will work for me – user6680 May 18 '20 at 16:56
  • @user6680 please refer to https://medium.com/@rkmusic75/uploading-image-multipart-to-azure-blob-from-azure-functions-streamifier-parse-multipart-79d9d679adef – Jim Xu May 20 '20 at 07:39
  • @JimXu I looked at that article and It got me farther. I was able to add a file to storage blob, but it stores the image file with the name blob https://postimg.cc/1nkxZmrs and it's no longer an image. Here's my updated code and console output https://pastebin.com/X281tp8Y Do you know what my issue is? – user6680 May 20 '20 at 13:54

1 Answers1

1

If you want to save the blob as image in Azure blob storage, you want to set the blob content type by creating CreateBlockBlobRequestOptions when we upload file with the method createBlockBlobFromStream. enter image description here

For example


const streamifier = require('streamifier');
const multipart = require('parse-multipart');
const azure = require('azure-storage');

module.exports =  function (context, req) {
  var bodyBuffer = Buffer.from(req.body);
  var boundary = multipart.getBoundary(req.headers['content-type']);
  var parts = multipart.Parse(bodyBuffer, boundary);

  var filedata = parts[0].data;         // Image buffer data
  var filename = parts[0].filename;     // testImage.png
  console.log("parts[0].data");
  console.log(parts[0].data);
  console.log("parts[0].filename");
  console.log(parts[0].filename);
  const accountname ="blobstorage0516";
  const key = "eGier5YJBzr5z3xgOJUb+sn***7Csvgx75NwiOZE7kYLJfLqWBg==";
  const containerName="test1";
  const blobClient  =azure.createBlobService(accountname,key);
 # set blob content type
  var options = {
    contentSettings:{contentType: parts[0].type}
  };
  blobClient.createBlockBlobFromStream(containerName,filename,streamifier.createReadStream(new Buffer(filedata)), filedata.length,options,(err,result)=>{

    if (!err) {
        console.log("Image upload successful", result);

    } else{

      throw err;
    }
  })
  context.res = {
    // status defaults to 200 */
    body: "ok"
};
context.done();
};

enter image description here enter image description here

Jim Xu
  • 21,610
  • 2
  • 19
  • 39
  • I updated my code using your answer and it uploads to storage: https://postimg.cc/LhQh8hVV. It shows image/jpeg as content-type, but file lacks file extension. If I click the file to view it from storage, then it says ```the image can't be displayed because it contained errors.``` I think it's related to ```console.log(parts[0].filename)``` that outputs the value ```blob``` instead of something like ```testImage.png``` It's not accessing filename property correctly, but it does have the array buffer coming in as you can see from my console.log https://pastebin.com/ise1z5CM . Any ideas? – user6680 May 21 '20 at 02:54
  • @user6680, `parts[0].filename` will get the vault of your `File` object's name in the `Formdata`. According to the picture you provide, the file name is blob – Jim Xu May 21 '20 at 03:17
  • So apparently it doesn't work when being sent from my Angular application, but it does work from postman. I sent a file from postman and it worked perfectly, but from my app I have the problem I've been experiencing, which means it's related to how I'm sending the file I'm guessing I have to send the file in a different format from Angular other than blob type. I believe blob is the type. ```console.log("imageData", file.name)``` outputs https://postimg.cc/8sTr5jrF ```console.log("imageData", file);``` outputs https://postimg.cc/hhR10DQg Updated angular service: https://pastebin.com/k2heZrrP – user6680 May 21 '20 at 03:55
  • @user6680 please try to send a file from your angular application as a [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) type to Azure function. For more details, please refer to https://stackoverflow.com/questions/47936183/angular-file-upload – Jim Xu May 21 '20 at 05:00