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 = "http://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 = "http://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 = "http://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 = "http://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 = "http://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 = "http://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


Skip to main content