SQL数据库管理API简介

SQL 数据库管理 API 可以编程方式访问与通过 Windows Azure 平台管理门户执行的相同管理操作,来管理 Windows Azure SQL服务器。使用 SQL 数据库管理 API 可以管理每个订阅的 SQL Database 服务器以及与每台服务器关联的防火墙规则。这有助于自动化应用程序的数据库支持,而无需直接与管理门户进行交互。

数据库管理 API 是一个 REST API。所发送的操作请求通过 SSL 进行加密,并使用 X.509 证书对其进行身份验证。可以通过 Internet 从可以发送 HTTPS 请求和接收 HTTPS 响应的任何应用程序发出这些请求。请求将发送到使用以下基本 URL 的端口 8443 上的 SQL Database 数据库管理服务:https://management.database.windows.net:8443

这个blog介绍了以编程方式 (使用 Visual Studio 2012 RC 中的 HttpClient) 创建一个Windows Azure SQL 数据库服务器,设置管理密码,并创建防火墙规则。我们可以使用如下步骤:

  1. 准备访问数据库管理 API 的客户端证书。
  2. 设置相应的HTTP请求标头,如版本号等。
  3. 创建数据库服务器
    1. 定义请求数据的 .net 对象
    2. 发送请求,并接收服务器响应数据
    3. 将响应数据转换为 .net (如C#) 的相应对象
    4. 从对象中读取信息
  4. 设置管理密码
  5. 创建防火墙规则
  6. 连接到新创建的数据库服务器

1、准备客户端证书

数据库管理 API 需要基于证书的相互身份验证。我们需要首先将公钥证书(.cer)文件与订阅相关联,方法是使用 Windows Azure 平台管理门户将该证书上载到 Windows Azure 中订阅的证书存储区。然后,将匹配的私钥证书(.pfx)文件附加到数据库管理 API 请求中。

有关证书创建,可以参考 如何创建管理证书 以及 如何为角色创建证书。例如,可以使用MakeCert工具,具体命令可参考 Step 1 - Create and Install a test certificate

进而我们可以获得 .cer 文件(包含公钥) 和 .pfx 文件 (包含私钥和公钥,私钥保护密码由用户指定),可以使用管理门户将公钥证书 (.cer 文件)上载到 Windows Azure中订阅的证书存储区,如:

之后,可以使用 System.Net.Http.WebRequestHandler 和 System.Security.Cryptography.X509Certificate2 .NET 类将私钥 (.pfx) 文件与安全请求相关联。

如以下代码片段,其中参数certFilename 和certPassword 分别是 .pfx 文件的全路径文件名和私钥保护密码 (私钥和密码不与请求一起发送;它们仅用于对请求进行验证):

 WebRequestHandler webRequestHandler = new WebRequestHandler();
 webRequestHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
 webRequestHandler.ClientCertificates.Add(
 new X509Certificate2(certFilename, certPassword));

2、设置相应的HTTP请求标头

HttpClient可用于发送 Http 请求,并用于接收 Http 响应。如下代码片段生成一个HttpClient实例,并设置访问 API 的版本信息:

 this.httpClient = new HttpClient(webRequestHandler);
this.httpClient.DefaultRequestHeaders.Add("x-ms-version", "1.0");

完整代码片段如下:

 public class SqlRestApiClient
{
 private const string ServerUri = "https://management.database.windows.net:8443/{0}/servers";
 private const string FirewallUri = ServerUri + "/{1}/firewallrules";
 private readonly string subscriptionId;
 private readonly HttpClient httpClient;
 private readonly XmlMediaTypeFormatter xmlFormatter;
 private readonly IEnumerable<XmlMediaTypeFormatter> xmlFormatters;
 
 public SqlRestApiClient(string certFilename, string certPassword, string subscriptionId)
 {
 WebRequestHandler webRequestHandler = new WebRequestHandler();
 webRequestHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
 webRequestHandler.ClientCertificates.Add(
 new X509Certificate2(certFilename, certPassword));
 
 this.httpClient = new HttpClient(webRequestHandler);
 this.httpClient.DefaultRequestHeaders.Add("x-ms-version", "1.0");
 
 this.xmlFormatter = new XmlMediaTypeFormatter()
 {
 UseXmlSerializer = true,
 };
 this.xmlFormatters = new XmlMediaTypeFormatter[] { xmlFormatter };
 this.subscriptionId = subscriptionId;
 }
}

3、创建数据库服务器

定义请求数据的 .net 对象

定义请求数据 .Net 对象 ServerRequest如下:

  [XmlRoot(ElementName = "Server",
 Namespace = "https://schemas.microsoft.com/sqlazure/2010/12/")]
 public class ServerRequest
 {
 public string AdministratorLogin { get; set; }
 public string AdministratorLoginPassword { get; set; }
 public string Location { get; set; }
 }

发送请求并接收服务器响应数据

设置枚举服务器的url,其中需要指定 Windows Azure 的订阅ID (参数:subscriptionId);构建请求数据:

  string url = string.Format(ServerUri, this.subscriptionId);
 var request = new ServerRequest()
 {
 AdministratorLogin = adminName,
 AdministratorLoginPassword = adminPwd,
 Location = location,
 };

设置Xml媒体类型序列化器,然后发送HTTP POST请求,并读取响应正文。

  HttpResponseMessage response = await this.httpClient
 .PostAsync<ServerRequest>(url, request, this.xmlFormatter);

将响应数据转换为 .net (如C#) 的相应对象

我们可以定义 .net 对象ServerName如下:

  [XmlRoot(ElementName = "ServerName",
 Namespace = "https://schemas.microsoft.com/sqlazure/2010/12/")]
 public class CreateServerResponse
 {
 [XmlText]
 public string ServerName { get; set; } 
 }

将响应正文数据转换为 C# 对象:

  CreateServerResponse server = await response.Content
 .ReadAsAsync<CreateServerResponse>(this.xmlFormatters);

从对象中读取信息

例如我们可以读取 server.ServerName 信息,如下:

  Console.WriteLine("ServerName: {0}", server.ServerName);

创建SQL数据库服务器的完整代码片段如下:

  async public Task CreateServer(string adminName, string adminPwd, string location)
 {
 string url = string.Format(ServerUri, this.subscriptionId);
 var request = new ServerRequest()
 {
 AdministratorLogin = adminName,
 AdministratorLoginPassword = adminPwd,
 Location = location,
 };
 
 HttpResponseMessage response = await this.httpClient
 .PostAsync<ServerRequest>(url, request, this.xmlFormatter);
 
 if (!response.IsSuccessStatusCode)
 {
 this.ErrorHandler(response);
 return;
 }
 
 CreateServerResponse server = await response.Content
 .ReadAsAsync<CreateServerResponse>(this.xmlFormatters);
 
 Console.WriteLine("ServerName: {0}", server.ServerName);
 }
 
 private async void ErrorHandler(HttpResponseMessage response)
 {
 Console.WriteLine("Caught HttpResponseException");
 Error error = await response.Content
 .ReadAsAsync<Error>(this.xmlFormatters);
 Console.WriteLine(
 "Code: {0}, Message: {1}, Severity: {2}, State: {3}",
 error.Code,
 error.Message,
 error.Severity,
 error.State);
 }

其中Error定义如下:

  [XmlRoot(Namespace = "https://schemas.microsoft.com/sqlazure/2010/12/")]
 public class Error
 {
 public uint Code { get; set; }
 public string Message { get; set; }
 public uint Severity { get; set; }
 public uint State { get; set; }
 }

调用方式如下:

  SqlRestApiClient sqlRestApiClient = new SqlRestApiClient(
 "windows_azure_tools.pfx",
 "certPassword",
 "c4a83956-af86-4606-8881-d12c0ae12ea6");
 await sqlRestApiClient.CreateServer("adm1", "Pa$$word123$$", "North Central US"); 

例如,输出如下:

 ServerName: ux5zdppgom

也可以登录Windows Azure管理门户查看新创建的SQL数据库服务器:

4、设置管理密码

在前面创建SQL数据库服务器时我们设置了管理员帐户名称和密码,过后我们可使用“设置服务器管理员密码” REST API重新设置 SQL 数据库服务器的管理密码。

我们可以定义重置密码请求的对象如下:

  [XmlRoot(ElementName = "AdministratorLoginPassword",
 Namespace = "https://schemas.microsoft.com/sqlazure/2010/12/")]
 public class AdministratorLoginPasswordRequest
 {
 [XmlText]
 public string AdministratorLoginPassword { get; set; }
 }

重置密码方法如创建SQL服务器类似。先设定请求的Url,创建请求消息,然后发送请求,接收响应数据。

设置管理密码的代码片段如下:

 
 async public Task ResetPassword(string serverName, string password)
 {
 string url = string.Format(ServerUri + "/{1}?op=ResetPassword",
 this.subscriptionId,
 serverName);
 var request = new AdministratorLoginPasswordRequest()
 {
 AdministratorLoginPassword = password,
 };
 
 HttpResponseMessage response = await this.httpClient
 .PostAsync(url, request, this.xmlFormatter);
 
 if (response.IsSuccessStatusCode)
 {
 Console.WriteLine(
 "server: {0}, password {1} is reset successfully",
 serverName,
 password);
 }
 else
 {
 this.ErrorHandler(response);
 }
 }

调用方式如下:

 await sqlRestApiClient.ResetPassword("ux5zdppgom", "Pa$word123$");

输出如下:

 server: ux5zdppgom, password Pa$word123$ is reset successfully

5、创建防火墙规则

 

为服务器创建防火墙规则

默认情况下,新创建的SQL服务器禁止来自客户端的访问。我们可以为服务器创建防火墙规则,以允许来之客户端,或/和允许从与 Windows Azure 相关的应用程序和服务连接到服务器。

防火墙规则对象可定义如下:

 [XmlRoot(ElementName = "FirewallRule",
 Namespace = "https://schemas.microsoft.com/sqlazure/2010/12/")]
 public class FirewallRuleRequest
 {
 public string StartIpAddress { get; set; }
 public string EndIpAddress { get; set; }
 }

使用类似设置管理密码的流程,一个不同之处是:我们需要发送HTTP PUT请求,而不是POST请求。代码片段如下:

 async public Task CreateFirewallRule(string serverName, string ruleName, string startIp, string endIp)
 {
 string url = string.Format(FirewallUri + "/{2}",
 this.subscriptionId,
 serverName,
 ruleName);
 var request = new FirewallRuleRequest()
 {
 StartIpAddress = startIp,
 EndIpAddress = endIp,
 };
 
 HttpResponseMessage response = await this.httpClient
 .PutAsync(url, request, this.xmlFormatter);
 
 if (response.IsSuccessStatusCode)
 {
 Console.WriteLine("rule: {0} [{1} - {2}] written successfully",
 ruleName,
 startIp,
 endIp);
 }
 else
 {
 this.ErrorHandler(response);
 }
 }

调用方式如下:

 await sqlRestApiClient.CreateFirewallRule("ux5zdppgom", "rule1", "0.0.0.0", "0.0.0.0");

输出如下:

 rule: rule1 [0.0.0.0 - 0.0.0.0] written successfully

其中起始和结束 IP 地址设置为 0.0.0.0 的防火墙规则允许从与 Windows Azure 相关的应用程序和服务连接到服务器。

使用 IP 检测为服务器创建防火墙规则

我们还可以使用 IP 检测为服务器创建防火墙规则。当用户由于地址转换、代理服务器等原因不知道自己的外部 IP 地址时,这可能会有用。方法与如上类似,先定义一个IpAddress对象:

 [XmlRoot(ElementName = "IpAddress",
 
 Namespace = "https://schemas.microsoft.com/sqlazure/2010/12/")]
 public class IpAddressResponse
 {
 [XmlText]
 public string IpAddress { get; set; }
 }

代码如下:

 async public Task CreateFirewallRuleWithClientIp(string serverName, string ruleName)
 
 {
 string url = string.Format(FirewallUri + "/{2}?op=AutoDetectClientIP",
 this.subscriptionId,
 serverName,
 ruleName);
 
 var requestMessage = new HttpRequestMessage();
 HttpResponseMessage response = await this.httpClient
 .PostAsync(url, requestMessage.Content);
 
 if (!response.IsSuccessStatusCode)
 {
 this.ErrorHandler(response);
 return;
 }
 
 IpAddressResponse ip = await response.Content
 .ReadAsAsync<IpAddressResponse>(this.xmlFormatters);
 
 Console.WriteLine("rule: {0} added with client ip: {1}",
 ruleName,
 ip.IpAddress);
 }

调用方式可以为:

 await sqlRestApiClient.CreateFirewallRuleWithClientIp("ux5zdppgom", "rule2");

输出如下:

 rule: rule2 added with client ip: 116.96.128.226

6、连接到新创建的数据库服务器

我们可以使用SQL Server Management Studio (SSMS) 连接到如上新创建的SQL数据库服务器。

输入服务器名称,验证方式选择为:SQL Server Authentication,然后输入用户名和密码。

点击连接,连接成功后我们可以看到:

有关SQL Database 数据库管理 API的更多信息,可以参考msdn中相应内容

软件开发工程师  苏从勇

AccessSqlRestApi.zip