SharePoint アドインで非同期操作を使用する

Microsoft Azure WebJobs を使用して SharePoint アドインに非同期操作を実装します。

適用対象:SharePoint 2013 | SharePoint アドイン | SharePoint Online

Core.QueueWebJobUsage サンプルは、プロバイダー ホスト型アドインと Azure WebJobs を使用して、Office 365 で非同期操作を作成して実行する方法を示しています。

このソリューションを使用して、以下を行うことができます。

  • リモート イベント レシーバーのパフォーマンスを改善します。

  • SharePoint Online に移行して、オンプレミスの SharePoint 環境にあったものと同じタイマー ジョブ機能を実装します。

  • SharePoint 環境に対して実行する、長時間実行される処理を実装します。 以下に例を示します。

次の図は、非同期操作が実行されるときに必要なコンポーネントと、それらのコンポーネント間の処理フローのアーキテクチャの概要を示しています。

非同期操作のフローを示すダイアグラム。SharePoint アドインはプロバイダー ホスト型のアドインを呼び出し、Azure ストレージ キューにメッセージが追加されます。Azure WebJob はメッセージを処理し、SharePoint サイトでアクションを実行します。

Azure WebJobs を使用して、プロバイダー ホスト型アドインに非同期操作を実装するには、次のようにします。

  1. SharePoint Online に展開されたアドインをユーザーが実行します。

  2. プロバイダー ホスト型アドインは、Azure WebJob に必要な入力パラメーターを提供してから、新しいメッセージを Azure ストレージ キューに追加します。

  3. Azure ストレージ キューは、継続して実行している Azure WebJob 内でイベントをトリガーして、新しいメッセージの処理を開始します。

  4. Azure WebJob は、SharePoint Online サイトに対してカスタム ビジネス ロジックを実行します。

注:

Azure ストレージ キューへのメッセージの追加を実行するときには、Azure WebJob を実行するプロセスとは異なるプロセスが使用されます。 そのため、アドインは 1 つのプロセスを使用して新しいメッセージをキューに追加してから Azure WebJob を使用してそれらのメッセージを別のプロセスで処理することにより、非同期操作を実装できます。

はじめに

最初に、Core.QueueWebJobUsage サンプル アドインを GitHub の Office 365 Developer Patterns and Practices プロジェクトからダウンロードして、Azure アカウントを作成し、そのアカウントに詳細を追加して、Azure WebJob が実行していることを検証します。

Azure ストレージ アカウントを作成して Azure ストレージ キューにアクセスするには、次のようにします。

  1. Microsoft Azure ポータルにサインインします。

  2. [ 新しい>Data Services>Storage>クイック作成] を選択します

  3. [URL] にドメイン名を入力します。 たとえば、「contoso」と入力します。

  4. [場所/アフィニティ グループ] で、適切な場所を選択します。

  5. [レプリケーション] で、[地理冗長] を選択します。

  6. [ストレージ アカウントの作成] を選択します。

新しく作成したストレージ アカウントに詳細を追加するには、次のようにします。

  1. Azure Storage アカウントが作成されたら、[ アクセス キーの管理] を選択します。

  2. [ アクセス キーの管理] で、 ストレージ アカウント名プライマリ アクセス キーをコピーします

  3. クライアント ID、クライアント シークレット、および Azure ストレージ アカウント情報をいくつかの構成ファイルに適用します。

  4. Helper Project\Core.QueueWebJobUsage.Console.SendMessage で、Program.cs を開いてサイトの URL を siteUrl ボックスに入力します。

  5. [Core.QueueWebJobUsage.Job のプロパティ] で、Microsoft.SharePoint.Client および Microsoft.SharePoint.Client.Runtime 参照で [ローカルコピー] を True に設定します。 [ ローカルコピー][True] に設定すると、参照先のアセンブリが Azure にコピーされ、Azure WebJob がこれらのアセンブリへの参照を解決できます。

  6. Azure、WebJob を展開します。 詳細については、「Web ジョブ プロジェクトをデプロイする」を参照してください。

Azure WebJobs が実行していることを確認するには、次のようにします。

  1. Azure ポータルにサインインします。

  2. [Web アプリ] を選択し、入力した Microsoft Azure Web サイトを選択します。

  3. [Web ジョブ] を選択します。

  4. Azure WebJob が一覧に表示され、 SCHEDULE[継続的に実行] に設定されていることを確認します。

  5. [構成] を選択します。

  6. [アドイン設定] で、ClientIdClientSecret の新しいアドイン設定を作成します。 Core.QueueWebJobUsage.Job\app.config ファイルから ClientIdClientSecret のキーと値のペアをコピーします。

  7. [接続文字列] で、AzureWebJobsDashboardAzureWebJobsStorage の接続文字列を新しく作成します。 azureWebJobsDashboardAzureWebJobsStorage キー (名前) と値のペアを Core.QueueWebJobUsage.Job\app.config ファイルからコピーし、型を [カスタム] に設定します。

  8. 保存] を選択します。

構成設定の適用

次の表の情報を使用して、構成設定を Core.QueueWebJobUsage Visual Studio ソリューションに適用します。

ファイルの場所 更新するキー 更新する値情報
Helper Project\Core.QueueWebJobUsage.Console.SendMessage\app.config StorageConnectionString [Your Account name] を、Azure ポータルからコピーしたストレージ アカウント名に置き換えます。
[Your Account Key] を、Azure ポータルからコピーしたプライマリ アクセス キーに置き換えます。
Core.QueueWebJobUsageWeb\web.config StorageConnectionString [YourAccountName] を、Azure ポータルからコピーしたストレージ アカウント名に置き換えます。
[YourAccountKey] を、Azure ポータルからコピーしたプライマリ アクセス キーに置き換えます。
Core.QueueWebJobUsage.Job\app.config StorageConnectionString [YourAccountName] を、Azure ポータルからコピーしたストレージ アカウント名に置き換えます。
[YourAccountKey] を、Azure ポータルからコピーしたプライマリ アクセス キーに置き換えます。
ClientId [Your Add-in ID] を Core.QueueWebJobUsageWeb\web.config からコピーしたクライアント ID に置き換えます。
ClientSecret [Your Add-in Secret] を Core.QueueWebJobUsageWeb\web.config からコピーしたクライアント シークレットに置き換えます。
AzureWebJobsDashboard [YourAccount] を、Azure ポータルからコピーしたストレージ アカウント名に置き換えます。
[YourKey] を、Azure ポータルからコピーしたプライマリ アクセス キーに置き換えます。
AzureWebJobsStorage [YourAccount] を、Azure ポータルからコピーしたストレージ アカウント名に置き換えます。
[YourKey] を、Azure ポータルからコピーしたプライマリ アクセス キーに置き換えます。

注:

たとえば、Core.QueueWebJobUsageWeb の ClientIdClientSecret が更新された場合、AppManifest.xml でバージョン番号を増分させるときには、Core.QueueWebJobUsage.Job\app.config の ClientIdClientSecret を更新してください。

Core.QueueWebJobUsage アドインを使用する

次の表は、Core.QueueWebJobUsage ソリューション内のすべての Visual Studio プロジェクトについて説明しています。

Visual Studio プロジェクト 説明
Core.QueueWebJobUsage SharePoint アドイン プロジェクト。 以下の許可が必要です。
  • AllowAppOnlyPolicy。

  • Web での FullControl 許可。

Core.QueueWebJobUsage.Common このソリューションのビジネス オブジェクトとビジネス ロジック コード (ストレージ キューにメッセージを追加するメソッドなど) が含まれます。 This project is included to share business objects and business logic between different projects. You may not need this in your implementation.
Core.QueueWebJobUsage.Job 新しいメッセージが Azure ストレージ キューに追加されるときに実行される Azure WebJob。 このプロジェクトには、カスタム ビジネス ロジック コードが含まれています。
Core.QueueWebJobUsageWeb Core.QueueWebJobUsage プロジェクトの UI が含まれる、プロバイダー ホスト型アドイン。
Helper Project\Core.QueueWebJobUsage.Console.SendMessage ストレージ アカウント情報とキュー作成プロセスを検証するため、およびこの記事で説明されているソリューション全体をセットアップせずにメッセージをキューに送信して処理するために使用できるヘルパー プロジェクト。

Core.QueueWebJobUsage コード サンプルを実行すると、プロバイダーホスト型アドインが表示され、 同期操作非同期操作の 2 つのボタンが表示されます。 [同期処理] を選択すると、Pages\Default.aspx の btnSync_Click が実行時間の長い同期プロセスをシミュレートします。 このコード サンプルで、btnSync_Click は現行スレッドを 10 秒間スリープ状態にしてから、ドキュメント ライブラリを作成します。 [非同期処理] を選択すると、Pages\Default.aspx の btnAsync_Click が以下を実行します。

  1. 現在のユーザーを取得します。

  2. Azure Storage キューに送信されるメッセージに含めるデータを格納する SiteModifyRequest ビジネス オブジェクトを作成します。 このコード サンプルの場合、送信されるデータには、現行ユーザーの名前と現行サイトの URL が含まれています。

  3. SiteManager() を呼び出します。AddAsyncOperationRequestToQueue を使用して、Azure Storage キューにメッセージを追加します。

注:

この記事で提供されるコードは、明示または黙示のいかなる種類の保証なしに現状のまま提供されるものであり、特定目的への適合性、商品性、権利侵害の不存在についての暗黙的な保証は一切ありません。

protected void btnAsync_Click(object sender, EventArgs e)
        {

            var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);

            using (var clientContext = spContext.CreateUserClientContextForSPHost())
            {
                // Get the current user.
                var currUser = clientContext.Web.CurrentUser;
                clientContext.Load(currUser);
                clientContext.ExecuteQuery();

                // Create business object, and then add the request to the queue.
                SiteModifyRequest request = new SiteModifyRequest() { RequestorName = currUser.Title, SiteUrl = Page.Request["SPHostUrl"] };
                new SiteManager().AddAsyncOperationRequestToQueue(request,
                                                                  ConfigurationManager.AppSettings["StorageConnectionString"]);

                processViews.ActiveViewIndex = 1;
                lblStatus.Text = "Asynchronous operation to create document library started.";
            }
        }

SiteManager.cs の Core.QueueWebJobUsage.Common で、AddAsyncOperationRequestToQueue は以下を実行します。

  1. Core.QueueWebJobUsageWeb\web.config ファイルの AccountName および AccountKey 構成情報を使用して、CloudStorageAccount オブジェクトを作成します。

  2. CloudStorageAccount.CreateCloudQueueClient を使用して Azure ストレージ キュー クライアントを作成します。

  3. CloudQueueClient.GetQueueReference を使用して、名前が SiteManager.StorageQueueName 定数の値と等しい Azure ストレージ キューへの参照を取得します。

  4. CloudQueue.CreateIfNotExists を使用して、Azure ストレージ キューが存在しない場合にそれを作成します。

  5. CloudQueue.AddMessage を使用して、Azure Storage キューに新しいメッセージを追加します。 modifyRequest ビジネス オブジェクトは CloudQueueMessage オブジェクトにシリアル化され、Azure Storage キューに追加されます。

public void AddAsyncOperationRequestToQueue(SiteModifyRequest modifyRequest, 
                                                    string storageConnectionString)
        {
            CloudStorageAccount storageAccount =
                                CloudStorageAccount.Parse(storageConnectionString);

            // Get queue or create a new one if one does not exist.
            CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
            CloudQueue queue = queueClient.GetQueueReference(SiteManager.StorageQueueName);
            queue.CreateIfNotExists();

            // Add a message to queue.
            queue.AddMessage(new CloudQueueMessage(JsonConvert.SerializeObject(modifyRequest)));
        }

メッセージが Azure Storage キューに追加されると、継続的に実行されている Azure WebJob が待機し、新しいメッセージを処理します。 Azure WebJob は Core.QueueWebJobUsage.Job で定義されています。 Azure WebJob が実行されると、Core.QueueWebJobUsage.Job\Program.cs の Main によって新しい JobHost が作成され、 RunAndBlock が呼び出されます。 JobHost は、QueueTrigger 属性でマークされたメソッドの呼び出しを調整し、特定のキュー上のメッセージを監視します。 RunAndBlock を使用すると、Azure WebJob が継続的に実行され、新しいメッセージが Azure Storage キューに追加されたときにトリガーするメソッドである ProcessQueueMessage が呼び出されます。 Azure WebJobs SDK は 、メイン スレッドを ProcessQueueMessage に関連付けます。 詳細については、「 Azure アドイン サービスで .NET WebJob を作成する」を参照してください。

static void Main()
        {
            var host = new JobHost();
            // The following code ensures that the WebJob will run continuously.
            host.RunAndBlock();
        }

ProcessQueueMessage は、Azure ストレージ キューに追加される新しいメッセージを以下の方法で処理します。

  1. QueueTrigger 属性を使用して、SiteManager.StorageQueueName の値と同じ名前の新しいメッセージがキューに書き込まれるときに ProcessQueueMessage をトリガーするように指定します。

  2. ProcessQueueMessage にパラメーターとして渡されたログ変数を使用して、Azure WebJob のログに書き込みます。

  3. SiteManager().PerformSiteModification を呼び出して、サイトで長時間実行されるビジネス プロセスを実行します。 このコード サンプルでは、スレッドが 10 秒間スリープ状態になってから、ドキュメント ライブラリが作成されます。

public static void ProcessQueueMessage(
            [QueueTrigger(SiteManager.StorageQueueName)] 
            SiteModifyRequest modifyRequest, TextWriter log)
        {
            log.WriteLine(string.Format("{0} '{1}' {2} '{3}'.",
                            "Received new site modification request with URL", 
                            modifyRequest.SiteUrl, 
                            "from person named as ", 
                            modifyRequest.RequestorName));
            
            try
            {
                Uri targetSite = new Uri(modifyRequest.SiteUrl);
                
                // Get the realm for the URL.
                string realm = TokenHelper.GetRealmFromTargetUrl(targetSite);

                // Get the access token for the URL.  
                // Requires this add-in to be registered with the tenant.
                string accessToken = TokenHelper.GetAppOnlyAccessToken(
                                                    TokenHelper.SharePointPrincipal,
                                                    targetSite.Authority, realm).AccessToken;

                // Get client context with access token.
                using (var ctx =
                    TokenHelper.GetClientContextWithAccessToken(
                                                    targetSite.ToString(), accessToken))
                {
                    // Call business logic code.
                    new SiteManager().PerformSiteModification(ctx, modifyRequest);
                }
            }
            catch (Exception ex)
            {
                log.WriteLine(string.Format("Site modification to URL {0} failed with following details.", modifyRequest.SiteUrl));
                log.WriteLine(ex.ToString());
                throw;
            }
        }

関連項目