您的位置:首页 > 其它

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的信息:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: