Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Building a 3-Tier App with Silverlight 3, .NET RIA Services, and Azure Table Storage

, 11 Jul 2009
This article presents the techniques and caveats of building a 3-tire Azure hosted application using Silverlight 3 (presentation tier), .NET RIA services (business logic and data access), and Windows Azure Table (data storage).
Azurelight_SourceCode.zip
Azurelight
Azure
DomainServices
Linq
Properties
StorageClient
Azurelight
Azurelight
Azurelight.ccproj
Azurelight_WebRole
ServiceConfiguration.cscfg
ServiceDefinition.csdef
Azurelight_WebRole
App_Data
Azurelight.mdf
Azurelight_log.ldf
App_GlobalResources
System.Web.Silverlight.dll
ClientBin
Global.asax
Model
Properties
Service
AzurelightNav
Command
Control
Generated_Code
Model
Properties
Resources
SilverlightCairngorm
Business
Command
Control
Model
Properties
Views
//
// <copyright file="Errors.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//
using System;
using System.IO;
using System.Collections.Generic;
using System.Net;
using System.Collections.Specialized;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Diagnostics.CodeAnalysis;
using System.Web;
using System.Linq;
using System.Xml;
using System.Xml.Linq;


// disable the generation of warnings for missing documentation elements for 
// public classes/members in this file
// justification is that this file contains many public constants whose names 
// sufficiently reflect their intended usage 
#pragma warning disable 1591

namespace Microsoft.Azure.StorageClient
{
    /// <summary>
    /// Error codes that can be returned by the storage service or the client library.
    /// These are divided into server errors and client errors depending on which side
    /// the error can be attributed to.
    /// </summary>
    public enum StorageErrorCode
    {
        None = 0,

        //Server errors
        ServiceInternalError = 1,
        ServiceTimeout,
        ServiceIntegrityCheckFailed,
        TransportError,
        ServiceBadResponse,

        //Client errors
        ResourceNotFound,
        AccountNotFound,
        ContainerNotFound,
        BlobNotFound,
        AuthenticationFailure,
        AccessDenied,
        ResourceAlreadyExists,
        ContainerAlreadyExists,
        BlobAlreadyExists,
        BadRequest,
        ConditionFailed,
        BadGateway
    }

    [Serializable]
    public class StorageExtendedErrorInformation
    {
        public string ErrorCode { get; internal set; }
        public string ErrorMessage { get; internal set; }
        public NameValueCollection AdditionalDetails { get; internal set; }
    }

    /// <summary>
    /// The base class for storage service exceptions
    /// </summary>
    [Serializable]
    public abstract class StorageException : Exception
    {
        /// <summary>
        /// The Http status code returned by the storage service
        /// </summary>
        public HttpStatusCode StatusCode { get; private set; }

        /// <summary>
        /// The specific error code returned by the storage service
        /// </summary>
        public StorageErrorCode ErrorCode { get; private set; }

        /// <summary>
        /// 
        /// </summary>
        public StorageExtendedErrorInformation ExtendedErrorInformation { get; private set; }

        protected StorageException()
        {
        }

        protected StorageException(
            StorageErrorCode errorCode,
            string message,
            HttpStatusCode statusCode,
            StorageExtendedErrorInformation extendedErrorInfo,
            Exception innerException
            )
            : base(message, innerException)
        {
            this.ErrorCode = errorCode;
            this.StatusCode = statusCode;
            this.ExtendedErrorInformation = extendedErrorInfo;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="StorageException"/> class with
        /// serialized data.
        /// </summary>
        /// <param name="info">The <see cref="SerializationInfo"/> object that contains serialized object
        /// data about the exception being thrown</param>
        /// <param name="context">The <see cref="StreamingContext"/> object that contains contextual information
        /// about the source or destionation. </param>
        protected StorageException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            if (null == info)
            {
                throw new ArgumentNullException("info");
            }

            this.StatusCode = (HttpStatusCode)info.GetValue("StatusCode", typeof(HttpStatusCode));
            this.ErrorCode = (StorageErrorCode)info.GetValue("ErrorCode", typeof(StorageErrorCode));
            this.ExtendedErrorInformation = (StorageExtendedErrorInformation)info.GetValue(
                        "ExtendedErrorInformation", typeof(StorageExtendedErrorInformation));
        }

        /// <summary>
        /// Sets the <see cref="SerializationInfo"/> object with additional exception information
        /// </summary>
        /// <param name="info">The <see cref="SerializationInfo"/> object that holds the 
        /// serialized object data.</param>
        /// <param name="context">The <see cref="StreamingContext"/> object that contains contextual information
        /// about the source or destionation. </param>
        [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (null == info)
            {
                throw new ArgumentNullException("info");
            }

            info.AddValue("StatusCode", this.StatusCode);
            info.AddValue("ErrorCode", this.ErrorCode);
            info.AddValue("ExtendedErrorInformation", this.ExtendedErrorInformation);
            base.GetObjectData(info, context);
        }

    }

    /// <summary>
    /// Server exceptions are those due to server side problems.
    /// These may be transient and requests resulting in such exceptions
    /// can be retried with the same parameters.
    /// </summary>
    [SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors",
        Justification = "Since this exception comes from the server, there must be an HTTP response code associated with it, hence we exclude the default constructor taking only a string but no status code.")]
    [Serializable]
    public class StorageServerException : StorageException
    {
        internal StorageServerException(
            StorageErrorCode errorCode,
            string message,
            HttpStatusCode statusCode,
            Exception innerException
            )
            : base(errorCode, message, statusCode, null, innerException)
        {
        }

        internal StorageServerException(
            StorageErrorCode errorCode,
            string message,
            HttpStatusCode statusCode,
            StorageExtendedErrorInformation extendedErrorInfo,
            Exception innerException
            )
            : base(errorCode, message, statusCode, extendedErrorInfo, innerException)
        {
        }


        /// <summary>
        /// Initializes a new instance of the <see cref="StorageServerException"/> class with
        /// serialized data.
        /// </summary>
        /// <param name="info">The <see cref="SerializationInfo"/> object that contains serialized object
        /// data about the exception being thrown</param>
        /// <param name="context">The <see cref="StreamingContext"/> object that contains contextual information
        /// about the source or destionation. </param>
        protected StorageServerException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
        }

        public StorageServerException()
        {
        }
    }

    /// <summary>
    /// Client side exceptions are due to incorrect parameters to the request.
    /// These requests should not be retried with the same parameters
    /// </summary>
    [SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors",
        Justification = "Since this exception comes from the server, there must be an HTTP response code associated with it, hence we exclude the default constructor taking only a string but no status code.")]
    [Serializable]
    public class StorageClientException : StorageException
    {
        internal StorageClientException(
            StorageErrorCode errorCode,
            string message,
            HttpStatusCode statusCode,
            StorageExtendedErrorInformation extendedErrorInfo,
            Exception innerException
            )
            : base(errorCode, message, statusCode, extendedErrorInfo, innerException)
        {
        }


        /// <summary>
        /// Initializes a new instance of the <see cref="StorageClientException"/> class with
        /// serialized data.
        /// </summary>
        /// <param name="info">The <see cref="SerializationInfo"/> object that contains serialized object
        /// data about the exception being thrown</param>
        /// <param name="context">The <see cref="StreamingContext"/> object that contains contextual information
        /// about the source or destionation. </param>
        protected StorageClientException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
        }

        public StorageClientException()
        {
        }

    }

    #region Error code strings that can be returned in the StorageExtendedErrorInformation.ErrorCode
    /// <summary>
    /// Error code strings that are common to all storage services
    /// </summary>
    public static class StorageErrorCodeStrings
    {
        public const string UnsupportedHttpVerb = "UnsupportedHttpVerb";
        public const string MissingContentLengthHeader = "MissingContentLengthHeader";
        public const string MissingRequiredHeader = "MissingRequiredHeader";
        public const string MissingRequiredXmlNode = "MissingRequiredXmlNode";
        public const string UnsupportedHeader = "UnsupportedHeader";
        public const string UnsupportedXmlNode = "UnsupportedXmlNode";
        public const string InvalidHeaderValue = "InvalidHeaderValue";
        public const string InvalidXmlNodeValue = "InvalidXmlNodeValue";
        public const string MissingRequiredQueryParameter = "MissingRequiredQueryParameter";
        public const string UnsupportedQueryParameter = "UnsupportedQueryParameter";
        public const string InvalidQueryParameterValue = "InvalidQueryParameterValue";
        public const string OutOfRangeQueryParameterValue = "OutOfRangeQueryParameterValue";
        public const string InvalidUri = "InvalidUri";
        public const string InvalidHttpVerb = "InvalidHttpVerb";
        public const string EmptyMetadataKey = "EmptyMetadataKey";
        public const string RequestBodyTooLarge = "RequestBodyTooLarge";
        public const string InvalidXmlDocument = "InvalidXmlDocument";
        public const string InternalError = "InternalError";
        public const string AuthenticationFailed = "AuthenticationFailed";
        public const string Md5Mismatch = "Md5Mismatch";
        public const string InvalidMd5 = "InvalidMd5";
        public const string OutOfRangeInput = "OutOfRangeInput";
        public const string InvalidInput = "InvalidInput";
        public const string OperationTimedOut = "OperationTimedOut";
        public const string ResourceNotFound = "ResourceNotFound";
        public const string InvalidMetadata = "InvalidMetadata";
        public const string MetadataTooLarge = "MetadataTooLarge";
        public const string ConditionNotMet = "ConditionNotMet";
        public const string InvalidRange = "InvalidRange";
        public const string ContainerNotFound = "ContainerNotFound";
        public const string ContainerAlreadyExists = "ContainerAlreadyExists";
        public const string ContainerDisabled = "ContainerDisabled";
        public const string ContainerBeingDeleted = "ContainerBeingDeleted";
        public const string ServerBusy = "ServerBusy";
    }

    /// <summary>
    /// Error code strings that are specific to blob service
    /// </summary>
    public static class BlobErrorCodeStrings
    {
        public const string InvalidBlockId = "InvalidBlockId";
        public const string BlobNotFound = "BlobNotFound";
        public const string BlobAlreadyExists = "BlobAlreadyExists";
        public const string InvalidBlobOrBlock = "InvalidBlobOrBlock";
        public const string InvalidBlockList = "InvalidBlockList";
    }

    /// <summary>
    /// Error code strings that are specific to queue service
    /// </summary>
    public static class QueueErrorCodeStrings
    {
        public const string QueueNotFound = "QueueNotFound";
        public const string QueueDisabled = "QueueDisabled";
        public const string QueueAlreadyExists = "QueueAlreadyExists";
        public const string QueueNotEmpty = "QueueNotEmpty";
        public const string QueueBeingDeleted = "QueueBeingDeleted";
        public const string PopReceiptMismatch = "PopReceiptMismatch";
        public const string InvalidParameter = "InvalidParameter";
        public const string MessageNotFound = "MessageNotFound";
        public const string MessageTooLarge = "MessageTooLarge";
        public const string InvalidMarker = "InvalidMarker";
    }

    /// <summary>
    /// Error code strings that are specific to queue service
    /// </summary>
    ///     public static class TableErrorCodeStrings
    public static class TableErrorCodeStrings
    {
        public const string XMethodNotUsingPost = "XMethodNotUsingPost";
        public const string XMethodIncorrectValue = "XMethodIncorrectValue";
        public const string XMethodIncorrectCount = "XMethodIncorrectCount";

        public const string TableHasNoProperties = "TableHasNoProperties";
        public const string DuplicatePropertiesSpecified = "DuplicatePropertiesSpecified";
        public const string TableHasNoSuchProperty = "TableHasNoSuchProperty";
        public const string DuplicateKeyPropertySpecified = "DuplicateKeyPropertySpecified";
        public const string TableAlreadyExists = "TableAlreadyExists";
        public const string TableNotFound = "TableNotFound";
        public const string EntityNotFound = "EntityNotFound";
        public const string EntityAlreadyExists = "EntityAlreadyExists";
        public const string PartitionKeyNotSpecified = "PartitionKeyNotSpecified";
        public const string OperatorInvalid = "OperatorInvalid";
        public const string UpdateConditionNotSatisfied = "UpdateConditionNotSatisfied";
        public const string PropertiesNeedValue = "PropertiesNeedValue";

        public const string PartitionKeyPropertyCannotBeUpdated = "PartitionKeyPropertyCannotBeUpdated";
        public const string TooManyProperties = "TooManyProperties";
        public const string EntityTooLarge = "EntityTooLarge";
        public const string PropertyValueTooLarge = "PropertyValueTooLarge";
        public const string InvalidValueType = "InvalidValueType";
        public const string TableBeingDeleted = "TableBeingDeleted";
        public const string TableServerOutOfMemory = "TableServerOutOfMemory";
        public const string PrimaryKeyPropertyIsInvalidType = "PrimaryKeyPropertyIsInvalidType";
        public const string PropertyNameTooLong = "PropertyNameTooLong";
        public const string PropertyNameInvalid = "PropertyNameInvalid";

        public const string BatchOperationNotSupported = "BatchOperationNotSupported";
        public const string JsonFormatNotSupported = "JsonFormatNotSupported";
        public const string MethodNotAllowed = "MethodNotAllowed";
        public const string NotImplemented = "NotImplemented";
    }
    #endregion

    #region Helper functions dealing with errors
    internal static partial class Utilities
    {
        internal static void ProcessUnexpectedStatusCode(HttpWebResponse response)
        {
            throw new StorageServerException(
                        StorageErrorCode.ServiceBadResponse,
                        response.StatusDescription,
                        response.StatusCode,
                        null
                        );
        }

        internal static Exception TranslateWebException(Exception e)
        {
            WebException we = e as WebException;
            if (null == we)
            {
                return e;
            }

            // If the response is not null, let's first see what the status code is.
            if (we.Response != null)
            {
                HttpWebResponse response = ((HttpWebResponse)we.Response);

                StorageExtendedErrorInformation extendedError =
                    GetExtendedErrorDetailsFromResponse(
                            response.GetResponseStream(),
                            response.ContentLength
                            );
                Exception translatedException = null;
                if (extendedError != null)
                {
                    translatedException = TranslateExtendedError(
                                                    extendedError,
                                                    response.StatusCode,
                                                    response.StatusDescription,
                                                    e);
                    if (translatedException != null)
                        return translatedException;
                }
                translatedException = TranslateFromHttpStatus(
                                            response.StatusCode,
                                            response.StatusDescription,
                                            extendedError,
                                            we
                                            );
                if (translatedException != null)
                    return translatedException;

            }

            switch (we.Status)
            {
                case WebExceptionStatus.RequestCanceled:
                    return new StorageServerException(
                        StorageErrorCode.ServiceTimeout,
                        "The server request did not complete within the specified timeout",
                        HttpStatusCode.GatewayTimeout,
                        we);

                case WebExceptionStatus.ConnectFailure:
                    return we;

                default:
                    return new StorageServerException(
                        StorageErrorCode.ServiceInternalError,
                        "The server encountered an unknown failure: " + e.Message,
                        HttpStatusCode.InternalServerError,
                        we
                        );
            }
        }

        internal static Exception TranslateFromHttpStatus(
                    HttpStatusCode statusCode,
                    string statusDescription,
                    StorageExtendedErrorInformation details,
                    Exception inner
                    )
        {
            switch (statusCode)
            {
                case HttpStatusCode.Forbidden:
                    return new StorageClientException(
                        StorageErrorCode.AccessDenied,
                        statusDescription,
                        HttpStatusCode.Forbidden,
                        details,
                        inner
                        );

                case HttpStatusCode.Gone:
                case HttpStatusCode.NotFound:
                    return new StorageClientException(
                        StorageErrorCode.ResourceNotFound,
                        statusDescription,
                        statusCode,
                        details,
                        inner
                        );

                case HttpStatusCode.BadRequest:
                    return new StorageClientException(
                        StorageErrorCode.BadRequest,
                        statusDescription,
                        statusCode,
                        details,
                        inner
                        );

                case HttpStatusCode.PreconditionFailed:
                case HttpStatusCode.NotModified:
                    return new StorageClientException(
                        StorageErrorCode.BadRequest,
                        statusDescription,
                        statusCode,
                        details,
                        inner);

                case HttpStatusCode.Conflict:
                    return new StorageClientException(
                        StorageErrorCode.ResourceAlreadyExists,
                        statusDescription,
                        statusCode,
                        details,
                        inner
                        );

                case HttpStatusCode.GatewayTimeout:
                    return new StorageServerException(
                        StorageErrorCode.ServiceTimeout,
                        statusDescription,
                        statusCode,
                        details,
                        inner
                        );

                case HttpStatusCode.RequestedRangeNotSatisfiable:
                    return new StorageClientException(
                        StorageErrorCode.BadRequest,
                        statusDescription,
                        statusCode,
                        details,
                        inner
                        );

                case HttpStatusCode.InternalServerError:
                    return new StorageServerException(
                        StorageErrorCode.ServiceInternalError,
                        statusDescription,
                        statusCode,
                        details,
                        inner
                        );

                case HttpStatusCode.BadGateway:
                    return new StorageServerException(
                        StorageErrorCode.BadGateway,
                        statusDescription,
                        statusCode,
                        details,
                        inner
                        );
            }
            return null;
        }

        private static Exception TranslateExtendedError(
                    StorageExtendedErrorInformation details,
                    HttpStatusCode statusCode,
                    string statusDescription,
                    Exception inner
                    )
        {
            StorageErrorCode errorCode = default(StorageErrorCode);
            switch (details.ErrorCode)
            {
                case StorageErrorCodeStrings.UnsupportedHttpVerb:
                case StorageErrorCodeStrings.MissingContentLengthHeader:
                case StorageErrorCodeStrings.MissingRequiredHeader:
                case StorageErrorCodeStrings.UnsupportedHeader:
                case StorageErrorCodeStrings.InvalidHeaderValue:
                case StorageErrorCodeStrings.MissingRequiredQueryParameter:
                case StorageErrorCodeStrings.UnsupportedQueryParameter:
                case StorageErrorCodeStrings.InvalidQueryParameterValue:
                case StorageErrorCodeStrings.OutOfRangeQueryParameterValue:
                case StorageErrorCodeStrings.InvalidUri:
                case StorageErrorCodeStrings.InvalidHttpVerb:
                case StorageErrorCodeStrings.EmptyMetadataKey:
                case StorageErrorCodeStrings.RequestBodyTooLarge:
                case StorageErrorCodeStrings.InvalidXmlDocument:
                case StorageErrorCodeStrings.InvalidXmlNodeValue:
                case StorageErrorCodeStrings.MissingRequiredXmlNode:
                case StorageErrorCodeStrings.InvalidMd5:
                case StorageErrorCodeStrings.OutOfRangeInput:
                case StorageErrorCodeStrings.InvalidInput:
                case StorageErrorCodeStrings.InvalidMetadata:
                case StorageErrorCodeStrings.MetadataTooLarge:
                case StorageErrorCodeStrings.InvalidRange:
                    errorCode = StorageErrorCode.BadRequest;
                    break;
                case StorageErrorCodeStrings.AuthenticationFailed:
                    errorCode = StorageErrorCode.AuthenticationFailure;
                    break;
                case StorageErrorCodeStrings.ResourceNotFound:
                    errorCode = StorageErrorCode.ResourceNotFound;
                    break;
                case StorageErrorCodeStrings.ConditionNotMet:
                    errorCode = StorageErrorCode.ConditionFailed;
                    break;
                case StorageErrorCodeStrings.ContainerAlreadyExists:
                    errorCode = StorageErrorCode.ContainerAlreadyExists;
                    break;
                case StorageErrorCodeStrings.ContainerNotFound:
                    errorCode = StorageErrorCode.ContainerNotFound;
                    break;
                case BlobErrorCodeStrings.BlobNotFound:
                    errorCode = StorageErrorCode.BlobNotFound;
                    break;
                case BlobErrorCodeStrings.BlobAlreadyExists:
                    errorCode = StorageErrorCode.BlobAlreadyExists;
                    break;
            }

            if (errorCode != default(StorageErrorCode))
                return new StorageClientException(
                                errorCode,
                                statusDescription,
                                statusCode,
                                details,
                                inner
                                );

            switch (details.ErrorCode)
            {
                case StorageErrorCodeStrings.InternalError:
                case StorageErrorCodeStrings.ServerBusy:
                    errorCode = StorageErrorCode.ServiceInternalError;
                    break;
                case StorageErrorCodeStrings.Md5Mismatch:
                    errorCode = StorageErrorCode.ServiceIntegrityCheckFailed;
                    break;
                case StorageErrorCodeStrings.OperationTimedOut:
                    errorCode = StorageErrorCode.ServiceTimeout;
                    break;
            }
            if (errorCode != default(StorageErrorCode))
                return new StorageServerException(
                                errorCode,
                                statusDescription,
                                statusCode,
                                details,
                                inner
                                );



            return null;
        }


        // This is the limit where we allow for the error message returned by the server.
        // Message longer than that will be truncated. 
        private const int ErrorTextSizeLimit = 8 * 1024;

        private static StorageExtendedErrorInformation GetExtendedErrorDetailsFromResponse(
            Stream httpResponseStream,
            long contentLength
            )
        {
            try
            {
                int bytesToRead = (int)Math.Max((long)contentLength, (long)ErrorTextSizeLimit);
                byte[] responseBuffer = new byte[bytesToRead];
                int bytesRead = CopyStreamToBuffer(httpResponseStream, responseBuffer, (int)bytesToRead);
                return GetErrorDetailsFromStream(
                            new MemoryStream(responseBuffer, 0, bytesRead, false)
                            );
            }
            catch (WebException)
            {
                //Ignore network errors when reading error details.
                return null;
            }
            catch (IOException)
            {
                return null;
            }
            catch (TimeoutException)
            {
                return null;
            }
        }

        private static StorageExtendedErrorInformation GetErrorDetailsFromStream(
            Stream inputStream
            )
        {
            StorageExtendedErrorInformation extendedError = new StorageExtendedErrorInformation();
            try
            {
                using (XmlReader reader = XmlReader.Create(inputStream))
                {
                    reader.Read();
                    reader.ReadStartElement(StorageHttpConstants.XmlElementNames.ErrorRootElement);
                    extendedError.ErrorCode = reader.ReadElementString(StorageHttpConstants.XmlElementNames.ErrorCode);
                    extendedError.ErrorMessage = reader.ReadElementString(StorageHttpConstants.XmlElementNames.ErrorMessage);
                    extendedError.AdditionalDetails = new NameValueCollection();

                    // After error code and message we can have a number of additional details optionally followed
                    // by ExceptionDetails element - we'll read all of these into the additionalDetails collection
                    do
                    {
                        if (reader.IsStartElement())
                        {
                            if (string.Compare(reader.LocalName, StorageHttpConstants.XmlElementNames.ErrorException, StringComparison.Ordinal) == 0)
                            {
                                // Need to read exception details - we have message and stack trace
                                reader.ReadStartElement(StorageHttpConstants.XmlElementNames.ErrorException);
                                extendedError.AdditionalDetails.Add(StorageHttpConstants.XmlElementNames.ErrorExceptionMessage,
                                    reader.ReadElementString(StorageHttpConstants.XmlElementNames.ErrorExceptionMessage));
                                extendedError.AdditionalDetails.Add(StorageHttpConstants.XmlElementNames.ErrorExceptionStackTrace,
                                    reader.ReadElementString(StorageHttpConstants.XmlElementNames.ErrorExceptionStackTrace));
                                reader.ReadEndElement();
                            }
                            else
                            {
                                string elementName = reader.LocalName;
                                extendedError.AdditionalDetails.Add(elementName, reader.ReadString());
                            }
                        }
                    }
                    while (reader.Read());
                }
            }
            catch (XmlException)
            {
                //If there is a parsing error we cannot return extended error information
                return null;
            }
            return extendedError;
        }

        internal static StorageExtendedErrorInformation GetExtendedErrorFromXmlMessage(string xmlErrorMessage)
        {
            string message = null;
            string errorCode = null;

            XName xnErrorCode = XName.Get(StorageHttpConstants.XmlElementNames.TableErrorCodeElement,
                StorageHttpConstants.XmlElementNames.DataWebMetadataNamespace);
            XName xnMessage = XName.Get(StorageHttpConstants.XmlElementNames.TableErrorMessageElement,
                StorageHttpConstants.XmlElementNames.DataWebMetadataNamespace);

            using (StringReader reader = new StringReader(xmlErrorMessage))
            {
                XDocument xDocument = null;
                try
                {
                    xDocument = XDocument.Load(reader);
                }
                catch (XmlException)
                {
                    // The XML could not be parsed. This could happen either because the connection 
                    // could not be made to the server, or if the response did not contain the
                    // error details (for example, if the response status code was neither a failure
                    // nor a success, but a 3XX code such as NotModified.
                    return null;
                }

                XElement errorCodeElement =
                    xDocument.Descendants(xnErrorCode).FirstOrDefault();

                if (errorCodeElement == null)
                    return null;

                errorCode = errorCodeElement.Value;

                XElement messageElement =
                    xDocument.Descendants(xnMessage).FirstOrDefault();

                if (messageElement != null)
                {
                    message = messageElement.Value;
                }

            }

            StorageExtendedErrorInformation errorDetails = new StorageExtendedErrorInformation();
            errorDetails.ErrorMessage = message;
            errorDetails.ErrorCode = errorCode;
            return errorDetails;
        }
    }


    #endregion
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)

About the Author

Modesty Zhang
Technical Lead
United States United States
Tech Lead of large scale consumer facing software offerings, specializing in Web and Mobile application architecting and development.
 
Specialties:
Web App/ iOS / Cocoa Touch / HTML5 / CSS3 / Ajax / jQuery / jQuery Mobile / jQuery UI / Node.js / Rich JavaScript Application / RESTful Web Services / Java EE 6 / Java 7 / PHP / Ruby on Rails / and Windows / .NET / RIA / Flex / Flash / Silverlight / Software Architecting / Front End Design and Development

| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 12 Jul 2009
Article Copyright 2009 by Modesty Zhang
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid