Continuing my blog posts about migrating code to make use of storage client library 2.0, in this post I will talk about some more changes done in the library for handling exceptions. You can read my previous posts on storage client library 2.0 here:
https://gauravmantri.com/2012/11/28/storage-client-library-2-0-migrating-blob-storage-code/
https://gauravmantri.com/2012/11/24/storage-client-library-2-0-migrating-queue-storage-code/
https://gauravmantri.com/2012/11/17/storage-client-library-2-0-migrating-table-storage-code/
Like the previous posts, I will attempt to provide some code sample through which I will try and demonstrate to handle exceptions. What I did is wrote two simple console applications: one which uses storage client library version 1.7 and the other which uses version 2.0 and in those two applications I demonstrated some simple functionality.
Read These First
Since version 2.0 library is significantly different than the previous ones, before you decide to upgrade your code to make use of this version I strongly urge you to read up the following blog posts by the storage team as there’re many breaking changes.
Introducing Windows Azure Storage Client Library 2.0 for .NET and Windows Runtime
Windows Azure Storage Client Library 2.0 Breaking Changes & Migration Guide
Getting Started
Before jumping into the code, there’re a few things I would like to mention:
Storage Client Libraries
To get the reference for storage client library 1.7, you can browse your local computer and navigate to the Azure SDK installation directory (C:\Program Files\Microsoft SDKs\Windows Azure\.NET SDK\2012-10\ref – assuming you have SDK 1.8 installed) and select Microsoft.WindowsAzure.StorageClient.dll from there.
To get the reference for storage client library 2.0 (or the latest version for that matter), I would actually recommend getting this using Nuget. That way you’ll always get the latest version. You can simply get it by executing the following command in Nuget Package Manager console: Install-Package WindowsAzure.Storage. While it’s an easy way to get the latest version upgrades, one must not upgrade it before ensuring the new version won’t break anything in the existing code.
Exception Handling
Now let’s talk about handling exceptions. There have been many changes in the way exception handling functionality is changed in the 2 versions.
Classes to Expose Exceptions
One of the major breaking change that as happened between 2.0 and 1.7 is the way the exceptions are exposed. In version 1.7, storage client library exposed exceptions through two different classes: StorageClientException which represented exception thrown by storage client library and StorageServerException which represented exception thrown due to a server side error. In version 2.0, these two exceptions are now combined in a single class called StorageException. So if your code made explicit use of either of StorageClientException or StorageServerException, you would need to make changes in your code. For example, consider this simple scenario where I’m trying to create a blob container with invalid name. If you’re using the following code with version 1.7 for exception handling:
try { var storageAccount = CloudStorageAccount.DevelopmentStorageAccount; string blobContainerName = "InvalidBlobContainerName"; var cloudBlobClient = storageAccount.CreateCloudBlobClient(); var cloudBlobContainer = cloudBlobClient.GetContainerReference(blobContainerName); cloudBlobContainer.Create(); } catch (StorageClientException exception) { //Handle exception here }
You would have to do something like the following with version 2.0:
try { var storageAccount = CloudStorageAccount.DevelopmentStorageAccount; string blobContainerName = "InvalidBlobContainerName"; var cloudBlobClient = storageAccount.CreateCloudBlobClient(); var cloudBlobContainer = cloudBlobClient.GetContainerReference(blobContainerName); cloudBlobContainer.Create(); } catch (StorageException exception) { //Handle exception here }
Extracting Details about Error
Another important change that has been done is the way more information about the errors can be fetched. With version 1.7, there were two important and handy properties ErrorCode and StatusCode which are members of StorageClientException. You could simply take the exception and get these two properties from there. Unfortunately they’re not directly available in version 2.0. With version 2.0, the process is rather convoluted.
In version 2.0, to get ErrorCode, first you have to get RequestInformation member of the exception and then get ExtendedErrorInformation member of RequestInformation and there you get ErrorCode. Much complicated process IMO.
Similarly to get StatusCode, first you have to get RequestInformation member of the exception and then get the HttpStatusCode property there.
Another important thing to understand is that StatusCode property in 1.7 is of type System.Net.HttpStatusCode while HttpStatusCode in 2.0 is of type Integer.
Continuing with ErrorCode, one good thing I liked about that in 1.7 there’s a class which contained a master list of these error codes (StorageErrorCodeStrings). That made the job considerably easier. Unfortunately this class is no longer available in version 2.0.
UPDATE [17-Jan-2013]: As of version 2.0.3.0 of storage client library, StorageErrorCodeStrings are available. Thank you storage team for putting this back. They are available in Microsoft.WindowsAzure.Storage.Shared.Protocol Namespace. I actually came to know about it from this post on StackOverflow: http://stackoverflow.com/questions/14363564/windowsazure-storage-v2-storageexception
To give an example, if I’m trying to create a blob container which already exists (I know I should use CreateIfNotExist() or CreateIfNotExists() :)), and in order to find ErrorCode and StatusCode if you’re using the following code in version 1.7:
try { var storageAccount = CloudStorageAccount.DevelopmentStorageAccount; string blobContainerName = "somerandomblobcontainer"; var cloudBlobClient = storageAccount.CreateCloudBlobClient(); var cloudBlobContainer = cloudBlobClient.GetContainerReference(blobContainerName); cloudBlobContainer.Create(); cloudBlobContainer.Create();//This line would throw exception } catch (StorageClientException exception) { var errorCode = exception.ErrorCode;//errorCode = ContainerAlreadyExists var statusCode = exception.StatusCode;//statusCode = Conflict }
You would have to do something like the following with version 2.0:
try { var storageAccount = CloudStorageAccount.DevelopmentStorageAccount; string blobContainerName = "somerandomblobcontainer"; var cloudBlobClient = storageAccount.CreateCloudBlobClient(); var cloudBlobContainer = cloudBlobClient.GetContainerReference(blobContainerName); cloudBlobContainer.Create(); } catch (StorageException exception) { var requestInformation = exception.RequestInformation; var errorCode = requestInformation.ExtendedErrorInformation.ErrorCode;//errorCode = ContainerAlreadyExists var statusCode = (System.Net.HttpStatusCode)requestInformation.HttpStatusCode;//requestInformation.HttpStatusCode = 409, statusCode = Conflict }
The Good Things
It may seem that exception handling is quite screwed up in version 2.0 but there’re some good things as well :). RequestInformation member of the exception actually exposes some nifty properties which could be of great help. Apart from StartTime and EndTime properties, it also exposes ServiceRequestId property which basically is a GUID sent by Windows Azure Storage Service (in x-ms-request-id response header, if you must know :)). This property can be really handy when viewing storage analytics data to find out what’s going on and also when communicating with the support staff. Using this, they can find your request very easily and find out what exactly went wrong.
Summary
As you saw above, there has been some significant changes to storage client library as far as handling exceptions are concerned and proper care must be taken before doing the migration. Please feel free to share your experience with migration exercise by providing comments. This will help me and the readers of this blog immensely. Finally, if you find any issues with this post please let me know and I will try and fix them ASAP.