Dynamics CRM 2011 サンプル紹介 REST エンドポイントを利用した JScript

みなさん、こんにちは。

前回宣言したとおり、今回から数回に渡り、REST エンドポイントの使い方を
紹介したいと思います。SDK には有用なサンプルが多く含まれているため
そこからいくつか紹介していきたいと思いますので、よろしくお願いします。

今回はまず REST エンドポイントを利用した JScript のサンプルです。
サンプル自体は SDK にあり、簡単に動作を確認できますが、この記事では
各ラインの意味や、その裏側で起こっていることに着目して解説をします。

サンプルは、sdk\samplecode\js\restendpoint\jscriptrestdataoperations\
にあるものを利用します。動作を試すために、事前にこのフォルダにある
jscriptrestdataoperations_1_0_0_0_managed.zip ファイルを、
ソリューションとしてインポートしておいてください。

このサンプルでは、REST エンドポイントを利用する JScript を記述して、
取引先企業を作成、作成したレコードの取得、更新そして削除を行っています。

では先にスクリプトから解説します。

JScript サンプル

まず変数を定義して、そこにサーバーの URL 等の情報を取り込みます。
以前の記事で、Xrm.Page.context を利用してサーバーや組織の情報を
取得する方法を解説しましたが、この方法は Form 上に読み込まれた
JScript でのみ利用可能です。今回の JScript は HTML 上に読み込み
実行する予定となっているため、代替手段を利用します。

ClientGlobalContext.js.aspx
Form 外の JScript から context を取得するためのライブラリです。
このファイルを読み込んでから、GetGlobalContext() 関数を実行して
context を取得します。

今回のサンプルでは、JScript をホストする HTML 側でこのファイルを
読み込むことにしていますので、このスクリプト内では、関数を直接
実行しています。

ではサンプルコードのはじめの部分を見ていきましょう。

変数の定義
ここでは 4 つの変数を定義しています。

var ODataPath; // REST エンドポイントのパス用変数
var startTime; // 処理の実行開始時間用変数
var accountName = "Sample Account"; // 作成する取引先企業名用の変数
var serverUrl; // 実行している CRM 2011 サーバーの URL 用変数

エントリ関数の作成
次に HTML が読み込まれた際に実行さるエントリの関数を定義します。

function init() {
// context の取得
// ClientGlobalContext.js.aspx で提供されている関数で context を取得
var context = GetGlobalContext(); 
// 取得した context を利用してサーバーの URL を取得
serverUrl = context.getServerUrl();
// REST エンドポイントのパスを組み合わせて ODataPath を作成
ODataPath = serverUrl + "/XRMServices/2011/OrganizationData.svc";
// 処理の実行開始時間を取得
startTime = new Date();
createAccountRecord(accountName);
}

エントリ関数で各種変数の初期化を行い、最後に createAccountRecord
関数を実行しています。では次に createAccountRecord を見ていきましょう。

createAccountRecord 関数
この関数では、実際に取引先企業のレコードを作成します。途中で
オブジェクトを JSON 形式にシリアライズするために、json2.js ライブラリの
stringify メソッド を使っていますが、こちらもホストとなる HTML で読み込む前提です。

function createAccountRecord(Name) {
// 画面に今から取引先企業のレコードを作成する旨表示
// 尚、showMessage は独自関数で、サンプルの下部に定義
showMessage("createAccountRecord function START");
// 取引先企業のデータを保持するためのオブジェクトを作成
var account = new Object();
// 取引先企業名を設定
account.Name = Name;
// json2.js ライブラリの stringify を使ってオブジェクトを JSON 形式
// 文字列にシリアライズする
var jsonAccount = window.JSON.stringify(account);

// HttpRequest の作成 
var createAccountReq = new XMLHttpRequest();
// REST エンドポイントに AccountSet を付加して接続をオープン
// レコード作成に使う HTTP 動詞として POST を指定
createAccountReq.open("POST", ODataPath + "/AccountSet", true);
// Http リクエストのヘッダー設定
createAccountReq.setRequestHeader("Accept", "application/json");
createAccountReq.setRequestHeader("Content-Type", "application/json; charset=utf-8");
// 処理は非同期で行われるため、リクエストの結果が返った場合
// (状態が変化した場合) に実行するコールバック用の関数を設定
// この関数が、実際の処理後に呼ばれる
createAccountReq.onreadystatechange = function () {
  createAccountReqCallBack(this);
};
// HttpRequest を送信
createAccountReq.send(jsonAccount);
// 画面にこの関数の呼び出しが完了したことを表示
showMessage("createAccountRecord function END");
}

さてここで、先日紹介した REST エンドポイントが実際に使われています。
HTTP 動詞の POST を利用して、JSON 形式でシリアライズしたデータを渡し、
レコードの作成を試みています。

またこの処理は非同期で行われるため、仮にサーバー側でこの処理に
10秒かかったとしても、UI の応答がなくなることはなく、ユーザーは、
引き続き画面の操作を行うことが可能です。

createAccountReqCallBack 関数
サーバー側の処理が終わった段階で HTTPRequest の状態が変わり、
先ほど指定した createAccountReqCallBack 関数が呼ばれます。

function createAccountReqCallBack(createAccountReq) {
// HTTPRequest の状態を確認して、完了か判断
if (createAccountReq.readyState == 4 /* complete */) {
   // 完了の場合、成功か確認
  if (createAccountReq.status == 201) {
   // 成功の場合、json2.js の parse 関数を使って HTTPResponse として
   // 返って来た文字列をオブジェクトにデシリアライズ
   var newAccount = JSON.parse(createAccountReq.responseText).d;
   // オブジェクトに戻っているので、.AccountId という形式で ID を取得でき
   // その結果を画面に表示
   showMessage("ACTION: Created new account id:{" + newAccount.AccountId + "}.");

   // 次のステップとして retrieveAccountRecord 関数を呼び出し
   retrieveAccountRecord(newAccount.AccountId);
   showMessage("createAccountReqCallBack function success END");
  }
  else {
   // 失敗の場合
   // エラーハンドラ関数に引渡しでメッセージを表示
   // 尚、errorHandler は独自関数で、サンプルの下部に定義
   errorHandler(createAccountReq);
   showMessage("createAccountReqCallBack function failure END");
  }
}
};

その他の処理
サンプルではその後、レコードの取得、更新、削除を行いますが、それぞれ
GET、MERGE、DELETE とデータを REST エンドポイントに渡していくだけで
同じような流れとなっています。

ホストする HTML ファイル

次に、このスクリプトファイルをホストする HTML ファイルを解説します。
HTML ファイルは Web リソースとして Dynamics CRM 2011 に保存されます。
今回このファイルは以下のファイル名で保存されます。

sample_/JScriptRESTDataOperation.htm

これはどういうことでしょうか。画面で見ると以下のようになります。
image

sample は発行元の接頭辞ですが、その後にあえてスラッシュを入れることで、
接頭辞を 1 つの階層にしています。結果固有の URL は以下のようになります。
https://[CRM組織URL]/WebResources/sample_/JScriptRESTDataOperations.htm

では HTML の中身を見ていきましょう。まず head のセクションで、利用する script
ファイルを読み込みます。はじめに読み込むファイルは ClientGlobalContext.js.aspx
ですが、このファイルは WebResources 直下に存在します。接頭辞の sample_ を
1 つの階層としたので、1 上の階層に戻れば、ClientGlobalContext.js.aspx を指定
することが可能なため、相対パスを使っています。

<script src="../ClientGlobalContext.js.aspx"></script>

次に json2.js ファイルと今回解説した JScript ファイルを読み込みますが、これらは
以下のようなパス指定で Web リソースに保存されています。
image

HTML ファイル同様に接頭辞を 1 つの階層とみなしていますが、さらに Scripts
という階層を指定しています。よって以下のような相対パスを使っています。

<script src="Scripts/json2.js" type="text/javascript"></script>
<script src="Scripts/JScriptRESTDataOperations.js" type="text/javascript"></script>

head セクションが終わると、body に div だけ作成し、最後にエントリ関数を
呼出して終わっています。

<body>
    <div id="status" />
</body>
</html>       
<script type="text/jscript">
init();
</script>

動作の確認
最後に実際の動作を確認したいと思います。サンプルは HTML Web リソース
として作成されているため、色んな場所におくことが可能ですが、今回は直接
表示して、結果を確認したいと思います。

設定 | カスタマイズ | システムのカスタマイズを開き、 Web リソースを選択。
その後 sample_/JScriptRESTDataOperations.htm を開きます。画面下部に
URL が出ていますので、そこをクリックしてください。

すると HTML ページが読み込まれ白い画面が表示されます。その後自動的に
処理が進み、レコードの削除確認のメッセージが表示されます。

この時点でサンプルのレコードが作成されているはずですので、メッセージは
そのままにして、ワークプレースより取引先企業を開き、レコード作成が成功
していることを確認してください。その後メッセージで OK をクリックすると、
ダミーで作成されたレコードが削除されます。

image

これを見る限り、レコード作成、読み取り、更新の作業が 0.145 秒で行われたことが
分かります。また削除も 0.3 秒程度です。

まとめ

今回は JScript から REST エンドポイントを利用したサンプルを紹介しました。
サンプルは HTML をホストにしているため、任意エンティティのフォームや
サイトマップのターゲットとしても指定できる他、直接開いて実行することも
可能です。今までこのような作業は複雑な SOAP を書いて処理していましたが
ずいぶんと簡潔になったのではないでしょうか。

次回は、このサンプルから一歩踏み込んだ、 JQuery を利用したサンプルを
紹介したいと思います。

参考リンク
JSON の紹介
https://www.json.org/json-ja.html

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