Microsoft Dynamics CRM : カスタムプラグインを利用した Azure 連携 : 二方向リスナーサンプル

みなさん、こんにちは。

先週は Microsoft Dynamics CRM と Azure 連携について 2 つの
記事を紹介しました。

Microsoft Dynamics CRM : 既定のプラグインを利用した Azure 連携サンプル紹介
Microsoft Dynamics CRM : Azure 連携用のカスタムプラグイン開発

今回は上記の記事を読んでいる前提で、さらに異なるオプションに
ついて説明します。

サポートされるリスナーの種類

これまではキューリスナーを利用したサンプルを紹介してきました。
Microsoft Dynamics CRM では、キューリスナー以外にも、一方向、
二方向、REST リスナーをサポートしています。

Windows Azure ソリューション用のリスナーの記述

キューリスナーとの大きな違いは以下の通りです。

- Windows Azure サービスバスに送信されたデータを、その場で
受信しないといけない。
- 二方向、REST リスナーは、受信したデータを加工して、送信元
に差し戻すことが出来る。

尚、差し戻されたデータをプラグイン内で処理するには、既定の
プラグインではなく、カスタムプラグインの利用が必須です。

事前準備

前回までの記事では、キューリスナーを利用していたため、一部
設定の変更が必要となります。

1. SDK\bin\PluginRegistrationTool.exe を実行します。

2. 必要な情報を入力して、組織に接続します。既に ServiceEndpoint
および Plug-ins プラグインが登録されていることを確認します。
※登録されていない場合は、以下の記事に沿って操作をしてください。

Microsoft Dynamics CRM : 既定のプラグインを利用した Azure 連携サンプル紹介
Microsoft Dynamics CRM : Azure 連携用のカスタムプラグイン開発

image

3. (ServiceEndpoint) プラグイン登録ツールに表示される名前を
ダブルクリックします。

4. Path として MyListener、Contract として TwoWay を指定します。

image

5. Save and Configure ACS ボタンをクリックします。

6. 以前の記事と同じ手順で構成を完了します。

二方向リスナーサンプル

1. Visual Studio で sdk\samplecode\cs\azure\windowsazure.sln を
開きます。

2. ソリューションエクスプローラーより TwoWayListener を右クリック
して、スターとアッププロジェクトに設定を選択します。

3. F5 を押下してアプリケーションを開始します。

4. サービスバスの名前空間、発行者名、アクセスキーを聞かれるので
順次入力します。尚、ここの発行者名はサービスバスのアクセスキー
から確認した名前で、通常は owner です。

5. Enter your endpoint path には先ほど指定した MyListerner を指定
し、Enter キーを押下します。

image

6. リスナーが開始されます。

ここでコードの確認をしておきます。

Utility クラス

受け取ったコンテキストを画面に出すためのクラスです。

Main メソッド

プログラムの入り口です。 Run メソッドを実行します。

Run メソッド

リスナーをホスティングする箇所です。コメントを入れました。

public void Run()
{
    // リスナーに必要な情報の設定
    ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.Http;

    // サービスバス名前空間の取得
    Console.Write("Enter your Azure service namespace: ");
    string serviceNamespace = Console.ReadLine();

    // 発行者の取得
    Console.Write("Enter your service namespace issuer name: ");
    string issuerName = Console.ReadLine();

    // アクセスキーの取得
    Console.Write("Enter your service namespace issuer key: ");
    string issuerKey = Console.ReadLine();

    // Path の設定。PluginRegistrationTool で指定したものを同じ文字列を指定
    Console.Write("Enter your endpoint path: ");
    string servicePath = Console.ReadLine();

    // リスナーが待ち受ける URI の作成
    Uri address = ServiceBusEnvironment.CreateServiceUri(
        Uri.UriSchemeHttps,
        serviceNamespace,
        servicePath);

    Console.WriteLine("The service address is: " + address);

    // サービスバス接続のための認証情報を生成
    var sharedSecretServiceBusCredential = new TransportClientEndpointBehavior()
    {
        TokenProvider = TokenProvider.CreateSharedSecretTokenProvider(issuerName, issuerKey)
    };

    // リスナーが利用するバインディングの指定
    WS2007HttpRelayBinding binding = new WS2007HttpRelayBinding();
    binding.Security.Mode = EndToEndSecurityMode.Transport;

    // ホストの作成
    ServiceHost host = new ServiceHost(typeof(TwoWayEndpoint));
    host.AddServiceEndpoint(typeof(ITwoWayServiceEndpointPlugin), binding, address);

    // エンドポイントで利用する Behavior の作成
    var serviceRegistrySettings = new ServiceRegistrySettings(DiscoveryType.Public);

    // エンドポイントへ上記で作成したものを追加

    foreach (var endpoint in host.Description.Endpoints)
    {
        endpoint.Behaviors.Add(serviceRegistrySettings);
        endpoint.Behaviors.Add(sharedSecretServiceBusCredential);
    }

    // 待ち受け開始
    host.Open();

    Console.WriteLine(Environment.NewLine + "Listening for messages from Azure" +
        Environment.NewLine + "Press [Enter] to exit");

    // Enter を押下したら待ち受け終了
    Console.ReadLine();

    Console.Write("Closing the service host...");
    host.Close();
    Console.WriteLine(" done.");
    //</snippetTwoWayListener1>
}

TwoWayEndpoint クラス

メッセージを受け取った際に処理をする箇所。ここは
単純にコンテキストを表示し、結果として ”Success" 文字列を
返します。

[ServiceBehavior]
private class TwoWayEndpoint : ITwoWayServiceEndpointPlugin
{
    #region ITwoWayServiceEndpointPlugin Member

    /// <summary>
    /// This method is called when a message is posted to the Azure Service Bus.
    /// </summary>
    /// <param name="context">Data for the request.</param>
    /// <returns>A 'Success' string.</returns>
    public string Execute(RemoteExecutionContext context)
    {
        Utility.Print(context);
        return "Success";
    }

    #endregion
}

動作確認

では実際に動かしてみましょう。

1. Microsoft Dynamics CRM Online でレターを作成します。

2. 今回は同期処理ですので、エラーがあればその場でエラーが
ポップアップし、処理が中断されます。

3. レコードの作成が完了した時点で、Visual Studio で起動している
アプリケーションに戻ります。

4. 操作コンテキストの情報が画面に出ていることを確認します。

戻り値の利用

二方向リスナーを利用するメリットは、戻り値をプラグイン内で利用
できることです。早速サンプルを改修してみましょう。

1. Plug-ins プロジェクト配下にある SandboxPlugin.cs を開きます。

2. Execute メソッド内でサービスバスに情報を渡している箇所を
確認します。

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.");
}

3. 戻り値である response をレターエンティティの件名に付与してみます。
以下のコードを if ステートメント内に追加します。

if (response == "Success") // 大文字小文字に注意
{
    //do something
}
else
{
    throw new InvalidPluginExecutionException(response);
}

4. ビルド後、PluginRegistrationTool より既存のアセンブリを更新します。

5. 再度動作確認を行います。無事レターが作成できれば成功です。

6. リスナーより Success 以外の文字列を返すよう TwoWayListener.cs
を変更します。

public string Execute(RemoteExecutionContext context)
{
    Utility.Print(context);
    return "Failed";
}

7. 再度動作確認を行います。

8. 返り値をプラグイン内で取得し、エラーが画面に出ることを確認します。

image

まとめ

Windows Azure サービスバスに Microsoft Dynamics CRM からデータを渡す
だけでなく、結果等の文字列を返して受け取れることで、利用シナリオが
増えると考えていますが、以下の点には十分注意してください。

・ すべての処理が同期のためパフォーマンスに懸念がある
・ 同期処理のため Windows Azure 上で問題があると Microsoft Dynamics
CRM の処理にも影響が出る

是非いろいろ試してください。

- Dynamics CRM サポート 中村 憲一郎