Azure 対応のカスタム プラグインの記述

注意

エンティティとテーブルの違いがわかりませんか? Microsoft Dataverse で「開発者: 用語を理解する」を参照してください。

Azure を操作するプラグインの記述は、他の Dataverse プラグインの記述と似ています。 ただし、目的の Web サービス メソッドの呼び出しに加えて、プラグインには、現在のトランザクションの実行コンテキストの Azure Service Bus へのポストを開始するコードを含める必要があります。

プラグインの設計に関する考慮事項

同期して実行するプラグインでは、リスナー アプリケーションなどの外部サービスから情報を取得するために Azure にメッセージを送信するようにプラグインを設計することをお勧めします。 データ文字列をプラグインに返すことができる Azure Service Bus エンドポイントでの二方向または REST 契約を使用します。

同期プラグインで Azure Service Bus を使用して外部サービスのデータを更新することはお勧めしません。 外部サービスが利用できない場合や更新するデータが大量にある場合、問題が起こる可能性があります。 同期プラグインは、高速実行し、長時間の操作を実行する間はログインしている組織のすべてのユーザーを保持しないようにします。 また、プラグインが起動する現在のコア操作のロールバックが発生すると、プラグインで行われたデータの変更は取り消されます。 これにより、Dynamics 365 と外部のサービスが非同期状態になることがあります。

同期登録されたプラグインで現在のトランザクションの実行コンテキストを Azure Service Bus に投稿することが可能であることに注意してください。

プラグインのコードを記述する

次のプラグイン例では、Azure サービス プロバイダーを取得し、Execute(EntityReference, IExecutionContext) を呼び出すことでサービスへの実行コンテキストの Service Bus へのポストを開始するコードが追加されています。 プラグインはサンドボックスで実行する必要があるため、プラグインのデバッグを容易にするトレース コードが追加されています。

注意

このコードでコンストラクターに渡された serviceEndpointId は、チュートリアル: Dataverse との統合のための Azure (SAS) の構成で説明されたサービス エンドポイントの作成から取得したものです

ユーザーのブラウザーと [organization Uri]/api/data/v9.0/serviceendpoints?$select=name,description,serviceendpointid のようなクエリを使用する Web API に対して GET 要求を使用することにより、ユーザーの環境で使用可能なサービス エンドポイントをクエリすることができます。

using System;
using System.Diagnostics;
using System.Threading;
using System.Runtime.Serialization;

using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;

using Microsoft.Xrm.Sdk;

namespace Microsoft.Crm.Sdk.Samples
{
    /// <summary>
    /// A custom plug-in that can post the execution context of the current message to the Windows
    /// Azure Service Bus. The plug-in also demonstrates tracing which assist with
    /// debugging for plug-ins that are registered in the sandbox.
    /// </summary>
    /// <remarks>This sample requires that a service endpoint be created first, and its ID passed
    /// to the plug-in constructor through the unsecure configuration parameter when the plug-in
    /// step is registered.</remarks>
    public sealed class SandboxPlugin : IPlugin
    {
        private Guid serviceEndpointId; 

        /// <summary>
        /// Constructor.
        /// </summary>
        public SandboxPlugin(string config)
        {
            if (String.IsNullOrEmpty(config) || !Guid.TryParse(config, out serviceEndpointId))
            {
                throw new InvalidPluginExecutionException("Service endpoint ID should be passed as config.");
            }
        }

        public void Execute(IServiceProvider serviceProvider)
        {
            // Retrieve the execution context.
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

            // Extract the tracing service.
            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            if (tracingService == null)
                throw new InvalidPluginExecutionException("Failed to retrieve the tracing service.");

            IServiceEndpointNotificationService cloudService = (IServiceEndpointNotificationService)serviceProvider.GetService(typeof(IServiceEndpointNotificationService));
            if (cloudService == null)
                throw new InvalidPluginExecutionException("Failed to retrieve the service bus service.");

            try
            {
                tracingService.Trace("Posting the execution context.");
                string response = cloudService.Execute(new EntityReference("serviceendpoint", serviceEndpointId), context);
                if (!String.IsNullOrEmpty(response))
                {
                    tracingService.Trace("Response = {0}", response);
                }
                tracingService.Trace("Done.");
            }
            catch (Exception e)
            {
                tracingService.Trace("Exception: {0}", e.ToString());
                throw;
            }
        }
    }
}

プラグイン コードで、ポストを開始する前にコンテキストで書き込み可能データを更新できます。 たとえば、コンテキスト内の共有変数にキー/値のペアを追加できます。

プラグイン登録

Azure 対応のカスタム プラグインの登録時には、いくつかの制限があります。 プラグインは、サンドボックスで実行するよう登録する必要があります。 このため、プラグインは、IOrganizationService メソッド、Azure ソリューション メソッドの呼び出し、または Web クライアントを使用した Network へのアクセスに制限されます。 ローカル ファイル システムへのアクセスなど、他の外部アクセスは許可されません。

非同期モードで実行するよう登録されたプラグインの場合、他の非同期プラグインとの比較でプラグイン実行の順序が保証されないことも意味します。 また、非同期プラグインは常に Dynamics 365 コア操作の後に実行されます。

Service Bus ポストの失敗の処理

失敗した Service Bus 送信での所定の動作は、プラグインが同期実行と非同期実行のどちらで登録されているかによって異なります。 非同期プラグインでは、実際に実行コンテキストをサービス バスに投稿するシステム ジョブが投稿を再試行します。 同期に登録されたプラグインの場合、例外が返されます。 詳細 ランタイム エラーの管理と通知

重要

非同期として登録されたプラグインの場合のみ、Azure Service Bus に投稿された非同期ジョブが投稿失敗後に再試行されると、プラグイン ロジック全体が再び実行されます。 このため、コンテキストの変更と Service Bus への投稿以外に、ユーザー定義の Azure 対応プラグインにほかのロジックを追加しないでください。

非同期に実行するように登録されたプラグインの場合、Service Bus 経由で送信されたメッセージの本文に含まれる RemoteExecutionContextOperationId のプロパティと OperationCreatedOn プロパティを含みます。 これらのプロパティは、関連するシステム ジョブ (AsyncOperation) の AsyncOperationIdCreatedOn 列が作成したデータと同じデータが含まれます。 Azure Service Bus ポストを再試行する必要がある場合、このような追加のプロパティにより順序付けと重複データ検出が容易に行われます。

関連項目

Dynamics 365 の Azure 拡張機能
Microsoft Azure Service Bus を利用して Dynamics 365 データを送信する
プラグインを記述する
イベント実行パイプライン
プラグインの登録および展開

注意

ドキュメントの言語設定についてお聞かせください。 簡単な調査を行います。 (この調査は英語です)

この調査には約 7 分かかります。 個人データは収集されません (プライバシー ステートメント)。