2

From a Coded UI test method, what is the way to upload a captured image into Azure Storage and not saving in local drive?

To save a captured image into a local file, I am doing the following, it works fine:

BrowserWindow window = new BrowserWindow();
Image cml1 = window.CaptureImage();
cml1.Save(screenshotDir + screenshotDirClickMainLinks + "1" + 
CMLelectAndNaturalGas + DateTime.Now.ToString(dateTime) + fileSuffix); 

How to upload "cml1" into Azure Storage without saving it in a local drive? Do I convert cml1 one into a stream that can be input into an Azure storage object? This link looks to have some info, but it does not talk about Azure Storage. This link has "UploadFromStream" method for CloudBlockBlob, but no example is given.

For Azure Storage, I know how to create a container and upload a local file into that container. Here is the code segment:

if (CloudStorageAccount.TryParse(storageConnectionString, out storageAccount))
{
    // Get the reference of the storage blob
    CloudBlobClient client = storageAccount.CreateCloudBlobClient();

    CloudBlobContainer container = client.GetContainerReference("testresult");

     container.CreateIfNotExists();

CloudBlockBlob cloudBlockBlob = container.GetBlockBlobReference(localFileName);
cloudBlockBlob.UploadFromFile(sourceFile);

// Uploading second file

CloudBlobContainer container2 = client.GetContainerReference("testresult");
            container2.CreateIfNotExists();


CloudBlockBlob cloudBlockBlob2 = container2.GetBlockBlobReference(localFileName2);
cloudBlockBlob2.UploadFromFile(sourceFile2);

}

How do I use "cml1" reference to upload the captured image into Azure Storage directly without saving it into a local folder first?

Thank you.

Sohel
  • 656
  • 2
  • 11
  • 31

1 Answers1

2

The output returned from BrowserWindow.CaptureImage is a System.Drawing.Image (the type of your variable cml1), which you can convert to a byte[] using a technique such as described here, or better, compress the image to a more concise format such as .PNG:

public static byte[] ImageToByte(Image img)
{
    using (var stream = new MemoryStream())
    {
        img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
        return stream.ToArray();
    }
}

Credit: Above code taken directly from this StackOverflow answer here

Once you have the byte[] array, you can then directly upload this to your Blobstorage container, with an approach similar to what you've tried, but using the more direct CloudBlockBlob.UploadFromByteArrayAsync method.

public async Task SaveBlob(string containerName, string key, byte[] blobToSave)
{
  var blobClient = _storageAccount.CreateCloudBlobClient();
  var blobContainer = blobClient.GetContainerReference(containerName);
  await blobContainer.CreateIfNotExistsAsync();
  var blockBlob = container.GetBlockBlobReference(key);
  await blockBlob.UploadFromByteArrayAsync(blobToSave, 0, blobToSave.Length);
}

Where _storageAccount is the CloudStorageAccount parsed from your Azure Storage account connection string, containerName is the (lowercase) name of the container (folder), key is a unique filename for your image, and of course blobToSave is the byte array you've just converted.

Performance note - if you are storing multiple blobs to the same container reference, that you won't want to do the CreateIfNotExists(Async) check each time - ideally, do a one-off check at bootstrap time when your app or test is launched.

StuartLC
  • 104,537
  • 17
  • 209
  • 285
  • Further to performance, if you are uploading a large number of blobs consecutively, you can retain and reuse the `blobContainer` reference. I'm not 100% sure of the thread safety, if you intend parallelizing uploads. – StuartLC May 16 '18 at 19:55
  • 1
    Thank you very much StuartLC for giving me detail answer that I sincerely appreciate. I will check your solution in detail and will update my code. – Sohel May 16 '18 at 20:04
  • Thanks again StuartLC. I am able to update my code with your help. Great response! – Sohel May 16 '18 at 20:48