注
このトピックのコード一覧は C# のみです。 C++/WinRT および C# の App Service サンプル アプリについては、App Services サンプルを参照するか、GitHub で App Services サンプル プロジェクトのソースを取得します。
Von Bedeutung
このトピックは、.NET Native を使用するユニバーサル Windows プラットフォーム (UWP) アプリに適用されます。 Visual Studio 2022 には、.NET 9 を使用する UWP プロジェクト テンプレートも含まれるようになりました。 このトピックでは、名前に ".NET Native" を含む UWP プロジェクト テンプレート (UWP 空のアプリ (.NET ネイティブ) など) を使用する必要があります。 .NET 9 を使用する UWP プロジェクトは、このトピックでテストされておらず、期待どおりに動作しない可能性があります。
アプリ サービスは、他の UWP アプリにサービスを提供する UWP アプリです。 これらは、デバイス上の Web サービスに似ています。 アプリ サービスは、ホスト アプリでバックグラウンド タスクとして実行され、そのサービスを他のアプリに提供できます。 たとえば、アプリ サービスは、他のアプリが使用できるバーコード スキャナー サービスを提供する場合があります。 または、エンタープライズ スイートのアプリには、スイート内の他のアプリで使用できる一般的なスペル チェック アプリ サービスがあります。 アプリ サービスを使用すると、アプリが同じデバイスで呼び出すことができる UI のないサービスを作成し、リモート デバイスで Windows 10 バージョン 1607 以降を実行できます。
Windows 10 バージョン 1607 以降では、ホスト アプリと同じプロセスで実行されるアプリ サービスを作成できます。 この記事では、別のバックグラウンド プロセスで実行されるアプリ サービスの作成と使用に焦点を当てます。 プロバイダーと同じプロセスでアプリ サービスを実行する方法の詳細については、「アプリ サービスをホスト アプリ と同じプロセスで実行するように変換する」を参照してください。
新しいアプリ サービス プロバイダー プロジェクトを作成する
このハウツーでは、わかりやすくするために、すべてを 1 つのソリューションで作成します。
- Visual Studio 2022 以降で、新しい UWP アプリ プロジェクトを作成し、 AppServiceProvider という名前を付けます。
- ファイル > 新しい > プロジェクトを選択します。..
- [ 新しいプロジェクトの作成 ] ダイアログ ボックスで、[ UWP 空のアプリ (.NET ネイティブ)] を選択します。 必ず C# プロジェクトの種類を選択してください。 これは、アプリ サービスを他の UWP アプリで使用できるようにするアプリです。
- [次 ] をクリックし、プロジェクトに AppServiceProviderという名前を付け、保存先を選択して、[作成] をクリックします。
ターゲット を選択し、プロジェクトの最小バージョン をするように求められたら、少なくとも 10.0.14393 を選択します。 新しい SupportsMultipleInstances 属性を使用する場合は、 10.0.15063 (Windows 10 Creators Update) 以降をターゲットにする必要があります。
App Service 拡張機能を Package.appxmanifest に追加する
AppServiceProvider プロジェクトで、Package.appxmanifest ファイルをテキスト エディターで開きます。
- ソリューション エクスプローラーので右クリックします。
- を選んでで開きます。
- XML(テキスト)エディタのを選択します。
AppService
要素内に次の <Application>
拡張機能を追加します。 この例では、com.microsoft.inventory
サービスをアドバタイズし、このアプリをアプリ サービス プロバイダーとして識別します。 実際のサービスはバックグラウンド タスクとして実装されます。 App Service プロジェクトは、サービスを他のアプリに公開します。 サービス名には逆ドメイン名スタイルを使用することをお勧めします。
xmlns:uap4
名前空間プレフィックスと uap4:SupportsMultipleInstances
属性は、Windows SDK バージョン 10.0.15063 以降を対象としている場合にのみ有効です。 古い SDK バージョンを対象としている場合は、安全に削除できます。
注
<Package
...
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4"
...
<Applications>
<Application Id="AppServiceProvider.App"
Executable="$targetnametoken$.exe"
EntryPoint="AppServiceProvider.App">
...
<Extensions>
<uap:Extension Category="windows.appService" EntryPoint="MyAppService.Inventory">
<uap3:AppService Name="com.microsoft.inventory" uap4:SupportsMultipleInstances="true"/>
</uap:Extension>
</Extensions>
...
</Application>
</Applications>
Category
属性は、このアプリケーションをアプリ サービス プロバイダーとして識別し、EntryPoint
属性は、サービスを実装する名前空間修飾クラスを識別します。 これを次に実装します。
SupportsMultipleInstances
属性は、アプリ サービスが呼び出されるたびに、新しいプロセスで実行されることを示します。 これは必須ではありませんが、その機能が必要で、10.0.15063 SDK (Windows 10 Creators Update) 以降を対象としている場合に使用できます。 また、uap4
名前空間の前に置く必要があります。
アプリ サービスを作成する
このセクションでは、バックグラウンド タスクとして実行されるアプリ サービスを作成します。 アプリ サービスは、他のアプリがインベントリ内のアイテムの名前と価格を照会できるようにするシンプルなインベントリ サービスを提供します。
アプリ サービスはバックグラウンド タスクとして実装できます。 これにより、フォアグラウンド アプリケーションは別のアプリケーションでアプリ サービスを呼び出すことができます。 バックグラウンド タスクとしてアプリ サービスを作成するには、MyAppServiceという名前の新しい Windows ランタイム コンポーネント プロジェクト (
ファイル の追加)新しいプロジェクト 追加します。 [ 新しいプロジェクトの追加 ] ダイアログ ボックスで、[ Windows ランタイム コンポーネント (.NET ネイティブ)] を選択します。 AppServiceProvider プロジェクトで、新しい MyAppService プロジェクトへのプロジェクト参照を追加します (ソリューション エクスプローラーで、AppServiceProvider プロジェクト >Add>Reference>Projects>Solution を右クリックし、MyAppService>OK を選択します)。 参照を追加しない場合、アプリ サービスは実行時に接続されないため、この手順は重要です。
MyAppService プロジェクトで、 ステートメントを使用して次のを Class1.cs の先頭に追加します。using Windows.ApplicationModel.AppService; using Windows.ApplicationModel.Background; using Windows.Foundation.Collections;
Class1.cs の名前を Inventory.csに変更し、Class1 のスタブ コード Inventoryという名前の新しいバックグラウンド タスク クラスに置き換えます。
public sealed class Inventory : IBackgroundTask { private BackgroundTaskDeferral backgroundTaskDeferral; private AppServiceConnection appServiceconnection; private String[] inventoryItems = new string[] { "Robot vacuum", "Chair" }; private double[] inventoryPrices = new double[] { 129.99, 88.99 }; public void Run(IBackgroundTaskInstance taskInstance) { // Get a deferral so that the service isn't terminated. this.backgroundTaskDeferral = taskInstance.GetDeferral(); // Associate a cancellation handler with the background task. taskInstance.Canceled += OnTaskCanceled; // Retrieve the app service connection and set up a listener for incoming app service requests. var details = taskInstance.TriggerDetails as AppServiceTriggerDetails; appServiceconnection = details.AppServiceConnection; appServiceconnection.RequestReceived += OnRequestReceived; } private async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) { // This function is called when the app service receives a request. } private void OnTaskCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) { if (this.backgroundTaskDeferral != null) { // Complete the service deferral. this.backgroundTaskDeferral.Complete(); } } }
このクラスは、アプリ サービスが作業を行う場所です。
実行 は、バックグラウンド タスクの作成時に呼び出されます。 バックグラウンド タスクは Run が完了すると終了するため、コードはタスクを続行して要求を処理できるように遅延を取得します。 バックグラウンド タスクとして実装されたアプリ サービスは、呼び出しを受信してから約 30 秒間存続します。ただし、その時間枠内で再度呼び出されるか、遅延が取り出されない限りです。アプリ サービスが呼び出し元と同じプロセスで実装されている場合、アプリ サービスの有効期間は呼び出し元の有効期間に関連付けられます。
アプリ サービスの有効期間は、呼び出し元によって異なります。
- 呼び出し元がフォアグラウンドにある場合、アプリ サービスの有効期間は呼び出し元と同じです。
- 呼び出し元がバックグラウンドにある場合、アプリ サービスは 30 秒実行されます。 遅延を利用すると、一度限りの追加時間として5秒が与えられます。
OnTaskCanceled は、タスクが取り消されたときに呼び出されます。 タスクは、クライアント アプリが AppServiceConnection
を破棄するか、クライアント アプリが中断されるか、OS がシャットダウンまたはスリープ状態になった場合、またはタスクを実行するためのリソースが不足しているときに取り消されます。
アプリ サービスのコードを記述する
OnRequestReceived は、アプリ サービスのコードが配置される場所です。 MyAppServiceの OnRequestReceived スタブを、この例にあるコードで Inventory.cs 内に置き換えます。 このコードは、インベントリ項目のインデックスを取得し、それをコマンド文字列と共にサービスに渡して、指定された在庫品目の名前と価格を取得します。 独自のプロジェクトの場合は、エラー処理コードを追加します。
private async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
// Get a deferral because we use an awaitable API below to respond to the message
// and we don't want this call to get canceled while we are waiting.
var messageDeferral = args.GetDeferral();
ValueSet message = args.Request.Message;
ValueSet returnData = new ValueSet();
string command = message["Command"] as string;
int? inventoryIndex = message["ID"] as int?;
if (inventoryIndex.HasValue &&
inventoryIndex.Value >= 0 &&
inventoryIndex.Value < inventoryItems.GetLength(0))
{
switch (command)
{
case "Price":
{
returnData.Add("Result", inventoryPrices[inventoryIndex.Value]);
returnData.Add("Status", "OK");
break;
}
case "Item":
{
returnData.Add("Result", inventoryItems[inventoryIndex.Value]);
returnData.Add("Status", "OK");
break;
}
default:
{
returnData.Add("Status", "Fail: unknown command");
break;
}
}
}
else
{
returnData.Add("Status", "Fail: Index out of range");
}
try
{
// Return the data to the caller.
await args.Request.SendResponseAsync(returnData);
}
catch (Exception e)
{
// Your exception handling code here.
}
finally
{
// Complete the deferral so that the platform knows that we're done responding to the app service call.
// Note for error handling: this must be called even if SendResponseAsync() throws an exception.
messageDeferral.Complete();
}
}
この例では、OnRequestReceived が 非同期 関数であることに注意してください。これは、SendResponseAsync に対して待機可能なメソッド呼び出しを行うためです。
サービスが OnRequestReceived ハンドラーで 非同期 メソッドを使用できるように、遅延が行われます。 これにより、OnRequestReceived の呼び出しは、メッセージの処理が完了するまで完了しません。 SendResponseAsync
App Services では、ValueSet オブジェクトを使用して情報を交換します。 渡すことのできるデータのサイズは、システム リソースによってのみ制限されます。
ValueSetで使用する定義済みのキーはありません。 App Service のプロトコルを定義するために使用するキー値を決定する必要があります。 呼び出し元は、そのプロトコルを念頭に置いて記述する必要があります。 この例では、Command
という名前のキーを選択しました。このキーには、App Service で在庫品目の名前またはその価格を指定するかどうかを示す値が含まれています。 インベントリ名のインデックスは、ID
キーの下に格納されます。 戻り値は、Result
キーの下に格納されます。
AppServiceClosedStatus 列挙型が呼び出し元に返され、アプリ サービスへの呼び出しが成功したか失敗したかが示されます。 アプリ サービスの呼び出しが失敗する可能性がある例は、リソースが超過したために OS がサービス エンドポイントを中止した場合です。
ValueSetを使用して、追加のエラー情報を返すことができます。 この例では、Status
という名前のキーを使用して、より詳細なエラー情報を呼び出し元に返します。
SendResponseAsync の呼び出しは、ValueSet を呼び出し元に返します。
サービス アプリをデプロイし、パッケージ ファミリ名を取得する
アプリ サービス プロバイダーは、クライアントから呼び出す前にデプロイする必要があります。 Visual Studio で ビルド、> ソリューション展開、 を選択してデプロイできます。
呼び出すには、アプリ サービス プロバイダーのパッケージ ファミリ名も必要です。 次の手順に従って取得できます。
- デザイナー ビューで AppServiceProvider プロジェクトの Package.appxmanifest ファイルを開きます ( ソリューション エクスプローラーでダブルクリックします)。
- [パッケージ
] タブを選択し、[パッケージ ファミリ名] の横にある値 をコピーし、メモ帳のようなところに貼り付けておいてください。
アプリ サービスを呼び出すクライアントを作成する
このセクションでは、先ほど作成したアプリ サービスを呼び出すクライアント アプリを作成します。 クライアント アプリは、テキスト ボックスとボタンを備える単純な UWP アプリになります。 ユーザーがテキスト ボックスにインデックスを入力し、ボタンをクリックすると、アプリはアプリ サービスを呼び出して、そのインデックスにあるインベントリ項目の名前と価格を取得します。
[ファイル] [追加] > [新しいプロジェクト] > を使用して、新しい空の Windows ユニバーサル アプリ プロジェクトをソリューションに追加します。 [ 新しいプロジェクトの追加 ] ダイアログ ボックスで、[ UWP 空のアプリ (.NET ネイティブ)] を選択し、 ClientApp という名前を付けます。
ClientApp プロジェクトで、 ステートメントを使用して次のを MainPage.xaml.cs の先頭に追加します。using Windows.ApplicationModel.AppService;
テキスト ボックスとボタンを追加できるように、メイン ページの グリッド を StackPanel に変更します。
TextBox という名前の TextBox とボタンを MainPage.xaml に追加します。
button_Clickと呼ばれるクリック イベント ハンドラーと、コンテンツのテキスト ("Click me" など) を含む Button を追加します。
MainPage.xaml.csのボタン ハンドラーのシグネチャに async キーワード を追加します。
ボタン クリック ハンドラーのスタブを次のコードに置き換えます。 クラスには必ず
inventoryService
フィールド宣言を含めます。private AppServiceConnection inventoryService; private async void button_Click(object sender, RoutedEventArgs e) { // Add the connection. if (this.inventoryService == null) { this.inventoryService = new AppServiceConnection(); // Here, we use the app service name defined in the app service // provider's Package.appxmanifest file in the <Extension> section. this.inventoryService.AppServiceName = "com.microsoft.inventory"; // Use Windows.ApplicationModel.Package.Current.Id.FamilyName // within the app service provider to get this value. this.inventoryService.PackageFamilyName = "Replace with the package family name"; var status = await this.inventoryService.OpenAsync(); if (status != AppServiceConnectionStatus.Success) { textBox.Text= "Failed to connect"; this.inventoryService = null; return; } } // Call the service. int idx = int.Parse(textBox.Text); var message = new ValueSet(); message.Add("Command", "Item"); message.Add("ID", idx); AppServiceResponse response = await this.inventoryService.SendMessageAsync(message); string result = ""; if (response.Status == AppServiceResponseStatus.Success) { // Get the data that the service sent to us. if (response.Message["Status"] as string == "OK") { result = response.Message["Result"] as string; } } message.Clear(); message.Add("Command", "Price"); message.Add("ID", idx); response = await this.inventoryService.SendMessageAsync(message); if (response.Status == AppServiceResponseStatus.Success) { // Get the data that the service sent to us. if (response.Message["Status"] as string == "OK") { result += " : Price = " + response.Message["Result"] as string; } } textBox.Text = result; }
this.inventoryService.PackageFamilyName = "Replace with the package family name";
行のパッケージ ファミリ名を、「サービス アプリをデプロイし、パッケージ ファミリ名を取得する」で前に取得した AppServiceProvider プロジェクトのパッケージ ファミリ名に置き換えます。注
変数に入れるのではなく、文字列リテラルを使用してください。 変数を使用する場合は機能しません。
コードは、最初に App Service との接続を確立します。 接続は、あなたが
this.inventoryService
を処分するまで開いたままです。 App Service 名は、AppService
プロジェクトのName
ファイルに追加した 要素の 属性と一致する必要があります。 この例では、<uap3:AppService Name="com.microsoft.inventory"/>
です。app service に送信するコマンドを指定するために、 という名前の
message
が作成されます。 このアプリ サービスの例では、2 つのアクションのうちどれを実行するかを示すコマンドが必要です。 クライアント アプリのテキスト ボックスからインデックスを取得し、Item
コマンドを使用してサービスを呼び出して項目の説明を取得します。 次に、Price
コマンドを使用してアイテムの価格を取得する呼び出しを行います。 ボタンのテキストが結果に設定されます。AppServiceResponseStatus は、オペレーティング システムがアプリ サービスに呼び出しを接続できたかどうかを示すだけなので、アプリ サービスから受け取った
Status
の キーを確認して、要求を満たすことができることを確認します。ClientApp プロジェクトをスタートアップ プロジェクトに設定し (ソリューション エクスプローラーで右クリック>スタートアップ プロジェクトとして設定)、ソリューションを実行します。 テキスト ボックスに数値 1 を入力し、ボタンをクリックします。 サービスから "Chair : Price = 88.99" が返されます。
を表示する
一般的な問題を解決する
アプリ サービスの呼び出しが失敗した場合は、ClientApp プロジェクトで次のことを確認します。
- インベントリ サービス接続に割り当てられているパッケージ ファミリ名が、AppServiceProvider アプリのパッケージ ファミリ名と一致することを確認します。
button_Click の中にある行を
this.inventoryService.PackageFamilyName = "...";
で参照してください。 -
button_Clickで、インベントリ サービス接続に割り当てられているアプリ サービス名が、AppServiceProvider'Package.appxmanifest ファイル内のアプリ サービス名と一致することを確認します。
this.inventoryService.AppServiceName = "com.microsoft.inventory";
を参照してください。 - AppServiceProvider アプリがデプロイされていることを確認します。 (ソリューション エクスプローラー で、ソリューションを右クリックして、[ソリューションの配置] を選択します)。
アプリ サービスをデバッグする
アプリ サービスをデバッグするには、アプリ サービス プロバイダーがデプロイされ、クライアント アプリからアプリ サービスを呼び出すことができるように、ソリューションを設定する必要があります。 次の手順に従います。
- サービスを呼び出す前にアプリ サービス プロバイダー アプリをデプロイする必要があるため、デバッグの前にソリューションがデプロイされていることを確認します。 (Visual Studio では、ビルド > 展開ソリューションします)。
ソリューション エクスプローラー で、AppServiceProvider プロジェクトを右クリックし、[プロパティ]選択します。 デバッグ タブで、開始アクション を 起動しないが、起動時にコードをデバッグするように変更します。 (C++ を使用してアプリ サービス プロバイダーを実装していた場合は、[デバッグ] タブで [アプリケーションの起動] を [いいえ] に変更してください。) - MyAppService プロジェクトの Inventory.cs ファイルで、OnRequestReceivedにブレークポイントを設定します。
AppServiceProvider プロジェクトをスタートアップ プロジェクトに設定し、F5キー押します。 - (Visual Studio からではなく) [スタート] メニューから ClientApp
起動します。 - テキスト ボックスに数値 1 を入力し、ボタンを押します。 デバッガーは、アプリサービスのブレークポイントでアプリサービス呼び出しの直前に停止します。
クライアントをデバッグする
アプリ サービスを呼び出すクライアント アプリをデバッグするには、クライアント アプリ プロセスにデバッガーをアタッチする必要があります。 次の手順に従います。
- 前の手順の手順に従って、アプリ サービスを呼び出すクライアントをデバッグします。
- [スタート] メニュー ClientApp を起動します。
- デバッガーを (ApplicationFrameHost.exe プロセスではなく) ClientApp.exe プロセスにアタッチします。 (Visual Studio で、[デバッグ] を選択し、> [プロセスにアタッチ]をクリックします)。
- ClientApp プロジェクトで、button_Clickにブレークポイントを設定します。
- ClientApp のテキストボックスに数値 1 を入力し、ボタンをクリックすると、クライアント及びアプリサービスの両方にある
ブレークポイントがヒットされるようになりました。
一般的な App Service のトラブルシューティング
アプリサービスに接続しようとした後に appUnavailable 状態が発生した場合は、次の項目を確認します。
- アプリ サービス プロバイダー プロジェクトと App Service プロジェクトがデプロイされていることを確認します。 クライアントを実行する前に両方を展開する必要があります。そうしないと、クライアントに接続するものがないためです。 Build>Deploy Solutionを使用して、Visual Studio からデプロイできます。
- ソリューション エクスプローラーで、アプリ サービス プロバイダー プロジェクトに、アプリ サービスを実装するプロジェクト間参照があることを確認します。
-
<Extensions>
エントリとその子要素が、「Package.appxmanifestにアプリ サービス拡張機能を追加する」で指定した、アプリ サービス プロバイダー プロジェクトに属する Package.appxmanifest ファイルに追加されていることを確認します。 - アプリ サービス プロバイダーを呼び出すクライアントの AppServiceConnection.AppServiceName 文字列が、アプリ サービス プロバイダー プロジェクトの
<uap3:AppService Name="..." />
ファイルで指定された と一致していることを確認します。 - AppServiceConnection.PackageFamilyName が、「App Service 拡張機能を Package.appxmanifest に追加する」で指定したアプリ サービス プロバイダー コンポーネントのパッケージ ファミリ名と一致していることを確認
- この例のようなアウトプロセス アプリ サービスの場合は、アプリ サービス プロバイダー プロジェクトの
Package.appxmanifest ファイルの要素で指定された が、アプリ サービス プロジェクトに IBackgroundTask 実装するパブリック クラスの名前空間とクラス名と一致することを検証します。
デバッグの問題を解決
デバッガーがアプリ サービス プロバイダーまたはアプリ サービス プロジェクトのブレークポイントで停止しない場合は、次の点を確認します。
- アプリ サービス プロバイダー プロジェクトと App Service プロジェクトがデプロイされていることを確認します。 クライアントを実行する前に、両方をデプロイする必要があります。 Build>Deploy Solutionを使用して、Visual Studio からデプロイできます。
- デバッグするプロジェクトがスタートアップ プロジェクトとして設定されていること、および F5 が押されたときに、そのプロジェクトのデバッグ プロパティがプロジェクト
実行されないように設定されていることを確認します。 プロジェクトを右クリックし、[プロパティ] を] をクリックし、[デバッグ] (または C++ の [デバッグ ) を します。 C# で、開始アクションの を 起動しないが、起動時にコードをデバッグするように変更します。 C++ で、[アプリケーション 起動] [ なし] に設定します。
注釈
この例では、バックグラウンド タスクとして実行されるアプリ サービスを作成し、別のアプリから呼び出す方法の概要を示します。 注意すべき重要な点は次のとおりです。
- アプリ サービスをホストするバックグラウンド タスクを作成します。
-
windows.appService
拡張機能をアプリ サービス プロバイダーの Package.appxmanifest ファイルに追加します。 - クライアント アプリからアプリに接続できるように、アプリ サービス プロバイダーのパッケージ ファミリ名を取得します。
- App Service プロバイダー プロジェクトから App Service プロジェクトへのプロジェクト間参照を追加します。
- サービス 呼び出すには、Windows.ApplicationModel.AppService.AppServiceConnection を使用します。
MyAppService の完全なコード
アプリ サービスをバックグラウンド タスクとして実装する MyAppService プロジェクトの完全なコードを次に示します。 このコードは、MyAppService プロジェクトのInventory.cs ファイルに配置する必要があります。
using System;
using Windows.ApplicationModel.AppService;
using Windows.ApplicationModel.Background;
using Windows.Foundation.Collections;
namespace MyAppService
{
public sealed class Inventory : IBackgroundTask
{
private BackgroundTaskDeferral backgroundTaskDeferral;
private AppServiceConnection appServiceconnection;
private String[] inventoryItems = new string[] { "Robot vacuum", "Chair" };
private double[] inventoryPrices = new double[] { 129.99, 88.99 };
public void Run(IBackgroundTaskInstance taskInstance)
{
// Get a deferral so that the service isn't terminated.
this.backgroundTaskDeferral = taskInstance.GetDeferral();
// Associate a cancellation handler with the background task.
taskInstance.Canceled += OnTaskCanceled;
// Retrieve the app service connection and set up a listener for incoming app service requests.
var details = taskInstance.TriggerDetails as AppServiceTriggerDetails;
appServiceconnection = details.AppServiceConnection;
appServiceconnection.RequestReceived += OnRequestReceived;
}
private async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
// Get a deferral because we use an awaitable API below to respond to the message
// and we don't want this call to get canceled while we are waiting.
var messageDeferral = args.GetDeferral();
ValueSet message = args.Request.Message;
ValueSet returnData = new ValueSet();
string command = message["Command"] as string;
int? inventoryIndex = message["ID"] as int?;
if (inventoryIndex.HasValue &&
inventoryIndex.Value >= 0 &&
inventoryIndex.Value < inventoryItems.GetLength(0))
{
switch (command)
{
case "Price":
{
returnData.Add("Result", inventoryPrices[inventoryIndex.Value]);
returnData.Add("Status", "OK");
break;
}
case "Item":
{
returnData.Add("Result", inventoryItems[inventoryIndex.Value]);
returnData.Add("Status", "OK");
break;
}
default:
{
returnData.Add("Status", "Fail: unknown command");
break;
}
}
}
else
{
returnData.Add("Status", "Fail: Index out of range");
}
// Return the data to the caller.
await args.Request.SendResponseAsync(returnData);
// Complete the deferral so that the platform knows that we're done responding to the app service call.
// Note for error handling: this must be called even if SendResponseAsync() throws an exception.
messageDeferral.Complete();
}
private void OnTaskCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
if (this.backgroundTaskDeferral != null)
{
// Complete the service deferral.
this.backgroundTaskDeferral.Complete();
}
}
}
}