Windows Azure入门教学系列 (七):使用REST API访问Storage Service
2010-05-16 12:53
465 查看
公告
:本博客为微软云计算中文博客
的镜像博客。
部分文章因为博客兼容性问题
,会影响阅读体验
。如遇此情况,请访问
原博客
。
Windows Azure
入门教学
的第七篇文章。
本文将会介绍如何使用
REST
API来直接访问
Storage Service。
在前三篇教学中,我们已经学习了使用
Windows Azure SDK所提供的
StorageClient来使用
Blob Storage,
Queue Storage以及
Table Storage的基本方法。我们在前几篇教学中也提及最终
StorageClient也是通过发送
REST请求来与服务器端通信的。
在这篇教学中,我们会以
Blob Storage为例,说明如何使用
REST API直接与服务器进行通信。需要说明的是,这篇教学中使用的是
C#语言。但是由于
REST API实际上是通过
HTTP发送的
HTTP消息,使用其他语言的工程师同样可以参考代码逻辑了解如何构造
HTTP消息以便在其他编程语言中使用。
在开始本教学之前,请确保你从
Windows Azure
平台下载
下载并安装了最新的
Windows Azure开发工具。
本教学使用
Visual Studio 2010作为开发工具。
步骤一:准备工作
在本教学中我们将使用
List Blobs API,欲了解详细信息,请参见
List
Blobs
。
该
API的作用是返回给定的
Container中的
Blob信息。为了测试我们的代码我们首先需要有一个已经创建的
Container并且向其中添加至少一个
Blob。由于如何添加
Container和
Blob的方法我们已经在
Windows Azure入门教学系列
(四
):使用
Blob Storage
中提过,在此不赘述。读者可以按照
Windows Azure入门教学系列
(四
):使用
Blob Storage
中的代码创建名为
helloworldcontainer的
Container和名为
myfile的
Blob。
(只需注释掉删除
Blob的代码并运行程序即可
)
步骤二:创建解决方案和项目
首先,请确保
Storage Emulator已经启动。我们可以找到管理器的进程手动启动或者让
Visual Studio 2010帮助我们启动他。
右击工具栏中
Windows Azure模拟器的图标,选择”
Show Storage Emulator UI”。弹出如下图所示的窗口:
我们要关注的是
Service management中
Blob所在的一行。要确保
Status为
Running。
确认完毕后启动
Visual Studio 2010,并且新建一个
Console项目。
步骤三:添加程序集引用
请在项目属性页里确认项目的
Target framework的值是
.NET Framework 4或
.NET Framework
3.5。然后在
Console项目中添加对
System.Web程序集的引用。该程序集安装在
GAC中。在
.NET标签下能够找到该程序集。我们将使用该程序集来发送
HTTP请求和接受
HTTP消息。
步骤四:添加代码
首先在项目中的
Program.cs中引用命名空间:
using
System.IO;
using
System.Collections.Specialized;
using
System.Collections;
using
System.Web;
using
System.Net;
然后在
Program.cs中添加如下代码
:
class
Program
{
internal
class
CanonicalizedString
{
private
StringBuilder
canonicalizedString =
new
StringBuilder
();
internal
CanonicalizedString(string
initialElement)
{
this
.canonicalizedString.Append(initialElement);
}
internal
void
AppendCanonicalizedElement(string
element)
{
this
.canonicalizedString.Append("/n"
);
this
.canonicalizedString.Append(element);
}
internal
string
Value
{
get
{
return
this
.canonicalizedString.ToString();
}
}
}
const
string
bloburi =
@"http://127.0.0.1:10000/devstoreaccount1"
;
const
string
accountname =
"devstoreaccount1"
;
const
string
key
=
"Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="
;
const
string
method =
"GET"
;
static
void
Main(string
[] args)
{
string
AccountName =
accountname;
string
AccountSharedKey =
key;
string
Address = bloburi;
string
container =
"helloworldcontainer"
;
//
创建请求字符串
string
QueryString =
"?restype=container&comp=list"
;
Uri
requesturi =
new
Uri
(Address +
"/"
+ container +
QueryString);
string
MessageSignature =
""
;
//
创建
HttpWebRequest
类
HttpWebRequest
Request = (HttpWebRequest
)HttpWebRequest
.Create(requesturi.AbsoluteUri);
Request.Method =
method;
Request.ContentLength =
0;
Request.Headers.Add("x-ms-date"
,
DateTime
.UtcNow.ToString("R"
));
Request.Headers.Add("x-ms-version"
,
"2009-09-19"
);
//
开始创建签名
MessageSignature +=
"GET/n"
;
//
Verb
MessageSignature +=
"/n"
;
//
Content-Encoding
MessageSignature +=
"/n"
;
//
Content-Language
MessageSignature +=
"/n"
;
//
Content-Length
MessageSignature +=
"/n"
;
//
Content-MD5
MessageSignature
+=
"/n"
;
//
Content-Type
MessageSignature +=
"/n"
;
//
Date
MessageSignature +=
"/n"
;
//
If-Modified-Since
MessageSignature +=
"/n"
;
//
If-Match
MessageSignature +=
"/n"
;
//
If-None-Match
MessageSignature +=
"/n"
;
//
If-Unmodified-Since
MessageSignature +=
"/n"
;
//
Range
//
CanonicalizedHeaders
ArrayList
list =
new
ArrayList
();
foreach
(string
str
in
Request.Headers.Keys)
{
if
(str.ToLowerInvariant().StartsWith("x-ms-"
,
StringComparison
.Ordinal))
{
list.Add(str.ToLowerInvariant());
}
}
list.Sort();
foreach
(string
str2
in
list)
{
StringBuilder
builder =
new
StringBuilder
(str2);
string
str3
=
":"
;
foreach
(string
str4
in
GetHeaderValues(Request.Headers,
str2))
{
string
str5
= str4.Replace("/r/n"
,
string
.Empty);
builder.Append(str3);
builder.Append(str5);
str3 =
","
;
}
MessageSignature +=
builder.ToString() +
"/n"
;
}
MessageSignature +=
GetCanonicalizedResourceVersion2(requesturi, AccountName);
//
开始创建签名
byte
[] SignatureBytes = System.Text.Encoding
.UTF8.GetBytes(MessageSignature);
System.Security.Cryptography.HMACSHA256
SHA256 =
new
System.Security.Cryptography.HMACSHA256
(Convert
.FromBase64String(AccountSharedKey));
//
创建
Authorization
HTTP
消息头的值
String
AuthorizationHeader =
"SharedKey
"
+ AccountName +
":"
+
Convert
.ToBase64String(SHA256.ComputeHash(SignatureBytes));
//
把编码后的签名加入到
Authorization
HTTP
消息头中
Request.Headers.Add("Authorization"
,
AuthorizationHeader);
//
获取返回消息
using
(HttpWebResponse
response = (HttpWebResponse
)Request.GetResponse())
{
if
(response.StatusCode ==
HttpStatusCode
.OK)
{
//
服务器返回成功消息
using
(Stream
stream =
response.GetResponseStream())
{
using
(StreamReader
sr =
new
StreamReader
(stream))
{
var
s =
sr.ReadToEnd();
//
输出返回消息
Console
.WriteLine(s);
}
}
}
else
{
//
这里可以抛出异常信息
}
}
Console
.ReadLine();
}
static
ArrayList
GetHeaderValues(NameValueCollection
headers,
string
headerName)
{
ArrayList
list =
new
ArrayList
();
string
[] values =
headers.GetValues(headerName);
if
(values
!=
null
)
{
foreach
(string
str
in
values)
{
list.Add(str.TrimStart(new
char
[0]));
}
}
return
list;
}
static
string
GetCanonicalizedResourceVersion2(Uri
address,
string
accountName)
{
StringBuilder
builder =
new
StringBuilder
("/"
);
builder.Append(accountName);
builder.Append(address.AbsolutePath);
CanonicalizedString
str =
new
CanonicalizedString
(builder.ToString());
NameValueCollection
values =
HttpUtility
.ParseQueryString(address.Query);
NameValueCollection
values2 =
new
NameValueCollection
();
foreach
(string
str2
in
values.Keys)
{
ArrayList
list =
new
ArrayList
(values.GetValues(str2));
list.Sort();
StringBuilder
builder2 =
new
StringBuilder
();
foreach
(object
obj2
in
list)
{
if
(builder2.Length >
0)
{
builder2.Append(","
);
}
builder2.Append(obj2.ToString());
}
values2.Add((str2 ==
null
) ?
str2 : str2.ToLowerInvariant(), builder2.ToString());
}
ArrayList
list2 =
new
ArrayList
(values2.AllKeys);
list2.Sort();
foreach
(string
str3
in
list2)
{
StringBuilder
builder3 =
new
StringBuilder
(string
.Empty);
builder3.Append(str3);
builder3.Append(":"
);
builder3.Append(values2[str3]);
str.AppendCanonicalizedElement(builder3.ToString());
}
return
str.Value;
}
}
步骤五:观察并分析代码
我们首先观察下面三行代码:
const
string
bloburi =
@"http://127.0.0.1:10000/devstoreaccount1"
;
const
string
accountname =
"devstoreaccount1"
;
const
string
key =
"Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="
;
这三行代码定义了
Blob Storage服务端口,我们使用的账户名和密码。由于使用的是本地模拟的
Storage,所以必须使用固定的端口地址,用户名以及密码。可以参考
Development
Storage与
Windows Azure Storage Services的不同之处
获取更多信息。
在代码中,我们使用
HttpWebRequest
构造并发送
HTTP请求。由于我们的例子中使用的是
List Blobs API我们需要查阅
List Blobs
对该
API的规定构造符合规定的
HTTP请求。
在规定中说明了如果该
container没有被设置为允许匿名访问,那么必须由于账户拥有者调用该
API才能返回结果。要这样做必须添加
Authorization HTTP消息头。我们必须严格按照
Authentication
Schemes
规定的格式来生成该
HTTP消息头。
步骤六:运行程序
如果一切正常,你将会看到
Console程序输出如下信息,内容为名为
helloworld的
Container中所有
Blob的信息:
相关文章推荐
- Windows Azure入门教学系列 (七):使用REST API访问Storage Service
- Windows Azure入门教学系列 (七):使用REST API访问Storage Service
- [转]Windows Azure入门教学系列 (六):使用Table Storage
- Windows Azure入门教学系列 (八):使用Windows Azure Drive
- Windows Azure入门教学系列 (四):使用Blob Storage
- Windows Azure入门教学系列 (四):使用Blob Storage
- Windows Azure入门教学系列 (六):使用Table Storage
- Windows Azure入门教学系列 (五):使用Queue Storage
- Windows Azure入门教学系列 (六):使用Table Storage
- Windows Azure入门教学系列 (四):使用Blob Storage
- Windows Azure入门教学系列 (五):使用Queue Storage
- Windows Azure入门教学系列 (八):使用Windows Azure Drive
- Windows Azure入门教学系列 (六):使用Table Storage
- Windows Azure入门教学系列 (八):使用Windows Azure Drive
- Windows Azure入门教学系列 (五):使用Queue Storage
- 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【三】——Web Api入门
- Windows Azure入门教学系列 (一): 创建第一个WebRole程序
- 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【三】——Web Api入门
- Windows Azure入门教学系列 (三):创建第一个Worker Role程序
- PHP on Windows Azure 入门教学系列(3) ——在Windows Azure中部署Wordpress