【IT168微软云计算博客征文专稿】本文介绍如何创建、查询和删除Blob数据,所使用的数据来自Queue的消息数据。
首先在 Default.aspx 中增加Blob相关的成员变量:
private static BlobStorage _blobStorage = null;
private static BlobContainer _blobContainer = null;
const int UPDATE_TIMEOUT_SEC = 5;
const string SUFFIX = "xml";
然后再给 _Initialization 处理程序增加初始化代码:
{
if (_initialized)
{
return;
}
lock (_syncObj)
{
try
{
_blobStorage =
BlobStorage.Create(StorageAccountInfo
.GetDefaultBlobStorageAccountFromConfiguration());
_blobContainer = _blobStorage.GetBlobContainer(BLOB_CONTAINER_NAME);
// 让容器公开,以便我们可以使用REST API从Web通过URI查询Blob
_blobContainer.CreateContainer(new NameValueCollection(),
ContainerAccessControl.Public);
_queueStorage =
QueueStorage.Create(StorageAccountInfo
.GetDefaultQueueStorageAccountFromConfiguration());
_queueStorage.RetryPolicy =
RetryPolicies.RetryN(3, TimeSpan.FromSeconds(5));
MessageQueue queue = _queueStorage.GetQueue(BLOB_PAYLOAD_QUEUE_NAME);
queue.CreateQueue();
queue.MessageReceived +=
new MessageReceivedEventHandler(_OnMessageReceive);
queue.PollInterval = 500; // 单位毫秒
queue.StartReceiving(); // 开始投票
}
catch (WebException ex)
{
throw new WebException(
string.Format(
"---{0}:_Initialization, Windows Azure failed to instatiate storage
using current account information. Exception caught : {1}",
this.ToString(),
ex.Message
)
);
}
_initialized = true;
}
}
ContainerAccessControl 应该被设置为 Public ,以便应用程序可以使用REST API查询Blob数据,为了改变访问范围,这里提供了两个 CreateContainer() 方法,第一个通过传递一个Blob容器名实例化Blob容器对象,第二个仅仅是调用Blob容器类的一个函数,它必须通过传递一个枚举值 ContainerAccessControl.Public 使用有效的Blob容器实例,这个调用不是必需的,不会覆盖实例本身,但可以修改访问范围。
调用 _Initialization() 后,Blob存储和Blob容器都已实例化,可以使用Blob容器实例创建一个Blob记录,如:
{
Message message = (args as MessageReceivedEventArgs).Message;
System.Diagnostics.Trace.WriteLine(
string.Format(
"--- {0}:_OnMessageReceive, message = <{1}>",
this.ToString(),
message.ContentAsString()
)
);
string blobName = string.Format("{0}{1}", message.Id, SUFFIX);
if (!_blobContainer.DoesBlobExist(blobName))
{
BlobProperties properties = new BlobProperties(blobName);
// 创建与Blob关联的元数据
NameValueCollection metadata = new NameValueCollection();
metadata["MediaID"] = message.Id;
properties.Metadata = metadata;
properties.ContentType = "text/xml";
// 创建Blob
byte[] buffer =
UTF8Encoding.UTF8
.GetBytes(message.ContentAsString().Replace("\r\n", string.Empty));
MemoryStream ms = new MemoryStream(buffer);
BlobContents mediaBlob = new BlobContents(ms);
_blobContainer.CreateBlob(properties, mediaBlob, true);
}
_DataBind();
}
在这个例子中,Blob存储的名字是在接收到Queue消息时创建的,而Blob名是Blob创建时指定的,Blob名可以是任意的,但最好不要包括账号名,因为账号名在部署到Azure云时是可以通过配置文件修改的。
Azure提供了一个名叫服务总线的服务,为了让Blob存储适应.NET服务总线,建议构思Blob名时多花点心思,下面就是我的一些心得体会:
· 使用.NET命名空间约定构思Blob名
· 基于Blob的逻辑或关系结构以分层思想构思Blob名
当 BlobProperties 对象实例化后,Azure Blob存储的元数据就构造好了,元数据对象是嵌入在 BlobProperties. 的对象实例中的,元数据是Blob存储的属性集,元数据是名称/值对的格式,元数据的真实类叫做 NameValueCollection, ,在这个类实例化之前,命名空间 System.Collections.Specialized 必须包括进来。
Blob容器在创建Blob存储时会用到两个参数: BlobContents 和 BlobProperties. 。第一个参数容纳了信息的主体,第二个参数容纳了信息的属性,只有 Strea m(流)和 Byte array (字节数组)数据类型可以用于这两个参数,信息主体在实例化成 BlobContents 对象之前,必须转换成这两个数据类型。我们在消息队列事件处理程序中创建Blob对象:
图1显示了运行时的 Default.aspx 页面。

图 1 Blob创建结果页面
图2显示了在 SQL Server Management Studio 中,从 DevelopmentStorageDb 查询 Accounts , AcctBlobContainerMap , BlobContainer 和Blob表的结果。
图 2 Blob存储记录创建后的查询结果
为了检索存储在Blob中的信息, BlobContainer 类提供了一套访问函数查询Blob容器中的Blob或特定Blob的属性,下面是从Blob检索信息的一般步骤。
1、首先创建一个C#容器类 MediaInfo ,它有三个属性: BlobName , MediaUri 和 MediaID ,这三个属性用来容纳Blob记录的信息。
{
public MediaInfo(string blobName,
string mediaAddress,
string mediaID)
{
BlobName = blobName;
MediaUri = mediaAddress;
MediaID = mediaID;
}
public string MediaUri{get; set;}
public string BlobName { get; set; }
public string MediaID { get; set; }
}
private void _DataBind()
{
IEnumerable<object> blobs = _blobContainer.ListBlobs(string.Empty, false);
List<MediaInfo> mediaList= new List<MediaInfo>();
foreach (object blob in blobs)
{
if ((blob as BlobProperties )!= null)
{
BlobProperties blobProperties =
_blobContainer.GetBlobProperties((blob as BlobProperties).Name);
NameValueCollection mediaEntryProperties = blobProperties.Metadata;
mediaList.Add(
new MediaInfo(
blobProperties.Name,
(blob as BlobProperties).Uri.ToString(),
mediaEntryProperties["MediaID"]
)
);
}
}
BlobLinksView.DataSource = filesList;
BlobLinksView.DataBind();
}
2、在 Default.aspx 中定义一个 GridView 显示Blob记录。
id="BlobLinksView"
DataKeyNames="BlobName"
AllowPaging="False"
AutoGenerateColumns="False"
GridLines="Vertical"
Runat="server"
onrowcommand="RowCommandHandler"
BackColor="#B3F2FD" ForeColor="Black"
BorderColor="#0066FF" BorderStyle="None" BorderWidth="1px" CellPadding="4"
Font-Size="Small" Width="394px">
<Columns>
<asp:ButtonField Text="Delete" CommandName="DeleteEntry"/>
<asp:HyperLinkField
HeaderText="Blob ID"
DataTextField="MediaID"
DataNavigateUrlFields="MediaUri" />
</Columns>
<RowStyle BackColor="#F7F7DE" />
<FooterStyle BackColor="#CCCC99" />
<PagerStyle BackColor="#F7F7DE" ForeColor="Black" HorizontalAlign="Right" />
<SelectedRowStyle BackColor="#CE5D5A" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#6B696B" Font-Bold="True" ForeColor="White" />
<AlternatingRowStyle BackColor="White" />
</asp:GridView>
protected void RowCommandHandler(object sender, GridViewCommandEventArgs e)
{
try
{
if (e.CommandName == "DeleteEntry")
{
int index = Convert.ToInt32(e.CommandArgument);
string blobName = (string)BlobLinksView.DataKeys[index].Value;
if (_blobContainer.DoesBlobExist(blobName))
{
_blobContainer.DeleteBlob(blobName);
}
}
}
catch { }
_DataBind();
}
GridView的列与 MediaInfo 的属性一一对应,如 DataTextField 与 MediaID 属性对应, DataNavigateUrlFields 与 MediaUri 属性对应。
3、使用 _blobContainer 实例调用 ListBlobs() ,传递两个参数: prefix (在这里是空字符串)和 boolean 标志,这个函数应该返回一个 IEnumerable 类型的实例。
4、遍历Blob记录集,用 List 类型填充 mediaList 实例本地集合。
5、将 mediaList 作为 GridView 的 DataSource (数据源),调用 DataBind() 方法将数据绑定到 GridView ,根据设计,调用 ListBlobs() 必须先于调用 GetBlobProperties() ,否则调用 GetBlobProperties() 将总是返回一个null对象。
如果要删除Blob,需要传递Blob名,为了获得Blob名,我们需要在 Default.aspx 的 GridView 中插入一个原始命令处理程序,并链接到一个按钮,点击相应的视图项目时,为了检索特定的Blob项目ID,在处理程序 RowCommandHandler 后应该插入下面的代码:
ListBlobs() 检索Blob记录外,也可以使用支持REST查询的工具或应用程序进行检索,如 Fiddler ,它可以产生 HTTP GET/POST/UPDATE 请求。
{
try
{
if (e.CommandName == "DeleteEntry")
{
int index = Convert.ToInt32(e.CommandArgument);
string blobName = (string)BlobLinksView.DataKeys[index].Value;
if (_blobContainer.DoesBlobExist(blobName))
{
_blobContainer.DeleteBlob(blobName);
}
}
}
catch { }
_DataBind();
}
除了使用 ListBlobs() 检索Blob记录外,也可以使用支持REST查询的工具或应用程序进行检索,如 Fiddler ,它可以产生 HTTP GET/POST/UPDATE 请求。
图3显示了使用 Fiddler 2. 执行REST查询的查询结果。
图 3 使用 Fiddler 2 HTTP 调试工具对Blob数据执行REST查询的查询结果
查询字符串的语法示例如下:
http://127.0.0.1:10000/devstoreaccount1/blobpayload/caa95517-3414-4bc2-8f16-0a44a6f156e1xml
成功的REST查询,返回代码是200。