はつねの日記

Kinect, Windows 10 UWP, Windows Azure, IoT, 電子工作

Windows Azure Mobile Serviceを入り口としてカスタムサービスを構築する

Windows Azure Mobile Serviceは、Windows Azure上で提供されているMobile Backend as a Serviceです。

Mobile Serviceとの接続はREST/JSONでの接続になりますが、Windows AzureポータルからMicrosoft.WindowsAzure.Mobileなどのクラスライブラリをダウンロードして使うことで非常に簡単にクライアント側とMobile Serviceとの連携ができるようになります。

Windows AzureポータルでMobile Serviceを定義する

image

 

テスト用としてはMobile Service利用時の無料枠として使える20MBのSQL Serverを使ってみるのがいいでしょう。

image

「→」を押すとデータベースの設定画面に遷移します。

 

もし、既存のデータベースを使うようなとき、Mobile Serviceとデータベースが別の位置にあるときにはエラーが表示されるので、そのようときは前画面の「地域」を正しく設定しましょう。

image

ログイン名やパスワードを設定して「レ」をクリックすれば、これで、Windows Azure側のMobile Serviceと既定のデータ格納先としてのSQL Serverの設定が完了します。

キーを取得する

キーの管理をクリックしてをアプリケーションキーとマスターキーを取得します。

image

テーブルの作成

imageimage

Mobile Serviceが作成できたら「データ」タブを選択して「新規」をクリックして新しいテーブルを作成します。

ここではテーブル名とアクセス権のみ設定して、テーブル構造などは指定しません。

SendDataテーブルとItemDataテーブルの2つのテーブルを作り、アクセス権はすべて「認証されたユーザーのみ」にします。

ポータルでの作業はひとまずここまでです。

接続用クラスライブラリの取得

接続用のライブラリは、Windows(デスクトップ / ストアアプリ)、Windows Phone 8、iOSAndroid、HTML/JavaScriptがあります。

今回はWindowsストアで作成します。

Visual Studio プロジェクトで、プロジェクトを右クリックし、[NuGet パッケージの管理] を選択します。Include Prerelease を選択し、WindowsAzure.MobileServices パッケージを検索してインストールします。

image

Mobile Serviceに格納するクラスを作成
    public class ItemData
    {
        public int Id { get; set; }
        public string StringData { get; set; }
    }
    public class SendData
    {
        public int Id { get; set; }
        public string MailAddress { get; set; }
        public string Subject { get; set; }
        public string BodyURL { get; set; }
    }

ここでの注意点は、「public int Id { get; set; }」 は必ず必要な点です。それ以外の項目は必要な項目を必要な形で設定します。

認証機構の登録

Windows Azure Mobile Serviceには次の4つの認証機構によりユーザー認証を行うことができます。

どの認証機構を選んだ場合でも、クライアントアプリを登録して認証機構から「キー(クライアントID/アプリケーションID/APIキー)」と「シークレットコード」を受け取り、それをWindows AzureポータルのMobile Serviceに対するID情報として登録します。

image

LiveIDによるログイン
if (App.Auth == null)
{
    App.Auth = new LiveAuthClient(SettingsClass.AppUrl);
}
LiveLoginResult loginResult = await App.Auth.LoginAsync(new[] { "wl.basic" });
if (loginResult.Status == LiveConnectSessionStatus.Connected)
{
    LiveConnectSession session = loginResult.Session;
    SettingsClass.AccessToken = loginResult.Session.AuthenticationToken;
    OnPropertyChanged("IsLogin");
}
else
{
    SettingsClass.AccessToken = null;
    OnPropertyChanged("IsLogin");
}
Mobile Serviceへのシングルサインオン
Mobile Serviceへの接続
using (MobileServiceClient mobileService = new MobileServiceClient(SettingsClass.AppUrl, SettingsClass.AppKey))
{
}

AppUrlやAppKeyは事前に記録しておいたMobile Serviceのアプリケーションキーとマスターになります。

 
LiveIDのアクセストークにによる認証

Mobile Serviceへの接続のusingブロックの中に次のコードを追記します。

var result = await mobileService.LoginWithMicrosoftAccountAsync(SettingsClass.AccessToken)

AccessTokenはLiveIDでのログイン時に取得したアクセストークンになります。

Mobile Serviceにデータを登録する

認証が通ったら次のコードを実行します。

var item = new ItemData
{
    StringData= "hogehoge"
};
IMobileServiceTable<Itemdata> qTable = mobileService.GetTable<Itemdata>();
await qTable.InsertAsync(item);

Mobile Serviceに格納したいクラスに値を設定し、GetTableメソッドによりテーブルを指定し、InsertAsyncによるクラスに設定した値をテーブルに格納します。

Windows Azure Mobile Serviceには登録時のクラスのメンバーをテーブルの列定義として採用して自動的に列を生成してくれる機能が実装されています。

そこで、このInsertAsyncメソッドが最初に実行された時にAzure側では列の生成が行われ、クラスのメンバの値が格納されます。

Mobile Serviceからデータを取得する
using (MobileServiceClient mobileService = new MobileServiceClient(SettingsClass.AppUrl, SettingsClass.AppKey))
{
    var result = await mobileService.LoginWithMicrosoftAccountAsync(SettingsClass.AccessToken);
    IMobileServiceTable qTable = mobileService.GetTable();
    var items = await qTable.ToCollectionAsync();
}

AppUrlとAppKeyでMobile Serviceと接続したら、AccessTokenを指定してLiveIDでログインします。次にGetTableでテーブルを指定し、ToCollectionAsyncでデータを取得します。

他のユーザが登録したデータを検索できないようなカスタム動作を定義する

Mobile Serviceの該当テーブルでスクリプトタグを選んで「挿入」操作で、userId列に認証ユーザIDを入れるように拡張します。

image

 

「読み取り」操作で、認証ユーザIDとuserId列が一致するレコードを返却するように拡張します。

image

 

この拡張によりMobile Serviceとのやり取りは自分の格納したレコードだけが対象となり、例え同一テーブルに他の人のレコードがあったとしても参照することはできません。

データ登録と同じコードでメール送信を行うように定義する

InsertAsyncしたときにデータを格納する代わりにメール送信するにはどうしたらいいでしょうか。

InsertAsyncではなくカスタムスクリプトを定義してもいいのですが、今回はクライアント側作成者が必要とする知識を最小にするために既存APIを使うことにします。

image

事前にSendGridを定義しておき、「挿入」操作のときに、request.executeせずにsendgrid.sendを実行してます。このようにすることで、レコードをテーブルに挿入せずにメール送信だけが実現可能です。