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

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

Rate This
  • Comments 17

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

Leave a Comment
  • Please add 2 and 8 and type the answer here:
  • Post
  • What about the problem with the connectivity to local storage with 2.0 SDK

    Follow this link in the MSDN forums.

    social.msdn.microsoft.com/.../b1b66cc0-5143-41fb-b92e-b03d017ea3c1

  • Hi navcode, the Windows Azure Storage Client Library 2.0 uses service version 2012-02-12, which is not supported by older versions of the storage emulator.

    Please install the latest emulator from www.microsoft.com/.../details.aspx and also look at blogs.msdn.com/.../windows-azure-storage-emulator-1-8.aspx for details.

  • To add reference for Windows Store App, dll file for winRT is needed. This update 2.0.3 doesn't include dll file for winRT. Please let me know of this.

  • A simple test with Azure Local Storage fails as of version 2.0.3.0.

    That is blocking any newcomer dev in the Azure ecosystem.

    Any ETA for a fix?

  • Hi LN,

    Can you please let us know the details of the test that is failing?

    Thanks,

    Jean

  • Hi ardentm,

    Please refer to blogs.msdn.com/.../windows-azure-storage-client-library-for-windows-runtime.aspx to download the Windows Runtime library.

  • The issue regarding "CloudStorageAccount.Parse cannot parse DevelopmentStorageAccount strings if a proxy is not specified" repros again in 2.0.3. Any updates on when this will be fixed again?

  • Hi Shawn,

    We tried to repro the issue with an Account String that does not use a proxy. Here is the exact code snippet we used:

    string accountString = "UseDevelopmentStorage=true";

    string retrAccountString = CloudStorageAccount.Parse(accountString).ToString();

    Console.WriteLine(retrAccountString);

    However, it seems to work fine and we get the expected result. Can you confirm that you are actually using version 2.0.3. Any release >=2.0.1 should have the

    fix for this issue. However, we recommend updating to the latest version since it addresses other issues as well. It can be got here : nuget.org/.../2.0.4.1

    Can you also please provide a sample account string with any account information omitted that repros this issue? That will help us with our investigation. Thanks!

  • I am building a Windows store app with the 2.0 SDK using C#, basically following sample codes described in blogs.msdn.com/.../introducing-table-sas-shared-access-signature-queue-sas-and-update-to-blob-sas.aspx.

    I got the "Could not load file or assembly 'Microsoft.Data.OData.WindowsStore", but I am using C# not JavaScript so I am not sure if it is the same known issue mentioned above.

    The detailed exception information is:

      InnerException: Microsoft.WindowsAzure.Storage.StorageException

          HResult=-2147467259

          Message=Could not load file or assembly 'Microsoft.Data.OData.WindowsStore, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The assembly version has a public key token that does not match that of the request. (Exception from HRESULT: 0x80132001)

          ErrorCode=-2147467259

          InnerException: System.IO.FileNotFoundException

               HResult=-2146230271

               Message=Could not load file or assembly 'Microsoft.Data.OData.WindowsStore, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The assembly version has a public key token that does not match that of the request. (Exception from HRESULT: 0x80132001)

               Source=Microsoft.WindowsAzure.Storage

               FileName=Microsoft.Data.OData.WindowsStore, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35

               FusionLog=""

               StackTrace:

                    at Microsoft.WindowsAzure.Storage.Table.Protocol.TableOperationHttpRequestMessageFactory.BuildRequestForTableOperation(Uri uri, Nullable`1 timeout, TableOperation operation, OperationContext ctx)

                    at Microsoft.WindowsAzure.Storage.Table.TableOperation.<>c__DisplayClass8.<InsertImpl>b__4(RESTCommand`1 cmd, HttpContent cnt, OperationContext ctx)

                    at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.<ExecuteAsyncInternal>d__4`1.MoveNext()

               InnerException:

  • It took me several hours debugging the "Could not load file or assembly 'Microsoft.Data.OData.WindowsStore" issue. After checking GAC, Process Monitor tool, etc, I finally found the Microsoft.Data.OData.WindowsStore.dll file installed from www.microsoft.com/.../details.aspx cannot be directly added as reference in the Windows store app project, because its "Strong Name" attribute is set to "False". The only way you can have it as "True" is to install it from the NuGet Package Manager. You can do it by adding another package source and point it to C:\Program Files (x86)\Microsoft WCF Data Services\5.0\bin\NuGet. The blog explained how to do this: www.damirscorner.com/WCFDataServicesToolsForWindowsStoreAppsAndNuGetPackageRestore.aspx

    Hope it helps!

  • What is the plan with CloudDrive ? it's gone and it's mentioned nowhere ...

    is the feature deprecated ?

  • Hey Bin - excellent - thanks!

    While I still have a few hairs left (pulled most of them out...) - can anyone provide some simple Win 8 App code to retrieve/display all the rows in a known table (WADPerformanceCountersTable in my case)?  I'm getting to the (real) storage account ok, just not seeing how to run a query and retrieve results...

  • @ Larry

    For more information on tables usage see this blog: blogs.msdn.com/.../windows-azure-storage-client-library-2-0-tables-deep-dive.aspx

    There is a specific example using the WinRT library that illustrates how to use the continuation tokens:

    // Create the table client.

    CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

    CloudTable table = tableClient.GetTableReference("tablename");

    List<ShapeEntity> shapeList = new List<ShapeEntity>();

    TableQuerySegment<ShapeEntity> currentSegment = null;

    while (currentSegment == null || currentSegment.ContinuationToken != null)

    {

       currentSegment = await table.ExecuteQuerySegmentedAsync(drawingQuery, currentSegment != null ? currentSegment.ContinuationToken : null);

       // Consume results

       shapeList.AddRange(currentSegment.Results);

    }

    Also regarding runtime dll load failures, I apologize for the confusion we will try to document this better for users. Please note, when using the library in JavaScript Applications the Table layer is currently unavailable due to a restriction in the Windows Runtime itself. For js apps the runtime will not allow a projected component to load / reference any dependent dlls which will cause a similar failure. This is an issue we have detailed to the win rt team, but currently there is not ETA for a resolution.

    joe

  • So I was able to get this to 'work'.  Is this reasonable code, or is there a much better way?  Examples from the team would be helpful...

                   CloudTableClient tableClient = CloudStorageAccount.CreateCloudTableClient();

                   CloudTable table = tableClient.GetTableReference("WADPerformanceCountersTable");

                   TableQuery<WADPerformanceCountersTableEntity> query = new TableQuery<WADPerformanceCountersTableEntity>().Take(100);

                   List<WADPerformanceCountersTableEntity> rawDataList = new List<WADPerformanceCountersTableEntity>();

                   TableQuerySegment<WADPerformanceCountersTableEntity> currentSegment = null;

                   currentSegment = await table.ExecuteQuerySegmentedAsync(query, null);

                   rawDataList.AddRange(currentSegment.Results);

                   ObservableCollection<WADPerformanceCountersTableEntity> tmp = RawData;

                   foreach (WADPerformanceCountersTableEntity rec in rawDataList)

                   {

                       tmp.Add(rec);

                   }

                   RawData = tmp;

  • Hi Greg,

    The CloudDrive "preview" is still supported with SDK 1.7, and you can use 2.0 and 1.7 in the same process if you want to migrate the rest of your code to 2.0.  Just do not use SAS urls created with SDK 2.0 with CloudDrive, as these are not compatible.   The supported network attached drive for Windows Azure going forward are the IaaS Disks that recently GA’d.  The future of the CloudDrive API is TBD at this time.

    Thanks

    Andrew Edwards

    Windows Azure Storage

Page 1 of 2 (17 items) 12