Dynamics CRM Online 2015 Update 1 新機能: Web API 開発者プレビュー その 5


前回に引き続き Dynamics CRM Online 2015 Update 1 で提供される
Web API 開発者プレビューについて紹介します。連載記事になるため
第 1 回からご覧ください。

Web API 開発者プレビュー その 1
Web API 開発者プレビュー その 2
Web API 開発者プレビュー その 3
Web API 開発者プレビュー その 4

Web API ではオプティミスティック同時実行制御もサポートしています。
オプティミスティック同時実行制御の SDK サポートは以下の記事を
ご覧ください。
Dynamics CRM Online 2015 Update 1 SDK 新機能: オプティミスティック同時実行制御

レコード Version の取得

まず取引先企業を 1 件作成してから、レコードの Version 情報を取得します。

プログラムの実装

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

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

    }
}

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

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

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

3. 新しく追加した RunOptimisticConcurrency メソッド内に
以下のコードを追加して、取引先企業を 1 件作成します。

// 取引先企業オブジェクトの作成
Account account = new Account();
account.name = “同時実行制御デモ”;
account.telephone1 = “555-5555”;

// 送信リクエストの作成
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, serviceUrl + “accounts”);
request.Content = new StringContent(JsonConvert.SerializeObject(account, new JsonSerializerSettings() { DefaultValueHandling = DefaultValueHandling.Ignore }));

request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(“application/json”);

// リクエストの送信
var result =await httpClient.SendAsync(request); 

4. 次に作成したレコードを取得して、バージョン番号を
表示します。以下のコードを追加します。

// 作成したレコードの取得
var retrieveRes = await httpClient.GetAsync(result.Headers.Location);

JToken jToken = JObject.Parse(retrieveRes.Content.ReadAsStringAsync().Result);
account = JsonConvert.DeserializeObject<Account>(jToken.ToString());

string version = jToken[“@odata.etag”].ToString();

// バージョンの表示
Console.WriteLine(“レコードのバージョンは {0} です。“, version );
Console.Read();

動作確認

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

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

image

3. レコードのバージョン情報が表示されることを確認します。

image

バージョンを指定したレコードの取得

一度レコードを取得した後、他のユーザーがそのレコードを更新
していないか確認する場面があると思います。その方法として、
バージョン番号が異なる場合のみレコードを取得できます。

プログラムの実装

1 先ほど取得したバージョン番号を指定したレコード取得を
行います。以下のコードを追加します。ポイントは Header
に If-None-Match とバージョン番号を追加することです。

// レコードのバージョンが異なる場合のみレコードを取得
HttpRequestMessage retrieveReq = new HttpRequestMessage(HttpMethod.Get, result.Headers.Location);
retrieveReq.Headers.Add(“If-None-Match”, version);

2. リクエストの送信と結果を表示します。

// レコードの取得
try
{
    retrieveRes = await httpClient.SendAsync(retrieveReq);

    jToken = JObject.Parse(retrieveRes.Content.ReadAsStringAsync().Result);
    account = JsonConvert.DeserializeObject<Account>(jToken.ToString());
                   
    string newVersion = jToken[“@odata.etag”].ToString();

    // バージョンの表示
    Console.WriteLine(“レコードのバージョンは {0} です。”, newVersion);
}
catch(Exception ex)
{
    Console.WriteLine(“レコードはまだ更新されていません”);
}

Console.Read();

動作確認

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

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

3. レコードのバージョン情報が表示されることを確認します。

image

4. Enter キーを押下してプログラムを進めます。以下の画面
が出ることを確認します。

image

5. Enter キーを押下してプログラムを終了した後、再度 F5
キーを押下してプログラムを実行します。

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

7. レコードのバージョン情報が表示されることを確認します。

image 

8. 再度レコードを取得する前に、ブラウザからレコードを更新します。
ブラウザで Dynamics CRM Online に接続してレコードの一部を変更
します。その後プログラムに戻り、Enter キーを押下します。
レコードのバージョンが変わるため、以下のように表示されます。

image

バージョンを指定したレコードの更新

最後にレコードの更新を同じようにやってみます。ここまで既に
いくつかレコードを作成しているため、このタイミングで一度
ブラウザで「同時実行制御デモ」と名前がついているものは削除
することをお勧めします。

1. 更新要求を作成します。今回はバージョンが変わっていない場合に
更新を行いたいので、If-Match ヘッダーを設定します。

// レコードの更新
account.name = “同時実行制御デモ 更新”;

// バージョンが一致する場合にのみ更新
HttpRequestMessage updateReq = new HttpRequestMessage(new HttpMethod(“PATCH”), result.Headers.Location);
updateReq.Content = new StringContent(JsonConvert.SerializeObject(account, new JsonSerializerSettings() { DefaultValueHandling = DefaultValueHandling.Ignore }));
updateReq.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(“application/json”);
updateReq.Headers.Add(“If-Match”, version);

2. リクエストを送信して、結果を表示します。

try
{
    HttpResponseMessage updateRes = await httpClient.SendAsync(updateReq);

    if (updateRes.IsSuccessStatusCode)
        Console.WriteLine(“レコードを更新しました。”, version);
    else
        Console.WriteLine(“レコードが更新できませんでした。”);
}
catch (Exception ex)
{

動作確認

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

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

3. レコードのバージョン情報が表示されることを確認します。

image

4. Enter キーを押下します。ブラウザでレコードを更新していない
ため、以下のメッセージが表示されます。

image

5. Enter キーを押下します。レコードをが更新されたかブラウザで
確認します。

image

image

6. Enter キーを押下してプログラムを終了した後、再度 F5 キーを
押下してプログラムを実行します。

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

8. レコードのバージョン情報が表示されることを確認します。

image

9. 今回はブラウザより手動でレコードを変更します。レコードを
変更した後、プログラムに戻り Enter キーを押下します。手動で
レコードを編集したため、意図したとおり更新に失敗しました。

image

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

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

        // 取引先企業オブジェクトの作成
        Account account = new Account();
        account.name = “同時実行制御デモ”;
        account.telephone1 = “555-5555”;

        // 送信リクエストの作成
        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, serviceUrl + “accounts”);
        request.Content = new StringContent(JsonConvert.SerializeObject(account, new JsonSerializerSettings() { DefaultValueHandling = DefaultValueHandling.Ignore }));

        request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(“application/json”);

        // リクエストの送信
        var result = await httpClient.SendAsync(request);

        // 作成したレコードの取得
        var retrieveRes = await httpClient.GetAsync(result.Headers.Location);

        JToken jToken = JObject.Parse(retrieveRes.Content.ReadAsStringAsync().Result);
        account = JsonConvert.DeserializeObject<Account>(jToken.ToString());

        string version = jToken[“@odata.etag”].ToString();

        // バージョンの表示
        Console.WriteLine(“レコードのバージョンは {0} です。”, version);
        Console.Read();

        // レコードのバージョンが異なる場合のみレコードを取得
        HttpRequestMessage retrieveReq = new HttpRequestMessage(HttpMethod.Get, result.Headers.Location);
        retrieveReq.Headers.Add(“If-None-Match”, version);

        // レコードの取得
        try
        {
            retrieveRes = await httpClient.SendAsync(retrieveReq);

            jToken = JObject.Parse(retrieveRes.Content.ReadAsStringAsync().Result);
            account = JsonConvert.DeserializeObject<Account>(jToken.ToString());
                   
            string newVersion = jToken[“@odata.etag”].ToString();

            // バージョンの表示
            Console.WriteLine(“レコードのバージョンは {0} です。”, newVersion);
        }
        catch(Exception ex)
        {
            Console.WriteLine(“レコードはまだ更新されていません”);
        }

        Console.Read();

        // レコードの更新
        account.name = “同時実行制御デモ 更新”;

        // バージョンが一致する場合にのみ更新
        HttpRequestMessage updateReq = new HttpRequestMessage(new HttpMethod(“PATCH”), result.Headers.Location);
        updateReq.Content = new StringContent(JsonConvert.SerializeObject(account, new JsonSerializerSettings() { DefaultValueHandling = DefaultValueHandling.Ignore }));
        updateReq.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(“application/json”);
        updateReq.Headers.Add(“If-Match”, version);

        try
        {
            HttpResponseMessage updateRes = await httpClient.SendAsync(updateReq);

            if (updateRes.IsSuccessStatusCode)
                Console.WriteLine(“レコードを更新しました。”, version);
            else
                Console.WriteLine(“レコードが更新できませんでした。”);
        }
        catch (Exception ex)
        {
        }
    }
}

まとめ

楽観的同時実行制御は、今回紹介した読み取りと更新以外に、
削除処理も制御できますので、是非お試しください!

– 中村 憲一郎

Comments (0)

Skip to main content