TweetYourBlobs サンプルソリューション from Windows Azure Toolkit for Windows Phone

サンプル概要

皆様、こんにちは!

今回はTweetYourBlobs サンプルアプリケーションのご紹介をします。

このアプリケーションは、Windows Phone で撮った写真画像ファイルを、Windows Azure ストレージサービスの Blob ストレージにアップロードします。その後、Blob の URL をtwitter の送信メッセージの中に埋め込みます。

image_thumb[4]

利用方法は、Readme.txtに書いてあります。下記がその内容です。

---

'TweetYourBlobs' Sample Setup
=============================

Before running the TweetYourBlobs sample, you need to:
・Setup a bitly Username and API Key

To achieve this, you can run the SetupSample.cmd script located in the root folder of the sample solution. The script will configure the bitly setting in the configuration files with the corresponding values for you.

The Sample setup utility will prompt for:
・The bitly Username
・The bitly API Key

---

この項ではまず、コンテナを管理する Windows Azure ホステッドサービスを作成します。

Windows Azure ストレージの構造 (確認)

連載中の iOS x Azure 連携開発記事でもご紹介していますが、Windows Azure のストレージ全体像について、もう一度押さえておきましょう。ストレージは、ストレージアカウント毎に作成され、Container、Table、Queue、にそれぞれ分類されます。そして各々、Container が Blob を、Table が Entity を、そして Queue が Message を内包しています。これを再度確認しておいてください。

image

コンテナを作成するメソッドの内容の確認

1. Visual Studio を管理者で起動します。

2. メニューバーから[ファイル]-[プロジェクトを開く]を選択します。[プロジェクトを開く] ダイアログが表示されます。

3. 普通にインストールを行うと、C:\WindowsAzure\WATWindowsPhone\Samples\WP7.1\TweetYourBlobs に出来上がるはずですので、[プロジェクトを開く]ダイアログで、同フォルダの下の、TweetYourBlobs.Azure.sln を選択して開きます。

4. ソリューションエクスプローラーで、「TweetYourBlobs.Web」プロジェクトのServices\SharedAccessSignatureService.csを開きます。

5. SharedAccessSignatureService.csで、SharedAccessSignatureServiceクラスのCreateContainerメソッドを探します。

6. CreateContainer メソッドが、以下のコードになっていることを確認します。

    1: public string CreateContainer(string containerName, bool createIfNotExists, bool isPublic)
    2: {
    3:     try
    4:     {
    5:         var container = this.cloudBlobClient.GetContainerReference(containerName.ToLowerInvariant());
    6:  
    7:         if (createIfNotExists)
    8:         {
    9:             container.CreateIfNotExist();
   10:         }
   11:         else
   12:         {
   13:             container.Create();
   14:         }
   15:  
   16:         if (isPublic)
   17:         {
   18:             BlobContainerPermissions containerPermissions = new BlobContainerPermissions();
   19:             containerPermissions.PublicAccess = BlobContainerPublicAccessType.Container;
   20:             container.SetPermissions(containerPermissions);
   21:         }
   22:  
   23:         return "Success";
   24:     }
   25:     catch (Exception exception)
   26:     {
   27:         throw new WebFaultException<string>(exception.Message, HttpStatusCode.InternalServerError);
   28:     }
   29: }

bit.ly への利用者登録

Readme.txt にも書いてありますとおり、bit.ly への利用者登録を行います。このアプリケーションでは、Windows Azure ストレージサービスにアップロードされた画像のURL をtwitter の送信メッセージの中に埋め込みます。このとき、通常の URL では長いため、bit.ly というWeb 上のサービスを利用して、URL を短縮します。このサービスを利用するためには、開発者の利用者登録が必要となります。そこでまず、bitly.com サイトにアクセスし、利用者登録をします。

1. Internet Explorer を開き、以下のサイトにアクセスします。

https://bitly.com/

2. [Sign Up] ボタンをクリックします。

image

3. 登録に必要な UserName、Email Address、Password を入力し、[Sign Up] ボタンをクリックします。

image

4. 表示されたページの右上のアイコンをクリックし、[Settings] を選択します。

image

5. [API Key] を選択し、右クリックしたら [コピー] を選びます。

image

注意: この後の手順で、API Key と 登録したユーザーID をアプリケーションの設定ファイルに埋め込みます。

Bitly 利用者情報の設定

1. Visual Studio を起動します。

2. メニューバーから[ファイル]-[プロジェクトを開く]を選択します。[プロジェクトを開く] ダイアログが表示されます。

3. [プロジェクトを開く]ダイアログで、C:\WindowsAzure\WATWindowsPhone\Samples\WP7.1\TweetYourBlobs\TweetYourBlobs.Phone.sln を選択して開きます。

4. ソリューションエクスプローラー上で、TweetYourBlobs.Phone プロジェクトを選択し、その中の App.xamlを開きます。

5. <system:String x:Key="BitLyLogin"> 及び <system:String x:Key="BitLyApiKey"> タグの内容に、Bitly サイトで登録した利用者アカウント及び API Key を代入・置換します。

    1: <system:String x:Key="BitLyLogin">
    2:  
    3: Bitlyの利用者アカウント
    4:  
    5: </system:String>
    6:  
    7: <system:String x:Key="BitLyApiKey">
    8:  
    9: BitlyのAPI Key
   10:  
   11: </system:String>

Windows Phone からのこの Blob の利用

次に、Windows Phone から,この Blob を利用します。

1. ソリューションエクスプローラーで、TweetYourBlobs.PhoneプロジェクトのPages\TweetPhotoPage.xaml をデザインモードで開きます。

image

2. tweet ボタンをダブルクリックし、分離コードの中の、OnUploadPicture () イベントハンドラーを開きます。

image

3. その中で、以下の部分のソースコードを確認します。

this.ViewModel.UploadPhoto()

注意: ここでは、分離コードではなく、ViewModel の UpdoadPhoto() メソッドを呼び出していることがわかります。このアプリケーションは、MVVM を使って開発されており、ViewModel は \ViewModel フォルダ内に格納されています。

4. Visual Studio のコードエディタ上の、UploadPhoto() メソッド上で右クリックし、[定義へ移動] を選択します。

image

5. そうすると、ViewModel\TweetPhotoPageViewModel.cs ファイル内の UploadPhoto() メソッドに移動します。UploadPhoto() メソッド内では、下記のような処理がされていることを確認してください。ICloudBlobClient インターフェースから派生した blobClient の持つメソッドを使って、Container オブジェクトや Blob オブジェクトの生成、そしてMetadata、等の設定を行い、Blob へのUpload と 書き込みを行っています。

    1: public void UploadPhoto(string latitude, string longitude, string userIdentifier, Action<string, string> successCallback, Action<string> failureCallback)
    2:         {
    3:             this.IsUploading = true;
    4:  
    5:             /*
    6:              * Pseudo code:
    7:              * var container = this.blobClient.GetContainerReference(this.ContainerName);
    8:              * container.CreateIfNotExist();
    9:              * 
   10:              * var blob = container.GetBlobReference(this.BlobName);
   11:              * blob.UploadFromStream(this.PhotoStream);
   12:              */
   13:  
   14:             var container = this.blobClient.GetContainerReference(this.ContainerName);
   15:  
   16:             container.CreateIfNotExist(
   17:                 this.IsPublic,
   18:                 r => this.dispatcher.BeginInvoke(
   19:                 () =>
   20:                     {
   21:                         // Successfull container creation
   22:                         if (r.Exception == null)
   23:                         {
   24:                             var blob = container.GetBlobReference(this.BlobName);
   25:  
   26:                             if (this.IncludeLocationData)
   27:                             {
   28:                                 blob.Metadata["ContentLocation"] = string.Concat("https://www.bing.com/maps/?v=2&cp=", latitude, "~", longitude, "&lvl=16&dir=0&sty=h");
   29:                             }
   30:  
   31:                             blob.Metadata["ImageType"] = "image/jpeg";
   32:  
   33:                             blob.UploadFromStream(
   34:                                 this.PhotoStream,
   35:                                 response => this.dispatcher.BeginInvoke(
   36:                                 () =>
   37:                                 {
   38:                                     this.IsUploading = false;
   39:     
   40:                                     if (response.Exception == null)
   41:                                     {
   42:                                         if (successCallback != null)
   43:                                         {
   44:                                             if (isPublic)
   45:                                             {
   46:                                                 successCallback(string.Format(CultureInfo.InvariantCulture, "Image file {0} successfully uploaded!", this.BlobName), blob.Uri.ToString());
   47:                                             }
   48:                                             else
   49:                                             {
   50:                                                 container.ListBlobs(
   51:                                                     this.BlobName,
   52:                                                     true,
   53:                                                     listResponse => this.dispatcher.BeginInvoke(
   54:                                                         () =>
   55:                                                         {
   56:                                                             if (listResponse.Exception == null)
   57:                                                             {
   58:                                                                 string responseUri = string.Empty;
   59:                                                                 var list = new List<ICloudBlob>(listResponse.Response);
   60:                                                                 if (list.Count > 0)
   61:                                                                 {
   62:                                                                     responseUri = list[0].Uri.AbsoluteUri;
   63:                                                                 }
   64:  
   65:                                                                 successCallback(string.Format(CultureInfo.InvariantCulture, "Image file {0} successfully uploaded!", this.BlobName), responseUri);
   66:                                                             }
   67:                                                             else
   68:                                                             {
   69:                                                                 if (failureCallback != null)
   70:                                                                 {
   71:                                                                     failureCallback(string.Format(CultureInfo.InvariantCulture, "Error: {0}", listResponse.Exception.Message));
   72:                                                                 }
   73:                                                             }
   74:                                                         }));
   75:                                             }
   76:                                         }
   77:                                     }
   78:                                     else
   79:                                     {
   80:                                         if (failureCallback != null)
   81:                                         {
   82:                                             failureCallback(string.Format(CultureInfo.InvariantCulture, "Error: {0}", response.Exception.Message));
   83:                                         }
   84:                                     }
   85:                                 }));
   86:                         }
   87:                         else
   88:                         {
   89:                             this.IsUploading = false;
   90:  
   91:                             // The container was not created successfully, some error ocurred.
   92:                             if (failureCallback != null)
   93:                             {
   94:                                 failureCallback(string.Format(CultureInfo.InvariantCulture, "Error: {0}", r.Exception.Message));
   95:                             }
   96:                         }
   97:                 }));
   98:         }

特に着目すべきなのは、この部分となります。

    1: if (r.Exception == null)
    2: {
    3:     var blob = container.GetBlobReference(this.BlobName);
    4:  
    5:     if (this.IncludeLocationData)
    6:     {
    7: blob.Metadata["ContentLocation"] =
    8:             string.Concat("https://www.bing.com/maps/?v=2&cp="
    9:             , latitude, "~", longitude, "&lvl=16&dir=0&sty=h");    }
   10:     blob.Metadata["ImageType"] = "image/jpeg";
   11:  
   12:     blob.UploadFromStream(
   13:         this.PhotoStream,
   14:         response => this.dispatcher.BeginInvoke()

アプリケーションの実行

1. Visual Stutio の [TweetYourBlobs]クラウドプロジェクトを右クリックし、[デバッグ] から、[新しいインスタンスを開始]を選択します。

image

3. [Internet Explorer] 上に証明書のエラーメッセージが表示されたら 、[このサイトの閲覧を続行する(推奨されません) ] を選択します。 [Internet Exolorer] 上に、「Web サイトによってこのページの表示を拒否されました」というメッセージが表示されたら、そのまま開いてきます。

※ まあ、ここはいつもの通りですね(^^;)!?w

5. [TweetYourBlobs.Phone] Phone プロジェクトを右クリックして、 [デバッグ] から、[新しいインスタンスを開始] を選択します。

7. アプリケーションが開始したら、ウィンドウ左下の [Install certificate] リンクをクリックします。

image

8. Internet Explorer が開いて、閲覧記録を送信するかどうかを聞いてきますので、[キャンセル] ボタンをクリックします。

image

9. [タップしてファイルを開く] 画面が表示されたら、マウスでクリックして証明書ファイルを開きます。

image

10. [証明書をインストールしますか] 画面が出ますので、その中の、[インストール] ボタンをクリックします。

image

11. 証明書がインストールされたことを確認し、[OK] ボタンをクリックします。

image

12. **Windows Phone エミュレータ上の [戻る] ボタンをクリック**します。

image

注意: これ意外に重要な、ポイントです。必ずBackボタンで戻ることを忘れないようにしてください(^^)

13. アプリケーションのホーム画面に戻りるので、カメラのイメージをクリックします。

image

14. カメラの画面で、右上のシャッターのボタンをクリックします。

image

15. [決定] ボタンをクリックします。

image

16. [tweet picture] 画面が表示されるので、そこに、Container 名、Blob 名等を設定し、[tweet] ボタンをクリックします。

image

17. Internet Explorer が起動し、Twitter のログインページが表示されますので、任意の Twitter の ID とパスワードを入力し、[ログイン] ボタンをクリックします。

image

18. [いまどうしてる?] テキストボックスに、URL が入力されていることを確認し、必要に応じてメッセージを編集・追加・削除後、[ツイート] ボタンをクリックします。

image

注意: 念のため、このURLが、本来の Blob の URL よりも短くなっていることを確認します。Bit.ly のURL の短縮サービスである bit.ly を利用しているためです。URL の短縮サービスでは、リダイレクトを利用して本来の長いURLに接続しています。

19. [更新] リンクをクリックします。

20. 書き込んだメッセージがリスト上に表示されますので、そのリンクをクリックします。

image_thumb[4]

21. Internet Explorer 上に、赤と緑の画像が表示されることを確認したら、アプリケーションを終了します。

image

以上です。次回はまた、別のネタになります(^^)!

鈴木 章太郎