MSC2011 D3-303 “Windows Phone/iOS/Android から Windows Azure を利用する” session follow up - Part 3 : スクラッチでのソリューション開発 - 4 Tables/Blobs/Queues/SQL Azure

Tables、Blobs 及び Queues の利用

新規 Windows Phone Cloud Application の作成の箇所で、Windows Azure Storage のサポートにチェックを入れた場合、Windows Azure に格納されている、Tables、Blobs、Queues、にアクセスすることができます。そのためのステップは以下の通りです。

フリックまたはパンで、画面を左側に移動して、Tables Pivot アイテムに遷移します。そうすると、Windows Azure Storage の中で、利用可能な Table がわかります。 アプリケーションバーの中にあるプラスボタン (clip_image0016_thumb_thumb_thumb) をクリックすると、新テーブルが追加でき、また、Table 名の隣にある削除ボタン(clip_image0028_thumb_thumb_thumb)をクリックすると、 当該 Table を削除できます。

clip_image0036_thumb2_thumb_thumb

ここのソースコードを見てみましょう。Pivot アプリケーションで、MVVM を採用して開発されているため、処理はおもに ViewModel フォルダにまとまっています。この中では、上記のボタンの動き、NewTable()、DeleteTable()、あたりのメソッドを確認しておいてください。

    1: namespace WPCloudApp5.Phone.ViewModel
    2: {
    3:     using System;
    4:     using System.Globalization;
    5:     using System.Linq;
    6:     using System.Windows;
    7:     using System.Windows.Threading;
    8:     using Microsoft.Phone.Shell;
    9:     using Microsoft.Samples.WindowsPhoneCloud.StorageClient;
   10:  
   11:     internal enum TableAction
   12:     {
   13:         None = 0,
   14:         Create = 1,
   15:         Delete = 2
   16:     }
   17:  
   18:     public class TablesPageViewModel : TableBaseViewModel<TableServiceSchema>
   19:     {
   20:         private const string IconsRootUri = "/Toolkit.Content/";
   21:  
   22:         private TableAction action = TableAction.None;
   23:         private TableServiceSchema currentTable = null;
   24:  
   25:         public TablesPageViewModel()
   26:             : this(App.CloudClientFactory, Deployment.Current.Dispatcher)
   27:         {
   28:         }
   29:  
   30:         public TablesPageViewModel(ICloudClientFactory cloudClientFactory, Dispatcher dispatcher)
   31:             : base(cloudClientFactory, dispatcher)
   32:         {
   33:         }
   34:  
   35:         public override string TableName
   36:         {
   37:             get { return "Tables"; }
   38:         }
   39:  
   40:         public void NewTable()
   41:         {
   42:             var newTableName = string.Format(CultureInfo.InvariantCulture, "Table{0}", DateTime.Now.ToString("yyyyMMddTHHmmss", CultureInfo.InvariantCulture));
   43:             this.currentTable = new TableServiceSchema(newTableName);
   44:             this.action = TableAction.Create;
   45:  
   46:             this.Message = "Creating new table...";
   47:             this.IsLoading = true;
   48:  
   49:             try
   50:             {
   51:                 this.Context.AddTable(this.currentTable);
   52:                 this.Context.BeginSaveChanges(this.OnBeginSaveChanges, null);
   53:             }
   54:             catch (Exception exception)
   55:             {
   56:                 var errorMessage = StorageClientExceptionParser.ParseDataServiceException(exception).Message;
   57:  
   58:                 this.IsLoading = false;
   59:                 this.Message = string.Format(CultureInfo.InvariantCulture, "Error: {0}", errorMessage);
   60:             }
   61:         }
   62:  
   63:         public void DeleteTable(TableServiceSchema table)
   64:         {
   65:             this.currentTable = table;
   66:             this.action = TableAction.Delete;
   67:  
   68:             this.Message = "Deleting table...";
   69:             this.IsLoading = true;
   70:  
   71:             try
   72:             {
   73:                 // In the case the table was previously detached in a failed operation.
   74:                 if (!this.Context.Entities.Any(e => e.Entity == this.currentTable))
   75:                 {
   76:                     this.Context.AttachTo("Tables", this.currentTable);
   77:                 }
   78:  
   79:                 this.Context.DeleteObject(this.currentTable);
   80:                 this.Context.BeginSaveChanges(this.OnBeginSaveChanges, null);
   81:             }
   82:             catch (Exception exception)
   83:             {
   84:                 var errorMessage = StorageClientExceptionParser.ParseDataServiceException(exception).Message;
   85:  
   86:                 this.IsLoading = false;
   87:                 this.Message = string.Format(CultureInfo.InvariantCulture, "Error: {0}", errorMessage);
   88:             }
   89:         }
   90:  
   91:         public void OnBeginSaveChanges(IAsyncResult asyncResult)
   92:         {
   93:             this.Dispatcher.BeginInvoke(
   94:                 () =>
   95:                 {
   96:                     try
   97:                     {
   98:                         this.Context.EndSaveChanges(asyncResult);
   99:  
  100:                         // Update the Table collection that is binded in the page.
  101:                         if (this.action == TableAction.Create)
  102:                         {
  103:                             this.Table.Add(this.currentTable);
  104:                         }
  105:                         else if (this.action == TableAction.Delete)
  106:                         {
  107:                             this.Table.Remove(this.currentTable);
  108:                         }
  109:  
  110:                         this.Message = "Changes saved successfully.";
  111:                     }
  112:                     catch (Exception exception)
  113:                     {
  114:                         this.Message = string.Format(
  115:                             CultureInfo.InvariantCulture,
  116:                             "Error: {0}",
  117:                             StorageClientExceptionParser.ParseDataServiceException(exception).Message);
  118:  
  119:                         // Detach from the Context the table that produced the failed operation.
  120:                         this.Context.Detach(this.currentTable);
  121:                     }
  122:                     finally
  123:                     {
  124:                         this.IsLoading = false;
  125:                     }
  126:                 });
  127:         }
  128:  
  129:         protected override void PopulateApplicationBarButtons(IApplicationBar applicationBar)
  130:         {
  131:             var refreshButton = new ApplicationBarIconButton(new Uri(string.Format(CultureInfo.InvariantCulture, "{0}{1}", IconsRootUri, "appbar.refresh.rest.png"), UriKind.Relative)) { Text = "refresh" };
  132:             refreshButton.Click += (s, e) => this.LoadTable();
  133:  
  134:             var addButton = new ApplicationBarIconButton(new Uri(string.Format(CultureInfo.InvariantCulture, "{0}{1}", IconsRootUri, "appbar.add.rest.png"), UriKind.Relative)) { Text = "add table" };
  135:             addButton.Click += (s, e) => this.NewTable();
  136:  
  137:             applicationBar.Buttons.Add(refreshButton);
  138:             applicationBar.Buttons.Add(addButton);
  139:         }
  140:     }
  141: }

注意 : PushUserEndpoints、 secMembership、UserPrivileges 及び secRole の各 Tableは、(この前の投稿でも中身を見た通り)、Toolkit サービスが内部的に使っているものです。したがって、それらのどれかをもし削除しようとすると、権限がないというメッセージとともに、エラーが発生します。

次に、フリックまたはパンで、画面を左側に移動して、Sample Data Pivot アイテムに遷移します。SampleData Table で、行が使用可能なのがわかります。もしこのテーブルが、それまでAzure Table ストレージに存在していなかった場合には、今回初めて(新規アプリケーションの作成により)生成されたものです。

Sample data Pivot アイテムの中で、アプリケーションバーの中にあるプラスボタン (clip_image0017_thumb_thumb_thumb) をクリックして、新しい行を追加します。もちろん、既に入っている行を編集したり、削除したりもできます。

clip_image0044_thumb2_thumb_thumb

ここで、サンプルコードを見てみましょう。SampleDataDetailsPageViewModel.cs に処理が書いてあります。まずは、SampleDataTablePageViewModel.cs の LoadTable() の処理です。

    1: public override void LoadTable()
    2:         {
    3:             if (!sampleDataTableCreated)
    4:             {
    5:                 try
    6:                 {
    7:                     this.cloudTableClient.CreateTableIfNotExist(
    8:                         this.TableName,
    9:                         r =>
   10:                         {
   11:                             if (this.Dispatcher != null)
   12:                             {
   13:                                 this.Dispatcher.BeginInvoke(() => this.HandleTableCreationResponse(r));
   14:                             }
   15:                             else
   16:                             {
   17:                                 this.HandleTableCreationResponse(r);
   18:                             }
   19:                         });
   20:                 }
   21:                 catch (Exception exception)
   22:                 {
   23:                     var errorMessage = StorageClientExceptionParser.ParseDataServiceException(exception).Message;
   24:  
   25:                     this.IsLoading = false;
   26:                     this.Message = string.Format(CultureInfo.InvariantCulture, "Error: {0}", errorMessage);
   27:                 }
   28:             }
   29:             else
   30:             {
   31:                 base.LoadTable();
   32:             }
   33:         }

続いて、SampleDataDetailsPageViewModel.cs の DeleteSampleData()メソッドの処理を見てみてください。こちらも、Microsoft.Samples.WindowsPhoneCloud.StorageClient のインターフェースである ITableServiceContext を実装したオブジェクトである Context を使ってCRUD操作をしています。上記と同じ動きですね。

    1: public void DeleteSampleData()
    2:         {
    3:             this.Message = "Deleting...";
    4:             this.IsSaving = true;
    5:  
    6:             this.SampleData.PropertyChanged -= this.OnUpdateSampleData;
    7:  
    8:             try
    9:             {
   10:                 this.context.DeleteObject(this.SampleData);
   11:                 this.context.BeginSaveChanges(this.OnBeginSaveChanges, null);
   12:             }
   13:             catch (Exception exception)
   14:             {
   15:                 var errorMessage = StorageClientExceptionParser.ParseDataServiceException(exception).Message;
   16:  
   17:                 this.IsSaving = false;
   18:                 this.Message = string.Format(CultureInfo.InvariantCulture, "Error: {0}", errorMessage);
   19:             }
   20:         }

こちらも、Microsoft.Samples.WindowsPhoneCloud.StorageClient のICloudTableClientインターフェースを実装したオブジェクトを使って操作を行っています。これにより、各メソッドでの操作を抽象化し、単純化させることができます。要は、最初の新規作成~Wizardの中で、ストレージ名と、キーだけ渡しておけば、あとはCRUD 操作ができるわけです。

次に、フリックまたはパンで、画面を左側に移動して、List Blobs Pivot アイテムに遷移します。そして、アプリケーションバーの中にある、カメラボタン(clip_image0056_thumb_thumb_thumb) をクリックします。Windows Phone のカメラが起動します。スクリーン右上にあるボタンをクリックして、写真を撮り、決定ボタンを押します。これにより、Upload Picture ページに遷移します。

clip_image0068_thumb2_thumb_thumb

Upload Picture ページの中で、Blobに名前を付けて、Upload を行います。 もし、期待通りにすべて動いてくれれば、メッセージボックスが出現し、”Image was successfully uploaded”と出るでしょう。OK を押して、メイン Pivot ページに遷移します。

clip_image0076_thumb2_thumb_thumb

ここの部分のソースコードを見てみましょう。UploadPhotoPageViewModel.csから、UploadPhoto() メソッドをご覧ください。

    1: public void UploadPhoto(Action<string> successCallback, Action<string> failureCallback)
    2:         {
    3:             this.IsUploading = true;
    4:             this.blobClient.Upload(
    5:                 this.BlobName,
    6:                 this.PhotoStream,
    7:                 r => this.dispatcher.BeginInvoke(
    8:                         () =>
    9:                         {
   10:                             this.IsUploading = false;
   11:  
   12:                             if (r.Exception == null)
   13:                             {
   14:                                 if (successCallback != null)
   15:                                 {
   16:                                     successCallback.Invoke(string.Format(CultureInfo.InvariantCulture, "Image file {0} successfully uploaded!", this.BlobName));
   17:                                 }
   18:                             }
   19:                             else
   20:                             {
   21:                                 if (failureCallback != null)
   22:                                 {
   23:                                     failureCallback.Invoke(string.Format(CultureInfo.InvariantCulture, "Error: {0}", r.Exception.Message));
   24:                                 }
   25:                             }
   26:                         }));
   27:         }

ここでも、blobClient というオブジェクトを使って、そのメソッドのUpload を使って処理が行われています。このblobClient も、Microsoft.Samples.WindowsPhoneCloud.StorageClient のICloudTableClientインターフェースを実装したオブジェクトです。これにより、各メソッドでの操作を抽象化し、単純化させることができます。こちらも、最初の新規作成~Wizardの中で、ストレージ名と、アクセスキーだけ渡しておけば、あとは操作ができるというわけです。

続いて、List Blobs Pivot ページの中で、リスト表示をするために、list blobs ボタンを押し、リスティングします (prefix を入力するとフィルタリングができます)。先ほど、撮影し Upload した画像のサムネールを、Blob へのリンクの形で見ることができます。このリンクをクリックすると、IE9 が起動し、画像を表示します。

clip_image0088_thumb2_thumb_thumb

ここでソースコードを見てみます。ListBlobsPageViewModel.cs の中の、ListBlobs() ですね。

    1: public void ListBlobs()
    2:         {
    3:             this.IsListing = true;
    4:             this.Message = "Listing blobs...";
    5:  
    6:             try
    7:             {
    8:                 this.blobClient.ListBlobsWithPrefix(
    9:                     this.Prefix,
   10:                     this.UseFlatBlobListing,
   11:                     r =>
   12:                     {
   13:                         if (this.dispatcher != null)
   14:                         {
   15:                             this.dispatcher.BeginInvoke(() => this.UpdateListBlobs(r));
   16:                         }
   17:                         else
   18:                         {
   19:                             this.UpdateListBlobs(r);
   20:                         }
   21:                     });
   22:             }
   23:             catch (Exception exception)
   24:             {
   25:                 var errorMessage = StorageClientExceptionParser.ParseDataServiceException(exception).Message;
   26:  
   27:                 this.IsListing = false;
   28:                 this.Message = string.Format(CultureInfo.InvariantCulture, "Error: {0}", errorMessage);
   29:             }
   30:         }

ここでも、blobClient は、Microsoft.Samples.WindowsPhoneCloud.StorageClient のICloudTableClientインターフェースを実装したオブジェクトです。こちらも、各メソッドでの操作を抽象化し、単純化させることができます。

左向きの矢印 (clip_image0098_thumb_thumb_thumb).を使って、アプリケーションに戻ります。続いて Queues Pivot ページの中で、リスト表示をするために、list queus ボタンを押し、Windows Azure ストレージにある 利用可能な queues をリスティングします (prefix を入力するとフィルタリングができます)。

clip_image0106_thumb2_thumb_thumb

Queues Pivot アイテムの中で、アプリケーションバーの中にあるプラスボタン (clip_image0018_thumb_thumb_thumb) をクリックし、新しい Queue を追加します ( Queue 名の隣にある削除ボタン(clip_image0029_thumb_thumb_thumb)も利用可能です)。

clip_image0118_thumb2_thumb_thumb

それぞれのソースコードを見てみましょう。ListQueuesPageViewModel.cs にある、NewQueue() 、および、DeleteQueue()、がそれです。

NewQueue()

    1: public void NewQueue()
    2: {
    3:     var newQueueName = string.Format(CultureInfo.InvariantCulture, "Queue{0}", DateTime.Now.ToString("yyyyMMddTHHmmss", CultureInfo.InvariantCulture)).ToLowerInvariant();
    4:  
    5:     this.Message = "Creating new queue...";
    6:     this.IsLoading = true;
    7:  
    8:     try
    9:     {
   10:         var currentQueue = this.queueClient.GetQueueReference(newQueueName);
   11:         currentQueue.Create(
   12:             creationResult =>
   13:             {
   14:                 if (this.dispatcher != null)
   15:                 {
   16:                     this.dispatcher.BeginInvoke(() => this.HandleQueueCreationResult(currentQueue, creationResult));
   17:                 }
   18:                 else
   19:                 {
   20:                     this.HandleQueueCreationResult(currentQueue, creationResult);
   21:                 }
   22:             });
   23:     }
   24:     catch (Exception exception)
   25:     {
   26:         this.IsLoading = false;
   27:         this.Message = string.Format(CultureInfo.InvariantCulture, "Error: {0}", exception.Message);
   28:     }
   29: }

DeleteQueue()

    1: public void DeleteQueue(ICloudQueue queue)
    2: {
    3:     this.Message = "Deleting queue...";
    4:     this.IsLoading = true;
    5:  
    6:     try
    7:     {
    8:         var currentQueue = this.queueClient.GetQueueReference(queue.Name);
    9:         currentQueue.Delete(
   10:             deletionResult =>
   11:             {
   12:                 if (this.dispatcher != null)
   13:                 {
   14:                     this.dispatcher.BeginInvoke(() => this.HandleQueueDeletionResult(currentQueue, deletionResult));
   15:                 }
   16:                 else
   17:                 {
   18:                     this.HandleQueueDeletionResult(currentQueue, deletionResult);
   19:                 }
   20:             });
   21:     }
   22:     catch (Exception exception)
   23:     {
   24:         this.IsLoading = false;
   25:         this.Message = string.Format(CultureInfo.InvariantCulture, "Error: {0}", exception.Message);
   26:     }
   27: }

ここでもやはり、Microsoft.Samples.WindowsPhoneCloud.StorageClient にある、ICloudQueue インターフェースを実装した queueClient オブジェクトのメソッドにより、簡単に Queue に対するCRUDを行っています。

次に、前のステップで作成したばかりのQueue の名前をクリックして、Queue details ページに遷移します。Queue details ページの中で、テキストボックスに、”message 1” と入力し Queue をクリックします。続いて、テキストボックスに、”message 2” と入力し Queue を再度クリックします。そうすると、Queueにメッセージを入れることができます。

続いて、Dequeue ボタンを2回クリックすることにより、Queue に入れたメッセージを正しい順序で取り出すことができます。

clip_image0124_thumb2_thumb_thumb

ここで当該部分のソースコードを見てみましょう。同じく QueueDetailsPageViewModel.cs の QueueMessage() メソッド及び DequeMessage() メソッドの箇所になります。

QueueMessage()

    1: public void QueueMessage()
    2: {
    3:     this.Message = "Queing message...";
    4:     this.IsBusy = true;
    5:     try
    6:     {
    7:         this.Queue.AddMessage(
    8:             new CloudQueueMessage { AsBytes = Encoding.UTF8.GetBytes(this.QueueMessageContent) },
    9:             r => this.dispatcher.BeginInvoke(
   10:                 () =>
   11:                 {
   12:                     this.Message = r.Exception == null
   13:                         ? "Message successfully queued!"
   14:                         : string.Format(CultureInfo.InvariantCulture, "Error: {0}", r.Exception.Message);
   15:  
   16:                     this.IsBusy = false;
   17:                 }));
   18:     }
   19:     catch (Exception exception)
   20:     {
   21:         var errorMessage = StorageClientExceptionParser.ParseDataServiceException(exception).Message;
   22:  
   23:         this.IsBusy = false;
   24:         this.Message = string.Format(CultureInfo.InvariantCulture, "Error: {0}", errorMessage);
   25:     }
   26: }

DequeueMessage()

    1: public void DequeueMessage()
    2: {
    3:     this.Message = "Dequeing message...";
    4:     this.IsBusy = true;
    5:     try
    6:     {
    7:         this.Queue.GetMessage(
    8:             s =>
    9:             {
   10:                 if (s.Exception == null)
   11:                 {
   12:                     if (s.Response == null)
   13:                     {
   14:                         this.dispatcher.BeginInvoke(
   15:                             () =>
   16:                             {
   17:                                 this.Message = "Queue is empty";
   18:                                 this.IsBusy = false;
   19:                             });
   20:                     }
   21:                     else
   22:                     {
   23:                         this.Queue.DeleteMessage(
   24:                             s.Response,
   25:                             r => this.dispatcher.BeginInvoke(
   26:                                 () =>
   27:                                 {
   28:                                     if (r.Exception == null)
   29:                                     {
   30:                                         this.CloudQueueMessages.Add(s.Response);
   31:                                         this.Message = "Message successfully dequeued!";
   32:                                     }
   33:                                     else
   34:                                     {
   35:                                         this.Message = string.Format(CultureInfo.InvariantCulture, "Error: {0}", r.Exception.Message);
   36:                                     }
   37:  
   38:                                     this.IsBusy = false;
   39:                                 }));
   40:                     }
   41:                 }
   42:                 else
   43:                 {
   44:                     this.dispatcher.BeginInvoke(
   45:                         () =>
   46:                         {
   47:                             this.Message = string.Format(CultureInfo.InvariantCulture, "Error: {0}", s.Exception.Message);
   48:                             this.IsBusy = false;
   49:                         });
   50:                 }
   51:             });
   52:     }
   53:     catch (Exception exception)
   54:     {
   55:         var errorMessage = StorageClientExceptionParser.ParseDataServiceException(exception).Message;
   56:  
   57:         this.IsBusy = false;
   58:         this.Message = string.Format(CultureInfo.InvariantCulture, "Error: {0}", errorMessage);
   59:     }
   60: }

ここでも、Microsoft.Samples.WindowsPhoneCloud.StorageClient にある、ICloudQueue インターフェースを実装した Queue オブジェクトのメソッドにより、簡単に Queue に対するCRUDを行っています。

Windows Phone Emulator のWindows ボタン(clip_image013_thumb_thumb_thumb) をクリックして、Start メニューに戻ります。

ユーザーメニュー及び権限管理について

ここはセッション内でデモをしていませんが、追加でご紹介しておきます。Web ブラウザーの方に戻り、User メニューオプションをクリックして開きます。新しいユーザー(ACSで認証した際にRegisiter したユーザー)が作成されており、デフォルトで、TablesBlobsQueues および SQL Azure に対する権限が付与されていることがわかります。

clip_image0144_thumb2_thumb_thumb

注意 : このWeb サイトの administrator ユーザー (admin) は、このWindows Azure Mobile Cloud アプリケーションが、ASP.NET Membership 認証を使う場合だけ、表示されます。この場合には、当該 admin ユーザーもまた有効なアプリケーションユーザーとなります。また、SQL のカラムが表示されるのは、このアプリケーションが、SQL Azure データベースを使用すると構成された場合だけです。

ここで、追加されたユーザーの、TablesBlobsと Queues のチェックボックスを外してみましょう。

clip_image015_thumb2_thumb_thumb

次に、Tables メニューのオプションをクリックします。このページでは、Windows Azure Tables ストレージに入っている Table につき、個別のユーザーに、権限をあたえることができます。

clip_image0166_thumb2_thumb_thumb

次に、Queues メニューのオプションをクリックします。このページでは、Windows Azure Tables ストレージに入っている Queue につき、個別のユーザーに、権限をあたえることができます。

clip_image0174_thumb2_thumb_thumb

Windows Phone Emulator に戻り、WAT Windows Phone アイコンをクリックして、再度アプリケーションを開きます。フリックまたはパンにより左側に遷移して、tables Pivot アイテムに遷移し、次いで、sample data Pivot アイテムに遷移します。そうすると、エラーメッセージが出ているのがわかります。いずれも、Table 使用権限がありません、という内容です。

clip_image018_thumb2_thumb_thumb

続いて、フリックまたはパンにより左側に遷移して、list blobs Pivot アイテムに遷移し、次いで、list blobs をクリックします。そうすると、エラーメッセージが出ているのがわかります。Blob 使用権限がありません、という内容です。

clip_image019_thumb2_thumb_thumb

これまた同様に、フリックまたはパンにより左側に遷移して、queues Pivot アイテムに遷移し、次いで、list queues をクリックします。そうすると、エラーメッセージが出ているのがわかります。Queue 使用権限がありません、という内容です。

clip_image020_thumb2_thumb_thumb

SQL Azure データベースの利用

この点も、セッション内ではデモをしていませんが、追加でご説明しておきます。もし、このアプリケーションを作成する際に、Creating a New Windows Phone Cloud Application Wizard のセクションで、SQL Azure データベースをサポートするように構成した場合、SQL Azure データベースの上に配置されている OData サービスにアクセスすることができます。下記のステップに従って、この特徴を見てみましょう。

注意 : このアプリケーションは、Entity Framework 4.1 Code First を使用して、必要なテーブルを作成するように設定されています。デフォルトでは、一つのデータベースが SQL Azure の中に作成され、その名前は、テンプレートのWizardが作成している場合は、ベースとなるプロジェクトと同じ名前になります。そこで、モデルが変更された際に、Entity Framework 4.1 Code First を使用して、必要なデータベースを再作成するには、必要となってくるのが、Persist Security Info=True を、当該データベースへの connection string に追加することです。この設定は、必ずしもプロダクション環境にそぐわないので、アプリケーションの配布の際には削除を検討してください。

フリックまたはパンにより左側に遷移して、sql azure data Pivot アイテムに遷移します。そうすると、SqlSampleData Table が確認できます。

clip_image021_thumb3_thumb_thumb

Windows Phone Emulator の Windows ボタン(clip_image0131_thumb_thumb_thumb) をクリックして、Start メニューに遷移します。Web ブラウザーに切り替えて、User メニューをクリックします。

clip_image0145_thumb2_thumb_thumb

このアプリケーションユーザーの SQL チェックボックスのチェックを外します。

clip_image022_thumb2_thumb_thumb

Windows Phone Emulator に切り替え、WAT Windows Phone アイコンをクリックして、再びアプリケーションを開きます。フリックまたはパンにより左側に遷移して、sql azure data Pivot アイテムに遷移します。そうすると、エラーメッセージが出ているのがわかります。SQL Azure 使用権限がありません、という内容です。

clip_image023_thumb2_thumb_thumb

以上で、セッションでご紹介した、スクラッチからのWindows Azure Toolkit for Windows Phone 開発編は完了です。

いかがでしたでしょうか?このようにデフォルトでも、かなりのことができるテンプレートに仕上がっていますので、ぜひこれをうまく利用して、皆様の Windows Phone x Windows Azure ソリューションを迅速に開発して戴ければ!と思う次第です。

次のエントリーは、Windows Azure への展開について、注意点を簡単に纏めます。

その次のエントリーでは、Windows Azure Toolkit for iOS による開発について書く予定です。

鈴木 章太郎