Search code examples
c#azureazure-storageazure-blob-storageblobstorage

Exception when creating blob asyncronously with Azure Storage - UploadTextAsync


In our project, we were using the Azure Storage 6.0.0 version and we were making use of the UploadTextAsync method to create blobs. After updating to the latest version, the UploadTextAsync function stopped working and now it throws an exception:

"Object reference not set to an instance of an object."

I've tried different methods to replace it but all throw the same exception. For example:

byte[] fileBytes = Encoding.UTF8.GetBytes(data);
await lockBlob.UploadFromByteArrayAsync(fileBytes, 0, fileBytes.Length);

The only way I made it work was to change to the synchronous version:

BlobRequestOptions blobOptions = new BlobRequestOptions
{
         MaximumExecutionTime = TimeSpan.FromSeconds(5),
};
lockBlob.UploadText(data, null, null, blobOptions, null);

How can I make the async version work? Is there a workaround? I really need the async version.

The UploadText (async and sync) method creates the blob if it doesn't already exist, and overwrites it if it does.

Why does it work with the sync version and not the async with the update?

For the blob creation this is the code:

var container= client.GetContainerReference("lockblobs");
await container.CreateIfNotExistsAsync();
var lockBlob = container.GetBlockBlobReference(data);

Solution

  • SOLVED:

    After debugging through the callstack inside the Azure package it turns out that there's a check in the BlobRequestOptions, by default there's a mismatch between the RequireEncryption and EncryptionPolicy.

    This is the culprit inside the BlobRequestOptions definition:

    internal void AssertPolicyIfRequired()
    {
        if (this.RequireEncryption.HasValue && this.RequireEncryption.Value && this.EncryptionPolicy == null)
        {
              throw new InvalidOperationException(SR.EncryptionPolicyMissingInStrictMode);
        }
    }
    

    in https://github.com/Azure/azure-storage-net/blob/master/Lib/Common/Blob/BlobRequestOptions.cs

    So basically by doing:

    BlobRequestOptions blobOptions = new BlobRequestOptions
    {
        MaximumExecutionTime = TimeSpan.FromSeconds(5),
        ParallelOperationThreadCount = 48,
        RequireEncryption = false
    };
    
    await lockBlob.UploadTextAsync(data, null, null, blobOptions, null);
    

    I avoid the check in the AssertPolicyIfRequired check. So bottom line, set RequireEncryption = false or set it to true and also defining a proper Encryption Policy.

    This now makes work all the Upload****Async methods.

    Here is the callstack that helped me to debug the issue:

    {"ClassName":"System.NullReferenceException","Message":"Object reference not set to an instance of an object.","Data":null,"InnerException":null,"HelpURL":null,"StackTraceString":"   at Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.<>c__DisplayClass1d.b__f(Action continuation) in c:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\ClassLibraryCommon\Blob\CloudBlockBlob.cs:line 620
       at Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.BeginUploadFromStreamHelper(Stream source, Nullable`1 length, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, Object state) in c:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\ClassLibraryCommon\Blob\CloudBlockBlob.cs:line 665
       at Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.BeginUploadFromStream(Stream source, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, Object state) in c:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\ClassLibraryCommon\Blob\CloudBlockBlob.cs:line 477
       at Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.BeginUploadFromByteArray(Byte[] buffer, Int32 index, Int32 count, AsyncCallback callback, Object state) in c:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\ClassLibraryCommon\Blob\CloudBlockBlob.cs:line 1146
       at Microsoft.WindowsAzure.Storage.Core.Util.AsyncExtensions.TaskFromVoidApm[T1,T2,T3](Func`6 beginMethod, Action`1 endMethod, T1 arg1, T2 arg2, T3 arg3, CancellationToken cancellationToken) in c:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\ClassLibraryCommon\Core\Util\AsyncExtensions.cs:line 210
       at Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.UploadFromByteArrayAsync(Byte[] buffer, Int32 index, Int32 count, CancellationToken cancellationToken) in c:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\ClassLibraryCommon\Blob\CloudBlockBlob.cs:line 1204
       at Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.UploadFromByteArrayAsync(Byte[] buffer, Int32 index, Int32 count) in c:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\ClassLibraryCommon\Blob\CloudBlockBlob.cs:line 1190