Dynamics CRM 2016 SDK 新機能: Web API その 5: Action の利用

みなさん、こんにちは。

前回に引き続き、Dynamics CRM 2016 SDK の新機能として、正式版と
なった Web API について紹介します。

今回は Action について紹介します。

Action 概要

正式版のリリースでは、より多くの組織要求をサポートしていますが、
大きく分類すると Function も Action も WhoAmI のような組織要求と
なります。違いは Function はデータの変更を伴わない作業であるのに
対して Action はデータの変更を伴うものとして分類されています。

Bound と Unbound Function

Function 同様、Action も Bound と Unbound に分類されます。Bound
Action はエンティティのレコードに依存しますが、Unbound Action は
レコードに依存しません。具体的な例は以下で紹介します。

Unbound Action

まず Unbound Action の例として WinOpportunity 要求を実装します。
WinOpportunity は営業案件を受注としてクローズします。ここでは
サンプルデータが存在する前提としています。

プログラムの実装

1. 前回利用した Visual Studio ソリューションを開き、Program.cs
ファイルを開きます。新しく以下のメソッドを追加します。

public async Task RunUnboundAction (string accessToken)
{
    // HttpClient の作成
    using (HttpClient httpClient = new HttpClient())
    {
        // Web API アドレスの作成
        string serviceUrl = serverUrl + "/api/data/v8.0/";
        // ヘッダーの設定
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

    }
}

2. Main メソッドの以下のコードを書き換えて、新しいメソッドを
呼ぶように変更します。

元)  
Task.WaitAll(Task.Run(async () => await app.RunFunction(result.AccessToken)));

変更後)
Task.WaitAll(Task.Run(async () => await app.RunUnboundAction (result.AccessToken)));

3. 新しく追加した RunUnboundAction メソッド内に以下のコードを追加
して、受注としてクローズするための営業案件を取得します。

// オープンしている営業案件の取得
HttpResponseMessage openOppsRes = await httpClient.GetAsync(serviceUrl + "opportunities?$select=opportunityid,name&$filter=statecode eq 0");
JToken openOpps = JObject.Parse(openOppsRes.Content.ReadAsStringAsync().Result)["value"];

// 営業案件名の表示
Console.WriteLine("クローズする営業案件:{0}", openOpps[0]["name"]);

4. WinOpportunity Action に渡すためのコンテンツを作成します。

// 営業案件のクローズオブジェクトの作成
string content = string.Format(@"{{
'Status': 3,
    'OpportunityClose': {{
        'subject': '営業案件のクローズ',
        'opportunityid@odata.bind': '{0}opportunities({1})'
    }}
}}", serviceUrl, openOpps[0]["opportunityid"].ToString());

5. WinOpportunity 要求を実行します。

// 営業案件のクローズ
HttpResponseMessage winOppRes = await httpClient.PostAsync(serviceUrl + "WinOpportunity ",
    new StringContent(content, Encoding.UTF8, "application/json"));

動作確認

1. F5 キーを押下してプログラムを実行します。

2. 認証ダイアログが表示されたらログインします。

image

3. クローズされる案件名を確認します。

image

4. ブラウザより該当の案件がクローズされていることを確認します。

Bound Action

次に Bound Action の例として AddToQueue 要求を実装します。

Action 定義の確認

まずは Action 定義を確認します。前回はブラウザで直接メタデータを
確認しましたが、今回は SDK で情報を参照する方法を紹介します。

1. 以下のリンクより Microsoft Dynamics CRM 2016 SDK を取得します。
https://www.microsoft.com/en-us/download/details.aspx?id=50032

2. ダウンロードしたファイルを実行後、解凍されたフォルダより
CrmSdk2016.chm を開きます。

3. Search タブより「Web API Action Reference」を検索して、結果から
コンテンツを表示します。

image

4. AddToQueue Action のリンクをクリックします。ページより
Queue エンティティに Bound していることと、パラメーターを
確認します。

キューの作成

割当先のキューを作成します。

1. ブラウザで Microsoft Dynamics CRM 組織に接続します。

2. 設定 | 事業部管理より「キュー」を選択し、「新規」ボタンを
クリックします。

3. 名前に「Web API テストキュー」と入力して「保存して閉じる」
ボタンをクリックします。

image

プログラムの実装

1. 新しく以下のメソッドを追加します。

public async Task RunBoundAction (string accessToken)
{
    // HttpClient の作成
    using (HttpClient httpClient = new HttpClient())
    {
        // Web API アドレスの作成
        string serviceUrl = serverUrl + "/api/data/v8.0/";
        // ヘッダーの設定
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

    }
}

2. Main メソッドの以下のコードを書き換えて、新しいメソッドを
呼ぶように変更します。

元)  
Task.WaitAll(Task.Run(async () => await app.RunUnboundAction (result.AccessToken)));

変更後)
Task.WaitAll(Task.Run(async () => await app.RunBoundAction (result.AccessToken)));

3. 新しく追加した RunBoundAction メソッド内に以下のコードを追加
して、キューとサポート案件をそれぞれ取得します。

// オープンしているサポート案件を 1 件取得
HttpResponseMessage openCaseRes = await httpClient.GetAsync(serviceUrl + "incidents?$select=incidentid,title&$filter=statuscode eq 1&$top=1");
JToken openCase = JObject.Parse(openCaseRes.Content.ReadAsStringAsync().Result)["value"];

// オープンしているサポート案件名の表示
Console.WriteLine("サポート案件名:{0}", openCase[0]["title"]);

// キューの取得
HttpResponseMessage queueRes = await httpClient.GetAsync(serviceUrl + "queues?$select=queueid,name&$filter=startswith(name,'Web API')");
JToken queue = JObject.Parse(queueRes.Content.ReadAsStringAsync().Result)["value"];

4. AddToQueue に渡すコンテンツを作成します。

// 割当する Target の作成
string content = string.Format(@"{{
    'Target': {{
        'incidentid': '{0}',
        '@odata.type': 'Microsoft.Dynamics.CRM.incident'
    }}                 
}}", openCase[0]["incidentid"].ToString());

5. AddToQueue を実行します。Bound Action ですので、特定の
レコードに対するアドレスとなります。

// キューへのアサイン
HttpResponseMessage winOppRes = await httpClient.PostAsync(serviceUrl + "queues(" + queue[0]["queueid"] + ")/Microsoft.Dynamics.CRM.AddToQueue()",
    new StringContent(content, Encoding.UTF8, "application/json"));

動作確認

1. F5 キーを押下してプログラムを実行します。

2. 認証ダイアログが表示されたらログインします。

3. サポート案件名が表示されます。

4. プログラム完了後、ブラウザでキューに該当のサポート案件が
割り当てられていることを確認します。

以下に今回追加したメソッドを示します。

public async Task RunUnboundAction(string accessToken)
{
    // HttpClient の作成
    using (HttpClient httpClient = new HttpClient())
    {
        // Web API アドレスの作成
        string serviceUrl = serverUrl + "/api/data/v8.0/";
        // ヘッダーの設定
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

        // オープンしている営業案件の取得
        HttpResponseMessage openOppsRes = await httpClient.GetAsync(serviceUrl + "opportunities?$select=opportunityid,name&$filter=statecode eq 0");
        JToken openOpps = JObject.Parse(openOppsRes.Content.ReadAsStringAsync().Result)["value"];

        // 営業案件名の表示
        Console.WriteLine("クローズする営業案件:{0}", openOpps[0]["name"]);

        // 営業案件のクローズオブジェクトの作成
        string content = string.Format(@"{{
        'Status': 3,
            'OpportunityClose': {{
                'subject': '営業案件のクローズ',
                'opportunityid@odata.bind': '{0}opportunities({1})'
            }}
        }}", serviceUrl, openOpps[0]["opportunityid"].ToString());

        // 営業案件のクローズ
        HttpResponseMessage winOppRes = await httpClient.PostAsync(serviceUrl + "WinOpportunity ",
            new StringContent(content, Encoding.UTF8, "application/json"));
    }
}

public async Task RunBoundAction(string accessToken)
{
    // HttpClient の作成
    using (HttpClient httpClient = new HttpClient())
    {
        // Web API アドレスの作成
        string serviceUrl = serverUrl + "/api/data/v8.0/";
        // ヘッダーの設定
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

        // オープンしているサポート案件を 1 件取得
        HttpResponseMessage openCaseRes = await httpClient.GetAsync(serviceUrl + "incidents?$select=incidentid,title&$filter=statuscode eq 1&$top=1");
        JToken openCase = JObject.Parse(openCaseRes.Content.ReadAsStringAsync().Result)["value"];

        // オープンしているサポート案件名の表示
        Console.WriteLine("サポート案件名:{0}", openCase[0]["title"]);

        // キューの取得
        HttpResponseMessage queueRes = await httpClient.GetAsync(serviceUrl + "queues?$select=queueid,name&$filter=startswith(name,'Web API')");
        JToken queue = JObject.Parse(queueRes.Content.ReadAsStringAsync().Result)["value"];
               
        // 割当する Target の作成
        string content = string.Format(@"{{
            'Target': {{
                'incidentid': '{0}',
                '@odata.type': 'Microsoft.Dynamics.CRM.incident'
            }}                 
        }}", openCase[0]["incidentid"].ToString());

        // キューへのアサイン
        HttpResponseMessage winOppRes = await httpClient.PostAsync(serviceUrl + "queues(" + queue[0]["queueid"] + ")/Microsoft.Dynamics.CRM.AddToQueue()",
            new StringContent(content, Encoding.UTF8, "application/json"));
    }
}

まとめ

今回は Action の利用方法を紹介しました。Function と Action を利用
すると、SOAP の利用を完全に置き換えることが可能となります。
是非既存システムの移行を試してください!

- 中村 憲一郎

※本情報の内容(添付文書、リンク先などを含む)は、作成日時点でのものであり、予告なく変更される場合があります