Windows
Azure Storage 允许云计算应用的开发者在云端存储应用程序数据,为云计算提供耐用、可扩充、具备可用性且有效率的储存服务。Windows
Azure Storage通过Development Storage和VS 2008/VS 2010结合使用,为开发者提供了熟悉、友好的程序设计界面。
Windows Azure Storage由三个重要部分构成:
Windows Azure Blob:存储大型数据,包括二进制数据和文件。
Windows Azure Table:存储表数据,类似关系数据库中的数据表,单有所不同,将在后文中介绍。
Windows Azure Queue:为异步工作提供分派消息服务,有点类似Windows系统的消息队列。
在某种程度上来说,我们可以把Blob认为是云端的文件系统。在本文中,我们的重点是Windows Azure
Blob。通过对Blob架构分析,以一个完整的实例来一步一步介绍如何使用Blob进行开发。
Blob架构分析
对Blob架构的分析从两个方面来介绍:Blob应用程序架构和Blob存储结构。
(1) Blob应用程序架构
Blob应用程序架构如图1所示:
图1 Blob应用程序架构
通过图1我们可以看到,Blob存储数据是通过一个简单的层级关系来实现的,每个账户Account下有一个容器,这个容器就是用户定义的一套只有一个属性的Blobs(Blob集合),容器不直接存储数据,每个Blobs包含了多个Blob,这些Blob可以分为Blocks和Pages两类。Blob的存储是采用REST(Representational
State Transfer,表象化状态转变)方式来进行的,有关REST可以访问维基百科地址:http://zh.wikipedia.org/zh-cn/REST来了解一下。
同时在图1中,我们可以看到存储账户的地址、Blob Container的地址、Blob的地址,如一个Blob的实际应用的地址如下:
http://127.0.0.1:10000/devstoreaccount1/imagefiles/0cd5c5f2-063e-4092-b960-a987c5654dee.png
那么标示我们使用的Storage是本地存储
账户:devstoreaccount1
Blob Container:imagefiles
Blob文件:0cd5c5f2-063e-4092-b960-a987c5654dee.png
(2) Blob存储结构
在本地开发的环境中,我们使用了安装在本地的SQL Express。要想了解Blob的存储结构,首先连接到数据库上看看。
使用SSMS连接本地的SQL Express数据库,如图1所示:
图2 连接本地SQL Express
在这里使用的SQL Express版本是SQL Express 2008,连接上本地SQL Express后,我们可以看到开发环境的存储数据库如图3所示
图3 开发环境存储表
由图3中的表我们可以看到,除了账户表(Account),这些表是针对Blob、Queue、Table三种存储服务来设计的,事实上,Blob的存储结构如图4所示:
图4 Blob的存储结构
应用与案例
在本文的案例中,我们将使用Blob存储上传到云端的图片文件,包括对云端的图片文件的列表展示、上传、删除、下载等功能。
在开始案例之前我们简要说明一下此案例的开发环境:
VS 2008 / VS 2010
SQL Express 2005 / SQL Express 2008
Windows Azure Tools for Microsoft Visual Studio 1.1,其下载的地址是:
http://www.microsoft.com/downloads/details.aspx?familyid=5664019E-6860-4C33-9843-4EB40B297AB6&displaylang=en
Windows Azure SDK
http://www.microsoft.com/downloads/details.aspx?FamilyID=21910585-8693-4185-826e-e658535940aa&displaylang=en
在本例中,将使用VS 2010来创建项目,下面我们开始介绍这个案例的详细开发步骤:
第一步:创建项目
在开始|所有程序里打开Microsoft Visual Studio 2010,创建新的Cloud项目DemoStorageBlob,
如图5所示:
图5 创建项目DemoStoragBlob
输入项目名称DemoStoragBlob,解决方案名称后,点击“确定
OK”,自动打开添加云应用项目界面,如图6所示:
图6 创建Web Role
选择Asp.Net Web Role,创建名为BlobWebRole的项目,点击“确定
OK”,我们创建的项目结构最终如图7所示:
图7 DemoStorageBlob项目结构
第二步:添加WebRole程序代码
在WebRole程序代码设计部分,我们要完成的任务是:设计图片实体类、设计上传显示界面,完成上传、显示、删除功能,可以说是整个案例的核心部分。
本案例中我们要处理的Blob对象是图片文件,因此,在BlobWebRole项目中,添加一个Image图片的实体类ImageEntity,代码如下:
public
class ImageEntity
{
public
Uri FileUri { get;
set;
}
public
string
FileName { get;
set;
}
public
long
Length { get;
set;
}
public
string
FolderName { get;
set;
}
public
bool IsReadOnly { get;
set;
}
public
bool IsExists { get;
set;
}
public
string
FullFileName { get;
set;
}
public
string
ExtendName { get;
set;
}
public
string
CreatorName { get;
set;
}
public
DateTime CreateTime { get;
set;
}
}
添加完ImageEntity类的代码后,对Default.Aspx页面进行简单的设计,在Default页面里,有两部分,一部分是上传图片,另一部分是列表显示Blob里的数据,代码如下:
<form id="form1"
runat="server">
<div>
<div><!--上传图片-->
<asp:Label
ID="lblFilePath"
Text="上传文件"
AssociatedControlID="fileUploadControl"
runat="server"
/>
<asp:FileUpload
ID="fileUploadControl"
runat="server"
/>
<asp:RequiredFieldValidator
ID="filUploadValidator"
ControlToValidate="fileUploadControl"
ValidationGroup="fileInfoGroup"
ErrorMessage="请选择文件!"
runat="Server">
</asp:RequiredFieldValidator>
<br
/>
<asp:Label
ID="lblFileName"
Text="文件名称:"
AssociatedControlID="txtFileName"
runat="server"
/>
<asp:TextBox
ID="txtFileName"
runat="server"
/>
<asp:RequiredFieldValidator
ID="fileNameValidator"
ControlToValidate="txtFileName"
ValidationGroup="fileInfoGroup"
ErrorMessage="请输入文件名!"
runat="Server">
</asp:RequiredFieldValidator>
<br
/>
<asp:Label
ID="lblCreator"
Text="创 建
者:" AssociatedControlID="txtCreator"
runat="server"
/>
<asp:TextBox
ID="txtCreator"
runat="server"
/>
<asp:RequiredFieldValidator
ID="submitterValidator"
ControlToValidate="txtCreator"
ValidationGroup="fileInfoGroup"
ErrorMessage="请输入创建者!"
runat="Server">
</asp:RequiredFieldValidator>
<br
/>
<asp:Button
ID="btnSave"
Text="保存"
CausesValidation="true"
ValidationGroup="fileInfoGroup"
runat="server"
OnClick="btnSave_Click"
/>
<br
/>
<br
/>
<asp:Label
ID="statusMessage"
runat="server"
/>
</div>
<div><!--列表显示图片-->
<asp:GridView
ID="fileView"
AutoGenerateColumns="false"
DataKeyNames="FileUri"
runat="server"
OnRowCommand="RowCommandHandler">
<Columns>
<asp:ButtonField
Text="Delete"
CommandName="DeleteItem"
/>
<asp:HyperLinkField
HeaderText="Link"
DataTextField="FileName"
DataNavigateUrlFields="FileUri"
/>
<asp:BoundField
DataField="CreatorName"
HeaderText="Created
by" />
<asp:BoundField
DataField="FolderName"
HeaderText="FolderName"
/>
<asp:BoundField
DataField="IsReadOnly"
HeaderText="IsReadOnly"
/>
<asp:BoundField
DataField="IsExists"
HeaderText="IsExists"
/>
<asp:BoundField
DataField="FullFileName"
HeaderText="FullFileName"
/>
<asp:BoundField
DataField="ExtendName"
HeaderText="ExtendName"
/>
<asp:BoundField
DataField="CreateTime"
HeaderText="CreateTime"
/>
</Columns>
</asp:GridView>
</div>
</div>
</form>
下面就是本案例中最重要的核心代码了。
打开defau.aspx.cs文件,添加如下代码:
添加引用:
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
添加代码:
private
CloudBlobClient _BlobClient = null;
private
CloudBlobContainer _BlobContainer = null;
private
const
string
conContainerAddress = "imagefiles";
private
const
string
conConfigStorageSetting =
"BlobConnectionString";
protected
void Page_Load(object
sender, EventArgs e)
{
//设置Windows
Azure Storage连接
var
storageAccount = CloudStorageAccount.FromConfigurationSetting(conConfigStorageSetting);
_BlobClient
= storageAccount.CreateCloudBlobClient();
//获取或创建container
_BlobContainer
= _BlobClient.GetContainerReference(conContainerAddress);
_BlobContainer.CreateIfNotExist();
//设置权限
var
permissions = new
BlobContainerPermissions();
permissions.PublicAccess
= BlobContainerPublicAccessType.Container;
_BlobContainer.SetPermissions(permissions);
//显示当前列表
DisplayFileList();
在这里我们定义了常量conContainerAddress,它表示我们将要创建的Blob Container名称,注意在这里设置的时候一定要全部使用小写字母,如果使用匈牙利命名法,可能会出现错误。
在这里初始化了Blob信息,主要是设置了Windows Azure Storage连接的账户、Blob
Container的名称。
/// <summary>
///
列表
///
</summary>
private
void DisplayFileList()
{
var
blobs = _BlobContainer.ListBlobs();
var
filesList = new
List<ImageEntity>();
//查询
foreach
(var blobItem in blobs)
{
var
cloudBlob = _BlobContainer.GetBlobReference(blobItem.Uri.ToString());
cloudBlob.FetchAttributes();
//实体字段
filesList.Add(new
ImageEntity()
{
FileUri
= blobItem.Uri,
FileName
= cloudBlob.Metadata["FileName"],
Length
= long.Parse(cloudBlob.Metadata["Length"]),
FolderName
= cloudBlob.Metadata["FileName"],
IsReadOnly
= bool.Parse(cloudBlob.Metadata["IsReadOnly"]),
IsExists
= bool.Parse(cloudBlob.Metadata["IsExists"]),
FullFileName
= cloudBlob.Metadata["FullFileName"],
ExtendName
= cloudBlob.Metadata["ExtendName"],
CreatorName
= cloudBlob.Metadata["CreatorName"],
CreateTime
= DateTime.Parse(cloudBlob.Metadata["CreateTime"])
});
}
//绑定列表
fileView.DataSource
= filesList;
fileView.DataBind();
}
在这里使用cloudBlob.FetchAttributes()来获取Blob的属性或者元数据,把查询出来的ImageEntity实体结合绑定到GridView上去,这样我们在列表里就能看到有哪些Blob的数据。
/// <summary>
///
上传
///
</summary>
///
<param name="sender"></param>
///
<param name="e"></param>
protected
void btnSave_Click(object
sender, EventArgs e)
{
//获取扩展名
string
extension = System.IO.Path.GetExtension(fileUploadControl.FileName);
//创建Blob并且重命名
var
blob = _BlobContainer.GetBlobReference(Guid.NewGuid().ToString()
+ extension);
blob.UploadFromStream(fileUploadControl.FileContent);
//设置元数据到Blob
blob.Metadata["FileName"]
= txtFileName.Text;
blob.Metadata["Length"]
= fileUploadControl.FileContent.Length.ToString();
DirectoryInfo
di = new
DirectoryInfo(string.Format("{0}\\",
conContainerAddress));
blob.Metadata["FolderName"]
= di.Name;
FileInfo
file = new
FileInfo(fileUploadControl.PostedFile.FileName);
blob.Metadata["IsReadOnly"]
= file.IsReadOnly.ToString();
blob.Metadata["IsExists"]
= file.Exists.ToString();
blob.Metadata["FullFileName"]
= file.FullName;
blob.Metadata["ExtendName"]
= file.Extension;//extension
blob.Metadata["CreatorName"]
= txtCreator.Text;
blob.Metadata["CreateTime"]
= DateTime.Now.ToShortTimeString();
blob.SetMetadata();
//设置属性
blob.Properties.ContentType
= fileUploadControl.PostedFile.ContentType;
blob.SetProperties();
//显示列表
DisplayFileList();
txtFileName.Text
= string.Empty;
txtCreator.Text
= string.Empty;
statusMessage.Text
= string.Empty;
}
在上传方法中,使用了blob.SetMetadata()来设置Blob的元数据,把元数据存到了Blob中,blob.SetProperties()来设置Blob的属性,并“Set”进去。
protected
void RowCommandHandler(object
sender, GridViewCommandEventArgs e)
{
//删除
if
(e.CommandName == "DeleteItem")
{
//
获取索引
var
index = Convert.ToInt32(e.CommandArgument);
var
blobUri = fileView.DataKeys[index].Value.ToString();
//Get
the container
var
blob = _BlobContainer.GetBlobReference(blobUri);
blob.DeleteIfExists();
}
//更新列表
DisplayFileList();
}
在点击“删除 Delete”的时候,将删除选中的Blob,调用了blob.DeleteIfExists(),注意在使用Blob对象时,首先要使用Container的GetBlobReference方法来获取到Blob对象。
第三步:配置应用程序
配置应用程序有两种方法,一种是直接修改服务定义文件:ServiceDefinition.csdef,服务配置文件ServiceConfiguration.cscfg;另一种是使用UI来直接配置。不管使用哪种方法,其最终的结果是一样的。在这里我们来使用第二种方法,添加配置节BlobConnectionString。
打开DemoStorageBlob下的Roles文件夹,双击BlobWebRole,打开“设置 Settings”页面,添加BlobConnectionString,如图9所示:
图9 添加BlobConnectionString
添加完后,我们的服务定义文件自动发生了修改:
<ConfigurationSettings>
<Setting name="BlobConnectionString"
/>
</ConfigurationSettings>
服务配置文件也同样发生了修改
<ConfigurationSettings>
<Setting name="BlobConnectionString"
value="UseDevelopmentStorage=true"
/>
</ConfigurationSettings>
服务配置文件也同样发生了修改
第四步:设置运行调试环境
配置完成后,编译应用程序,保证没有编译错误的情况,我们要进行调试运行程序之前的设置工作,设置工作主要是Development
Fabric和Storage,设置项目的启动项和起始页。
首先需要设置DemoStorageBlob为启动项目,如图10所示:
图10 设置启动项目
设置完启动项目后,设置BlobWebRole下的Default为起始页。设置完成后,在开始|所有程序|
Windows Azure SDK v1.2|打开Development Fabric,确保我们调试时候的模拟器是开着的,在本案例中,要确保Storage的Blob是运行的,界面如图11所示:
图11 启动development Storage
第五步:调试运行程序
这里没有设置断点来调试程序,直接“Run”起来我们的案例,初始化的界面如图12所示:
图12 上传初始界面
选择文件,输入文件名称、创建者,点击上传,上传几个文件后的界面如图13所示:
图13 上传4个图片文件到Blob
图13中已经上传了4个图片文件,点击文件文件名,可以在打开已经上传的图片文件,点击“Delete”,删除文件TestBlob4,界面如图14所示:
图14 删除后的界面
不仅能通过运行的前台页面来查看文件,还可以在VS 2010中通过Server Explorer来查看Blob对象,这也是VS开发平台强大的地方之一,通过VS打开Blob的界面如图15所示:
图15 服务器浏览器查看Blob
在图15所示的界面中,可以输入文件名进行查找,可以打开文件,另存文件到本地。
我们在页面上做的所有操作的结果都存入到了SQL Express的数据库中,在Blob架构分析中,已经介绍了如何连接SQL
Express数据库,连接上数据库后,我们查看一下与Blob相关的几个表里数据,界面如图16所示:
图16 查询Blob数据
总结
本文介绍了Windows Azure Storage三驾马车之一的Blob,对开发者来说Blob是一个存储大容量二进制文件或文件的“虚拟空间”,同时从应用程序和数据结构两个方面介绍了Blob的结构,并通过图片管理的一个应用案例的讲解,使大家对Blob有一个深入的了解。
|