normalian blog

Let's talk about Microsoft Azure, ASP.NET and Java!

Windows Azure SDK for Visual Studio Novemberについて色々確認してみた

以前 id:waritohutsu:20091115 で記述したとおり、Windows Azure SDK for Visual Studio Novemberにおいて、Windows Azureストレージに対するアクセス方法が大幅に変更されました。具体的に、以下の点が大きな変更点だと思っています。

  1. 設定ファイルを読み取る際に、予め初期化処理が必要
  2. ストレージアクセスの設定(*.cscfg、*.csdef)のフォーマット変更
  3. ストレージアクセスに用いるクラス名の変更
  4. サポートされたLINQメソッドが変更している*1

設定ファイルを読み取る際に、予め初期化処理が必要

以下の手順を踏まないとWindows Azure SDK for Visual Studio Novemberでは *.cscfgファイルから設定値を読み取る際に例外が発生します

  • RoleEntryPointクラスを継承したクラスを作成し、RoleEntryPoint#OnStartメソッドをオーバーライド
  • 上記メソッド内で、CloudStorageAccount.SetConfigurationSettingPublisherにハンドラを登録

以下が、件のRoleEntryPoint#OnStartのメソッド

    public class WebRole : RoleEntryPoint
    {
        public override bool OnStart()
        {
            DiagnosticMonitor.Start("DiagnosticsConnectionString");

            #region Setup CloudStorageAccount Configuration Setting Publisher

            // This code sets up a handler to update CloudStorageAccount instances when their corresponding
            // configuration settings change in the service configuration file.
            CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
            {
                // Provide the configSetter with the initial value
                configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));

                RoleEnvironment.Changed += (sender, arg) =>
                {
                    if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>()
                        .Any((change) => (change.ConfigurationSettingName == configName)))
                    {
                        // The corresponding configuration setting has changed, propagate the value
                        if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
                        {
                            // In this case, the change to the storage account credentials in the
                            // service configuration is significant enough that the role needs to be
                            // recycled in order to use the latest settings. (for example, the 
                            // endpoint has changed)
                            RoleEnvironment.RequestRecycle();
                        }
                    }
                };
            });
            #endregion on handling configuration changes
            // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
            RoleEnvironment.Changing += RoleEnvironmentChanging;

            return base.OnStart();
        }

        private void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
        {
            // If a configuration setting is changing
            if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange))
            {
                // Set e.Cancel to true to restart this role instance
                e.Cancel = true;
            }
        }
    }

ストレージアクセスの設定(*.cscfg、*.csdef)が変わっている

新旧二つの*.cscfg設定ファイルを例として記述します。ご覧の通り、旧設定ファイルがWindows Azure独自形式な事に対して、新設定ファイルはADO.NETを意識した記述方法になっています。

  • 新*.cscfg

設定ファイルは以下の形式となります

  <Role name="WebRole1">
    <Instances count="1" />
    <ConfigurationSettings>
      <Setting name="DiagnosticsConnectionString" value="UseDevelopmentStorage=true" />
      <Setting name="DataConnectionString" value="DefaultEndpointsProtocol=http;AccountName=<アカウント名>;AccountKey=<ハッシュキー>" />
    </ConfigurationSettings>
  </Role>


設定ファイルの値を取得する方法は以下となります。

CloudStorageAccount cloudStorageAccount
 = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
CloudTableClient cloudTableClient = cloudStorageAccount.CreateCloudTableClient();
  • 旧*.cscfgについて

設定ファイルは以下の形式となります

  <Role name="WebRole1">
    <Instances count="1" />
    <ConfigurationSettings >
      <Setting name="BlobStorageEndpoint" value="http://<アカウント名>.blob.core.windows.net/" />
      <Setting name="QueueStorageEndpoint" value="http://<アカウント名>.queue.core.windows.net/" />
      <Setting name="TableStorageEndpoint" value="http://<アカウント名>.table.core.windows.net/" />
      <Setting name="AccountName" value="<アカウント名>" />
      <Setting name="AccountSharedKey" value="<ポータルサイトに表示されるキー>" />
    </ConfigurationSettings>
  </Role>

設定ファイルの値を取得する方法は以下となります。

StorageAccountInfo tableAaccountInfo
 = StorageAccountInfo.GetAccountInfoFromConfiguration("TableStorageEndpoint");
//TableStorageDataServiceContextを継承したクラスから、テーブルを作成
TableStorage.CreateTablesFromModel(typeof(CommentDataServiceContext), tableAccountInfo);

ストレージアクセスに用いるクラス名の変更

分かっている範囲の情報において、Windows AzureストレージTableについての情報を記述します*2。ご覧の通り、設定ファイルからの値取得、テーブルの作成方法、クラス名等々が結構変わってます。実際に開発する際にはこれらに注意する必要があります。

//アカウント情報取得
CloudStorageAccount cloudStorageAccount
 = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

//TableClient作成
CloudTableClient cloudTableClient = cloudStorageAccount.CreateCloudTableClient();
cloudTableClient.CreateTableIfNotExist("Comments");

//サービスコンテキストを定義
CommentServiceContext commentServiceContext =
    new CommentServiceContext(
    cloudStorageAccount.TableEndpoint.ToString(),
    cloudStorageAccount.Credentials);

//Table内のデータにアクセス
var query = commentServiceContext.CreateQuery<Comment>("Comments").AsQueryable();
//アカウント情報取得
StorageAccountInfo accountInfo
 = StorageAccountInfo.GetAccountInfoFromConfiguration("TableStorageEndpoint");

//TableClient作成
TableStorage.CreateTablesFromModel(typeof(CommentDataServiceContext), accountInfo);

//サービスコンテキストを定義
CommentServiceContext commentServiceContext
 = new CommentDataServiceContext(accountInfo);

//Table内のデータにアクセス
var query = commentServiceContext.Comments.AsQueryable();

サポートされたLINQメソッドが変更している

自作アプリケーションを用いて、Windows Azure SDK for Visual Studio NovemberでサポートさているLINQメソッドを一部チェックしてみました。

  • サポート
    • Select
    • Where
    • ToList
    • Take
    • OrderBy 今回新たにサポート
    • OrderByDescending 今回新たにサポート
    • FirstOrDefault
  • 未サポート
    • SingleOrDefault
    • LastOrDefault
    • Count
    • Min
    • Max
    • Average
    • All
    • Any
    • LongCount

相変わらずCountやらAnyやらAllやらのメソッドは駄目らしい。「特定の条件に合ったEntityが一件以上存在するか?」というクエリを発行させようと思ったら、以下の様に記述すればOK?

bool isExistRecord = commentServiceContext.CreateQuery<Comment>("Comments")
                     .Where( comment => IsValid(comment) ).FirstOrDefault() != null

*1:現在はWindows AzureストレージTableのみ確認

*2:同様の変更がQueue、Blobでも行われています