Quantcast
Channel: Japan Microsoft Dynamics 365 Team Blog
Viewing all 589 articles
Browse latest View live

Dynamics CRM 2016 新機能: ソリューションフレームワークの拡張 その 5 SDK サポート

$
0
0

みなさん、こんにちは。

前回に引き続き、Dynamics CRM Online 2016 で拡張されたソリューション
フレームワークの機能を紹介します。前回までで UI での操作を紹介しましたが
今回は SDK での操作を紹介します。

過去の記事は以下のリンクよりご参照ください。

ソリューションフレームワークの拡張 その 1
ソリューションフレームワークの拡張 その 2 パッチソリューション
ソリューションフレームワークの拡張 その 3 ソリューションのマージ
ソリューションフレームワークの拡張 その 4 ソリューションのアップグレード

パッチソリューションの作成 CloneAsPatchRequest

ベースソリューションである ソリューション A、 バージョン 1.0.0.0 が存在する
前提で以下のコードを実行すると新しいパッチを作成できます。

// CloneAsPatchRequest の作成
CloneAsPatchRequest cloneAsPatchRequest = new CloneAsPatchRequest();
// パッチソリューションの表示名を指定
cloneAsPatchRequest.DisplayName = "ソリューション A";
// パッチのバージョンを指定。既存のパッチレベルより大きいバージョンが必須
cloneAsPatchRequest.VersionNumber = "1.0.1.0";
// ベースソリューションの名前 (論理名) を指定
cloneAsPatchRequest.ParentSolutionUniqueName = "SolutionA";

// 処理の実行
CloneAsPatchResponse result = (CloneAsPatchResponse)_serviceProxy.Execute(cloneAsPatchRequest);

ソリューションのマージ CloneAsSolutionRequest

ベースソリューションを複数のパッチソリューションが存在する場合、以下の
コードでソリューションをマージすることができます。

// CloneAsSolutionRequest の作成
CloneAsSolutionRequest cloneAsSolutionRequest = new CloneAsSolutionRequest();
// マージされたソリューションの表示名を指定
cloneAsSolutionRequest.DisplayName = "ソリューション A";
// バージョンを指定。
cloneAsSolutionRequest.VersionNumber = "1.1.0.0";
// ベースソリューションの名前 (論理名) を指定
cloneAsPatchRequest.ParentSolutionUniqueName = "SolutionA";

// 処理の実行
CloneAsSolutionResponse result = (CloneAsSolutionResponse)_serviceProxy.Execute(cloneAsSolutionRequest);

マージソリューションのインポート ImportSolutionRequest

パッチソリューションは通常のインポートと同じ方法でインポートできますが
マージソリューションをインポートする際は、以下コードを使用します。

// ImportSolutionRequest の作成
ImportSolutionRequest importSolutionRequest = new ImportSolutionRequest();
// HoldingSolution プロパティを true に設定
importSolutionRequest.HoldingSolution = true;
// ソリューションをバイト配列をして読み取り
importSolutionRequest.CustomizationFile = System.IO.File.ReadAllBytes(@"<Path>\SolutionA_1_1_0_0_managed.zip");

// インポートの実行
ImportSolutionResponse result = (ImportSolutionResponse)_serviceProxy.Execute(importSolutionRequest);

ソリューションのアップグレード DeleteAndPromoteRequest

マージしたソリューションをリリース環境へインポートした後、以下のコード
でソリューションをアップグレードできます。

// DeleteAndPromoteRequest の作成
DeleteAndPromoteRequest deleteAndPromoteRequest = new DeleteAndPromoteRequest();
// ベースソリューションの名前 (論理名) を指定
deleteAndPromoteRequest.UniqueName = "SolutionA";

// 処理の実行
DeleteAndPromoteResponse result = (DeleteAndPromoteResponse)_serviceProxy.Execute(cloneAsSolutionRequest);

まとめ

複数組織への展開などでも活用できると思いますので、是非ご活用ください。

- 中村 憲一郎

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


Dynamics CRM 2016 SDK 新機能: Web API その 1

$
0
0

みなさん、こんにちは。

今回から数回で、Dynamics CRM 2016 SDK の新機能として、正式版と
なった Web API について紹介します。

概要

Web API は Microsoft Dynamics CRM Online 2015 Update 1 にてプレビュー
���として公開されましたが、今回のリリースで正式版となりました。

尚、Web API のリリースを受け、REST エンドポイントは Deprecated
となり、今後のリリースで機能が削除される可能性がありますので、
ご注意ください。

提供される機能

Web API は以下の機能がサポートされます。

- OData 4.0 プロトコルのサポート: OData 4.0 についての詳細は次の
リンクをご参照ください。 http://www.odata.org/libraries/
- レコードの CRUD (作成、読み取り、更新、削除)
- WhoAmI など組織サービス Execute メソッドで実行される各種
組織要求の実行
- メタデータの操作
- 探索サービス
- ビューの実行など一部特殊な操作
- エンドポイントのバージョニング

プレビューの時はレコードの CRUD と一部の組織要求のみサポート
していましたが、今回のリリースでは SOAP エンドポイントを
置き換えられるだけの機能を提供しています。

サポートされる認証方式

Microsoft Dynamics CRM Online の場合は OAuth 2.0 認証のみ
ですが、設置型の場合は Windows 統合認証もサポートされます。
また Web リソース内から利用する場合は別途認証は不要です。

検証のための事前準備

次回以降で具体的なコードを紹介していきます。Microsoft
Dynamics CRM Online 環境での操作を紹介しますので、以下の
手順でベースとなるプログラムを準備します。

Azure AD への登録

OAuth 2.0 を利用するには、Dynamics CRM Online の認証を行う Azure
AD 上で開発するアプリケーションを事前に登録する必要があります。
以下の手順で登録を行います。

1. ブラウザで http://manage.windowsazure.comへ接続します。

2. Azure サブスクリプションがあるアカウントでログインします。
利用する Dynamics CRM Online とは異なるアカウントでも結構です。

3. 左のメニュー一覧より Active Directory を選択します。

image

4. 利用する Dynamics CRM Online と異なるテナントにログインした場合で
ディレクトリの一覧に Dynamics CRM Online のディレクトリが表示されて
いない場合、以下手順で追加します。Dynamics CRM Online のディレクトリ
が表示されている場合はステップ 10 に進んでください。

5. 新規ボタンをクリックして、APP SERVICE | ACTIVE DIRECTORY より
ディレクトリを選択します。

image

6. カスタム作成をクリックして「既存ディレクトリの使用」を選択します。

image

7. 「サインアウトする準備ができました。」をチェックしてチェック
マークをクリックします。自動的にサインアウトされた後、サインインを
求められるので Dynamics CRM Online の管理者でログインします。

8. ユーザーをディレクトリの管理者にするか聞かれるので承認します。

9. 再度自動的にサインアウトされるので元のアカウントでログインします。

10. ディレクトリ一覧より Dynamics CRM Online のテナントを選択します。

11. アプリケーションタブをクリックして、画面下にある「追加」ボタンを
クリックします。

image

12. 「組織で開発中のアプリケーションを追加」を選択します。

image

13. 名前に「CRM Web API Test」と入力し、「ネイティブクライアント
アプリケーション」を選択して次へ進みます。

image

14. リダイレクト URI に 「http://localhost/webapi」と
入力して、完了します。

image

15. アプリケーション登録後、「構成」タブを選択します。

image

16. 表示されている「クライアント ID」を控えます。

17. 画面下部にある「アプリケーションの追加」をクリックします。

image

18. アプリケーションの一覧より Dynamics CRM Online を選択して
画面右下の完了マークをクリックします。

image

19. デリゲートされたアクセスより「Access CRM Online as organization
users」にチェックを入れます。

20. 画面下部の「保存」ボタンをクリックしたら登録完了です。

コンソールアプリケーションの作成

まず検証で利用するコンソールアプリケーションを準備します。

1. Visual Studio を起動します。新しいプロジェクトより Visual C# の
コンソールアプリケーションを作成します。ここでは名前を
CrmWebAPITest としました。

image

2. Web API は OAuth 2.0 での認証/認可が必要なため、NuGet より
ADAL (Active Directory Authentication Library) を追加します。
プロジェクトを右クリックして、「NuGet パッケージの管理」を
クリックします。

3. 左ペインで「オンライン」を選択して、画面右上の検索窓に
「ADAL」と入力して検索します。

4. 検索結果より 「Active Directory Authentication Library」を選択
してインストールします。

image

5. 同様に 「JSON.NET」もインストールしてください。

image

6. プロジェクト内の「参照設定」を右クリックして「参照の追加」を
クリックします。アセンブリより以下のアセンブリを追加します。

System.Net
System.Net.Http

また以下の using ステートメントを追加します。

using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Net.Http;
using System.Net.Http.Headers;

7. クラスレベルのフィールドとして Main メソッドの前に以下を
追加します。 clientId は先ほど取得したものを入力してください。
※serverUrl をご利用の環境にアドレスに変更してください。

#region クラスレベルメンバー

static string serverUrl = "https://<CRM組織名>.crm7.dynamics.com";
static string authUrl = "https://login.windows.net/common";
static string clientId = "取得したIDを入力";
static string redirectUri = “http://localhost/webapi”;

#endregion クラスレベルメンバー

8. Main メソッドに認証および実行部分とエラーハンドリングのコードを
追加します。

try
{
    AuthenticationContext authContext = new AuthenticationContext(authUrl);
    AuthenticationResult result = authContext.AcquireToken(serverUrl, clientId, new Uri(redirectUri));

    Program app = new Program();
    Task.WaitAll(Task.Run(async () => await app.Run(result.AccessToken)));
}          
catch (System.Exception ex)
{
    Console.WriteLine("エラーが発生しました。");
    Console.WriteLine(ex.Message);
}
finally
{
    Console.WriteLine("Press <Enter> to exit.");
    Console.ReadLine();
}     

9. プログラムを実行するメソッドを追加します。

public async Task Run(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);
    }
}

10. ソリューションをビルドします。参考までのプログラムの
全体を以下に示します。

using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace CrmWebAPITest
{
    class Program
    {
        #region クラスレベルメンバー
        static string serverUrl = "https://<CRM組織名>.crm7.dynamics.com";
        static string authUrl = "https://login.windows.net/common";
        static string clientId = "取得したIDを入力";
        static string redirectUri = “http://localhost/webapi”;

        #endregion クラスレベルメンバー

        public async Task Run(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);
            }
        }

        static void Main(string[] args)
        {
            try
            {
                AuthenticationContext authContext = new AuthenticationContext(authUrl);
                AuthenticationResult result = authContext.AcquireToken(serverUrl, clientId, new Uri(redirectUri));

                Program app = new Program();
                Task.WaitAll(Task.Run(async () => await app.Run(result.AccessToken)));
            }          
            catch (System.Exception ex)
            {
                Console.WriteLine("エラーが発生しました。");
                Console.WriteLine(ex.Message);
            }
            finally
            {
                Console.WriteLine("Press <Enter> to exit.");
                Console.ReadLine();
            }       
        }
    }
}

まとめ

次回から実際の Web API の機能と利用方法を紹介していきます。
お楽しみに!

- 中村 憲一郎

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

Dynamics CRM 2016 SDK 新機能: Web API その 2: ビューを利用したレコードの取得

$
0
0

みなさん、こんにちは。

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

Web API は Microsoft Dynamics CRM Online 2015 Update 1 にて
プレビューとして公開されました。以下の操作はプレビューの時と
同様のコードで実行が可能です。

レコードの作成、読み取り、更新、削除
Upsert を使ったレコードの作成と更新
オプティミスティック同時実行制御
フォーマットされた値の取得
OData クエリの使用例

今回はプレビューから操作方法が変更になっているものとして、ビューを
利用したレコードの取得を紹介します。

概要

ビューを利用したレコードの取得は以下の流れでレコードを取得します。

1. 特定エンティティのビュー一覧を取得します。
2. 取得したビューの情報を利用してレコードの一覧を取得します。

では早速実装していきましょう。

特定エンティティのビュー一覧取得

まず取引先企業エンティティ用のビュー一覧を取得します。

プログラムの実装

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

public async Task RunViewQueries(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.Run(result.AccessToken)));

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

3. 新しく追加した RunViewQueries メソッド内に以下のコードを追加
して、取引先企業用のビュー一覧を取得します。

// 取引先企業ビューの一覧取得
HttpResponseMessage retrieveRes = await httpClient.GetAsync(serviceUrl + "savedqueries?$select=name&$filter=returnedtypecode eq 'account'");
JToken results = JObject.Parse(retrieveRes.Content.ReadAsStringAsync().Result)["value"];

// ビュー名の表示
foreach (JToken result in results)
{
    Console.WriteLine("ビュー名: {0}", result["name"]);
}

動作確認

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

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

image

3. ビューの一覧が表示されることを確認します。

image

4. Enter キーを押下してプログラムを終了します。

ビューを利用したレコードを一覧の取得

次に取得したビューを利用してレコードの一覧を取得します。

プログラムの実装

1. 上記に続いて、以下のコードを追加します。api/data/v8.0/accounts
アドレスに savedQuery=<savedQueryId> を渡すことで、該当の
ビュー定義を利用したレコードを取得出来ます。

// 取引先企業レコードの取得
retrieveRes = await httpClient.GetAsync(serviceUrl + "accounts?savedQuery=" + results[0]["savedqueryid"]);
JToken accounts = JObject.Parse(retrieveRes.Content.ReadAsStringAsync().Result)["value"];

2. 取得した結果を表示します。以下のコードを追加します。

// 取引先企業名の表示
foreach (JToken account in accounts)
{
    Console.WriteLine("取引先企業名: {0}", account["name"]);
}

動作確認

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

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

3. ビューの一覧と 1 つめのビュー定義を利用して取得された
取引先企業一覧が表示されることを確認します。

image

個人ビューの利用

上記の例ではシステムビューを取得して利用しましたが、個人ビューを利用
したい場合は savedqueriesを userqueries に、savedqueryid を userqueryid に、
accounts?savedQuery を accounts?userQuery に書き換えることで対応できます。

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

public async Task RunViewQueries(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 retrieveRes = await httpClient.GetAsync(serviceUrl + "savedqueries?$select=name&$filter=returnedtypecode eq 'account'");
        JToken results = JObject.Parse(retrieveRes.Content.ReadAsStringAsync().Result)["value"];

        // ビュー名の表示
        foreach (JToken result in results)
        {
            Console.WriteLine("ビュー名: {0}", result["name"]);
        }

        // 取引先企業レコードの取得
        retrieveRes = await httpClient.GetAsync(serviceUrl + "accounts?savedQuery=" + results[0]["savedqueryid"]);
        JToken accounts = JObject.Parse(retrieveRes.Content.ReadAsStringAsync().Result)["value"];

        // 取引先企業名の表示
        foreach (JToken account in accounts)
        {
            Console.WriteLine("取引先企業名: {0}", account["name"]);
        }
    }
}

まとめ

今回は Web API 固有の機能としてエンティティビューを利用したレコード
取得を紹介しました。是非お試しください!

- 中村 憲一郎

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

Dynamics CRM 2016 SDK 新機能: Web API その 3: FetchXML を利用したレコードの取得

$
0
0

みなさん、こんにちは。

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

今回は FetchXML を利用したレコードの取得を紹介します。

概要

FetchXML を利用したレコードの取得は以下の流れとなります。

1. FetchXML を定義します。
2. 定義した FetchXML を利用してレコードの一覧を取得します。

では早速実装していきましょう。

FetchXML の作成

今回は高度な検索を利用して FetchXML を作ります。

1. ブラウザで Dynamics CRM 組織に接続して、高度な検索を開きます。

2. 任意の条件作成します。ここでは「自分のアクティブな取引先企業」
ビューの定義をそのまま再利用しました。

3. 「FetchXML のダウンロード」をクリックします。

image

4. ファイルを任意の場所に保存します。

プログラムの実装

1. 前回利用した Visual Studio ソリューションを開きます。

2. FetchXML を UrlEncode するために System.Web.HttpUtility を使うため、
参照を右クリックして「参照の追加」をクリックします。

image

3. アセンブリ | フレームワークより 「System.Web」を選択して「OK」を
クリックします。

image

4. Program.cs ファイルを開きます。新しく以下のメソッドを追加します。

public async Task RunFetchXMLQuery(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);

    }
}

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

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

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

6. 先ほど保存した FetchXML をメモ帳で開き、ダブルクォーテーションを
シングルクォーテーションに変換します。

7. 以下のコードを追加して FetchXML を UrlEncode します。

string fetch = @"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
  <entity name='account'>
    <attribute name='name' />
    <attribute name='address1_city' />
    <attribute name='primarycontactid' />
    <attribute name='telephone1' />
    <attribute name='accountid' />
    <order attribute='name' descending='false' />
    <filter type='and'>
      <condition attribute='ownerid' operator='eq-userid' />
      <condition attribute='statecode' operator='eq' value='0' />
    </filter>
    <link-entity name='contact' from='contactid' to='primarycontactid' visible='false' link-type='outer' alias='accountprimarycontactidcontactcontactid'>
      <attribute name='emailaddress1' />
    </link-entity>
  </entity>
</fetch>";

string encodedFetch = System.Web.HttpUtility.UrlEncode(fetch);

8. 以下のコードを追加します。

HttpResponseMessage retrieveRes = await httpClient.GetAsync(serviceUrl + "accounts?fetchXml=" + encodedFetch);
JToken accounts = JObject.Parse(retrieveRes.Content.ReadAsStringAsync().Result)["value"];

foreach (JToken account in accounts)
{
    Console.WriteLine("取引先企業名: {0}", account["name"]);
}

動作確認

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

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

3. FetchXML で定義したクエリに対応する取引先企業一覧が表示される
ことを確認します。

image

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

public async Task RunFetchXMLQuery(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);

        string fetch = @"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
<entity name='account'>
<attribute name='name' />
<attribute name='address1_city' />
<attribute name='primarycontactid' />
<attribute name='telephone1' />
<attribute name='accountid' />
<order attribute='name' descending='false' />
<filter type='and'>
<condition attribute='ownerid' operator='eq-userid' />
<condition attribute='statecode' operator='eq' value='0' />
</filter>
<link-entity name='contact' from='contactid' to='primarycontactid' visible='false' link-type='outer' alias='accountprimarycontactidcontactcontactid'>
<attribute name='emailaddress1' />
</link-entity>
</entity>
</fetch>";
        string encodedFetch = System.Web.HttpUtility.UrlEncode(fetch);

        // FetchXML の実行
        HttpResponseMessage retrieveRes = await httpClient.GetAsync(serviceUrl + "accounts?fetchXml=" + encodedFetch);
        JToken accounts = JObject.Parse(retrieveRes.Content.ReadAsStringAsync().Result)["value"];

        foreach (JToken account in accounts)
        {
            Console.WriteLine("取引先企業名: {0}", account["name"]);
        }
    }
}

まとめ

実際のシナリオでは定義した FetchXML の条件などをコード内で動的に
変えて実行する場合が多いと思います。是非前回紹介したビューの取得と
組み合わせて利用してみてください。

- 中村 憲一郎

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

Dynamics CRM 2016 SDK 新機能: Web API その 4: Function の利用

$
0
0

みなさん、こんにちは。

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

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

Function 概要

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

Bound と Unbound Function

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

Unbound Function

まず Unbound Function の例として WhoAmI 要求を実装します。

プログラムの実装

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

public async Task RunFunction(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.RunFetchXMLQuery(result.AccessToken)));

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

3. 新しく追加した RunFunctionメソッド内に以下のコードを追加
して、WhoAmI を実行します。

// WhoAmI 要求の実行
HttpResponseMessage whoamiRes = await httpClient.GetAsync(serviceUrl + "WhoAmI");
JToken whoami = JObject.Parse(whoamiRes.Content.ReadAsStringAsync().Result);

// 結果の表示
Console.WriteLine("UserId:{0}", whoami["UserId"]);
Console.WriteLine("OrganizationId:{0}", whoami["OrganizationId"]);
Console.WriteLine("BusinessUnitId:{0}", whoami["BusinessUnitId"]);

動作確認

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

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

image

3. WhoAmI の実行結果が表示されることを確認します。

image

Bound Function

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

Function 定義の確認

まずは Function 定義を確認します。

1. ブラウザで Dynamics CRM 組織にログインします。

2. 新しいタブを開き、以下のアドレスを入力します。
https://<組織名>.crm7.dynamics.com/api/data/v8.0/$metadata

3. XML の結果が表示されたら RetrieveUserPrivileges を検索します。
Function の IsBound 要素が true であることを確認します。第一引数が
Bound するエンティティとなります。また返り値の型とプロパティを
確認しておきます。

image


プログラムの実装

1. 以下のコードを上記のコードに続けて追加します。systemusers(<id>) で
SystemUser を特定して、Microsoft.Dynamics.CRM.RetrieveUserPrivileges() と
続けています。

// RetrieveUserPrivileges  要求の実行
HttpResponseMessage retrieveUserPrivilegesRes = await httpClient.GetAsync(serviceUrl + "systemusers(" + whoami["UserId"] + ")/Microsoft.Dynamics.CRM.RetrieveUserPrivileges()");

2. 以下のコードで結果を表示します。戻り値の型の情報より RolePrivilege が
あることが分かっているため、プロパティを取得しています。

// 結果のデシリアライズ
JToken userPrivileges = JObject.Parse(retrieveUserPrivilegesRes.Content.ReadAsStringAsync().Result)["RolePrivileges"];

// 権限の表示
foreach (JToken userPrivilege in userPrivileges)
{
    Console.WriteLine("Depth: {0}", userPrivilege["Depth"]);
    Console.WriteLine("PrivilegeId: {0}", userPrivilege["PrivilegeId"]);
    Console.WriteLine("BusinessUnitId: {0}", userPrivilege["BusinessUnitId"]);
}

動作確認

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

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

3. 権限の一覧が表示されることを確認します。

image

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

public async Task RunFunction(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);

        // WhoAmI 要求の実行
        HttpResponseMessage whoamiRes = await httpClient.GetAsync(serviceUrl + "WhoAmI");
        JToken whoami = JObject.Parse(whoamiRes.Content.ReadAsStringAsync().Result);

        // 結果の表示
        Console.WriteLine("UserId:{0}", whoami["UserId"]);
        Console.WriteLine("OrganizationId:{0}", whoami["OrganizationId"]);
        Console.WriteLine("BusinessUnitId:{0}", whoami["BusinessUnitId"]);

        // RetrieveUserPrivileges  要求の実行
        HttpResponseMessage retrieveUserPrivilegesRes = await httpClient.GetAsync(serviceUrl + "systemusers(" + whoami["UserId"] + ")/Microsoft.Dynamics.CRM.RetrieveUserPrivileges()");
        JToken userPrivileges = JObject.Parse(retrieveUserPrivilegesRes.Content.ReadAsStringAsync().Result)["RolePrivileges"];

        // 権限の表示
        foreach (JToken userPrivilege in userPrivileges)
        {
            Console.WriteLine("Depth: {0}", userPrivilege["Depth"]);
            Console.WriteLine("PrivilegeId: {0}", userPrivilege["PrivilegeId"]);
            Console.WriteLine("BusinessUnitId: {0}", userPrivilege["BusinessUnitId"]);
        }
    }
}

まとめ

今回は Function の利用方法を紹介しました。次回は Action を
紹介しますので、お楽しみに!

- 中村 憲一郎

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

Microsoft Dynamics CRM 2016 サーバー設置型が公開されました!

$
0
0

みなさん、こんにちは。

今日は Microsoft Dynamics CRM 2016 サーバー関連モジュールの
ダウンロードセンタ―公開のお知らせです。

Microsoft Dynamics CRM Server 2016
https://www.microsoft.com/ja-JP/download/details.aspx?id=50372

Microsoft Dynamics CRM 2016 E-mail Router
https://www.microsoft.com/ja-JP/download/details.aspx?id=50373

Microsoft Dynamics CRM 2016 Report Authoring 拡張
(SQL Server データ ツール サポート付き)
https://www.microsoft.com/ja-JP/download/details.aspx?id=50375

Microsoft Dynamics CRM 2016 言語パック
https://www.microsoft.com/ja-jp/download/details.aspx?id=50371

Microsoft SharePoint Server 2010 用および Microsoft SharePoint Server 2013 用の
Microsoft Dynamics CRM 2016 リスト コンポーネント (複数ブラウザー用)
https://www.microsoft.com/ja-jp/download/details.aspx?id=50374

Microsoft Office Outlook 用 Microsoft Dynamics CRM 2016 (Outlook クライアント)
https://www.microsoft.com/ja-jp/download/details.aspx?id=50370

また MSDN Subscription でも公開されていますので、是非お試しください。

- 中村 憲一郎

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

$
0
0

みなさん、こんにちは。

前回に引き続き、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 の利用を完全に置き換えることが可能となります。
是非既存システムの移行を試してください!

- 中村 憲一郎

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

Dynamics CRM 2016 SDK 新機能: Web API その 6: 代替えキー の利用

$
0
0

みなさん、こんにちは。

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

今回は代替えキーの利用について紹介します。

概要

レコードを特定する際に、既定ではレコードの GUID を利用しますが、
他システム連携時などレコード ID が不明な場合は代替えキーを利用
できます。代替えキーについては以下の記事を参照してください。

Dynamics CRM Online 2015 Update 1 SDK 新機能: 代替えキー

代替えキーの作成

まず代替えキーの設定を行います。

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

2. 設定 | カスタマイズ | システムのカスタマイズより、代替えキーを
設定するエンティティを開きます。今回は取引先企業を使います。

3. キーをクリックします。右側の画面で「新規」ボタンをクリックします。

image

4. キーとなる列を選択します。今回は取引先企業番号をキーとして
指定しました。任意の表示名と名前を付けます。 尚、ここで選択
したキーは全てのレコードで一意である必要があります。

image

5. 「保存して閉じる」をクリックします。状態が保留となります。

image

6. しばらく待ってから画面を更新します。状態が保留中からアクティブに
なると準備完了です。

image

7. 少なくとも 1 件の取引先企業レコードが取引先企業番号を持っている
ことを確認し、存在しない場合には作成してください。

プログラムの実装

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

public async Task RunAlternativeKey (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.RunAlternativeKey(result.AccessToken)));

3. 新しく追加した RunAlternativeKey メソッド内に以下のコードを追加
して、取引先企業番号が存在する取引先企業レコードを取得します。

// 取引先企業番号が存在する取引先企業の取得
HttpResponseMessage accountsRes = await httpClient.GetAsync(serviceUrl + "accounts?$select=name,accountnumber&$filter=accountnumber ne null&$top=1");
JToken accounts = JObject.Parse(accountsRes.Content.ReadAsStringAsync().Result)["value"];

4. 1 件目のレコードの名前を画面に表示します。

// 取引先企業名の表示
Console.WriteLine("取引先企業名: {0}", accounts[0]["name"]);

5. 次は取引先企業番号で同じレコードを取得してみます。以下の
コードを追加します。

// 取引先企業番号が存在する取引先企業の取得
HttpResponseMessage accountWithNumberRes = await httpClient.GetAsync(serviceUrl + "accounts(accountnumber=" + accounts[0]["accountnumber"]  + ")");
JToken account = JObject.Parse(accountsRes.Content.ReadAsStringAsync().Result)["value"];

// 取引先企業名の表示
Console.WriteLine("取引先企業名: {0}", account[0]["name"]);

動作確認

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

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

image

3. 同じレコードが取得できていることを確認します。

image

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

public async Task RunAlternativeKey(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 accountsRes = await httpClient.GetAsync(serviceUrl + "accounts?$select=name,accountnumber&$filter=accountnumber ne null&$top=1");
        JToken accounts = JObject.Parse(accountsRes.Content.ReadAsStringAsync().Result)["value"];

        // 取引先企業名の表示
        Console.WriteLine("取引先企業名: {0}", accounts[0]["name"]);

        // 取引先企業番号が存在する取引先企業の取得
        HttpResponseMessage accountWithNumberRes = await httpClient.GetAsync(serviceUrl + "accounts(accountnumber=" + accounts[0]["accountnumber"]  + ")");
        JToken account = JObject.Parse(accountsRes.Content.ReadAsStringAsync().Result)["value"];

        // 取引先企業名の表示
        Console.WriteLine("取引先企業名: {0}", account[0]["name"]);

    }
}

まとめ

代替えキーはレコード ID 以外を利用してレコードを特定する場合に非常に
有効な手段です。Web API からもキーを利用できるため他システム連携が
よりスムーズに行えます。是非お試しください。

- 中村 憲一郎

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


Dynamics CRM 2016 SDK 新機能: Web API その 7: 複数レコード取得時のページング

$
0
0

みなさん、こんにちは。

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

今回は複数レコードを取得する際のページングについて紹介します。

概要

Web API を利用した複数レコードの取得では、既定で最大 5000 件の
レコードが取得可能です。一度に取得する件数をより少なくすることも、
ページングを使って 5000 件以上のデータも取得が可能です。

取得するレコード数の設定

まずは 5000 件より少ない件数を取得したい場合について説明します。

プログラムの実装

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

public async Task RunPaging(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.RunAlternativeKey(result.AccessToken)));

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

3. 新しく追加した RunPaging メソッド内に以下のコードを追加
して、ページサイズを 10 とします。

// MaxPageSize を 10 に設定
httpClient.DefaultRequestHeaders.Add("Prefer", "odata.maxpagesize=10");

4. 以下のコードを追加して、取引先企業を取得し、件数を表示します。

// 取引先企業番号が存在する取引先企業の取得
HttpResponseMessage accountsRes = await httpClient.GetAsync(serviceUrl + "accounts?$select=name");
JToken accounts = JObject.Parse(accountsRes.Content.ReadAsStringAsync().Result)["value"];

// 件数の表示
Console.WriteLine("レコードの件数:{0} 件", accounts.Count());

動作確認

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

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

image

3. 指定したページングサイズ以下の件数が取得できることを
確認します。

image

ページングの利用

次にページングを利用して残りのレコードを取得します。次のページの
データのアクセスするためのアドレスは、応答より取得が可能です。

プログラムの実装

1. 先ほどのコードに続いて、以下のコードを追加して、先ほど取得した
レコードを表示します。

// レコードの表示
foreach (JToken account in accounts)
{
    Console.WriteLine("取引先企業名: {0}", account["name"]);
}

2. 以下のコードを追加して、次のページのアドレスを取得します。
応答の @odata.nextLink にアドレスが格納されています。

// 次のページリンクを取得
var nextLink = JObject.Parse(accountsRes.Content.ReadAsStringAsync().Result)["@odata.nextLink"];

3. 以下のコードを追加してレコードを取得します。

// 次の 10 件の取得
HttpResponseMessage nextAccountsRes = await httpClient.GetAsync(nextLink.ToString());
JToken nextAccounts = JObject.Parse(nextAccountsRes.Content.ReadAsStringAsync().Result)["value"];

4. 以下のコードを追加 レコードの名前を画面に表示します。

// レコードの表示
foreach (JToken account in nextAccounts)
{
    Console.WriteLine("取引先企業名: {0}", account["name"]);
}

動作確認

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

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

3. 合計で 20 件のレコードが表示されることを確認します。

image

まとめ

うまくページングの機能を利用して、パフォーマンスの調整や
処理すべきレコードをすべて取得できます。是非お試しください!

- 中村 憲一郎

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

Dynamics CRM 2016 SDK 新機能: Web API その 8: バッチ処理実行

$
0
0

みなさん、こんにちは。

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

今回は Web API でのバッチ処理実行について紹介します。

概要

Web  API は複数の操作を同じトランザクションとして実行することが可能
です。取引先企業レコードと同時に関連する取引先担当者を作成するなど、
関連があるレコードの同時処理は、通常の作成処理が利用できます。よって
バッチ処理に適したシナリオは、お互いに関連が無いレコードの操作を同じ
トランザクション内で実行したい場合となります。

複数レコードのバッチ作成

取引先企業 2 件を同じトランザクション内で作成する例を紹介します。
バッチ処理実行を行うためには、複数の要求を MutlPartContent の
一部として追加していきます。

参照の追加

プログラム内で利用するクラスを含むアセンブリを参照します。

1. 参照を右クリックして「参照の追加」をクリックします。

image

2. アセンブリ | 拡張より System.Net.Http.Formatting を選択して
「OK」をクリックします。

image

プログラムの実装

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

public async Task RunBatch(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.RunPaging(result.AccessToken)));

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

3. 新しく追加した RunBatchメソッド内に以下のコードを追加して、
レコードの作成要求を作成します。またトランザクションの処理番号として
固有の Content-ID をヘッダーとして追加します。

// 取引先企業レコードの作成要求
HttpRequestMessage addAccount1 = new HttpRequestMessage(HttpMethod.Post, serviceUrl + "accounts");
addAccount1.Content = new StringContent("{'name':'test1'}", Encoding.UTF8, "application/json");
addAccount1.Content.Headers.Add("Content-ID", "1");

4. 以下のコードを追加して、作成要求を HttpContent にします。

// 作成要求をコンテントに追加
HttpMessageContent addAccountContent1 = new HttpMessageContent(addAccount1);

5. 以下のコードを追加して必要なヘッダー情報を指定します。

// ヘッダーの指定
addAccountContent1.Headers.Remove("Content-Type");
addAccountContent1.Headers.Add("Content-Type", "application/http");
addAccountContent1.Headers.Add("Content-Transfer-Encoding", "binary");

6. 同様に以下のコードで 2 つ目の作成要求を作成します。

// 取引先企業レコードの作成要求
HttpRequestMessage addAccount2 = new HttpRequestMessage(HttpMethod.Post, serviceUrl + "accounts");
addAccount2.Content = new StringContent("{'name':'test2'}", Encoding.UTF8, "application/json");
addAccount2.Content.Headers.Add("Content-ID", "2");

HttpMessageContent addAccountContent2 = new HttpMessageContent(addAccount2);
addAccountContent2.Headers.Remove("Content-Type");
addAccountContent2.Headers.Add("Content-Type", "application/http");
addAccountContent2.Headers.Add("Content-Transfer-Encoding", "binary");

7. 以下のコードを追加して MultipartContent を作成します。これは
トランザクションに含める操作をすべて保持するコンテンツとなります。

// ChangeSet を作成
MultipartContent changeSetContent = new MultipartContent("mixed", "changeset_boundary");

8. 作成済みのコンテンツを追加します。

// 作成要求の追加
changeSetContent.Add(addAccountContent1);
changeSetContent.Add(addAccountContent2);

9. 次に以下のコードを追加してバッチの本体を作成し、上記のコンテンツを
追加します。

// バッチ用のコンテンツを作成し ChangeSet を追加
MultipartContent batchcontent = new MultipartContent("mixed", "batch_boundary");
batchcontent.Add(changeSetContent);

10. 以下のコードを追加して要求を実行します。

// $batch エンドポイントへ要求の実行
HttpResponseMessage batchRes = await httpClient.PostAsync(serviceUrl + "$batch", batchcontent);

動作確認

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

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

image

3. プログラムが完了したらレコードが作成されていることを
確認します。

image

トランザクション処理の確認

次に処理に失敗する要求を追加して、トランザクション処理が実際に
機能するか確認します。事前に先ほど追加したレコードは削除します。

プログラムの変更

バッチ操作実行直前に以下のコードを追加します。以下のコードは
Guid が空のレコードを作成しようとするため失敗します。

// 処理が失敗するレコードの作成要求
HttpRequestMessage addAccount3 = new HttpRequestMessage(HttpMethod.Post, serviceUrl + "accounts");

addAccount3.Content = new StringContent("{'name':'test3','accountid':'00000000-0000-0000-0000-000000000000'}", Encoding.UTF8, "application/json");
addAccount3.Content.Headers.Add("Content-ID", "3");

HttpMessageContent addAccountContent3 = new HttpMessageContent(addAccount3);
addAccountContent3.Headers.Remove("Content-Type");
addAccountContent3.Headers.Add("Content-Type", "application/http");
addAccountContent3.Headers.Add("Content-Transfer-Encoding", "binary");

changeSetContent.Add(addAccountContent3);

動作確認

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

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

3. レコードが 1 件も作成されていない事を確認します。

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

public async Task RunBatch(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);

        // 取引先企業レコードの作成要求
        HttpRequestMessage addAccount1 = new HttpRequestMessage(HttpMethod.Post, serviceUrl + "accounts");
        addAccount1.Content = new StringContent("{'name':'test1'}", Encoding.UTF8, "application/json");
        addAccount1.Content.Headers.Add("Content-ID", "1");

        // 作成要求をコンテントに追加
        HttpMessageContent addAccountContent1 = new HttpMessageContent(addAccount1);
        // ヘッダーの指定
        addAccountContent1.Headers.Remove("Content-Type");
        addAccountContent1.Headers.Add("Content-Type", "application/http");
        addAccountContent1.Headers.Add("Content-Transfer-Encoding", "binary");

        // 取引先企業レコードの作成要求
        HttpRequestMessage addAccount2 = new HttpRequestMessage(HttpMethod.Post, serviceUrl + "accounts");
        addAccount2.Content = new StringContent("{'name':'test2'}", Encoding.UTF8, "application/json");
        addAccount2.Content.Headers.Add("Content-ID", "2");
        HttpMessageContent addAccountContent2 = new HttpMessageContent(addAccount2);
        addAccountContent2.Headers.Remove("Content-Type");
        addAccountContent2.Headers.Add("Content-Type", "application/http");
        addAccountContent2.Headers.Add("Content-Transfer-Encoding", "binary");

        // ChangeSet を作成
        MultipartContent changeSetContent = new MultipartContent("mixed", "changeset_boundary");
        // 作成要求の追加
        changeSetContent.Add(addAccountContent1);
        changeSetContent.Add(addAccountContent2);
        // 処理が失敗するレコードの作成要求
        HttpRequestMessage addAccount3 = new HttpRequestMessage(HttpMethod.Post, serviceUrl + "accounts");
        addAccount3.Content = new StringContent("{'name':'test3','accountid':'00000000-0000-0000-0000-000000000000'}", Encoding.UTF8, "application/json");
        addAccount3.Content.Headers.Add("Content-ID", "3");

        HttpMessageContent addAccountContent3 = new HttpMessageContent(addAccount3);
        addAccountContent3.Headers.Remove("Content-Type");
        addAccountContent3.Headers.Add("Content-Type", "application/http");
        addAccountContent3.Headers.Add("Content-Transfer-Encoding", "binary");

        changeSetContent.Add(addAccountContent3);

        // バッチ用のコンテンツを作成し ChangeSet を追加
        MultipartContent batchcontent = new MultipartContent("mixed", "batch_boundary");
        batchcontent.Add(changeSetContent);

        // $batch エンドポイントへ要求の実行
        HttpResponseMessage batchRes = await httpClient.PostAsync(serviceUrl + "$batch", batchcontent);
    }
}

まとめ

Web サービスを利用した処理における、トランザクションの利用の
サポートは強く要望があった機能の 1 つです。これまではプラグインを
活用するなど工夫が必要でしたが、これからは任意の複数の処理実行の
トランザクション管理ができますので、是非お試しください!

- 中村 憲一郎

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

Dynamics CRM 2016 SDK 新機能: Web API その 9: ユーザーの偽装

$
0
0

みなさん、こんにちは。

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

今回は Web API でのユーザー偽装について紹介します。

概要

現在認証しているユーザーとは異なるアカウントで処理を行いたい
場合に、権限があればユーザーを偽装することが可能です。

必要な権限 

偽装を利用する場合には、prvActOnBehalfOfAnotheruser 権限が
必要です。この権限は「代理人」セキュリティロールを付与するか、
「別のユーザーの代わりに操作します」権限を付与します。

image

プログラムの実装

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

public async Task RunImpersonate(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.RunBatch(result.AccessToken)));

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

3. 新しく追加した RunImpersonate メソッド内に以下のコードを追加して、
ユーザーの ID を取得します。ここでは “crm user 1” ユーザーが存在する
前提としています。

// ユーザー情報の取得
HttpResponseMessage usersRes = await httpClient.GetAsync(serviceUrl + "systemusers?$select=fullname,systemuserid&$filter=fullname eq 'crm user 1'");
JToken user = JObject.Parse(usersRes.Content.ReadAsStringAsync().Result)["value"][0];

4. 以下のコードを追加して、偽装用のヘッダーを追加します。

// 偽装用のヘッダーを追加
httpClient.DefaultRequestHeaders.Add("MSCRMCallerID", user["systemuserid"].ToString());

5. 以下のコードを追加してタスクレコードを作成します。

// タスクの作成
HttpResponseMessage taskRes = await httpClient.PostAsync(serviceUrl + "tasks",
    new StringContent("{'subject':'Impersonate test'}", Encoding.UTF8, "application/json"));

動作確認

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

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

image

3. 作成されたタスクの所有者の作成者と代理実行者を確認します。

image

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

public async Task RunImpersonate(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 usersRes = await httpClient.GetAsync(serviceUrl + "systemusers?$select=fullname,systemuserid&$filter=fullname eq 'crm user 1'");
        JToken user = JObject.Parse(usersRes.Content.ReadAsStringAsync().Result)["value"][0];

        // 偽装用のヘッダーを追加
        httpClient.DefaultRequestHeaders.Add("MSCRMCallerID", user["systemuserid"].ToString());

        // タスクの作成
        HttpResponseMessage taskRes = await httpClient.PostAsync(serviceUrl + "tasks",
            new StringContent("{'subject':'Impersonate test'}", Encoding.UTF8, "application/json"));
    }
}

まとめ

他システム連携などで偽装が必要になることがよくあります。
是非お試しください!

- 中村 憲一郎

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

Dynamics CRM 2016 SDK 新機能: Web API その 10: 現状の制限

$
0
0

みなさん、こんにちは。

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

今回は現時点での Web API の制限について紹介します。

概要

Web API は今回のリリースで正式版となりましたが、まだ一部機能に
制限があります。以下に主な制限の内容を紹介します。

ナビゲーションプロパティ値でのフィルターが行えない

参照フィールドのように特定できる関連の値であっても現時点では
ナビゲーションプロパティの値を利用したフィルターは行えません。

例えば以下の例では、取引先責任者の名前 ’Renee' で取引先企業の
レコードのフィルターをしますが、失敗して501 エラーが返されます。

GET [Organization URI]/api/data/v8.0/accounts?$select=name&$filter=primarycontactid/firstname eq 'Renee' HTTP/1.1
Accept: application/json
OData-MaxVersion: 4.0
OData-Version: 4.0

一部の組織サービス要求に対応する Function か Action がない

以下の組織サービスに対応する Function や Action がまだ存在しません。

BookRequest
CalculateRollupFieldRequest
CheckIncomingEmailRequest
FindParentResourceGroupRequest
GetQuantityDecimalRequest
IncrementKnowledgeArticleViewCountRequest
InitializeFromRequest
IsValidStateTransitionRequest
QualifyLeadRequest
QueryMultipleSchedulesRequest
ReactivateEntityKeyRequest
RemoveItemCampaignActivityRequest
RemoveItemCampaignRequest
RemoveMemberListRequest
RescheduleRequest
RetrieveByResourcesServiceRequest
RetrieveDuplicatesRequest
RetrieveFilteredFormsRequest
RetrieveLocLabelsRequest
RetrievePrincipalAccessRequest
RetrieveRecordWallRequest
SearchByBodyKbArticleRequest
SearchByKeywordsKbArticleRequest
SearchByTitleKbArticleRequest
ValidateRecurrenceRuleRequest

$expand クエリにおける $select クエリが無視される

2 つ以上のナビゲーションプロパティをクエリした際、最後のナビゲーション
プロパティで $select を利用しないと、1 つ目のナビゲーションプロパティは
すべての列を返します。

例えば以下のクエリは取引先企業の名前、関連する担当者の名前、関連する
営業案件の名前だけを返します。

GET [Organization URI]/api/data/v8.0/accounts(D05B5D26-2F99-E511-80DB-C4346BC51068)?$select=name&$expand=contact_customer_accounts($select=fullname),opportunity_customer_accounts($select=name)

しかし最後の select を省略すると、関連する取引先担当者の列も fullname
だけではなく、すべてが返されます。

GET [Organization URI]/api/data/v8.0/accounts(D05B5D26-2F99-E511-80DB-C4346BC51068)?$select=name&$expand=contact_customer_accounts($select=fullname),opportunity_customer_accounts

公開前のメタデータが取得できない

Web API を利用してメタデータを取得することができますが、公開済みの
メタデータのみ取得可能です。メタデータの操作については次回以降で
紹介します。

ナビゲーションプロパティの値がない場合、Null が返されない

OData 4.0 の仕様では、ナビゲーションプロパティの値が存在しない場合
Null が返されるべきですが、現状は項目が返されません。

ActivityPointer をリンクした FetchXML の制限

ActivityPointer をリンクエンティティとして指定した FetchXML を利用
した場合、リンクエンティティ側のフィールド値が返りません。

例えば以下の FetchXML を利用した場合、subject フィールドの値は
返りません。

<fetch version="1.0"
       output-format="xml-platform"
       mapping="logical"
       distinct="true"><entity name="account"><attribute name="name" /><link-entity name="activitypointer"
                 from="regardingobjectid"
                 to="accountid"
                 link-type="inner"><attribute name="subject" /></link-entity></entity></fetch>

まとめ

Web API で開発する場合に、現時点でいくつか制限があることを知っておく必要が
あります。期待した動作をしない場合にはそれが制限であるか、まず SDK をご確認ください。

- 中村 憲一郎

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

Dynamics CRM 2016 SDK 新機能: Web API その 11: 探索サービス

$
0
0

みなさん、こんにちは。

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

今回は Web API の機能より 探索サービスを紹介します。

概要

Web API の探索サービスは、既存探索サービス同様、ユーザーが
所属する組織の情報を取得することができます。

探索サービスの実行

まずは単純にユーザーが所属する組織一覧と詳細を表示します。

プログラムの実装

1. 前回利用した Visual Studio ソリューションを開き、Program.cs
ファイルを開きます。新しく以下のメソッドを追加します。
アドレスが今までと異なり、探索サービス用のアドレスとなります。

探索サービス用のアドレスは環境によって異なります。Microsoft
Dynamics CRM Online の場合はリージョンに一致したアドレスを
ご利用さい。
例) 日本の場合: disco.crm7.dynamics.com
US の場合: disco.crm.dynamics.com

public async Task RunDiscovery(string accessToken)
{
    // HttpClient の作成
    using (HttpClient httpClient = new HttpClient())
    {
        // Web API 探索アドレスの作成
        string serviceUrl = "https://disco.crm7.dynamics.com/api/discovery/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.RunImpersonate(result.AccessToken)));

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

3. 新しく追加した RunDiscoveryメソッド内に以下のコードを追加して、 探索サービスを
実行します。

// ユーザーが所属する組織一覧の取得
HttpResponseMessage orgRes = await httpClient.GetAsync(serviceUrl + "Instances");
JToken orgs = JObject.Parse(orgRes.Content.ReadAsStringAsync().Result)["value"];

4. 以下のコードを追加して、取得結果を表示します。

foreach(JToken org in orgs)
{
    Console.WriteLine("API URL: {0}", org["ApiUrl"]);
    Console.WriteLine("フレンドリー名: {0}", org["FriendlyName"]);
    Console.WriteLine("Id: {0}", org["Id"]);
    Console.WriteLine("ステータス: {0}", org["State"]);
    Console.WriteLine("固有組織名: {0}", org["UniqueName"]);
    Console.WriteLine("アプリケーション URL: {0}", org["Url"]);
    Console.WriteLine("URL名: {0}", org["UrlName"]);
    Console.WriteLine("バージョン: {0}", org["Version"]);
}

動作確認

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

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

image

3. ユーザーが所属する組織の詳細が表示されます。

image

探索サービスを利用したクエリ

探索サービスも OData を利用したクエリが可能です。

プログラムの実装

1. 上記のコードに続いて以下のコードを追加します。ここではバージョンが
8 から始まる組織のフレンドリー名と ID を取得しています。

// ユーザーが所属する組織一覧の取得
HttpResponseMessage org8Res = await httpClient.GetAsync(serviceUrl + "Instances?$select=FriendlyName,Id&$filter=startswith(Version, '8')");
JToken org8s = JObject.Parse(org8Res.Content.ReadAsStringAsync().Result)["value"];

2. 以下のコードを追加して結果を表示します。

foreach (JToken org8 in org8s)
{
    Console.WriteLine("フレンドリー名: {0}", org8["FriendlyName"]);
    Console.WriteLine("Id: {0}", org8["Id"]);                   
}

動作確認

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

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

3. 期待した結果が表示されることを確認します。

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

public async Task RunDiscovery(string accessToken)
{
    // HttpClient の作成
    using (HttpClient httpClient = new HttpClient())
    {
        // Web API 探索アドレスの作成
        string serviceUrl = "https://disco.crm7.dynamics.com/api/discovery/v8.0/";
        // ヘッダーの設定
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

        // ユーザーが所属する組織一覧の取得
        HttpResponseMessage orgRes = await httpClient.GetAsync(serviceUrl + "Instances");
        JToken orgs = JObject.Parse(orgRes.Content.ReadAsStringAsync().Result)["value"];

        foreach(JToken org in orgs)
        {
            Console.WriteLine("API URL: {0}", org["ApiUrl"]);
            Console.WriteLine("フレンドリー名: {0}", org["FriendlyName"]);
            Console.WriteLine("Id: {0}", org["Id"]);
            Console.WriteLine("ステータス: {0}", org["State"]);
            Console.WriteLine("固有組織名: {0}", org["UniqueName"]);
            Console.WriteLine("アプリケーション URL: {0}", org["Url"]);
            Console.WriteLine("URL名: {0}", org["UrlName"]);
            Console.WriteLine("バージョン: {0}", org["Version"]);
        }

        // ユーザーが所属する組織一覧の取得
        HttpResponseMessage org8Res = await httpClient.GetAsync(serviceUrl + "Instances?$select=FriendlyName,Id&$filter=startswith(Version, '8')");
        JToken org8s = JObject.Parse(org8Res.Content.ReadAsStringAsync().Result)["value"];

        foreach (JToken org8 in org8s)
        {
            Console.WriteLine("フレンドリー名: {0}", org8["FriendlyName"]);
            Console.WriteLine("Id: {0}", org8["Id"]);                   
        }
    }
}

まとめ

ユーザーにプログラム実行先の組織を選択させたい場合や、組織の
詳細を動的に取得したい場合に有効です。

さて、こちらの記事が 2015 年最後の記事となりました。今年も 1 年間ご愛読いただき、
誠にありがとうございました。来年も引き続き少しでもお役に立てる記事を出せるよう
チーム全員精進して参りますので、よろしくお願いいたします。

よいお年を!

- 中村 憲一郎

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

Dynamics CRM 2016 SDK 新機能: メタデータ Web API その 1: エンティティ

$
0
0

あけましておめでとうございます。

年末年始はいかがお過ごしだったでしょうか。私は主に Windows
Universal Application を作って遊んでおりました。

今年も Microsoft Dynamics CRM に関連する記事を公開して参り
ますので、ご愛読いただきますようお願いいたします。

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

今回から Web API の機能よりメタデータサービスの詳細を紹介しますが
初回はまずエンティティメタデータの操作を紹介します。

概要

既存の組織サービス同様、Web API を利用してメタデータを操作する
ことが可能です。サポートされる操作は多岐に渡りますが、今回は
エンティティの操作を紹介します。

エンティティの作成

まずカスタムエンティティを作成します。

プログラムの実装

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

public async Task RunEntityMetadata(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.RunDiscovery(result.AccessToken)));

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

3. 新しく追加した RunEntityMetadata メソッド内に以下のコードを追加して、
カスタムエンティティの情報を作成します。

// カスタムエンティティの情報を作成
string customEntityMeta = @"
{
    'SchemaName':'new_SampleEntity',
    'HasActivities':'false',
    'HasNotes':'false',
    'IsActivity':'false',
    'OwnershipType':'UserOwned',
    'DisplayCollectionName': {
        'LocalizedLabels': [{
            'Label': 'サンプルエンティティ',
            'LanguageCode': 1041
        }],
        'UserLocalizedLabel': {
            'Label': 'サンプルエンティティ',
            'LanguageCode': 1041
        }
    },
    'DisplayName': {
        'LocalizedLabels': [{
            'Label': 'サンプルエンティティ',
            'LanguageCode': 1041
        }],
        'UserLocalizedLabel': {
            'Label': 'サンプルエンティティ',
            'LanguageCode': 1041
        }    
    },    
    'PrimaryNameAttribute':'new_name',
    'Attributes':[{
        '@odata.type': '#Microsoft.Dynamics.CRM.StringAttributeMetadata',
        'AttributeType':'String',
        'IsPrimaryName':'true',
        'SchemaName':'new_name',
        'MaxLength':'100',
        'FormatName': {
            'Value': 'Text'
        },
        'RequiredLevel': {
            'Value': 'ApplicationRequired',
            'CanBeChanged': true,
            'ManagedPropertyLogicalName': 'canmodifyrequirementlevelsettings'
        },
        'DisplayName': {
            'LocalizedLabels': [{
                'Label': 'サンプルエンティティ名',
                'LanguageCode': 1041
            }],
            'UserLocalizedLabel': {
                'Label': 'サンプルエンティティ名',
                'LanguageCode': 1041
            }
        }
    }]
}";

4. 以下のコードを追加して、作成要求を送信します。

// カスタムエンティティの作成
HttpResponseMessage createRes = await httpClient.PostAsync(serviceUrl + "EntityDefinitions",
    new StringContent(customEntityMeta, Encoding.UTF8, "application/json"));

動作確認

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

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

image

3. プログラム完了後、カスタムエンティティが作成されて
いることを確認します。

image

image

エンティティの取得

メタデータサービスも OData を利用したクエリが可能です。次の作業に
あたり上記で追加したカスタムエンティティの作成要求はコメントアウト
しておきます。

プログラムの実装

1. 上記のコードに続いて以下のコードを追加します。エンティティの
論理名を利用してフィルターします。

// 作成したエンティティの取得
HttpResponseMessage entityRes = await httpClient.GetAsync(serviceUrl + "EntityDefinitions?$filter=LogicalName eq 'new_sampleentity'");
JToken entity = JObject.Parse(entityRes.Content.ReadAsStringAsync().Result)["value"][0];

2. 以下のコードを追加して結果を表示します。エンティティ���メタ
データは内容が多いため、今回はそのまますべて表示しました。

// 詳細を表示
Console.WriteLine(entity);

動作確認

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

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

3. エンティティの詳細が表示されます。

image

エンティティの削除

更新および削除も通常のレコード同様に行えます。ここでは削除の
方法を紹介します。

プログラムの実装

上記のコードに続いて以下のコードを追加します。レコードの ID に
相当するものとして、MetadataId があります。これを取得した内容から
取り出して、指定しています。

// 作成したエンティティの削除
HttpResponseMessage deleteRes = await httpClient.DeleteAsync(serviceUrl + "EntityDefinitions(" + entity["MetadataId"] + ")");

動作確認

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

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

3. 作成したエンティティが削除されることを確認します。

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

public async Task RunEntityMetadata(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);

        // カスタムエンティティの情報を作成
        string customEntityMeta = @"
        {
            'SchemaName':'new_SampleEntity',
            'HasActivities':'false',
            'HasNotes':'false',
            'IsActivity':'false',
            'OwnershipType':'UserOwned',
            'DisplayCollectionName': {
                'LocalizedLabels': [{
                    'Label': 'サンプルエンティティ',
                    'LanguageCode': 1041
                }],
                'UserLocalizedLabel': {
                    'Label': 'サンプルエンティティ',
                    'LanguageCode': 1041
                }
            },
            'DisplayName': {
                'LocalizedLabels': [{
                    'Label': 'サンプルエンティティ',
                    'LanguageCode': 1041
                }],
                'UserLocalizedLabel': {
                    'Label': 'サンプルエンティティ',
                    'LanguageCode': 1041
                }    
            },    
            'PrimaryNameAttribute':'new_name',
            'Attributes':[{
                '@odata.type': '#Microsoft.Dynamics.CRM.StringAttributeMetadata',
                'AttributeType':'String',
                'IsPrimaryName':'true',
                'SchemaName':'new_name',
                'MaxLength':'100',
                'FormatName': {
                    'Value': 'Text'
                },
                'RequiredLevel': {
                    'Value': 'ApplicationRequired',
                    'CanBeChanged': true,
                    'ManagedPropertyLogicalName': 'canmodifyrequirementlevelsettings'
                },
                'DisplayName': {
                    'LocalizedLabels': [{
                        'Label': 'サンプルエンティティ名',
                        'LanguageCode': 1041
                    }],
                    'UserLocalizedLabel': {
                        'Label': 'サンプルエンティティ名',
                        'LanguageCode': 1041
                    }
                }
            }]
        }";

        // カスタムエンティティの作成
        HttpResponseMessage createRes = await httpClient.PostAsync(serviceUrl + "EntityDefinitions",
          new StringContent(customEntityMeta, Encoding.UTF8, "application/json"));

        Console.WriteLine("Press Enter to continue");
        Console.ReadLine();

        // 作成したエンティティの取得
        HttpResponseMessage entityRes = await httpClient.GetAsync(serviceUrl + "EntityDefinitions?$filter=LogicalName eq 'new_sampleentity'");
        JToken entity = JObject.Parse(entityRes.Content.ReadAsStringAsync().Result)["value"][0];

        // 詳細を表示
        Console.WriteLine(entity);

        Console.WriteLine("Press Enter to continue");
        Console.ReadLine();

        // 作成したエンティティの削除
        HttpResponseMessage deleteRes = await httpClient.DeleteAsync(serviceUrl + "EntityDefinitions(" + entity["MetadataId"] + ")");
               
    }
}

まとめ

メタデータブラウザや初期構成時のエンティティ操作などを
プログラムから行いたい場合利用できます。是非お試しください!

- 中村 憲一郎

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

Dynamics CRM 2016 新機能: 対話型サービス ハブ その 1: 概要

$
0
0

みなさん、こんにちは。

Microsoft Dynamics CRM 2016 がリリースされてから数週間が経ちましたが、
お試しいただいていますでしょうか。Dynamics CRM Online の 30 日間トライアルを申し込むと
Dynamics CRM 2016 の新機能を検証いただくことが可能です、是非お試しください。

今回は、Dynamics CRM 2016 の新機能から対話型サービスハブについて紹介します。

概要

新しい対話型サービスハブは、日常のジョブを単純化するように設計されており、
特に顧客サービス向けに最適化されています。重要な情報が一か所に統合され、
注意を要する事柄に焦点を当てることができます。

これまで提供されていた Dynamics CRM の画面とは異なる画面が提供されます。
これまでのサービス機能はそのまま利用可能ですが、よりタスクベースの顧客サービスを
提供可能したい場合、対話型サービスハブをお勧めいたします。

アクセス方法

対話型サービスハブは、以下の URL にアクセスします。

Microsoft Dynamics CRM (設置型):
http(s)://<CRM Server>/<orgname>/engagementhub.aspx
Microsoft Dynamics CRM Online​​ :
https://<CRM Server>.crm#.dynamics.com/engagementhub.aspx

またログイン直後に出てくるポップアップからアクセスすることも可能です。

1. Dynamics CRM にログインします。

2. 以下画面のメッセージが表示されたら、「今すぐ試す」ボタンをクリックします。

image

3. 別ウィンドが表示されるので、構成が完了するまでしばらく待ちます。

image

4. 対話型サービスハブが表示されます。

image

ダッシュボード

ログインした直後は、ダッシュボードの画面が表示されます。

image

1: ナビゲーションバー

既存機能と同様、ナビゲーションバーよりエンティティのデータにアクセスすることが出来ます。
ナビゲーションには、対話型サービスハブ機能が有効なエンティティのみ表示されます。

2: 最近表示したビュー、最近表示したレコード、簡易作成、マルチ検索

既存機能と同様、最近アクセスしたビューやレコードが表示されます。
また、簡易作成機能や複数エンティティを跨ぐ、マルチ検索機能が利用できます。

3. 時間枠フィルター

時間枠フィルターは、表示されているビューのレコードをさらに特定の期間に
絞り込みたい場合に利用することが出来ます。たとえば、先月、先週、特定の日付、
または今日のデータを表示するよう選択することができます。既定値は先週となっており、
システム全体で一律に変更することが可能です。

この時間枠フィルターは、各レコードの作成日(CreatedOn)に適用されます。

4. 対話型グラフ

左のグラフアイコンをクリックすると、対話型グラフを表示することができます。

image

各グラフの要素にカーソルを当てると、内容がポップアップ表示されます。

image

さらに、その要素をクリックするとドリルダウンすることが出来ます。

image

5. グローバルフィルター

右のフィルターアイコンをクリックすることで、項目ごとにフィルターすることができます。

image

6. 並び替え、プロパティの編集

修正日をクリックすると修正日で並び替えができます。

image

右上の「…」から並び替えるフィールドを変更することが出来ます。

image

image

7. ストリームビュー、タイルビュー

右下にあるアイコンで表示形式を切り替えることが出来ます。

image

[ビュー形式]

image

[タイル形式]

image

有効なエンティティ

既定で有効なエンティティは以下の通りです。

- 取引先企業
- 取引先担当者
- サポート案件
- 活動: 電子メール、タスク、予定、電話、ソーシャル活動
- キュー アイテム
- ダッシュボード​​
- ソーシャル プロファイル

カスタムエンティティもカスタマイズ画面から有効化/無効化の切り替えが行えます。

image

注意点

- iOS や Safari はサポートされません
- ブラウザのプライベートモード(InPrivate)を使用して対話型サービスハブにアクセスすることはできません

まとめ

次回は、各レコードにアクセスした際に操作するフォームについて紹介していきます。

- プレミアフィールドエンジニアリング 河野 高也

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


Dynamics CRM 2016 SDK 新機能: メタデータ Web API その 2: フィールド

$
0
0

みなさん、こんにちは。

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

今回は Web API メタデータサービスの機能より、フィールドのメタ
データ操作を紹介します。

概要

既存の組織サービス同様、Web API を利用してメタデータを操作する
ことが可能です。サポートされる操作は多岐に渡りますが、今回は
フィールドの操作を紹介します。

フィールドの作成

まずカスタムフィールドを作成します。

プログラムの実装

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

public async Task RunFieldMetadata(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.RunEntityMetadata(result.AccessToken)));

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

3. 新しく追加した RunFieldMetadata メソッド内に以下のコードを追加して、
カスタムフィールドを作成するエンティティを取得します。今回は取引先企業に
カスタムフィールドを作成してみます。

// 取引先企業エンティティの取得
HttpResponseMessage entityRes = await httpClient.GetAsync(serviceUrl + "EntityDefinitions?$select=MetadataId&$filter=LogicalName eq 'account'");
JToken entity = JObject.Parse(entityRes.Content.ReadAsStringAsync().Result)["value"][0];

4. 以下のコードを追加して、カスタムフィールドの情報を作成します。

// カスタムフィールドの情報を作成
string customFieldMeta = @"
{    
    '@odata.type': '#Microsoft.Dynamics.CRM.StringAttributeMetadata',
    'Format': 'Text',
    'FormatName': { 'Value': 'Text' },
    'ImeMode': 'Auto',
    'MaxLength': 100,
    'AttributeType': 'String',
    'DisplayName': {
        'LocalizedLabels': [{
            'Label': 'サンプルテキスト列',
            'LanguageCode': 1041
        }],
        'UserLocalizedLabel': {
            'Label': 'サンプルテキスト列',
            'LanguageCode': 1041
        }
    },
    'RequiredLevel': { 'Value': 'ApplicationRequired' },
    'SchemaName': 'new_textfield'
}";

5. 以下のコードを追加して作成要求を送信します。

// カスタムフィールドの作成
HttpResponseMessage createRes = await httpClient.PostAsync(serviceUrl + "EntityDefinitions(" + entity["MetadataId"] + ")/Attributes",
    new StringContent(customFieldMeta, Encoding.UTF8, "application/json"));

動作確認

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

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

image

3. プログラム完了後、カスタムフィールドが作成されて
いることを確認します。

image

フィールドの取得

メタデータサービスも OData を利用したクエリが可能です。次の作業に
あたり上記で追加したカスタムフィールドの作成要求はコメントアウト
しておきます。

プログラムの実装

1. 上記のコードに続いて以下のコードを追加します。フィールドの
論理名を利用してフィルターします。

// 作成したフィールドの取得
HttpResponseMessage fieldRes = await httpClient.GetAsync(serviceUrl + "EntityDefinitions(" + entity["MetadataId"] + ")/Attributes?$filter=LogicalName eq 'new_textfield'");
JToken field = JObject.Parse(fieldRes.Content.ReadAsStringAsync().Result)["value"][0];

2. 以下のコードを追加して結果を表示します。フィールドのメタ
データは内容が多いため、今回はそのまますべて表示しました。

// 詳細を表示
Console.WriteLine(field);

動作確認

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

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

3. フィールドの詳細が表示されます。

image

フィールドの削除

更新および削除も通常のレコード同様に行えます。ここでは削除の
方法を紹介します。

プログラムの実装

上記のコードに続いて以下のコードを追加します。レコードの ID に
相当するものとして、MetadataId があります。これを取得した内容から
取り出して、指定しています。

// 作成したフィールドの削除
HttpResponseMessage deleteRes = await httpClient.DeleteAsync(serviceUrl + "EntityDefinitions(" + entity["MetadataId"] + ")/Attributes(" + field["MetadataId"] + ")");

動作確認

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

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

3. 作成したフィールドが削除されることを確認します。

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

public async Task RunFieldMetadata(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 entityRes = await httpClient.GetAsync(serviceUrl + "EntityDefinitions?$select=MetadataId&$filter=LogicalName eq 'account'");
        JToken entity = JObject.Parse(entityRes.Content.ReadAsStringAsync().Result)["value"][0];

        // カスタムフィールドの定義作成
        string customFieldMeta = @"
        {    
            '@odata.type': '#Microsoft.Dynamics.CRM.StringAttributeMetadata',
            'Format': 'Text',
            'FormatName': { 'Value': 'Text' },
            'ImeMode': 'Auto',
            'MaxLength': 100,
            'AttributeType': 'String',
            'DisplayName': {
                'LocalizedLabels': [{
                    'Label': 'サンプルテキスト列',
                    'LanguageCode': 1041
                }],
                'UserLocalizedLabel': {
                    'Label': 'サンプルテキスト列',
                    'LanguageCode': 1041
                }
            },
            'RequiredLevel': { 'Value': 'ApplicationRequired' },
            'SchemaName': 'new_textfield'
        }";

        // カスタムフィールドの作成
        HttpResponseMessage createRes = await httpClient.PostAsync(serviceUrl + "EntityDefinitions(" + entity["MetadataId"] + ")/Attributes",
            new StringContent(customFieldMeta, Encoding.UTF8, "application/json"));

        Console.WriteLine("Press Enter to continue");
        Console.ReadLine();

        // 作成したフィールドの取得
        HttpResponseMessage fieldRes = await httpClient.GetAsync(serviceUrl + "EntityDefinitions(" + entity["MetadataId"] + ")/Attributes?$filter=LogicalName eq 'new_textfield'");
        JToken field = JObject.Parse(fieldRes.Content.ReadAsStringAsync().Result)["value"][0];

        // 詳細を表示
        Console.WriteLine(field);
        Console.WriteLine("Press Enter to continue");
        Console.ReadLine();

        // 作成したフィールドの削除
        HttpResponseMessage deleteRes = await httpClient.DeleteAsync(serviceUrl + "EntityDefinitions(" + entity["MetadataId"] + ")/Attributes(" + field["MetadataId"] + ")");
    }
}

まとめ

エンティティ同様にフィールドのメタデータ操作ができます。
次回は関連について紹介します。お楽しみに!

- 中村 憲一郎

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

Dynamics CRM 2016 新機能: 対話型サービス ハブ その 2: タスクベース体験

$
0
0

みなさん、こんにちは。

前回に引き続き、Dynamics CRM 2016 の新機能から対話型サービスハブについて紹介します。
前回の記事を見られていない方は、是非ご覧ください。

Dynamics CRM 2016 新機能: 対話型サービス ハブ その 1: 概要

ダッシュボードからフォームへ

利用者は、ダッシュボードにより自身が実施すべきタスクを認識します。
タスクを実行するため、各レコードのフォームに遷移します。

image

以下サポート案件のフォームが表示されます。

image

1: 次のレコード

次のレコードへ遷移することができます。

2. タブ

従来のフォームに比べ、よりタブへのアクセスしやすくなりました。
これにより即座に移動したい場所へ移動することが出来ます。

image

3. 顧客カード

顧客カードによりサポート案件フォーム上から顧客の基本情報を参照することができ、
電話や電子メールにて即座に連絡することが可能です。

image

4. コマンドバー

右上のコマンドバーから従来の機能が利用することが出来ます。

image

5. タイムライン

関係する活動の検索や絞り込み、新たな活動の作成が容易にすることが出来ます。

image

またタイムラインのアイテムを検索することが出来ます。

image

タイムラインの情報を日付や属性により絞り込むことが可能です。

image

image

6. 関連

関連セクションには、2 つの機能が利用できます。

[最近のサポート案件と権利]

最近使用したサポート案件および権利が表示されます。

image

[記事の検索]

特定のキーワードを含むサポート情報記事を検索することもできます。

image

動作確認

ダッシュボードからレコードの作成、変更、削除の操作を確認してみましょう。

新規作成

1. 簡易作成ボタンからサポート案件をクリックします。

image

2. 情報を入力し、保存ボタンをクリックします。

image

3. ダッシュボード上に表示されます。

image

変更

1. ダッシュボードから作成したレコードをクリックします。

2. 業務プロセスに従い入力します。

image

削除

1. フォームの削除コマンドを実行します

image

2. 確認画面から削除を実行します。

image

まとめ

今回は、対話型サービスハブのフォームについてご紹介しました。
次回は、ダッシュボードの詳細な機能を紹介します。

- プレミアフィールドエンジニアリング 河野 高也

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

Dynamics CRM 2016 SDK 新機能: メタデータ Web API その 3: 関連

$
0
0

みなさん、こんにちは。

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

今回は Web API メタデータサービスの機能より、関連のメタデータ
操作を紹介します。

概要

既存の組織サービス同様、Web API を利用してメタデータを操作する
ことが可能です。サポートされる操作は多岐に渡りますが、今回は
関連の操作を紹介します。

1:N 関連の作成

まずは取引先企業と取引先担当者の間に、カスタム 1:N 関連を作成
してみます。

プログラムの実装

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

public async Task RunRelationshipMetadata(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.RunFieldMetadata(result.AccessToken)));

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

3. 新しく追加した RunRelationshipMetadata メソッド内に以下のコードを
追加して、1:N 関連の情報を作成します。

// 1:N 関連の情報を作成
string customRelationshipMeta = @"
{
    '@odata.type': '#Microsoft.Dynamics.CRM.OneToManyRelationshipMetadata',
    'AssociatedMenuConfiguration': {
        'Behavior': 'UseCollectionName',
        'Group': 'Details',
        'Label': {
            'LocalizedLabels': [],
            'UserLocalizedLabel': null
        },
        'Order': 10000
    },
    'CascadeConfiguration': {
        'Assign': 'NoCascade',
        'Delete': 'RemoveLink',
        'Merge': 'Cascade',
        'Reparent': 'NoCascade',
        'Share': 'NoCascade',
        'Unshare': 'NoCascade'
    },
    'ReferencedEntity': 'account',
    'ReferencingEntity': 'contact',
    'SchemaName': 'new_account_contacts',
    'Lookup': {
        'SchemaName':'new_accountId',
        'DisplayName': {
            'LocalizedLabels': [{
                'Label': 'サンプル取引先企業',
                'LanguageCode': 1041
            }],
            'UserLocalizedLabel': {
                'Label': 'サンプル取引先企業',
                'LanguageCode': 1041
            }
        }
    }
}";

4. 以下のコードを追加して作成要求を送信します。

// カスタム 1:N 関連の作成
HttpResponseMessage createRes = await httpClient.PostAsync(serviceUrl + "RelationshipDefinitions",
    new StringContent(customRelationshipMeta, Encoding.UTF8, "application/json"));

動作確認

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

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

image

3. プログラム完了後、カスタム 1:N 関連が作成されて
いることを確認します。

image

関連の取得: システムレベル

次に作成した関連を取得します。関連はシステム全体からでも、特定
エンティティからでも取得できます。次の作業にあたり上記で追加した
1:N 関連の作成要求はコメントアウトしておきます。

プログラムの実装

1. 上記のコードに続いて以下のコードを追加します。ここではシステム
全体から特定の 1:N 関連を取得しています。

// 作成した関連をシステムレベルから取得
HttpResponseMessage relationshipRes = await httpClient.GetAsync(serviceUrl + "RelationshipDefinitions?$filter=SchemaName eq 'new_account_contacts'");
JToken relationship = JObject.Parse(relationshipRes.Content.ReadAsStringAsync().Result)["value"][0];

2. 以下のコードを追加して結果を表示します。

// 詳細を表示
Console.WriteLine(relationship);

動作確認

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

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

3. 関連の詳細が表示されます。

image

関連の取得: エンティティレベル

次に取引先企業のメタデータから関連を取得します。

プログラムの実装

1. 上記のコードに続いて以下のコードを追加して、取引先企業の
メタデータ ID を取得します。

// 取引先企業エンティティの取得
HttpResponseMessage entityRes = await httpClient.GetAsync(serviceUrl + "EntityDefinitions?$select=MetadataId&$filter=LogicalName eq 'account'");
JToken entity = JObject.Parse(entityRes.Content.ReadAsStringAsync().Result)["value"][0];

2. 以下のコードを追加して関連を取得します。エンティティの
メタデータから /OneToManyRelationships ナビゲーションで
1:N 関連を取得できます。

// 関連をエンティティレベルから取得
HttpResponseMessage relationshipRes2 = await httpClient.GetAsync(serviceUrl + "EntityDefinitions(" + entity["MetadataId"] + ")/OneToManyRelationships?$filter=SchemaName eq 'new_account_contacts'");
JToken relationship2 = JObject.Parse(relationshipRes2.Content.ReadAsStringAsync().Result)["value"][0];

3. 以下のコードを追加して結果を表示します。

// 詳細を表示
Console.WriteLine(relationship2);

動作確認

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

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

3. 関連の詳細が表示されます。

関連の削除

更新および削除も通常のレコード同様に行えます。ここでは削除の
方法を紹介します。

プログラムの実装

上記のコードに続いて以下のコードを追加します。レコードの ID に
相当するものとして、MetadataId があります。これを取得した内容から
取り出して、指定しています。

// 作成した関連の削除
HttpResponseMessage deleteRes = await httpClient.DeleteAsync(serviceUrl + "RelationshipDefinitions(" + relationship["MetadataId"] + ")");

動作確認

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

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

3. 作成した 1:N 関連が削除されることを確認します。

N:N 関連の作成

N:N 関連の作成も基本的には同じ手法で行いますが、以��の点が
異なります。

作成時に指定するタイプ:
"@odata.type": "Microsoft.Dynamics.CRM.ManyToManyRelationshipMetadata"

エンティティメタデータからのナビゲーション
EntityDefinitions(<MetadataId>/ManyToManyRelationships

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

public async Task RunRelationshipMetadata(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:N 関連の情報を作成
        string customRelationshipMeta = @"
        {
            '@odata.type': '#Microsoft.Dynamics.CRM.OneToManyRelationshipMetadata',
            'AssociatedMenuConfiguration': {
                'Behavior': 'UseCollectionName',
                'Group': 'Details',
                'Label': {
                    'LocalizedLabels': [],
                    'UserLocalizedLabel': null
                },
                'Order': 10000
            },
            'CascadeConfiguration': {
                'Assign': 'NoCascade',
                'Delete': 'RemoveLink',
                'Merge': 'Cascade',
                'Reparent': 'NoCascade',
                'Share': 'NoCascade',
                'Unshare': 'NoCascade'
            },
            'ReferencedEntity': 'account',
            'ReferencingEntity': 'contact',
            'SchemaName': 'new_account_contacts',
            'Lookup': {
                'SchemaName':'new_accountId',
                'DisplayName': {
                    'LocalizedLabels': [{
                        'Label': 'サンプル取引先企業',
                        'LanguageCode': 1041
                    }],
                    'UserLocalizedLabel': {
                        'Label': 'サンプル取引先企業',
                        'LanguageCode': 1041
                    }
                }
            }
        }";

        // カスタム 1:N 関連の作成
        HttpResponseMessage createRes = await httpClient.PostAsync(serviceUrl + "RelationshipDefinitions",
            new StringContent(customRelationshipMeta, Encoding.UTF8, "application/json"));

        // 作成した関連をシステムレベルから取得
        HttpResponseMessage relationshipRes = await httpClient.GetAsync(serviceUrl + "RelationshipDefinitions?$filter=SchemaName eq 'new_account_contacts'");
        JToken relationship = JObject.Parse(relationshipRes.Content.ReadAsStringAsync().Result)["value"][0];

        // 詳細を表示
        Console.WriteLine(relationship);

        // 取引先企業エンティティの取得
        HttpResponseMessage entityRes = await httpClient.GetAsync(serviceUrl + "EntityDefinitions?$select=MetadataId&$filter=LogicalName eq 'account'");
        JToken entity = JObject.Parse(entityRes.Content.ReadAsStringAsync().Result)["value"][0];

        // 関連をエンティティレベルから取得
        HttpResponseMessage relationshipRes2 = await httpClient.GetAsync(serviceUrl + "EntityDefinitions(" + entity["MetadataId"] + ")/OneToManyRelationships?$filter=SchemaName eq 'new_account_contacts'");
        JToken relationship2 = JObject.Parse(relationshipRes2.Content.ReadAsStringAsync().Result)["value"][0];

        Console.WriteLine(relationship2);

        // 作成した関連の削除
        HttpResponseMessage deleteRes = await httpClient.DeleteAsync(serviceUrl + "RelationshipDefinitions(" + relationship["MetadataId"] + ")");
    }
}

まとめ

次回はオプションセットについて紹介します。
お楽しみに!

- 中村 憲一郎

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

Dynamics CRM 2016 SDK 新機能: メタデータ Web API その 4: グローバルオプションセット

$
0
0

みなさん、こんにちは。

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

今回は Web API メタデータサービスの機能より、グローバルの
オプションセットメタデータ操作を紹介します。

概要

オプションセットにはグローバルオプションセットとフィールド
レベルのオプションセットがありますが、今回はグローバルの
オプションセット操作を紹介します。

オプションセットの作成

まずカスタムのグローバルオプションセットを作成します。

プログラムの実装

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

public async Task RunGlobalOptionSet(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.RunRelationshipMetadata(result.AccessToken)));

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

3. 新しく追加した RunGlobalOptionSet メソッド内に以下のコードを
追加して、グローバルオプションセットの情報を作成します。

// グローバルオプションセットの情報を作成
string globalOptionSetMeta = @"
{
    '@odata.type': '#Microsoft.Dynamics.CRM.OptionSetMetadata',
    'Options': [
        {
            'Value': 10000,
            'Label': {
                'LocalizedLabels': [{
                    'Label': 'オプション 1',
                    'LanguageCode': 1041
                }],
                'UserLocalizedLabel': {
                    'Label': 'オプション 1',
                    'LanguageCode': 1041
                }
            },
            'Description': {    
                'LocalizedLabels': [],
                'UserLocalizedLabel': null
            }
        },
        {
            'Value': 10001,  
            'Label': {      
                'LocalizedLabels': [{
                    'Label': 'オプション 2',
                    'LanguageCode': 1041
                }],
                'UserLocalizedLabel': {
                    'Label': 'オプション 1',
                    'LanguageCode': 1041
                }
            },
            'Description': {
                'LocalizedLabels': [],
                'UserLocalizedLabel': null
            }   
        }
    ],
    'Description': {
        'LocalizedLabels': [{
            'Label': 'カスタムのグローバルオプションセットです。',
            'LanguageCode': 1041
        }],
        'UserLocalizedLabel': {
            'Label': 'カスタムのグローバルオプションセットです。',
            'LanguageCode': 1041
        }
    },
    'DisplayName': {
        'LocalizedLabels': [{
            'Label': 'カスタムグローバルオプションセット',
            'LanguageCode': 1041
        }],
        'UserLocalizedLabel': {
            'Label': 'カスタムグローバルオプションセット',
            'LanguageCode': 1041
        }
    },
    'Name': 'new_CustomOptionSet',
    'OptionSetType': 'Picklist'    
}";

4. 以下のコードを追加して作成要求を送信します。

// カスタムグローバルオプションセットの作成
HttpResponseMessage createRes = await httpClient.PostAsync(serviceUrl + "GlobalOptionSetDefinitions",
    new StringContent(globalOptionSetMeta , Encoding.UTF8, "application/json"));

動作確認

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

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

image

3. プログラム完了後、カスタムグローバルオプションセットが
作成されていることを確認します。

image

オプションセットの取得

次に作成したグローバルオプションセットを取得します。
GlobalOptionSetDefinitions は filter クエリをサポートして��ないため、
詳細を取得するには MetadataId を知る必要があります。次の作業に
あたり、上記で追加したグローバルオプションセットの作成要求は
コメントアウトしておきます。

プログラムの実装

1. 上記のコードに続いて以下のコードを追加します。グローバル
オプションセットをすべてクエリしますが、MetadataId と Name
だけを取得します。

// グローバルオプションセットの取得
HttpResponseMessage optionSetRes = await httpClient.GetAsync(serviceUrl + "GlobalOptionSetDefinitions?$select=MetadataId,Name");
                JToken optionSets = JObject.Parse(optionSetRes.Content.ReadAsStringAsync().Result)["value"];

2. 以下のコードを追加して、作成したグローバルオプションセットの
MetadataId を取得します。

// MetadataId の取得
var metadataId = optionSets.Where(x => (string)x["Name"] == "new_customoptionset").First()["MetadataId"];

3. 以下のコードを追加して詳細を取得します。

// 作成したカスタムグローバルオプションセットの取得
optionSetRes = await httpClient.GetAsync(serviceUrl + "GlobalOptionSetDefinitions(" + metadataId + ")");
JToken optionSet = JObject.Parse(optionSetRes.Content.ReadAsStringAsync().Result);

4. 結果を表示します。

// 詳細を表示
Console.WriteLine(optionSet);

動作確認

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

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

3. グローバルオプションセットの詳細が表示されます。

image

オプションの追加

次に作成したカスタムグローバルオプションセットに新しい
オプションを追加してみます。新規オプションの追加は
InsertOptionValue アクションを実行する必要があります。
アクションについてはこちらの記事を参照してください。

プログラムの実装

1. 上記のコードに続いて以下のコードを追加して、追加する
オプションを定義します。

// 追加するオプションの定義
string newOption = @"{
    'OptionSetName': 'new_customoptionset',
    'Value': 10002,
    'Label': {
        'LocalizedLabels': [{
            'Label': 'オプション 3',
            'LanguageCode': 1041
        }],
        'UserLocalizedLabel': {
            'Label': 'オプション 3',
            'LanguageCode': 1041
        }
    },
    'Description': {    
        'LocalizedLabels': [],
        'UserLocalizedLabel': null
    }
}";

2. 以下のコードを追加して InsertOptionValue Action を実行
します。

// オプションの追加
HttpResponseMessage updateOptionRes = await httpClient.PostAsync(serviceUrl + "InsertOptionValue",
    new StringContent(newOption, Encoding.UTF8, "application/json"));

動作確認

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

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

3. プログラム実行完了後、オプションが追加された事を確認します。

image

オプションの削除

次に既存のオプションを削除してみます。オプションセットの削除は
DeleteOptionValue アクションを利用します。次の操作のため、上記で
追加したオプションの追加はコメントアウトします。

プログラムの実装

1. 以下のコードを追加して、削除するオプションを定義します。

// 削除するオプションの定義
string removeOption = @"{
    'OptionSetName': 'new_customoptionset',
    'Value': 10000
}";

2. 以下のコードを追加して DeleteOptionValue Action を実行
します。

// オプションの削除
HttpResponseMessage removeOptionRes = await httpClient.PostAsync(serviceUrl + "DeleteOptionValue",
      new StringContent(removeOption, Encoding.UTF8, "application/json"));

動作確認

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

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

3. 指定したオプションが削除されていることを確認します。

image

グローバルオプションセットの削除

最後のカスタムグローバルオプションセットを削除します。次の
操作のために、上記で追加したオプションの削除コードはコメント
アウトしておきます。

プログラムの実装

以下のコードを追加して、削除するオプションを定義します。

// カスタムグローバルオプションセットの削除
HttpResponseMessage deleteRes = await httpClient.DeleteAsync(serviceUrl + "GlobalOptionSetDefinitions(" + metadataId + ")");

動作確認

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

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

3. カスタムグローバルオプションセットが削除されていることを
確認します。

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

public async Task RunGlobalOptionSet(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);

        string globalOptionSetMeta = @"
        {
            '@odata.type': '#Microsoft.Dynamics.CRM.OptionSetMetadata',
            'Options': [
                {
                    'Value': 10000,
                    'Label': {
                        'LocalizedLabels': [{
                            'Label': 'オプション 1',
                            'LanguageCode': 1041
                        }],
                        'UserLocalizedLabel': {
                            'Label': 'オプション 1',
                            'LanguageCode': 1041
                        }
                    },
                    'Description': {    
                        'LocalizedLabels': [],
                        'UserLocalizedLabel': null
                    }
                },
                {
                    'Value': 10001,  
                    'Label': {      
                        'LocalizedLabels': [{
                            'Label': 'オプション 2',
                            'LanguageCode': 1041
                        }],
                        'UserLocalizedLabel': {
                            'Label': 'オプション 1',
                            'LanguageCode': 1041
                        }
                    },
                    'Description': {
                        'LocalizedLabels': [],
                        'UserLocalizedLabel': null
                    }   
                }
            ],
            'Description': {
                'LocalizedLabels': [{
                    'Label': 'カスタムのグローバルオプションセットです。',
                    'LanguageCode': 1041
                }],
                'UserLocalizedLabel': {
                    'Label': 'カスタムのグローバルオプションセットです。',
                    'LanguageCode': 1041
                }
            },
            'DisplayName': {
                'LocalizedLabels': [{
                    'Label': 'カスタムグローバルオプションセット',
                    'LanguageCode': 1041
                }],
                'UserLocalizedLabel': {
                    'Label': 'カスタムグローバルオプションセット',
                    'LanguageCode': 1041
                }
            },
            'Name': 'new_CustomOptionSet',
            'OptionSetType': 'Picklist'    
        }";

        // カスタムグローバルオプションセットの作成
        HttpResponseMessage createRes = await httpClient.PostAsync(serviceUrl + "GlobalOptionSetDefinitions",
            new StringContent(globalOptionSetMeta, Encoding.UTF8, "application/json"));

        // グローバルオプションセットの取得
        HttpResponseMessage optionSetRes = await httpClient.GetAsync(serviceUrl + "GlobalOptionSetDefinitions?$select=MetadataId,Name");
        JToken optionSets = JObject.Parse(optionSetRes.Content.ReadAsStringAsync().Result)["value"];
               
        // MetadataId の取得
        var metadataId = optionSets.Where(x => (string)x["Name"] == "new_customoptionset").First()["MetadataId"];

        // 作成したカスタムグローバルオプションセットの取得
        optionSetRes = await httpClient.GetAsync(serviceUrl + "GlobalOptionSetDefinitions(" + metadataId + ")");
        JToken optionSet = JObject.Parse(optionSetRes.Content.ReadAsStringAsync().Result);

        // 詳細の表示
        Console.WriteLine(optionSet);
                               
        // 追加するオプションの定義
        string newOption = @"{
            'OptionSetName': 'new_customoptionset',
            'Value': 10002,
            'Label': {
                'LocalizedLabels': [{
                    'Label': 'オプション 3',
                    'LanguageCode': 1041
                }],
                'UserLocalizedLabel': {
                    'Label': 'オプション 3',
                    'LanguageCode': 1041
                }
            },
            'Description': {    
                'LocalizedLabels': [],
                'UserLocalizedLabel': null
            }
        }";

        // オプションの追加
        HttpResponseMessage updateOptionRes = await httpClient.PostAsync(serviceUrl + "InsertOptionValue",
            new StringContent(newOption, Encoding.UTF8, "application/json"));

        // 削除するオプションの定義
        string removeOption = @"{
            'OptionSetName': 'new_customoptionset',
            'Value': 10000
        }";

        // オプションの削除
        HttpResponseMessage removeOptionRes = await httpClient.PostAsync(serviceUrl + "DeleteOptionValue",
            new StringContent(removeOption, Encoding.UTF8, "application/json"));

        // カスタムグローバルオプションセットの削除
        HttpResponseMessage deleteRes = await httpClient.DeleteAsync(serviceUrl + "GlobalOptionSetDefinitions(" + metadataId + ")");
    }
}

まとめ

Web API のメタデータ機能紹介は今回で終わりとなりますがいかが
だったでしょうか。今後の開発では組織サービスと合わせて Web API
も是非ご検討ください。

- 中村 憲一郎

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

Dynamics CRM 2016 新機能: 対話型サービス ハブ その 3: ダッシュボード

$
0
0

みなさん、こんにちは。

前回に引き続き、Dynamics CRM 2016 の新機能から対話型サービスハブについて紹介します。  
今回は、対話型サービスハブのダッシュボードの詳細を紹介していきます。

Dynamics CRM 2016 新機能: 対話型サービス ハブ その 1: 概要
Dynamics CRM 2016 新機能: 対話型サービス ハブ その 2: タスクベース体験

ダッシュボードの種類

対話型サービスハブには、2 つの新しいダッシュボードの種類が追加されました。

マルチストリーム

複数のストリーム(エンティティのビューまたはキュー)でデータを分析することができます。
以下の例では、「アクティブなサポート案件ビュー」「自分の下書き電子メールビュー」など
4 つのストリームを一つのダッシュボード内で分析することが出来ます。

image

単一ストリーム

シンプルに単一の切り口だけでデータを分析したい場合に利用します。

image

タイルでは、タイル固有のストリームに該当するレコード数が表示され、個々のレコードへアクセスすることができます。

image image

標準で準備されているダッシュボード

対話型サービスハブには、標準でダッシュボードのメニューから選択できるダッシュボードと
エンティティ固有のダッシュボードが準備されます。

ダッシュボードのメニューから選択できるダッシュボード

image

- マルチストリーム: ナレッジマネージャー

主にナレッジ管理を担当するマネージャーが利用するためのマルチストリームダッシュボードです。
提案された記事、レビューが必要な記事のビューなど記事の管理業務に必要な情報がまとめられています。

image

- 単一ストリーム: 自分のサポート情報ダッシュボード

自分が作成した記事を分析することが出来ます。

image

- マルチストリーム: Tier 1 Dashboard

主に顧客サービスの担当者が利用するマルチストリームダッシュボードです。
アクティブなサポート案件から自分の下書き電子メールのビューなどサポート担当者に必要な
複数エンティティの情報がまとめられています。

image

- 単一ストリーム: Tier 2 Dashboard

サポート案件顧客サービスの担当者が利用するマルチストリームダッシュボードです。
アクティブなサポート案件から自分の下書き電子メールのビューなどサポート担当者に必要な
複数エンティティの情報がまとめられています。

image

エンティティ固有のダッシュボード

エンティティ固有のダッシュボードを作成することが出来ます。
サポート案件エンティティ固有のダッシュボードを表示する場合、以下の通りアクセスします。

1. 対話型サービスハブにアクセスします。

2. サービス | サポート案件 にアクセスします。

image

3. 左下のアイコンをクリックします。

image

4. サポート案件エンティティ固有のダッシュボードが表示されます。
エンティティ固有のダッシュボードは、マルチストリームのみ作成することが出来ます。

image

ビュー、コマンドバー

対話型サービスハブは、ダッシュボードからタスクを実行するようにデザインされていますが、
ナビゲーションより各エンティティへアクセスする方法も提供しています。

1. 対話型サービスハブにアクセスします。

2. サービス | サポート案件 にアクセスします。

image

3. 自分のアクティブなサポート案件ビューが表示されます。

image

4. 下部にあるアルファベットをクリックすることでレコードを絞り込むことができます。

image

5. ビューのレコードを選択するとコマンドバーが動的に切り替わります。

image

まとめ

次回は、対話型サービスハブのナレッジ管理について紹介していきます。

- プレミアフィールドエンジニアリング 河野 高也

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

Viewing all 589 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>