1

I downloaded a file from an FTP server using an azure function and save it in the target that I get from this code:

var target = Path.Combine(context.FunctionAppDirectory, "File.CSV");

Which will be somewhere in "File Shares" that we can see in "Microsoft Azure storage Explorer".

Now my question is about how to copy this file from File Share to Blob container or Directly save it to Blob Storage that azure SQL has access to?

sishanov
  • 141
  • 2
  • 9

3 Answers3

0
    private static void AzureStorageAccountBlob()
    {
        string filename = "mytestfile.txt";
        string fileContents = "some content";

        StorageCredentials creds = new StorageCredentials("mystorageaccount2020", "XXXXX");
        CloudStorageAccount acct = new CloudStorageAccount(creds, true);
        CloudBlobClient client = acct.CreateCloudBlobClient();
        CloudBlobContainer container = client.GetContainerReference("myfirstcontainer");

        container.CreateIfNotExists();
        ICloudBlob blob = container.GetBlockBlobReference(filename);
        using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(fileContents)))
        {
            blob.UploadFromStream(stream);
        }
    }

In my example I have assumed that content already achieved from file. And also one important thing you must create StorageAccount.

Tigran
  • 51
  • 3
  • blob.UploadFromStream(stream); this is only available with Async. I cannot see UploadFromStream! – sishanov Nov 04 '19 at 14:37
  • @sishanov You must install WindowsAzure.Storage library from nuget. void UploadFromStream(Stream source, AccessCondition accessCondition = null, BlobRequestOptions options = null, OperationContext operationContext = null); – Tigran Nov 05 '19 at 07:41
0

Use the below extention to upload to azure:

    /// <summary>
    /// </summary>
    /// <param name="file"></param>
    /// <param name="fileName"></param>
    /// <param name="connectionString"></param>
    /// <param name="containerName"></param>
    /// <param name="blobContentType"></param>
    /// <returns></returns>
    public static async Task<string> AzureUpload(this Stream file, string fileName, string connectionString, string containerName, string blobContentType = null)
    {
        CloudBlobClient blobClient = CloudStorageAccount.Parse(connectionString).CreateCloudBlobClient();
        CloudBlobContainer container = blobClient.GetContainerReference(containerName);
        if (await container.CreateIfNotExistsAsync())
        {
           // Comment this code below if you don't want your files
           // to be publicly available. By default, a container is private.
           // You can see more on how
           // to set different container permissions at: 
           // https://learn.microsoft.com/en-us/azure/storage/blobs/storage-manage-access-to-resources
            await container.SetPermissionsAsync(new BlobContainerPermissions() { PublicAccess = BlobContainerPublicAccessType.Blob });
        }

        CloudBlockBlob blockBlob = container.GetBlockBlobReference(fileName);

        await blockBlob.UploadFromStreamAsync(file);

        blobContentType = blobContentType.HasValue() ? blobContentType : getBlobContentType(fileName);
        if (blobContentType.HasValue())
        {
            blockBlob.Properties.ContentType = blobContentType;
            await blockBlob.SetPropertiesAsync();
        }

        return blockBlob.Uri.AbsoluteUri;
    }

Do something like this:

var target = Path.Combine(context.FunctionAppDirectory, "File.CSV");
FileStream fileStream = new FileStream(target, FileMode.Open, FileAccess.Read);;
string azureUriForUploadedCSV = await fileStream.AzureUpload(
                "File.CSV",
                "StorageConnectionString",
                "csv-folder",
                "application/csv");

Then save azureUriForUploadedCSV into your database...

McKabue
  • 2,076
  • 1
  • 19
  • 34
  • I don't want that BlobContainerPublicAccessType access to the blob, what that public does for us in this case – sishanov Nov 04 '19 at 14:41
  • just comment this line: `await container.SetPermissionsAsync(new BlobContainerPermissions() { PublicAccess = BlobContainerPublicAccessType.Blob });` – McKabue Nov 04 '19 at 17:02
0

We can use CloudBlockBlob.StartCopy(CloudFile). You may refer to the code below:

using System;
using Microsoft.Azure.Storage;
using Microsoft.Azure.Storage.Blob;
using Microsoft.Azure.Storage.File;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            // Parse the connection string for the storage account.
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=*************");

            // Create a CloudFileClient object for credentialed access to File storage.
            CloudFileClient fileClient = storageAccount.CreateCloudFileClient();

            // Get a reference to the file share you created previously.
            CloudFileShare share = fileClient.GetShareReference("hurytest");

            // Get a reference to the file("test.csv") which I have uploaded to the file share("hurytest")
            CloudFile sourceFile = share.GetRootDirectoryReference().GetFileReference("test.csv");

            // Get a reference to the blob to which the file will be copied.(I have created a container with name of "targetcontainer")
            CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
            CloudBlobContainer container = blobClient.GetContainerReference("targetcontainer");
            //container.CreateIfNotExists();
            CloudBlockBlob destBlob = container.GetBlockBlobReference("test.csv");

            // Create a SAS for the file that's valid for 24 hours.
            // Note that when you are copying a file to a blob, or a blob to a file, you must use a SAS
            // to authenticate access to the source object, even if you are copying within the same
            // storage account.
            string fileSas = sourceFile.GetSharedAccessSignature(new SharedAccessFilePolicy()
            {
                // Only read permissions are required for the source file.
                Permissions = SharedAccessFilePermissions.Read,
                SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24)
            });

            // Construct the URI to the source file, including the SAS token.
            Uri fileSasUri = new Uri(sourceFile.StorageUri.PrimaryUri.ToString() + fileSas);

            // Copy the file to the blob.
            destBlob.StartCopy(fileSasUri);
        }
    }
}

Hope it would be helpful to your problem~

Hury Shen
  • 14,948
  • 1
  • 9
  • 18
  • I get an error in this one Uri fileSasUri = new Uri(sourceFile.StorageUri.PrimaryUri.ToString() + fileSas); – sishanov Nov 04 '19 at 14:42
  • Hi @sishanov, could you please share the error message ? – Hury Shen Nov 04 '19 at 14:46
  • The specifed resource name contains invalid characters. @hury – sishanov Nov 04 '19 at 15:26
  • Hi @sishanov, sorry for the delay. I test it just now, the code do the copy operation successfully and I didn't meet the same error you mentioned. I update the code in my answer, could you please check if there is any differences between your code and mine ? If still have any problem, please let me know. – Hury Shen Nov 05 '19 at 02:09
  • Hi @sishanov, is there any update ? May I know if you have solved this problem ? – Hury Shen Nov 05 '19 at 09:53
  • Thank you for your solution it worked even though it took almost a day for me to get it up and running. I changed two things 1. I hardcoded fileSasUri 2. I used destBlob.StartCopyAsync(fileSasUri)) instead because destBlob.StartCopy(...) was not available for me – sishanov Nov 05 '19 at 14:42
  • @sishanov I'm glad to hear that. The problem of StartCopyAsync() maybe caused by some difference between your nuget and mine, I guess you "using Microsoft.WindowsAzure.Storage.Blob" nuget in your code. If this solution helps your problem, could you please [mark](https://stackoverflow.com/help/someone-answers) my answer as "accepted" ? Thanks in advance~ – Hury Shen Nov 06 '19 at 03:23
  • when I use azure storage explorer to create this SharedAccessFilePlocy I get a value which is different from what your code gives me I get this one in the azure explorer : ?st=2019-11-05**** &se=2019-11-06**** &sp=rl&sv=2018-03-28 &sr=**** &sig=**** and the one I get from your code is this one and that's why it did not work with code but wehn i hardcoded that value ir worked then. Do you have any idea why is that? ?sv=2018-03-28 &sr=**** &sig=1**** &se=2019-11-0**** sp=r" – sishanov Nov 06 '19 at 09:29
  • @sishanov I'm not sure, but could you please try to modify the nuget which you used in your code. Did you use "WindowsAzure" nuget ? In my code, I use "using Microsoft.Azure.Storage" instead of "using Microsoft.WindowsAzure.Storage". The other two nuget in my code are like the same. Please have a try. – Hury Shen Nov 06 '19 at 09:52
  • I changed the Nuget but it seems like the new one does not have this CreateCloudFileClient in it – sishanov Nov 06 '19 at 10:10
  • that's a bit strange because I had to install all these Nugets separately using Microsoft.Azure.Storage; using Microsoft.Azure.Storage.Auth; using Microsoft.Azure.Storage.Blob; using Microsoft.Azure.Storage.File; – sishanov Nov 06 '19 at 10:25
  • @sishanov So have you solved the issue after change these three nugets ? – Hury Shen Nov 06 '19 at 13:24
  • not really and then I created this new question for the new issue: https://stackoverflow.com/questions/58731067/create-a-share-account-signature-in-c-sharp?noredirect=1#comment103752941_58731067 – sishanov Nov 06 '19 at 13:31