/// <summary>
        /// Gets a sql auth connection context.
        /// </summary>
        /// <param name="cmdlet">The cmdlet requesting the context</param>
        /// <param name="serverName">The name of the server to connect to</param>
        /// <param name="manageUrl">The manage url of the server</param>
        /// <param name="credentials">The credentials to connect to the server</param>
        /// <param name="sessionActivityId">The session activity ID</param>
        /// <param name="managementServiceUri">The URI for management service</param>
        /// <returns>The connection context</returns>
        public static IServerDataServiceContext GetContext(
            PSCmdlet cmdlet,
            string serverName,
            Uri manageUrl,
            SqlAuthenticationCredentials credentials,
            Guid sessionActivityId,
            Uri managementServiceUri)
        {
            Version version;
            
            // If a version was specified (by tests) us it.
            if (sqlVersion == SqlVersion.v2)
            {
                version = new Version(11, 0);
            }
            else if (sqlVersion == SqlVersion.v12)
            {
                version = new Version(12, 0);
            }
            else // If no version specified, determine the version by querying the server.
            {
                version = GetVersion(manageUrl, credentials);
            }
            sqlVersion = SqlVersion.None;

            IServerDataServiceContext context = null;

            if (version.Major >= 12)
            {
                context = new TSqlConnectionContext(
                    sessionActivityId,
                    manageUrl.Host,
                    credentials,
                    serverName);
            }
            else
            {
                context = ServerDataServiceSqlAuth.Create(
                    managementServiceUri,
                    sessionActivityId,
                    credentials,
                    serverName);

                // Retrieve $metadata to verify model version compatibility
                XDocument metadata = ((ServerDataServiceSqlAuth)context).RetrieveMetadata();
                XDocument filteredMetadata = DataConnectionUtility.FilterMetadataDocument(metadata);
                string metadataHash = DataConnectionUtility.GetDocumentHash(filteredMetadata);
                if (!((ServerDataServiceSqlAuth)context).metadataHashes.Any(knownHash => metadataHash == knownHash))
                {
                    cmdlet.WriteWarning(Resources.WarningModelOutOfDate);
                }

                ((ServerDataServiceSqlAuth)context).MergeOption = MergeOption.PreserveChanges;
            }

            return context;
        }
        /// <summary>
        /// Retrieves and returns the Management Service access token for the specified user credentials.
        /// </summary>
        /// <param name="accessUri">The <see cref="Uri"/> to the Management Service <c>GetAccessToken</c> operation.</param>
        /// <param name="credentials">The credentials to be used to authenticate the user.</param>
        /// <returns>An instance of <see cref="AccessTokenResult"/> with the retrieved access token and cookie.</returns>
        public static AccessTokenResult GetAccessToken(Uri accessUri, SqlAuthenticationCredentials credentials)
        {
            if (accessUri == null)
            {
                throw new ArgumentNullException("accessUri");
            }

            if (credentials == null)
            {
                throw new ArgumentNullException("credentials");
            }

            HttpWebRequest    request  = CreateGetAccessTokenRequest(accessUri, credentials);
            HttpWebResponse   response = (HttpWebResponse)request.GetResponse();
            AccessTokenResult result   = RetrieveAccessTokenFromResponse(response);

            return(result);
        }
        /// <summary>
        /// Retrieves and returns the Management Service access token for the specified user credentials.
        /// </summary>
        /// <param name="accessUri">The <see cref="Uri"/> to the Management Service <c>GetAccessToken</c> operation.</param>
        /// <param name="credentials">The credentials to be used to authenticate the user.</param>
        /// <returns>An instance of <see cref="AccessTokenResult"/> with the retrieved access token and cookie.</returns>
        public static AccessTokenResult GetAccessToken(Uri accessUri, SqlAuthenticationCredentials credentials)
        {
            if (accessUri == null)
            {
                throw new ArgumentNullException("accessUri");
            }

            if (credentials == null)
            {
                throw new ArgumentNullException("credentials");
            }

            HttpWebRequest request = CreateGetAccessTokenRequest(accessUri, credentials);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            AccessTokenResult result = RetrieveAccessTokenFromResponse(response);

            return result;
        }
        /// <summary>
        /// Utility method that creates and returns an instance of <see cref="HttpWebRequest"/> that
        /// connects to <c>GetAccessToken</c> WCF operation with the specified user name and password.
        /// </summary>
        /// <param name="accessUri">The <see cref="Uri"/> to the Management Service <c>GetAccessToken</c> operation.</param>
        /// <param name="userName">The user name to retrieve the access token for.</param>
        /// <param name="password">The user password.</param>
        /// <returns>An instance of <see cref="HttpWebRequest"/> object.</returns>
        private static HttpWebRequest CreateGetAccessTokenRequest(Uri accessUri, SqlAuthenticationCredentials credentials)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(accessUri);

            request.Method = "GET";

            string escapedUserName = EscapeConnectionCredentials(credentials.UserName);
            string escapedPassword = EscapeConnectionCredentials(credentials.Password);

            string escapedCredentials = string.Format(
                CultureInfo.InvariantCulture,
                "{0}:{1}",
                escapedUserName,
                escapedPassword);

            string encodedCredentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(escapedCredentials));

            request.Headers[LogOnServiceHeader] = string.Format(CultureInfo.InvariantCulture, HeaderFormatter, encodedCredentials);
            request.UserAgent = ApiConstants.UserAgentHeaderValue;

            request.CookieContainer = new CookieContainer();

            return(request);
        }
        /// <summary>
        /// Utility method that creates and returns an instance of <see cref="HttpWebRequest"/> that
        /// connects to <c>GetAccessToken</c> WCF operation with the specified user name and password.
        /// </summary>
        /// <param name="accessUri">The <see cref="Uri"/> to the Management Service <c>GetAccessToken</c> operation.</param>
        /// <param name="userName">The user name to retrieve the access token for.</param>
        /// <param name="password">The user password.</param>
        /// <returns>An instance of <see cref="HttpWebRequest"/> object.</returns>
        private static HttpWebRequest CreateGetAccessTokenRequest(Uri accessUri, SqlAuthenticationCredentials credentials)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(accessUri);

            request.Method = "GET";

            string escapedUserName = EscapeConnectionCredentials(credentials.UserName);
            string escapedPassword = EscapeConnectionCredentials(credentials.Password);

            string escapedCredentials = string.Format(
                CultureInfo.InvariantCulture,
                "{0}:{1}",
                escapedUserName,
                escapedPassword);

            string encodedCredentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(escapedCredentials));

            request.Headers[LogOnServiceHeader] = string.Format(CultureInfo.InvariantCulture, HeaderFormatter, encodedCredentials);
            request.UserAgent = ApiConstants.UserAgentHeaderValue;

            request.CookieContainer = new CookieContainer();

            return request;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ServerDataServiceSqlAuth"/> class.
        /// </summary>
        /// <param name="managementServiceUri">The server's management service Uri.</param>
        /// <param name="connectionType">The server connection type with the server name</param>
        /// <param name="sessionActivityId">An activity ID provided by the user that should be associated with this session.</param>
        /// <param name="accessToken">The authentication access token to be used for executing web requests.</param>
        /// <param name="credentials">The SQL authentication credentials used for this context</param>
        private ServerDataServiceSqlAuth(
            Uri managementServiceUri,
            DataServiceConnectionType connectionType,
            Guid sessionActivityId,
            AccessTokenResult accessToken,
            SqlAuthenticationCredentials credentials)
            : base(new Uri(managementServiceUri, connectionType.RelativeEntityUri))
        {
            this.sessionActivityId = sessionActivityId;
            this.connectionType = connectionType;
            this.accessToken = accessToken;
            this.credentials = credentials;

            // Generate a requestId and retrieve the server name
            this.clientRequestId = SqlDatabaseCmdletBase.GenerateClientTracingId();
            this.serverName = this.Servers.First().Name;
        }
        /// <summary>
        /// Creates and returns a new instance of the <see cref="ServerDataServiceSqlAuth"/> class which
        /// connects to the specified server using the specified credentials.
        /// </summary>
        /// <param name="managementServiceUri">The server's management service <see cref="Uri"/>.</param>
        /// <param name="sessionActivityId">An activity ID provided by the user that should be associated with this session.</param>
        /// <param name="accessTokenResult">The accessToken to be used to authenticate the user.</param>
        /// <param name="serverName">The name of the server to connect to. (Optional)</param>
        /// <param name="credentials">The SQL authentication credentials used for this context</param>
        /// <returns>An instance of <see cref="ServerDataServiceSqlAuth"/> class.</returns>
        public static ServerDataServiceSqlAuth Create(
            Uri managementServiceUri,
            Guid sessionActivityId,
            AccessTokenResult accessTokenResult,
            string serverName,
            SqlAuthenticationCredentials credentials)
        {
            if (managementServiceUri == null)
            {
                throw new ArgumentNullException("managementServiceUri");
            }

            if (accessTokenResult == null)
            {
                throw new ArgumentNullException("accessTokenResult");
            }

            // Create a ServerDataServiceSqlAuth object
            if (serverName == null)
            {
                return new ServerDataServiceSqlAuth(
                    managementServiceUri,
                    new DataServiceConnectionType(ServerModelConnectionType),
                    sessionActivityId,
                    accessTokenResult,
                    credentials);
            }
            else
            {
                return new ServerDataServiceSqlAuth(
                    managementServiceUri,
                    new DataServiceConnectionType(ServerModelConnectionType, serverName),
                    sessionActivityId,
                    accessTokenResult,
                    credentials);
            }
        }
        /// <summary>
        /// Creates and returns a new instance of the <see cref="ServerDataServiceSqlAuth"/> class which
        /// connects to the specified server using the specified credentials. If the server name
        /// is null, the default server name from the serviceRoot Uri will be used.
        /// </summary>
        /// <param name="managementServiceUri">The server's management service <see cref="Uri"/>.</param>
        /// <param name="sessionActivityId">An activity ID provided by the user that should be associated with this session.</param>
        /// <param name="credentials">The credentials to be used to authenticate the user.</param>
        /// <param name="serverName">The name of the server to connect to. (Optional)</param>
        /// <returns>An instance of <see cref="ServerDataServiceSqlAuth"/> class.</returns>
        public static ServerDataServiceSqlAuth Create(
            Uri managementServiceUri,
            Guid sessionActivityId,
            SqlAuthenticationCredentials credentials,
            string serverName)
        {
            if (managementServiceUri == null)
            {
                throw new ArgumentNullException("managementServiceUri");
            }

            if (credentials == null)
            {
                throw new ArgumentNullException("credentials");
            }

            // Retrieve GetAccessToken operation Uri
            Uri accessUri = DataConnectionUtility.GetAccessTokenUri(managementServiceUri);

            // Synchronously call GetAccessToken
            AccessTokenResult result = DataServiceAccess.GetAccessToken(accessUri, credentials);

            // Validate the retrieved access token
            AccessTokenResult.ValidateAccessToken(managementServiceUri, result);

            // Create and return a ServerDataService object
            return Create(managementServiceUri, sessionActivityId, result, serverName, credentials);
        }
        /// <summary>
        /// Performs the call to export database using the server data service context channel.
        /// </summary>
        /// <param name="serverName">The name of the server to connect to.</param>
        /// <param name="blobUri">The storage blob Uri to export to.</param>
        /// <param name="storageAccessKey">The access key for the given storage blob.</param>
        /// <param name="fullyQualifiedServerName">The fully qualified server name.</param>
        /// <param name="databaseName">The name of the database to export.</param>
        /// <param name="sqlCredentials">The credentials used to connect to the database.</param>
        /// <returns>
        /// The result of export request.  Upon success the <see cref="ImportExportRequest"/>
        /// for the request.
        /// </returns>
        internal ImportExportRequest ExportSqlAzureDatabaseProcess(
            string serverName,
            Uri blobUri,
            string storageAccessKey,
            string fullyQualifiedServerName,
            string databaseName,
            SqlAuthenticationCredentials sqlCredentials)
        {
            this.WriteVerbose("BlobUri: " + blobUri);
            this.WriteVerbose("ServerName: " + fullyQualifiedServerName);
            this.WriteVerbose("DatabaseName: " + databaseName);
            this.WriteVerbose("UserName: " + sqlCredentials.UserName);

            // Get the SQL management client for the current subscription
            SqlManagementClient sqlManagementClient = SqlDatabaseCmdletBase.GetCurrentSqlClient();

            // Start the database export operation
            DacImportExportResponse response = sqlManagementClient.Dac.Export(
                serverName,
                new DacExportParameters()
                {
                    BlobCredentials = new DacExportParameters.BlobCredentialsParameter()
                    {
                        Uri = blobUri,
                        StorageAccessKey = storageAccessKey,
                    },
                    ConnectionInfo = new DacExportParameters.ConnectionInfoParameter()
                    {
                        ServerName = fullyQualifiedServerName,
                        DatabaseName = databaseName,
                        UserName = sqlCredentials.UserName,
                        Password = sqlCredentials.Password,
                    }
                });

            ImportExportRequest result = new ImportExportRequest()
            {
                OperationStatus = Services.Constants.OperationSuccess,
                OperationDescription = CommandRuntime.ToString(),
                OperationId = response.RequestId,
                RequestGuid = response.Guid,
                ServerName = serverName,
                SqlCredentials = sqlCredentials,
            };

            return result;
        }
        /// <summary>
        /// Queries the server to get the server version
        /// </summary>
        /// <param name="manageUrl">The manage url of the server. Eg: https://{serverName}.database.windows.net</param>
        /// <param name="credentials">The login credentials</param>
        /// <returns>The server version</returns>
        private static Version GetVersion(Uri manageUrl, SqlAuthenticationCredentials credentials)
        {
            string serverName = manageUrl.Host.Split('.').First();
            SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
            builder["Server"] = manageUrl.Host;
            builder.UserID = credentials.UserName + "@" + serverName;
            builder.Password = credentials.Password;
            builder["Database"] = null;
            builder["Encrypt"] = false;
            builder.ConnectTimeout = 60;

            string commandText = "select serverproperty('ProductVersion')";

            using(SqlConnection conn = new SqlConnection(builder.ConnectionString))
            {
                using (SqlCommand command = new SqlCommand(commandText, conn))
                {
                    conn.Open();

                    string val = (string)command.ExecuteScalar();
                    return new Version(val);
                }
            }
        }
        /// <summary>
        /// Connect to a Azure SQL Server with the given ManagementService Uri using
        /// SQL authentication credentials.
        /// </summary>
        /// <param name="serverName">The server name.</param>
        /// <param name="managementServiceUri">The server's ManagementService Uri.</param>
        /// <param name="credentials">The SQL Authentication credentials for the server.</param>
        /// <returns>A new <see cref="ServerDataServiceSqlAuth"/> context,
        /// or <c>null</c> if an error occurred.</returns>
        internal IServerDataServiceContext GetServerDataServiceBySqlAuth(
            string serverName,
            Uri managementServiceUri,
            SqlAuthenticationCredentials credentials,
            Uri manageUrl)
        {
            IServerDataServiceContext context = null;
            Guid sessionActivityId = Guid.NewGuid();

            try
            {
                context = SqlAuthContextFactory.GetContext(this, serverName, manageUrl, credentials, sessionActivityId, managementServiceUri);
            }
            catch (Exception ex)
            {
                SqlDatabaseExceptionHandler.WriteErrorDetails(
                    this,
                    sessionActivityId.ToString(),
                    ex);

                // The context is not in an valid state because of the error, set the context 
                // back to null.
                context = null;
            }

            return context;
        }
        /// <summary>
        /// Connect to a Azure SQL Server with the given ManagementService Uri using
        /// SQL authentication credentials.
        /// </summary>
        /// <param name="serverName">The server name.</param>
        /// <param name="managementServiceUri">The server's ManagementService Uri.</param>
        /// <param name="credentials">The SQL Authentication credentials for the server.</param>
        /// <returns>A new <see cref="ServerDataServiceSqlAuth"/> context,
        /// or <c>null</c> if an error occurred.</returns>
        internal ServerDataServiceSqlAuth GetServerDataServiceBySqlAuth(
            string serverName,
            Uri managementServiceUri,
            SqlAuthenticationCredentials credentials)
        {
            ServerDataServiceSqlAuth context = null;

            Guid sessionActivityId = Guid.NewGuid();
            try
            {
                context = ServerDataServiceSqlAuth.Create(
                    managementServiceUri,
                    sessionActivityId,
                    credentials,
                    serverName);

                // Retrieve $metadata to verify model version compatibility
                XDocument metadata = context.RetrieveMetadata();
                XDocument filteredMetadata = DataConnectionUtility.FilterMetadataDocument(metadata);
                string metadataHash = DataConnectionUtility.GetDocumentHash(filteredMetadata);
                if (!context.metadataHashes.Any(knownHash => metadataHash == knownHash))
                {
                    this.WriteWarning(Resources.WarningModelOutOfDate);
                }

                context.MergeOption = MergeOption.PreserveChanges;
            }
            catch (Exception ex)
            {
                SqlDatabaseExceptionHandler.WriteErrorDetails(
                    this,
                    sessionActivityId.ToString(),
                    ex);

                // The context is not in an valid state because of the error, set the context
                // back to null.
                context = null;
            }

            return context;
        }