Updated: Known Issues for Windows Azure Storage Client Library 2.0 for .NET and Windows Runtime

The client issues detailed in this blog have been resolved in version 2.0.4 or earlier, and you can obtain the latest NuGet Package here .

We recently released the 2.0 version of the Windows Azure Storage Client Library. This is our largest update to our .NET library to date which includes new features, broader platform compatibility, and revisions to address the great feedback you’ve given us over time. For more about this release see here. For information regarding breaking changes see here.

This Storage Client 2.0 release contains some known issues that are being addressed in the current and upcoming releases of the libraries and are detailed below. Some of these were reported by you, and we appreciate you bringing them to our attention!

 

The following are the set of issues that have been fixed.

Some Azure SDK assemblies still reference Storage Client Library 1.7
  • Description: SDK assemblies such as Microsoft.WindowsAzure.Diagnostics.dll and Microsoft.WindowsAzure.CloudDrive.dll still reference Storage Client Library version 1.7.
  • Status: Will be resolved in a future release of the Windows Azure SDK
  • Impacted Platforms: .NET
  • Workaround: Please add references to both the old version (Microsoft.WindowsAzure.StorageClient.dll; version 1.7) and the new version (Microsoft.WindowsAzure.Storage.dll; version 2.0 or greater) of Storage Client Library in your project.

    

Service Client RetryPolicy does not support null
  • Description: The Cloud[Blob|Queue|Table]Client.RetryPolicy does not support null.
  • Status: Not resolved
  • Impacted Platforms: All
  • Workaround: If you wish to disable retries, please use:
 client.RetryPolicy = new NoRetry();
Windows Store Apps developed in JavaScript cannot use Table Service layer due to missing OData dependencies
  • Description: Windows Store Apps developed in JavaScript are unable to load the dependent dlls to a referenced component (WinMD). Because the Table Storage API is dependent on Microsoft.Data.OData.WindowsStore.dll, invoking Table APIs will result in a FileNotFoundException at runtime.
  • Status: Not Resolved. We are actively exploring options to bring Table Storage support to Windows Store Apps developed in JavaScript.
  • Impacted Platforms: Windows Store Apps
  • Workaround: Not available

 

TableEntity does not support deserializing nullable values
  • Description: TableEntity does not support nullable values such as int? or long? during deserialization. The example below illustrates this issue:
 class AgeEntity : TableEntity
{
    public int? Age { get; set; }
}

…

AgeEntity entity = new AgeEntity()
{
    PartitionKey = "FirstName",
    RowKey = "LastName",
    Age = 25,
};

table.Execute(TableOperation.Insert(entity));
…
TableResult result = table.Execute(TableOperation.Retrieve<AgeEntity>("FirstName", "LastName"));

entity = (AgeEntity)result.Result;  // entity.Age will be null
  • Status: Will be resolved in version 2.0.3
  • Resolution: TableEntity will support deserializing nullable values.
  • Impacted Platforms: All
  • Workaround: If this impacts you, then upgrade to 2.0.3 when it is available. If you are unable to upgrade, please use the legacy Table Service implementation as described in the Migration Guide.
Extra TableResults returned via ExecuteBatch when a retry occurs
  • Description: When a batch execution fails and is subsequently retried, it is possible to receive extraneous TableResult objects from any failed attempt(s). The resulting behavior is that upon completion the correct N TableResults are located at the end of the IList<TableResult> that is returned, with the extraneous results listed at the start.
  • Status: Will be resolved in version 2.0.3
  • Resolution: The list returned back will only contain the results from the last retry.
  • Impacted Platforms: All
  • Workaround: If this impacts you, then upgrade to 2.0.3 when it is available. If you are unable to upgrade, please only check the last N TableResults in the list returned. As an alternative, you can also disable retries:
 client.RetryPolicy = new NoRetry();
GenerateFilterConditionForLong does not work for values larger than maximum 32-bit integer value
  • Description: When doing a table query and filtering on a 64-bit integer property (long), values larger than maximum 32-bit integer value do not work correctly. The example below illustrates this issue:
 TableQuery query = new TableQuery().Where(
    TableQuery.GenerateFilterConditionForLong("LongValue", QueryComparisons.Equal, 1234567890123));
List<DynamicTableEntity> results = table.ExecuteQuery(query).ToList();  // Will throw StorageException
  • Status: Will be resolved in version 2.0.3
  • Resolution: The required ‘L’ suffix will be correctly added to 64-bit integer values.
  • Impacted Platforms: All
  • Workaround: If this impacts you, then upgrade to 2.0.3 when it is available. If you are unable to upgrade, please convert the value to a string and then append the required ‘L’ suffix:
 TableQuery query = new TableQuery().Where(
    TableQuery.GenerateFilterCondition("LongValue", QueryComparisons.Equal, "1234567890123L"));
List<DynamicTableEntity> results = table.ExecuteQuery(query).ToList();
CloudTable.EndListTablesSegmented method does not work correctly
  • Description: Listing tables segment by segment using APM does not work, because CloudTable.EndListTablesSegmented method always throws an exception. The example below illustrates this issue:
 IAsyncResult ar = tableClient.BeginListTablesSegmented(null, null, null);
TableResultSegment results = tableClient.EndListTablesSegmented(ar);  // Will throw InvalidCastException
  • Status: Will be resolved in version 2.0.3
  • Resolution: EndListTablesSegmented will correctly return the result segment.
  • Impacted Platforms: .NET
  • Workaround: If this impacts you, then upgrade to 2.0.3 when it is available. If you are unable to upgrade, please use the synchronous method instead:
 TableResultSegment results = tableClient.ListTablesSegmented(null);
CloudQueue.BeginCreateIfNotExists and CloudQueue.BeginDeleteIfExists methods expect valid options argument
  • Description: BeginCreateIfNotExists and BeginDeleteIfExists methods on a CloudQueue object do not work if the options argument is null. The example below illustrates this issue:
 queue.BeginCreateIfNotExists(null, null);  // Will throw NullReferenceException

queue.BeginCreateIfNotExists(null, null, null, null);  // Will throw NullReferenceException
  • Status: Will be resolved in version 2.0.3
  • Resolution: Both methods will be updated to accept null as a valid argument.
  • Impacted Platforms: .NET
  • Workaround: If this impacts you, then upgrade to 2.0.3 when it is available. If you are unable to upgrade, please create a new QueueRequestOptions object and use it instead:
 queue.BeginCreateIfNotExists(new QueueRequestOptions(), null, null, null);
Metadata Correctness tests fail when submitting apps to the Windows Store
  • Description: An application that references Storage Client Library will fail the Metadata Correctness test during Windows Store certification process.
  • Status: Will be resolved in version 2.0.3
  • Resolution: All non-sealed public classes will be either removed or sealed.
  • Impacted Platforms: Windows Store Apps
  • Workaround: Not available
Missing Queue constants
  • Description: A few general purpose queue constants have not been exposed as public on CloudQueueMessage . Missing constants are shown below:
 public static long MaxMessageSize { get; }

public static TimeSpan MaxTimeToLive { get; }

public static int MaxNumberOfMessagesToPeek { get; }
  • Status: Will be resolved in version 2.0.3
  • Resolution: CloudQueueMessage constants will be made public.
  • Impacted Platforms: Windows Store Apps
  • Workaround: If this impacts you, then upgrade to 2.0.3 when it is available. If you are unable to upgrade, please use the values directly in your code. MaxMessageSize is 64KB, MaxTimeToLive is 7 days, and MaxNumberOfMessagesToPeek is 32.
IAsyncResult object returned by asynchronous methods is not compatible with TaskFactory.FromAsync
  • Description: Both the System.Threading.Tasks.TaskFactory and System.Threading.Tasks.TaskFactory<TResult> classes provide several overloads of the FromAsync and FromAsync methods that let you encapsulate an APM Begin/End method pair in one Task instance or Task<TResult> instance. Unfortunately, the IAsyncResult implementation of Storage Client Library is not compatible with these methods, which leads to the End method being called twice. The effect of calling the End method multiple times with the same IAsyncResult is not defined. The example below illustrates this issue. The call will throw a SemaphoreFullException even if the actual operation succeeds:
 TableServiceContext context = client.GetTableServiceContext();

// Your Table Service operations here

await Task.Factory.FromAsync<DataServiceResponse>(
    context.BeginSaveChangesWithRetries,
    context.EndSaveChangesWithRetries,
    null);  // Will Throw SemaphoreFullException
  • Status: Resolved in version 2.0.2
  • Resolution: IAsyncResult.CompletedSynchronously flag now reports the status correctly and thus FromAsync methods can work with the Storage Client Library APM methods.
  • Impacted Platforms: .NET
  • Workaround: If you are unable to upgrade to 2.0.2, please use APM methods directly without passing them to FromAsync methods.
Public DynamicTableEntity constructors use DateTime even though the Timestamp property is of type DateTimeOffset

· Description: DynamicTableEntity class defines the Timestamp property as a DateTimeOffset value. However, its public constructors use DateTime.MinValue to initialize the property. Therefore, if the machine’s time zone is ahead of UTC (such as UTC+01), DynamicTableEntity references cannot be instantiated. The example below illustrates this issue if the time zone is ahead of UTC:

 CloudTable table = client.GetTableReference(tableName);
TableQuery query = new TableQuery();
IEnumerable<DynamicTableEntity> result = table.ExecuteQuery(query);  // Will Throw StorageException
  • Status: Resolved in version 2.0.2
  • Resolution: IAsyncResult.CompletedSynchronously flag now reports the status correctly and thus FromAsync methods can work with the Storage Client Library APM methods.
  • Impacted Platforms: All
  • Workaround: Not available
BeginSaveChangesWithRetries ignores SaveChangesOptions argument
  • Description: TableServiceContext class provides several overloads of the BeginSaveChangesWithRetries method that let you begin an asynchronous operation to save changes. One of the overloads ignores the “options” argument. The example below illustrates this issue:
 IAsyncResult ar = tableContext.BeginSaveChangesWithRetries(
    SaveChangesOptions.Batch, null, null);
…
DataServiceResponse response = tableContext.EndSaveChangesWithRetries(ar);
int statusCode = response.BatchStatusCode;  // Will return -1

 

  • Status: Resolved in version 2.0.2
  • Resolution: All overloads of BeginSaveChangesWithRetries now make use of the “options” argument correctly.
  • Impacted Platforms: .NET
  • Workaround: If you are unable to upgrade to 2.0.2, please use a different overload of BeginSaveChangesWithRetries method:
 IAsyncResult ar = tableContext.BeginSaveChangesWithRetries(
    SaveChangesOptions.Batch, null, null, null, null);
…
DataServiceResponse response = tableContext.EndSaveChangesWithRetries(ar);
int statusCode = response.BatchStatusCode;
CloudStorageAccount.Parse cannot parse DevelopmentStorageAccount strings if a proxy is not specified
  • Description: CloudStorageAccount.Parse() and TryParse() do not support DevelopmentStorageAccount strings if a proxy is not specified. CloudStorageAccount.DevelopmentStorageAccount.ToString() will serialize to the string: “UseDevelopmentStorage=true” which illustrates this particular issue. Passing this string into CloudStorageAccount.Parse() or TryParse() will throw a KeyNotFoundException.
 CloudStorageAccount myAccount = CloudStorageAccount.Parse("UseDevelopmentStorage=true");  // Will Throw KeyNotFoundException

 

  • Status: Resolved in version 2.0.1
  • Resolution: CloudStorageAccount can now parse this string correctly.
  • Impacted Platforms: All
  • Workaround: If you are unable to upgrade to 2.0.1, you can use:
 CloudStorageAccount myAccount = CloudStorageAccount.DevelopmentStorageAccount;
StorageErrorCodeStrings class is missing
  • Description: Static StorageErrorCodeStrings class that contains common error codes across Blob, Table, and Queue services is missing. The example below shows some of the missing error codes:
 public const string OperationTimedOut = "OperationTimedOut";
public const string ResourceNotFound = "ResourceNotFound";
  • Status: Resolved in version 2.0.1
  • Resolution: StorageErrorCodeStrings class is added.
  • Impacted Platforms: All
  • Workaround: If you are unable to upgrade to 2.0.1, you can directly use the error strings listed in the Status and Error Codes article.
ICloudBlob interface does not contain Shared Access Signature creation methods
  • Description: Even though both CloudBlockBlob and CloudPageBlob have methods to create a shared access signature, the common ICloudBlob interface does not contain them which prevents a generic method to create a SAS token for any blob irrespective of its type. Missing methods are shown below:
 string GetSharedAccessSignature(SharedAccessBlobPolicy policy);
string GetSharedAccessSignature(SharedAccessBlobPolicy policy, string groupPolicyIdentifier);
  • Status: Resolved in version 2.0.1
  • Resolution: GetSharedAccessSignature methods are added to ICloudBlob interface.
  • Impacted Platforms: All
  • Workaround: If you are unable to upgrade to 2.0.1, please cast your object to CloudBlockBlob or CloudPageBlob depending on the blob’s type and then call GetSharedAccessSignature:
 CloudBlockBlob blockBlob = (CloudBlockBlob)blob;
string signature = blockBlob.GetSharedAccessSignature(policy);

Summary

We continue to work hard on delivering a first class development experience for the .NET and Windows 8 developer communities to work with Windows Azure Storage. We have actively embraced both NuGet and GitHub as release mechanisms for our Windows Azure Storage Client libraries. As such, we will continue to release updates to address any issues as they arise in a timely fashion. As always, your feedback is welcome and appreciated!

Joe Giardino

Serdar Ozler

Windows Azure Storage