Azure Storage Connection - arp6333/xplusplus GitHub Wiki
Connecting to Azure storage without using WindowsAzure.Storage / Connection String (deprecated in 10.0.44)
Follow the initial steps by Microsoft to register an Azure app and assign it the correct roles for the Azure storage location. The only steps needed are "Register the app in Azure" and "Assign roles to the application service principal". Be sure to keep note of the Application (Client) Id, Directory (Tenant) Id, and Client Secret from the "Register the app in Azure" step (the client secret especially as it will be censored after generation).
The following code shows how to connect to the storage location, along with pulling files from storage and uploading a file to storage.
We use a custom table called ConnectionParameters as the method parameter for these functions, which is a parameter table containing the fields necessary to connect. The application id, directory id, and client secret fields retrieved in the setup steps above are stored in the database as an EncryptedField EDT. This makes the data obfuscated, including unable to be parsed when a data refresh is completed (ex. Production data refreshed to Test / Dev will NOT allow any EncryptedField EDT values to be viewed or used and they will need to be reinputted). You will see in the code below that retrieving these fields is via a special method which decrypts the field (ex. 'azureAppIdEdit()'). The app id and tenant id don't necessarily need to be encrypted, but the secret definitely should be. See here for more info on this process of creating / using an EncryptedField.
The relevant list of fields from this table include:
- Application (client) id from Azure app created above, encrypted [AzureAppId]
- Directory (tenant) id from Azure app created above, encrypted [AzureTenantId]
- Client secret from Azure app created above, encrypted [AzureSecretValue]
- Name of the Azure storage account [AzureStorageAccount]
- Name of the Azure container within the Azure storage account [AzureContainer]
- Name of the Azure folder within the Azure container; optional if there are no inner folders [AzureFolder]
using System.Net;
using System.IO;
using System.Collections;
using System.Uri;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.BlobClient;
using Azure.Storage.Blobs.BlobServiceClient;
using Azure.Storage.Blobs.Models;
using Azure.Identity;
using System.Threading;
/// <summary>
/// Helper class for Azure blob storage functionality.
/// </summary>
public static class AzureStorageHelper
{
/// <summary>
/// Connect to an Azure blob storage location.
/// </summary>
/// <param name = "connParam">Connection parameters.</param>
/// <returns>Blob container client.</returns>
public static BlobContainerClient connectToStorage(ConnectionParameters connParam)
{
str blobUri = strFmt("https://%1.blob.core.windows.net", connParam.AzureStorageAccount); // This can be a label
str appId = connParam.azureAppIdEdit(false, ''); // Decrypt the field
str tenantId = connParam.azureTenantIdEdit(false, ''); // Decrypt the field
str clientSecret = connParam.azureSecretValueEdit(false, ''); // Decrypt the field
ClientSecretCredential credential = new ClientSecretCredential(tenantId, appId, clientSecret);
BlobServiceClient blobServiceClient = new BlobServiceClient(new System.Uri(blobUri), credential);
BlobContainerClient blobContainerClient = blobServiceClient.GetBlobContainerClient(connParam.AzureContainer);
return blobContainerClient;
}
/// <summary>
/// Retrieve files from an Azure blob storage location.
/// </summary>
/// <param name = "connParam">Connection parameters.</param>
/// <returns>List of files retrieved.</returns>
public static List retrieveFilesFromBlob(ConnectionParameters connParam)
{
IEnumerable blobEnumerable;
IEnumerator blobEnumerator;
BlobContainerClient blobContainerClient;
BlobClient blobClient;
BlobItem blobFile;
List fileList = new List(Types::AnyType);
// Connect to Azure storage
blobContainerClient = AzureStorageHelper::connectToStorage(connParam);
// Add each blob file to the list of files to return
blobEnumerable = blobContainerClient.GetBlobs(
BlobTraits::None, BlobStates::None, connParam.AzureFolder + @'/', CancellationToken::None);
blobEnumerator = blobEnumerable.GetEnumerator();
while (blobEnumerator.MoveNext())
{
var blobItem = blobEnumerator.Current;
if (blobItem is BlobItem)
{
blobFile = blobItem;
blobClient = blobContainerClient.GetBlobClient(blobFile.Name);
fileList.addEnd(blobClient);
}
}
return fileList;
}
/// <summary>
/// Upload a file to Azure blob storage.
/// </summary>
/// <param name = "connParam">Connection parameters.</param>
/// <param name = "fileName">File name to upload.</param>
/// <param name = "fileStream">File stream to upload.</param>
public static void sendFileToBlob(ConnectionParameters connParam, str fileName, System.IO.MemoryStream fileStream)
{
BlobContainerClient blobContainerClient;
BlobClient blobClient;
// Connect to Azure storage
blobContainerClient = AzureStorageHelper::connectToStorage(connParam);
// Upload the file
blobClient = blobContainerClient.GetBlobClient(fileName);
blobClient.Upload(fileStream, true, CancellationToken::None);
fileStream.Close();
}
}
To read in the actual file from the list of files given in the retrieveFilesFromBlob() method, you can use this code (or you can put this code directly in the method to read the files right away if that works better for your needs):
str fileName, blobContents;
BlobClient cloudBlockBlob;
BlobDownloadResult downloadResult;
List fileList = AzureStorageHelper::retrieveFilesFromBlob(connParam);
ListIterator fileIterator = new ListIterator(fileList);
while (fileIterator.more())
{
try
{
blobClient = fileIterator.value();
fileName = blobClient.Name;
// Read in the file
downloadResult = blobClient.DownloadContent();
blobContents = downloadResult.Content.ToString();
}
}