normalian blog

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

Windows Azure SDK for Node.js でテーブルストレージを利用する その2 〜成功編〜

先日紹介した Windows Azure SDK for Node.js でテーブルストレージを利用する〜失敗編?〜 id:waritohutsu:20120126:1327602448 では、ストレージサービスのアクセスに失敗していたことが分かった。今回は、更に検証し、ストレージサービスに無事疎通が完了したノウハウを共有する。
本記事のサンプルを利用するには、以下のコマンドを実行して必須ライブラリのインストールが完了していることが前提になることに留意して頂きたい。

>npm install azure node-uuid

ローカルエミュレータのテーブルストレージへアクセス

以下のコードでストレージサービスにデータを挿入することが可能

  • テーブルストレージへの挿入(基礎編)
var azure = require('azure');
var ServiceClient = azure.ServiceClient;
var TableQuery = azure.TableQuery;
var uuid = require('node-uuid');

var tableName = 'posts';
var partition = 'part1';

var tableClient = azure.createTableService(ServiceClient.DEVSTORE_STORAGE_ACCOUNT,
 ServiceClient.DEVSTORE_STORAGE_ACCESS_KEY,
 ServiceClient.DEVSTORE_TABLE_HOST);

tableClient.createTableIfNotExists(tableName, function (err, created) {
  console.log('Setting up demo data ...');
  
  //「var now = new Date().toString();」 だと「Thu Feb 09 2012 01:48:37 GMT+0900 (東京 (標準時))」とかで半角が入って死ぬ
  var now = new Date().toGMTString();
  var entity = { PartitionKey: partition, RowKey: uuid(), title: 'Post one', body: 'Body one', created_at: now };
  tableClient.insertEntity(tableName, entity, null, function(err){
     console.log(err);
  });
});

上記はエンティティの挿入ごとにトランザクションが発生する例だが、Entity Group Transaction も利用可能だ。以下に利用例を記載する。

  • テーブルストレージへの挿入(Entity Group Transaction編)
var azure = require('azure');
var ServiceClient = azure.ServiceClient;
var TableQuery = azure.TableQuery;
var uuid = require('node-uuid');

var tableName = 'posts';
var partition = 'part1';
tableClient = azure.createTableService(
  ServiceClient.DEVSTORE_STORAGE_ACCOUNT,
  ServiceClient.DEVSTORE_STORAGE_ACCESS_KEY,
  ServiceClient.DEVSTORE_TABLE_HOST);

tableClient.createTableIfNotExists(tableName, function (err, created) {
  if (created) {
    console.log('Setting up demo data ...');

    //トランザクションの開始を宣言
    tableClient.beginBatch();

    var now = new Date().toGMTString();
    tableClient.insertEntity(tableName, { PartitionKey: partition, RowKey: uuid(), title: 'Post one', body: 'Body one', created_at: now });
    tableClient.insertEntity(tableName, { PartitionKey: partition, RowKey: uuid(), title: 'Post two', body: 'Body two', created_at: now });
    tableClient.insertEntity(tableName, { PartitionKey: partition, RowKey: uuid(), title: 'Post three', body: 'Body three', created_at: now });
    tableClient.insertEntity(tableName, { PartitionKey: partition, RowKey: uuid(), title: 'Post four', body: 'Body four', created_at: now });

    //トランザクションを実行
    tableClient.commitBatch(function () {
      console.log('Done');
    });
  }
});

時刻の文字列を取得する際に、 new Date().toString() の場合には日本語が入ってしまう。私が試した時点の Node.js 版のストレージサービス・ライブラリは日本語が取り扱えなかったため、「テーブルストレージの挿入(基礎編)」では以下のエラーログが出力された。

C:\tmp\MyService\WorkerRole1>node.exe server.js
Setting up demo data ...
{ code: 'OutOfRangeInput',
  message: 'One of the request inputs is out of range.' }

      var now = new Date().toGMTString();

次に、テーブルストレージの検索例を以下に記載する。

  • テーブルストレージの検索
var azure = require('azure');
var ServiceClient = azure.ServiceClient;
var TableQuery = azure.TableQuery;
var uuid = require('node-uuid');

var tableName = 'posts';
var partition = 'part1';
tableClient = azure.createTableService(
  ServiceClient.DEVSTORE_STORAGE_ACCOUNT,
  ServiceClient.DEVSTORE_STORAGE_ACCESS_KEY,
  ServiceClient.DEVSTORE_TABLE_HOST);

var tableQuery = TableQuery.select().from(tableName);
tableClient.queryEntities(tableQuery, function( error, posts ){
    console.log(posts.length)
    if( posts.length > 0 ){
        console.log( posts[0] );
    }
});

以下の様にデータが取得できる。エンティティに対してのプロパティ(posts[i].body等)で値を取得が可能だ。

>node.exe table-main.js
4
{ id: 'http://127.0.0.1:10002/devstoreaccount1/posts(PartitionKey=\'part10\',Row
  link: 'posts(PartitionKey=\'part10\',RowKey=\'0e04ff7f-5fe8-4c8b-b971-c1e30306
  updated: '2012-02-11T08:04:30Z',
  etag: 'W/"datetime\'2012-02-09T15%3A17%3A15.88Z\'"',
  PartitionKey: 'part10',
  RowKey: '0e04ff7f-5fe8-4c8b-b971-c1e3030600cb',
  Timestamp: Thu, 09 Feb 2012 15:17:15 GMT,
  title: 'Post four',
  body: 'Body four',
  created_at: 'Thu, 09 Feb 2012 15:17:15 GMT' }
(省略)

ストレージサービス(本番)へのアクセス

本番側へアクセスする際に留意事項が存在ので紹介する。TableClientを作成する createTableService() メソッドの第三引数に対し、本番アクセス用のURLを渡すとDNS解決の失敗を示すエラーが表示された。テーブルストレージに対し、カスタムドメイン等を設定していなければ以下の例に従う事を推奨したい。

var azure = require('azure');
var ServiceClient = azure.ServiceClient;
var TableQuery = azure.TableQuery;
var uuid = require('node-uuid');

var tableName = 'posts';
var partition = 'part1';

tableClient = azure.createTableService(
 "<アカウント名>",
 "<プライマリキー>");

Azure Diagnostics Manager 2 が Public Beta に!

訓練されたあじゅらー各位なら良くご存じであろうRed Gate Software(旧Cerebrata)のリリースしている Windows Azure 向けツールの一つ、Azure Diagnostics Manager 2 が Public Beta となった。Windows Azure で出力可能なログは多々存在するが、それらを容易に取り扱うためのツールだ。

以下のサイトにアクセスすることで、 Azure Diagnostics Manager 2を入手することができる。

Click Onceを利用する場合は、以下のURLにアクセスすることで入手可能だ。

画面のスクリーンショット

  • ツールの起動画面

以下が Azure Diagnostics Manager 2の起動画面となる。

  • アカウント情報のインポート機能

今までは Subscription や証明書の情報を設定するのが面倒だったが、昨今 Cloud9 IDE 等でも利用されているホスティッドサービス側の認証情報をインポートする機能を利用することが可能になった。これにより、以下のように当該認証情報を読み込むだけでLive IDに紐づけられたSubscription管理が可能になる。

Visual Studio Tools for Office プロジェクトのことはじめ

Visual Studio Tools for Office(以下、VSTO)を触る機会があったので、備忘録もかねて情報を記載する。VSTOではVBAスクリプトを利用した開発とは異なり、.NET Frameworkを利用したアドオン開発が可能であるため、.NET開発者にとって開発勝手の良い開発手法だといえる。

VSTOプロジェクトの作成

Visual Studio を管理者モードで起動し、[ファイル]-[新規作成]-[プロジェクト]から新規作成ダイアログを起動する。Officeのカテゴリから Excel 2010 アドオンを選択してVSTOプロジェクトを作成する。

プロジェクト内にはThisAddIn.cs が自動生成されており、以下のメソッドが記載されている。

こちらに対し、以下の処理を追記する。

  • ThisAddin.cs の抜粋
namespace ExcelAddIn1
{
    public partial class ThisAddIn
    {
        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
            //追記
            System.Windows.Forms.MessageBox.Show("アドオンのロード");
        }

        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
            //追記
            System.Windows.Forms.MessageBox.Show("アドオンのアンロード");
        }

次に、Visual Studioからアドオンを実行する。F5を押下するとExcelが起動し、「アドオンのロード」と表示されたダイアログが起動するはずだ。また、、Excelを閉じる際に「アドオンのアンロード」と表示されたダイアログが起動する。

リボンインタフェースの追加

プロジェクトを右クリックし、メニューの[新規項目の追加]から[リボン(ビジュアルなデザイナー)]を選択する。Ribbon1.cs が追加され、デザイナが起動する。ここからボタンを新規に配置し、Clickイベントにメソッドを追加し、メソッド内に以下を記載する。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Tools.Ribbon;

namespace ExcelAddIn1
{
    public partial class Ribbon1
    {
        private void Ribbon1_Load(object sender, RibbonUIEventArgs e)
        {
        }

        private void button1_Click(object sender, RibbonControlEventArgs e)
        {
            var activeSheet = ExcelAddIn1.Globals.ThisAddIn.Application.ActiveSheet
                as Microsoft.Office.Interop.Excel.Worksheet;

            //Excelのセルは添え字が1から開始な点に注意
            activeSheet.Cells[1, 1] = "書き込んでみるでござる";
        }
    }
}

上記の記述後、Visual Studio からアドオンを起動する。Excelのリボンインターフェースに[アドオン]が追加されるので、[アドオン]から追加したボタンを押下して処理を実行する。正常にアプリケーションの処理が実行されれば、以下の画面が表示されるはずだ。

アドイン本体とリボンインターフェースで値を共有する

ThisAddInインスタンスとRibbon1インスタンスで値を共有する際にも ExcelAddIn1.Globals を利用する。以下の様に処理を記述する。

  • ExcelAddIn1.cs の抜粋
namespace ExcelAddIn1
{
    public partial class ThisAddIn
    {
        public string Status { get; set; }

        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
            Status = "読み込まれたでござる";

            System.Windows.Forms.MessageBox.Show("アドオンのロード");
        }

        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
            System.Windows.Forms.MessageBox.Show("アドオンのアンロード");
        }
  • Ribbon1.cs の抜粋
namespace ExcelAddIn1
{
    public partial class Ribbon1
    {
        private void Ribbon1_Load(object sender, RibbonUIEventArgs e)
        {
        }

        private void button1_Click(object sender, RibbonControlEventArgs e)
        {
            var activeSheet = ExcelAddIn1.Globals.ThisAddIn.Application.ActiveSheet
                as Microsoft.Office.Interop.Excel.Worksheet;
            activeSheet.Cells[1, 1] = "書き込んでみるでござる";
            activeSheet.Cells[2, 1] = ExcelAddIn1.Globals.ThisAddIn.Status;
        }
    }
}

処理の記述後にVisual Studio からアドオンを起動し、リボンインタフェースの追加 と同様の手順でアドオンの処理を実行する。以下の画面が表示されれば処理は完了だ。

Windows Azure SDK for Node.js でテーブルストレージを利用する〜失敗編?〜

Windows Azure 上での Node.js 開発が非常に容易になったが、今回は Windows Azure SDK for Node.js の簡単な利用方法について更に紹介する。以前記述したエントリである Windows Azure の大幅更新 〜Node.js編〜 id:waritohutsu:20111213:1323798292 を事前に一読して頂けると幸いだ。
前回までの記事では、Node.js 単体の機能しか利用しておらず、 express や socket.io といった Node.js の著名ライブラリのほか、Windows Azure ストレージサービスを利用する Node.js ライブラリ等も利用していなかった。今回は、これらの機能を利用するための簡単なTIPSを紹介する。

Node Package Manager について

Node.js をご存じの方には今更説明するまでもないことだと思うが、Node.js には npm(Node Package Manager)と呼ばれるパッケージ管理機構が存在する。.NETに詳しい方には、「Node.js版のNuGet」と言えば理解が容易だろう。以下にコマンドの実行例を紹介するが、インストールするライブラリの依存関係も含めて解決してくれる便利な機能だ。
以前は Windows版の Node.js では利用できなかったが、最近の Node.js では npm が利用できるようになった。

npm を利用してWindows Azure アプリケーションをセットアップ

前回の記事で紹介した手順を参考にサービスを作成する。まず、Azureのサービスを作成し、Workerロールを追加する。Windows Azure SDK for .NETPowerShellコマンドは Windows Azure PowerShell for Node.js Cmdlet Reference を参照して欲しい。

PS C:\temp> New-AzureService AzureNodeBlog

Service has been created at C:\temp\AzureNodeBlog

PS C:\temp\AzureNodeBlog> Add-AzureNodeWorkerRole

Role has been created at C:\temp\AzureNodeBlog\WorkerRole1. For easy access to
Windows Azure Services from your application code, install Windows Azure client
 library for Node.js by running ‘npm install azure’.

次に、Workerロールのディレクトリに移動して必要なライブラリをインストールする。本来は azure と express だけで十分だが、stylus ejs node-uuidをインストールした理由は後で述べる。

PS C:\temp\AzureNodeBlog> cd .\WorkerRole1
PS C:\temp\AzureNodeBlog\WorkerRole1> npm install azure
azure@0.5.1 ./node_modules/azure
├── xmlbuilder@0.3.1
├── qs@0.4.1
├── mime@1.2.4
├── xml2js@0.1.13
├── log@1.2.0
└── sax@0.3.5
PS C:\temp\AzureNodeBlog\WorkerRole1> npm install express stylus ejs node-uuid
express@2.5.6 ./node_modules/express
├── mime@1.2.4
├── mkdirp@0.0.7
├── qs@0.4.1
└── connect@1.8.5
ejs@0.6.1 ./node_modules/ejs
node-uuid@1.3.3 ./node_modules/node-uuid
stylus@0.22.6 ./node_modules/stylus
├── growl@1.1.0
├── mkdirp@0.0.7
└── cssom@0.2.1

最後に、Windows Azure エミュレータでアプリケーションを起動する。ただし、この時点では npm でインストールしたライブラリは利用していない。

PS C:\temp\AzureNodeBlog\WorkerRole1> Start-AzureEmulator -launch


Creating local package...
Starting Emulator...
Role is running at tcp://127.0.0.1:81
Role is running at tcp://127.0.0.1:8
Started

テーブルストレージを利用したブログサンプルを利用する

npm install azure でインストールしたパッケージ内にサンプルが存在するためそちらを利用しよう。サンプルは「C:\temp\AzureNodeBlog\WorkerRole1\node_modules\azure\examples\blog」に配置されており、こちらのサンプルがstylus ejs node-uuidを利用するために先ほどの手順では同パッケージもインストールしていただいた。こちらのサンプルを「C:\temp\AzureNodeBlog\WorkerRole1」に上書きする。次に、同フォルダに存在する blog.js を開き、以下の様に編集する。

//var azure = require('./../../lib/azure');
var azure = require('azure');
var ServiceClient = azure.ServiceClient;
var TableQuery = azure.TableQuery;
var uuid = require('node-uuid');

var tableName = 'posts';
var partition = 'part1';

Blog = function () {
  this.tableClient = azure.createTableService(ServiceClient.DEVSTORE_STORAGE_ACCOUNT, ServiceClient.DEVSTORE_STORAGE_ACCESS_KEY, ServiceClient.DEVSTORE_TABLE_HOST);
};

(以下略)

上記の完了後、再度以下の手順でエミュレータを起動する。

PS C:\temp\AzureNodeBlog\WorkerRole1> Start-AzureEmulator -launch


Creating local package...
Starting Emulator...
Role is running at tcp://127.0.0.1:81
Role is running at tcp://127.0.0.1:8
Started

無事アプリケーションの実行が完了した場合、次の画面が表示されるはずだ。

しかし、ポストを投稿したところうまく反映されなかった。Compute Storageを確認したところ、テーブルそのものは作成されていたので、引き続き問題を解析したいと思う。

テーブルストレージの利用方法

今回はテーブルストレージを利用したブログサンプルであり、以下の様に .NET版ライブラリと大差ないインターフェースでストレージサービスを利用できる(はずだったが。。。)。以下は参考LVで書いたコードであるため、実際に動作検証をしてるわけではないので注意してほしい。

var ServiceClient = azure.ServiceClient;
var TableQuery = azure.TableQuery;
var uuid = require('node-uuid');

var tableName = 'posts';
var partition = 'part1';

Blog = function () {
  //開発ストレージの利用設定
  this.tableClient = azure.createTableService(ServiceClient.DEVSTORE_STORAGE_ACCOUNT, ServiceClient.DEVSTORE_STORAGE_ACCESS_KEY, ServiceClient.DEVSTORE_TABLE_HOST);
};

//全県検索
var tableQuery = TableQuery.select().from(tableName);
tableClient.queryEntities(tableQuery, callback);

//ID検索
tableClient.queryEntity(tableName, partition, id);

//エンティティを削除
var entity = { PartitionKey: partition, RowKey: id };
tableClient.deleteEntity(tableName, entity);

//エンティティの挿入
tableClient.insertEntity(tableName, { PartitionKey: partition, RowKey: uuid(), title: 'Post one', body: 'Body one', created_at: now });

WinJS でタッチデバイス向けUIのWinJS.UI.TimePickerを利用する

Windows 8 Developer Preview の機能についてのTIPSを今回も紹介する。HTML+JSでネイティブアプリが作成できるWinJSだが、こちらで利用できるUIコンポーネントには以下の分類がある。

今回は、タッチデバイス向けのUIコンポーネントのうち、WinJS.UI.TimePicker を利用して紹介する。

サンプル

早速サンプルを紹介する。Windows 8 Developer Preview でWinJS向けの新規プロジェクトを作成し、以下のソースコードを記述する。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>WinWebApp3</title>
    <!-- WinJS references -->
    <link rel="stylesheet" href="/winjs/css/ui-dark.css" />
    <script src="/winjs/js/base.js"></script>
    <script src="/winjs/js/wwaapp.js"></script>
    <script src="/winjs/js/ui.js"></script>
    <script src="/winjs/js/controls.js"></script>
    <!-- WinWebApp3 references -->
    <link rel="stylesheet" href="/css/default.css" />
    <script src="/js/default.js"></script>
    <script type="text/javascript">
        window.onload = function () {
            WinJS.UI.processAll();
        }
</script>
</head>
<body>
    <div data-win-control="WinJS.UI.TimePicker" data-win-options="{minuteIncrement: 15}">
    </div>
</body>
</html>

サンプルコードで注意して頂きたい点は、data-win-control でUIコンポーネントを指定している点と、data-win-options でUIコンポーネントのオプションを指定している点だ。
この様な<div>タグを配置したのち、windows.onload 等で WinJS.UI.processAll() を利用してUIコンポーネントを活性化する。当該処理後にタッチデバイス向けのUIコンポーネントが利用可能だ。

実行結果

以下の様なUIが表示される。

data-win-options で指定した通り、15分毎の刻みで時間を指定できる。

Metro UI向けアプリを作るWinJSを利用した音声ファイル再生

Windows 8 Developer Preview が出て大分時間が経過したが、HTML5 + JavaScript でネイティブアプリの開発が可能な WinJS のTIPSをしようと考えている。今回は、WinJS を利用した音声ファイルの再生を紹介する。なお、今回の音声ファイルには MSDN > ホーム > クラウド ガール > キャラクター利用ガイドライン、解説集 の クラウディア・窓辺 ボイス サンプル を利用させて頂いた。

音声ファイルの再生方法

WinJS は HTML5+JS で作成されるとはいえ、ネイティブアプリである。音声ファイルは専用の名前空間(私の妄想では WinRT.Media.Sound とか)が存在するのかと思ったが、HTML5 の仕様で策定されている

<audio id="my_sound" src="<プロジェクトルートからの相対パス等、どっかのURI>" autoplay loop />

サンプル

まず、Visual Studio 11を起動してWinJSプロジェクトを作成する。次に、 プロジェクトルートに sound フォルダを作成し、クラウディア・窓辺 ボイス サンプル から 01sahajimeru.wav ファイルを抜き出して同フォルダ内に配置した。下準備は完了したので、以下の様に記述することでWinRTを利用した音声ファイルの再生が可能になる。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=1024, height=768" />
    <title>WinWebApp1</title>
    <!-- WinJS references -->
    <link rel="stylesheet" href="/winjs/css/ui-dark.css" />
    <script src="/winjs/js/base.js"></script>
    <script src="/winjs/js/wwaapp.js"></script>
    <script src="/winjs/js/ui.js"></script>
    <script src="/winjs/js/controls.js"></script>
    <!-- WinWebApp1 references -->
    <link rel="stylesheet" href="/css/default.css" />
    <script src="/js/default.js"></script>
</head>
<body>
    <div data-win-control="WinJS.UI.ViewBox">
        <div class="fixed-layout">
            <div>
                <audio id="my_sound" src="sound/01sahajimeru.wav">
                </audio>
            </div>
            <input type="button" value="開始" onclick="document.getElementById('my_sound').play();">
        </div>
    </div>
</body>
</html>

タグ内でWinRT用の共通ライブラリが色々読み込まれているが、原則的に HTML5 のWebアプリケーションとなんら変わりない方法で音声ファイルが再生されることが分かると思う。是非、各位も存分にクラウディア様に叱責されればよいだろう。

WebMatrix を利用して ExpressWeb にアプリをデプロイする

ふと TL を眺めていたら、 @chack411 さんのブログから以下を発見した。

せっかくの年始なので、WebMatrix を利用して ExpressWeb と MS からお年玉を頂くことにしたいと思う。せっかくなのでブログにまとめようと思ったが、以下のサイトに情報がしっかり載っていたので、ぜひ参照して頂きたい。

無事に http://normalian.expressweb.jp/ に以下のサイトを公開した。

サイトにデプロイ後、ExpressWeb の問い合わせフォームから、件名「WebMatrix からアップロードしてみようキャンペーン」として参加連絡をすれば対応完了だ。