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有一个深入的了解。 
                        |