WEB开发网
开发学院服务器云计算 Windows Azure实战:如何创建云数据存储 阅读

Windows Azure实战:如何创建云数据存储

 2010-05-21 00:00:00 来源:WEB开发网   
核心提示:Windows Azure SDK开发环境包括一个开箱即用的开发存储(Development Storage),实际上它是一个在本地模拟云存储服务的工具,Windows Azure实战:如何创建云数据存储,Azure SDK提供了开发存储服务,在将应用程序部署到云之前,PartitionKey和RowKey的值可以允许

Windows Azure SDK开发环境包括一个开箱即用的开发存储(Development Storage),实际上它是一个在本地模拟云存储服务的工具,Azure SDK提供了开发存储服务,在将应用程序部署到云之前,允许开发人员在本机创建、调试和测试云数据服务。默认情况下,开发存储是以SQL Server Express版为基础模拟云存储环境的,开发存储使用Windows身份认证连接到SQL Server Express。本文将向大家展示如何在本地云开发环境中创建一个数据表。

第1步:创建新的Worker Cloud Service项目

使用Visual Studio中的Worker Cloud Service模板创建一个新项目,命名为CreateDataStorage。

Windows Azure实战:如何创建云数据存储

图 1 创建新的Worker Cloud Service项目

第2步:添加StorageClient.dll引用

Visual Studio默认会为这个解决方案生成两个项目,需要给项目添加一个到StorageClient.dll的引用,这个程序集在安装Windows Azure SDK的目录下,如我这里是C:\Program Files\Windows Azure SDK\v1.0\Samples\StorageClient\Lib\bin\Debug,如果没有这个文件,那么就需要载入SDK自带的示例,重新编译一次即可生成这个文件。

public class Address : TableStorageEntity 
    { 
        private State? _state; 
        public string Address1 { get; set; } 
        public string Address2 { get; set; } 
        public string City { get; set; } 
        public int? State { get { return (int)_state; } set { _state = (State)value; } } 
        public string Zip { get; set; } 
        public string County { get; set; } 
        public string Country { get; set; } 
        public Address():this(Guid.NewGuid()) 
        { 
        } 
        public Address(Guid internalID) 
: base(ConfigurationManager.AppSettings["PartitionKey"], internalID.ToString()) 
        { } 
        public Address(string address1, 
                       string address2, 
                       string city, 
                       State state, 
                       string zip, 
                       string county, 
                       string country, 
                       Guid internalID) 
            :this(internalID) 
        { 
            Address1 = address1; 
            Address2 = address2;
           City = city; 
            State = (int)state; 
            Zip = zip; 
            County = county; 
            Country = country; 
        } 
    }

第3步:添加新的C#库项目CloudData.Models

接下来给解决方案添加一个C#库项目CloudData.Models,在这里,我定义了一个很简单的数据实体类Address,它继承了SDK基础类 Microsoft.Samples.ServiceHosting.StorageClient.TableStorageEntity,下面的代码显示了这个类的定义。

第4步:创建CloudDataService文件夹

在同一个项目中,创建一个CloudDataService文件夹,在它上面增加三个接口定义 – IdataTableService,IHasDependencyTableService和INoDependencyTableService。 IDataTableService接口暴露三个基本的数据表访问功能 – Insert,Update和Delete,所有这些功能都接受 Microsoft.Samples.ServiceHosting.StorageClient命名空间中定义的TableStorageEntity 类参数;其它两个接口都衍生自IDataTableService接口,IHasDependencyTableService接口暴露 UpdateDependencyTable()方法,它也接受TableStorageEntity类参数;INoDependencyTableService接口不暴露任何方法,但它提供了一个类型定义,用于标记一个类为无逻辑依赖数据对象。

第5步:在CloudDataService文件夹下添加两个类

接下来在CloudDataServices文件夹中增加两个类 – DataTableService和AddressTableService,将第一个类标记为抽象类,AddressTableService类是DataTableService类的衍生类。

所有类和接口的代码如下:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
namespace CreateDataStorage.Models.CloudDataServices 
{ 
    using Microsoft.Samples.ServiceHosting.StorageClient; 
    public interface IDataTableService 
    { 
        bool Insert(TableStorageEntity entity); 
        bool Update(TableStorageEntity entity); 
        bool Delete(TableStorageEntity entity); 
    } 
    public interface IHasDependencyTableService : IDataTableService 
    { 
        bool UpdateDependencyTable(TableStorageEntity entity); 
    }
public interface INoDependencyTableService : IDataTableService 
    { 
    } 
} 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
namespace CreateDataStorage.Models.CloudDataServices 
{ 
    using Microsoft.Samples.ServiceHosting.StorageClient; 
    using CreateDataStorage.Models.CloudDataContext; 
    abstract public class DataTableService 
    { 
        protected UserDataContext _userDataContext = null; 
        protected string _Table { get; set; } 
        public DataTableService() 
        { 
            _userDataContext = new UserDataContext(); 
        } 
        public UserDataContext DataContext() { return _userDataContext; } 
        virtual public bool Insert(TableStorageEntity entity) 
        { 
            bool success = false; 
            try 
            { 
                if (this is IHasDependencyTableService) 
                { 
                    (this as IHasDependencyTableService).UpdateDependencyTable(entity); 
                } 
                _userDataContext.AddObject(_Table, entity); 
                _userDataContext.SaveChanges(); 
                success = true; 
            } 
            catch { } 
            return success; 
        } 
        public bool Update(TableStorageEntity entity) 
        { 
            bool success = false; 
            try
   { 
                if (Delete(entity)) 
                { 
                    success = Insert(entity); 
                } 
            } 
            catch { } 
            return success; 
        } 
        virtual public bool Delete(TableStorageEntity entity) 
        { 
            bool success = false; 
            try 
            { 
                if (this is IHasDependencyTableService) 
                { 
                    (this as IHasDependencyTableService).UpdateDependencyTable(entity); 
                } 
                _userDataContext.DeleteObject(entity); 
                _userDataContext.SaveChanges(); 
                success = true; 
            } 
            catch { } 
            return success; 
        } 
    } 
} 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Configuration; 
namespace CreateDataStorage.Models.CloudDataServices 
{ 
    using Microsoft.Samples.ServiceHosting.StorageClient; 
    using CreateDataStorage.Models.CloudData; 
    public class AddressTableService : DataTableService, INoDependencyTableService 
    { 
        public AddressTableService() 
        { 
            _Table = ConfigurationManager.AppSettings["AddressTable"]; 
        } 
    } 
}

第6步:添加UserDataContext类

在同一个项目上,添加UserDataContext类,这个类衍生自Azure SDK基础类TableStorageDataServiceContext,它封装了一个云存储查询函数,UserDataContext的定义代码如下:

public class UserDataContext : TableStorageDataServiceContext 
    { 
        public DataServiceQuery<Address> AddressTable 
        { 
            get 
            { 
                return 
CreateQuery<Address>(ConfigurationManager.AppSettings["AddressTable"]); 
            } 
        } 
    }

第7步:指定数据库名

在CreateDataStorage项目节点上点击右键,选择“属性”,在属性对话框中,选择左侧的“开发”,输入数据库名AzureForDotNetDeveloper,如下图所示。

Windows Azure实战:如何创建云数据存储

图 2 输入数据库名

第8步:添加CloudData.Models.dll引用

给CloudStorageService_WorkerRole项目添加CloudData.Models.dll引用。

第9步:创建测试存储表

在CreateDataStorage项目上点击右键,选择“创建测试存储表(Create Test Storage Table)”,如下图所示,编译器将会分析代码,为数据库生成一个表。

Windows Azure实战:如何创建云数据存储

图 3 创建测试存储表

生成的表如下图所示。

Windows Azure实战:如何创建云数据存储

图 4 生成的AddressTable表

第一次在本地创建Development Storage(开发存储)时,会弹出一个提示消息框,如下图所示。

Windows Azure实战:如何创建云数据存储

图 5 第一次创建开发存储时的提示框

点击“是”,弹出如下图所示的对话框。

Windows Azure实战:如何创建云数据存储

图 6 开发存储初始化确认对话框

启动成功后,可以查看其运行状态,如下图所示。

Windows Azure实战:如何创建云数据存储

图 7 查看开发存储的运行状态

这就是使用Windows Azure SDK开发存储表服务创建云数据存储表的基本步骤,但实际上,在云环境中的存储利用率和在本地环境中的存储利用率有所不同,因此我们应该遵循一些规则和最佳实践。

为数据列使用可移植型数据类型

数据列的数据类型应该可移植到SQL数据类型,或可以被转换为系统定义的基本数据类型。

使用Windows Azure开发工具生成数据表

使用Azure SDK提供的开发工具调用开发存储服务生成数据库和数据表,开发工具分析所有项目的数据对象生成数据结构,数据表的数量等于衍生自TableStorageEntity类的数据实体类的数量,列的数量等于该数据实体类公共访问属性的数量。

非可移植数据类型解决方案

如果数据类型是自定义的,SDK开发工具将不能调用DevelopmentStorage.exe和DevtableGen.exe,下面的例子展示了在数据表中使用自定义数据列类型的解决方案,我们定义了两个数据对象类 - State和Address,State是枚举类型,它有59个成员,代表美国邮政服务使用的州,每个Address类有一个使用这个自定义类型的属性成员。这两个类的定义如下:

public enum State 
    { 
        AL,AK,AS,AZ,AR,CA,CO,CT,DE,DC,FM,FL,GA,GU,HI, 
        ID,IL,IN,IA,KS,KY,LA,ME,MH,MD,MA,MI,MN,MS,MO, 
        MT,NE,NV,NH,NJ,NM,NY,NC,ND,MP,OH,OK,OR,PW,PA, 
        PR,RI,SC,SD,TN,TX,UT,VT,VI,VA,WA,WV,WI,WY 
    } 
    public class Address : TableStorageEntity 
    { 
        ... 
        public State State { get; set; } 
        ... 
    }

当我们再次调用创建测试存储表时,将会要求我们移除数据库中的现有存储,如下图所示。

Windows Azure实战:如何创建云数据存储

图 8 删除现有存储表的确认对话框

点击“是”,弹出一个执行失败的对话框,如下图所示。

Windows Azure实战:如何创建云数据存储

图 9 创建开发存储表失败的消息提示框

Visual Studio输出窗口显示的错误消息是:

DevTableGen(0,0): error DG10: No tables were generated. Either no candidate classes were  
found or they did not meet the requirements for the table storage.

光从这个错误输出信息看不出失败的原因,我们可以通过以下步骤重新生成数据表:

1、让State类型继承int类型,因为int是系统定义的类型,是可移植到SQL数据库的;

2、在Address类中,使用State类型定义一个成员变量_state;

3、应用.NET可为空设计模式给这个成员变量;

4、执行类型转换。

下面是修改后的代码:

public enum State : int 
    { 
        AL,AK,AS,AZ,AR,CA,CO,CT,DE,DC,FM,FL,GA,GU,HI, 
        ID,IL,IN,IA,KS,KY,LA,ME,MH,MD,MA,MI,MN,MS,MO, 
        MT,NE,NV,NH,NJ,NM,NY,NC,ND,MP,OH,OK,OR,PW,PA, 
        PR,RI,SC,SD,TN,TX,UT,VT,VI,VA,WA,WV,WI,WY 
    } 

    public class Address : TableStorageEntity 
    { 
        private State _state; 
        public int? State 
        { 
            get { return (int)_state; } 
            set { _state = (State)value; } 
        } 
    }

完成修改后,使用Visual Studio重新生成表,错误将会消失,在本地SQL数据库中重新创建表成功。

数据上下文类继承

除了数据实体类外,对于每一个数据存储表,必须定义一个继承自TableStorageDataServiceContext的类,如:

public class UserDataContext : TableStorageDataServiceContext 
    { 
        ... 
        public DataServiceQuery<Address> AddressTable 
        { 
            get 
            { 
                CreateQuery<Address>(ConfigurationManager.AppSettings["AddressTable"]); 
            } 
        } 
        ... 
    }

使用PartitionKey和RowKey组织分散的数据

为了支持负载均衡,云中的表和实体都是跨存储节点分区的,也就是说,物理上可能是位于不同服务器上的,每个分区容纳连续范围的实体,它们的分区键值相同,分区就是通过分区键组织的。我们在表上指定了PartitionKey属性为分区键,分区键必须是唯一的,分区键是由实体主键和RowKey组成的。

对于每一个数据表实体,数据可以根据PartitionKey和RowKey组织,PartitionKey和RowKey的值可以允许是空字符串,但不能是null,下表显示了PartitionKey和RowKey可能的组合。

表 1 使用PartitionKey和RowKey组织表结构

  PartitionKey  RowKey  使用条款
  空字符串  空字符串  一个分区或一行
  有值  空字符串  多个分区或一行
  空字符串  有值  一个分区或每个分区有多行
  有值  有值  多个分区或每个分区有多行

Tags:Windows Azure 实战

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接