Dynamics CRM 2011 強化された Plug-in


みなさん、こんにちは。

今日は Dynamics CRM 2011 の強化された Plug-in を紹介します。また Dynamics CRM 2011 から
開発を始めた方も多いかと思いますので、 Plug-in の基本的な機能も合わせて紹介します。

Plug-in

Dynamics CRM 2011 はいくつかの拡張ポイントを提供しています。Plug-in はプラットフォームの
オペレーションパイプラインに登録できる、カスタムロジックです。また Plug-in はプラットフォームの
操作によって発生したイベントのハンドラーと捕らえることも可能です。

たとえば、取引先企業の作成時にカスタムロジックを実行したり、レコードのアサインのタイミングで
ロジックを実行することが可能です。

イベント実行パイプライン

Dynamics CRM 2011 の Web サービスやクライアントから、レコードの作成、更新、削除等の
操作が行われた場合に、それらの処理はイベント実行パイプラインで実行されます。パイプランは
5つのステージに分かれており、それぞれ以下のように定義されています。

ステージ 10 Pre-Validation
一番初めのステージで、メインのシステム処理外の前処理に位置します。基本的にデータベースの
トランザクション外に位置するステージで、Plug-in の登録が可能です。

ステージ 20 Pre-Operation
メインのシステム処理内の、前処理のステージになります。データベースのトランザクション内に
位置し、Dynamics CRM 2011 から Plug-in の登録が可能になりました。

ステージ 30 Main-Operation
メインのシステム処理です。システム内部で使用されるステージで、Plug-in は登録できません。

ステージ 40 Post-Operation
メインのシステム処理内の、後処理のステージになります。データベースのトランザクション内に
位置し、、Dynamics CRM 2011 から Plug-in の登録が可能になりました。

ステージ 50 Post-Operation
一番初めのステージで、メインのシステム処理外の前処理に位置します。基本的にデータベースの
トランザクション外に位置するステージで、Dynamics CRM 4.0 では Plug-in が登録できましたが
Dynamics CRM 2011 ではサポートされません。

以上のように、Dynamics CRM 4.0 では、ステージ10 と 50 への Plug-in 登録がサポートされ、
Dynamics CRM 2011 からは、ステージ 10、20、40 への Plug-in 登録がサポートされます。

トランザクションサポート

上記で紹介したように、 Dynamics CRM 2011 から、Plug-in をメインの操作内に登録することで、
トランザクション内でカスタムロジックを実行することが可能になりました。具体的なサンプルで
実際の動作を実験します。

準備

動作を検証するにあたり、まず以下の準備が必要です。

– Visual Studio 2010 のインストール
– Dynamics CRM 2011 SDK のダウンロード
– Plug-in Registration Tool のコンパイル
– サンプルの作成

Visual Studio 2010 はインストールされている前提で進めます。

Plug-in Registration Tool の準備

1. 以下の URL より Dynamics CRM 2011 SDK をダウンロードします。
http://www.microsoft.com/downloads/en/details.aspx?FamilyID=420f0f05-c226-4194-b7e1-f23ceaa83b69

2. ダウンロードしたモジュールを任意のフォルダに解凍します。

3. Visual Studio 2010 を起動します。

4. プロジェクトを開くメニューより、SDK を解凍したフォルダ\sdk\tools\pluginregistration 内の
PluginRegistrationTool ソリューションを開いてください。

5. プロジェクトを開いたら、ビルドメニューより、ソリューションのビルドを実行してください。

6. ビルドが正常に完了したら、ツールの準備は完了です。

サンプルの作成

1. Visual Studio 2010 より、新規のプロジェクトを作成します。
ファイル | 新規作成 | プロジェクトを選択してください。

2. 言語を選択し(ここでは C#)、種類を Windows のクラスライブラリを選択してください。
名称は CRMPluginSample とします。選択したら OK をクリックします。
image

3. ソリューション エクスプローラー内の参照設定を右クリックして、参照の追加を選択します。

4. 参照タブを選択して、SDK を解凍したフォルダ\sdk\bin フォルダより
Microsoft.Xrm.Sdk.dll を選択し、OK をクリックします。
image

同様に .NET タブをクリックし、System.Runtime.Serialization を選択し、OKをクリックします。
image

5. コードを以下の内容に置き換えます。このコードは、例外のみを発生させるクラスと、
ダミー取引先担当者を作成するクラスを含んでいます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xrm.Sdk;

namespace CRMPluginSample
{
    public class RaiseException : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            // エラーのみを返す
            throw new InvalidPluginExecutionException();
        }
    }

    public class CreateDummyContact : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            // context を取得
            IPluginExecutionContext context =
                (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

            // organization サービスを取得
            IOrganizationServiceFactory factory =
                (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = factory.CreateOrganizationService(context.UserId);
           
            try
            {
                // ダミー取引先担当者を作成
                Entity myContact = new Entity(“contact”);
                myContact[“lastname”] = “DummyContact”;

                service.Create(myContact);
            }
            catch (Exception ex)
            {
                // Handle the exception.
            }
        }

    }
}

6. ソリューション エクスプローラーより、CRMPluginSample を右クリックして、プロパティを
クリックします。

7. 署名タブをクリックして、アセンブリ署名にチェックし、新規作成を選択します。
image

8. 任意のキーファイル名を入力し、任意のパスワードを入力します。OK をクリックします。
image

9. ビルドより、ソリューションのビルドを実行します。これで準備完了です。

実験 1

準備が完了しましたので、実験を開始します。まずは取引先企業の作成操作に対して
ダミー取引先担当者作成の Plug-in を ステージ 10 に、例外発生を、ステージ 40 に登録してみます。
これでダミー取引先担当者の作成はトランザクション外に、例外発生がトランザクション内に登録されます。

Plug-in 登録

1. SDK を解凍したフォルダ\sdk\tools\pluginregistration\bin\Debug より
PluginRegistration.exe を実行します。

2. 起動した画面から、 Create New Connection をクリックします。
image

3. Connection Information が画面左下に開きます。 Dynmics CRM 2011 の URL と
システム管理者権限のあるユーザー情報を入力して、Connect をクリックします。
image

4. 画面左上に組織の一覧が出ます。検証で使いたい組織をダブルクリックします。

5. 画面右側に組織の詳細が出ます。Register メニューより Register New Assembly を
クリックします。
image

6. ファイルとして先ほどコンパイルした CRMPluginSample.dll を指定します。

7. 後は既定のまま、Register Selected ボタンをクリックします。

8. 登録に成功すると以下のメッセージが出ます。OK をクリックします。

image

9. 元の画面に戻り、新しく登録したアセンブリが表示されます。
image

10. まず CRMPluginSample.CreateDummyContact を右クリックして、
Register New Step をクリックし、以下の情報で登録します。

Message: Create
Primary Entity: account
Pipeline Stage (画面左下): Pre-Validation

他は既定値のままで、Register New Step をクリックします。

11. 同様に CRMPluginSample.RaiseException を右クリックして、
Register New Step をクリックし、以下の情報で登録します。

Message: Create
Primary Entity: account
Pipeline Stage (画面左下): Post-Operation (Dynamics CRM 2011 Only)

以上で準備が完了しました。現在ダミー取引先担当者の作成はトランザクション外、
エラーの発生はトランザクション内に登録されています。

取引先企業の作成を結果確認

では、取引作業企業を作成してみましょう。

1. Internet Explorer で Dynamics CRM 2011 に接続し、取引先企業を作成。

2. 必須フィールドを入力後保存して閉じるをクリックすると、以下のエラー発生。
image

3. OK をクリックしてエラーを閉じた後、[x] で新規作成画面を閉じる。

4. 取引先担当者のグリッドに移動。レコードができている。
image

よって、エラーの発生によってダミー取引先担当者の作成はロールバックされませんでした。

実験 2

次に、ダミー取引先担当者の作成を、ステージ 20 に移して実験します。これで両方の操作が
トランザクション内に登録されます。

Plug-in 登録更新

1. Plug-in Registration Tool に戻ります。

2. CRMPluginSample.CreateDummyContact を展開して、作成されたステップを
ダブルクリックします。ステップの登録画面が開きます。

3. Pipeline Stage を Pre-Validation から Pre-Operation (Dynamics CRM 2011 Only) に
変更して、Update をクリックします。

取引先企業の作成を結果確認

1. Internet Explorer に戻り、まず作成されたダミーの取引先担当者を削除します。

2. レコードが削除されたことを確認したら、新規に取引先企業を作成します。

3. 必須フィールドを入力して、保存して閉じるをクリックすると、先ほどと同じ
エラーが確認できます。

4. OK をクリックして、[x] で閉じてから、取引先担当者のグリッドに移動します。

5. レコードができていないことを確認します。

今回はエラーの発生によって、ダミー取引先担当者の作成もロールバックされました。

以上のようにステージ 20 および 40 に登録された Plug-in は同じトランザクションのスコープで
処理が実施されます。これにより、 Plug-in 内で行った作業とメインのオペレーションの整合性が
取れることとなります。

Azure 連携

Dynamics CRM 2011 は、 Plug-in を利用した Azure 連携機能を提供しています。
Azure 用の機能は Registration Tool に含まれており、またセキュリティ設定なども
容易に行えるよう、機能が提供されています。

詳細を紹介するには、Azure 側の手順紹介なども必要なため今回のブログでは紹介が
できませんが、英語の資料でも問題ないよという方は、以下の URL より Training Kit を
入手していただくか、SDK の Step By Step を見て概要を掴んでいただければと思います。

http://www.microsoft.com/downloads/en/details.aspx?FamilyID=78498c29-28ac-440b-9c20-ec5da6ee6e98

尚、現在ダウンロードできる SDK に含まれる Plug-in Registration Tool には不具合が
あり、そのままでは Azure 連携用の Plug-in にステップが登録できません。

※以下のようなエラーが出ます。
image

対処方法は現在確認中ですので、確認出来次第アップデートしたいと思います。

(更新) SDK 5.0.3 で修正されました!

ステップの無効化 (非アクティブ化)

登録済みのステップを、一時的に無効化することが可能です。該当の Plug-in を停止したい
場合に、ステップを削除するより簡単で、後で有効化ができます。無効化したいステップを
右クリックして、Disable をクリックしてください。また無効化後に、有効に戻したい場合には
Enable をクリックしてください。

※下記赤のビックリマークが無効になったステップです。

image

またステップの有効化/無効化 (アクティブ化/非アクティブ化) は、ソリューションの内部からも操作が可能です。

1. Internet Explorer で Dynamics CRM 2011 に接続します。

2. 設定 | カスタマイズ | システムのカスタマイズを開きます。

3. プラグイン アセンブリを確認すると、登録されたアセンブリの情報が確認できます。

4. SDK メッセージ処理手順からは、ステップのアクティブ化、非アクティブ化が行えます。
状態列の値で、有効/無効を確認してください。

非同期 Plug-in 完了時のログ

Plug-in はステージ 40 に登録した場合、非同期処理にすることが可能です。非同期で
登録された Plug-in は非同期サービスによって処理が行われ、その結果はシステムジョブに
出力されます。多数の非同期 Plug-in がある場合には、システムジョブの結果レコードが
多くなり、テーブルが肥大化するため、処理成功時にはログを削除するオプションが
あります。

image

上記画面一番下のチェックボックスにチェックを入れることで、処理が成功したら
完了ログは削除され、テーブルの肥大化を抑えることが可能です。

※ Plug-in の処理を非同期にした場合には、ステージ 40 であってもトランザクションの対象になりません。

処理のタイムアウト

Plug-in は同期、非同期にかかわらず、2分間で処理が終わらない場合にはタイムアウト
するよう設定されています。パフォーマンスを考慮した対応のため、2分以上かかるような
ロジックは、ワークフローでの対処を検討してください。

サンドボックスサービス

よりセキュアな環境で Plug-in が実行できるよう、通常の非同期サービスに加えて、
サンドボックスサービスが提供されます。サンドボックスサービス上に登録された Plug-in は
ファイルシステムやイベントログ、レジストリなどのアクセスが行えません。

また、Dynamics CRM オンラインは サンドボックスへの登録のみサポートしていますので
設置型、オンラインともに利用したい場合には、サンドボックス内でのみ動作する Plug-in を
作成するようにしてください。

image

ソリューション対応

Dynamics CRM 2011 より、Plug-in もソリューション対応となり、他組織への移行が容易です。
以前は、手動でアセンブリをコピーして、Plugin Registration Tool で再登録する必要があったため
多くの Plug-in がある場合、その作業は非常に煩雑でした。

ソリューション対応したことで、Plug-in のコピーや再登録は不要になり、作業の短縮や移行
し忘れるといった問題が解消されます。

今回は Dynamics CRM 2011 で拡張された Plug-in の機能を紹介しました。いかがだったでしょうか。
他にも Plug-in で気になることがあれば、是非ご連絡ください。

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

Comments (43)

  1. dehyon.chon より:

    いつもいい情報ありがとうございます。

    Plug-inについて質問ですが、


    Plug-in は同期、非同期にかかわらず、2分間で処理が終わらない場合にはタイムアウト

    するよう設定されています。パフォーマンスを考慮した対応のため、2分以上かかるような

    ロジックは、ワークフローでの対処を検討してください。


    と記述していますが、ワークフローではなく、タイムアウト時間を設定する方法はありませんでしょうか。

    宜しくお願いします。

  2. こんにちは。コメントありがとうございます。

    残念ながら現時点でタイムアウト値の設定変更はサポートしておりません。短くすることも長くすることもできないため、常に2分となります。よろしくお願いします。

  3. dehyon.chon より:

    早速の回答ありがとうございます。

    できないですか。。。了解しました。

    思い込みで簡単にできると思っていました。

    ワークフローで対応します。

    宜しくお願いします。

  4. smd より:

    情報ありがとうございます。

    プラグインから少し話がそれてしまうのですが、取引先担当者を新規作成するのではなく、既存の取引先担当者レコードを更新・削除する場合、レコードを検索し指定するにはどのようなコードを書けば良いのでしょうか。

    調べたところ、この例に適用できる検索コードの情報が見当たらなかったため、もしよろしければご教授いただきたいと思います。

  5. コメントありがとうございます。

    新規作成ではなく、更新・削除で処理をしたいとのことですが、こちらはプラグインの実行自体を更新、削除処理で行いたいという意味になりますでしょうか。その場合は、プラグイン登録ステップにて Create メッセージではなく、Update か Delete に登録いただくことになります。

    具体的なシナリオを教えていただけるともう少し参考情報を提供できると思いますので、よろしくおねがいします。

    中村 憲一郎

  6. smd より:

    早速のご回答ありがとうございます。

    プラグインの実行自体を更新・削除処理で行いたいです。

    シナリオとしましては、取引先企業の作成を行ったタイミングで、既に存在する取引先担当者のレコードを更新するというものです。

    レコードの指定はRetrieveメソッドで行うことができるようですが、レコードの検索とGUIDの取得方法が分かりません。

    上記方法もしくは他の方法がありましたらご教授いただきたく思います。

  7. コメントありがとうございます。

    頂戴した内容からはプラグインを実行するきっかけ (トリガー) は取引先企業の作成であり、トリガーされたプラグインの処理の中でレコードの検索と更新を行いたいと受け取りましたがあっていますでしょうか。

    まずレコードの検索ですが、取得対象のレコード (今回の場合は取引先担当者) の Guid が分かっている場合は Retrieve メソッドを利用できますが、そうでない場合先に検索する必要がありますので、RetrieveMultiple メソッドを利用して、FetchXML や QueryExpression にて取引先担当者を検索してください。検索結果から該当するレコードを 1 件特定することでそのレコードを更新処理に利用することが可能です。

    サンプルは RetrieveMultiple だけを示したものはなさそうですが、多くのサンプルで QueryExpression や FetchXML を使っていますので、是非参考にしてください。

    また参考までに以下に FetchXMLを使った例を示します。この例では FetchXML を使い、emailaddress1 で検索しています。必要に応じてクエリは変更してください。

    // クエリの作成を実行

    string fetch = String.Format(@"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>

    <entity name='contact'>

    <attribute name='lastname' />

    <filter type='and'>

    <condition attribute='emailaddress1' operator='eq' value='{0}' />

    </filter>

    </entity>

    </fetch>", "test@test.com");

    var result = _service.RetrieveMultiple(new FetchExpression(fetch));

    // 取引先担当者を取得 (1件以上結果がある前提)

    var contact = result.Entities[0];

    // 取得したレコードに対して必要な処理を実行

    contact["lastname"] = "new last name";

    // 更新処理

    _service.Update(contact);

    最後のところではレコードが 1 件以上ある前提で配列にアクセスしていますが、レコードが 1 件も返ってこない場合がありますので、必ず件数確認をしてから取得するようにしてください。

    中村 憲一郎

  8. smd より:

    RetrieveMultipleメソッドを使用した更新処理について、サンプルコードまでご提示いただきありがとうございました。

    お陰様で更新処理が実装でき、またメソッドについての理解することができました。

    今後も色々なサンプルを参考にしながら勉強していきたいと思います。

    回答ありがとうございました。

  9. コメントありがとうございます。

    実装がうまくいったようで嬉しい限りです。SDK には非常に多くのサンプルが含まれており、極力シンプルな処理を提示するようにコンテンツが開発されていますが、どうしてもピンポイントで必要な情報が提供できない場面も出てくるため、複数のサンプルを組み合わせて開発する必要が出てまいります。

    どのようなサンプルがあるかはサンプルディレクトを参照いただくのが一番容易ですので、お時間がある際に是非ご覧ください。

    msdn.microsoft.com/…/gg309721.aspx

    msdn.microsoft.com/…/gg309721(v=crm.5).aspx

    中村 憲一郎

  10. hattori より:

    DynamicsCRM2015にてバッチ処理を行いたく、色々と調べていたところこのサイトにたどり着きました。

    あるメインとなるエンティティのテーブル全件に対して、1レコードずつfetchさせながら、そのレコードに対して

    別のエンティティのテーブルにアクセスし、必要情報を取得して、色々と項目の編集を行い、

    その結果を、別のエンティティのテーブルにレコード追加するという処理を行いたいのですが、

    そういったことは、可能でしょうか。

    「あるエンティティーのテーブルを1レコードずつfetchさせる」ということを、DynamicsCRMのプログラムでどうプログラミングしていいかがわからず、ご質問させていただきました。

    ご回答いただければ幸いです。

    よろしくお願いいたします。

  11. コメントありがとうございます。

    詳細な要件によって変わると思いますが、Dynamics CRM SDK にて期待した処理は行えると思います。以下は案の一例ですがご参考まで。

    1. メインとなるエンティティのレコードを RetrieveMultiple メソッドを利用して取得。5000 件が一度に取得できるデータ数の条件ですので、ページングを利用して全件取得してください。

    msdn.microsoft.com/…/gg309717.aspx

    1. RetrieveMultiple の結果は EntityCollection 型で返ってきますので、結果変数を results とした場合、results.Entities を foreach ループなどループ処理に利用して、1 レコードずつ処理
    2. 別エンティティのデータは必要に応じて Retrieve メソッドまたは RetrieveMultiple メソッドでデータを取得

    3. レコードの追加は Create メソッド、更新は Update メソッドで実施

    Dynamics CRM SDK のサンプルは以下にありますのでご覧ください。

    msdn.microsoft.com/…/gg309721.aspx

    • 中村 憲一郎
  12. hattori より:

    返信ありがとうございました。

    頂いたアドバイスをサイトを見て早速試してみます!

  13. hattori より:

    すいません。

    前回いただいた質問についてさらに追加で質問させてください。

    PluginRegistration.exeを使用して作成する場合は、あるレコードが追加された場合/更新された場合/削除された場合などのトリガーをもとに起動されるものだと認識しておりますが、

    RibbonWorkBenchで固有のボタンを追加し、そのボタンを押すと、教えていただいた

    「msdn.microsoft.com/…/gg309717.aspx」で作成した処理が起動される、

    といったことをしたい場合はどうすればよいのでしょうか?

  14. hattori より:

    すいません。前回の質問でさらに追加で質問させてください。

    このPlug-inは、「PluginRegistration.exe」を使用してレコードの追加、更新、削除といったイベントが発生

    した際に、教えていただいた「msdn.microsoft.com/…/gg309717.aspx」といったような処理が

    実行されるものだと理解しておりますが、

    ribbonWorkBenchで個別に追加したボタンをクリック時に、同じ処理が実行されるということをしたい場合は

    どうすればよいでしょうか?

  15. コメントありがとうございます。

    前回の回答については、バッチ処理ということでコンソールアプリケーションを想定した回答をいたしましたが、プラグインでそのような処理をしたい場合は以下の点をご注意ください。

    • Online 環境もしくはプラグインがサンドボックス環境で実行される場合は 2 分のタイムアウトがある。
    • プラグインはあくまで作成、更新、削除されるレコードを対象に実行されるべきであり、その他のレコードの一括処理としては適切ではない

    プラグインはレコードの作成、更新、削除で実行されますので、リボンから直接呼び出すことはできません。Microsoft Dynamics CRM 2013 以上をご利用の場合は「ユーザー定義アクション」が利用可能かご検討ください。

    blogs.msdn.com/…/dynamics-crm-2013-fall-13-custom-operation-1.aspx

    -中村 憲一郎

  16. Furutani より:

    先日は別の件でご回答いただきましたFurutaniです。

    すみません。また困ってしまいましたのでご教授いただけないでしょうか?

    見積もりエンティティに合計金額フィールドを追加し、カスタムで作成した見積もり製品エンティティ(見積もりエンティティと1:Nの関係)の金額フィールドの合計値を見積もりの合計金額フィールドに更新する処理をVisualStudioで作成しました。

    PluginRegistration.exeにてCreate、Update、Deleteメッセージでそれぞれ登録し、Create、Updateについてはうまく更新できましたがDeleteについては更新されません。

    デバッグをしてみたところ、入力パラメーターのターゲットエンティティが取得できないため、何もしないまま処理が終わっていました。

    Post-Operationで登録の場合は既に対象の見積もり製品レコードは削除されてしまっているのでターゲットは得られないと思い、Pre-Validation、Pre-Operationでも登録してそれぞれデバッグしてみましたが同じようにターゲットエンティティが取得できませんでした。

    見積もり製品レコードが削除される前に削除対象以外のレコードの金額の合計を計算して見積もりエンティティの合計金額フィールドを更新したいと思っていますが、どのようにすればターゲットエンティティを取得できるのでしょうか?

    お手数ではありますが、ご回答いただけると助かります。

  17. Furutani より:

    すみません、上記のFurutaniです。

    いろいろ調べて問題解決しました。

    Create、Updateメッセージの際にはターゲットはEntitiyですが、Delete時はEntityReferenceを取得するんですね。

    これが解ったのでターゲットのGuidを取得でき、処理を作成することができました。

    お騒がせしました。

    これからも参考にさせていただきます。

  18. コメントありがとうございます。

    削除時については、削除されるエンティティが InputParameter の Target として EntityReference 型で渡されますので、レコードの Guid は取得が可能です。Entity ではなく EntityReference で取得を試していただけますでしょうか。

    中村 憲一郎

  19. コメントありがとうございます。

    こちらでの回答前に解決されたようで安心いたしました。

    プラグインに落ちてくる型は Entity だったり EntityReference だったりします。また名前も Target だったり BusinessEntity だったりします。

    他の Tips としては Stage 10、20 では InputParameter にメイン処理で利用する値が入りますが、Stage 40 では OutputParameter に処理結果が入るだけでなく、InputParameter の値もそのまま確認が可能です。

    状況に応じて使い分けをご検討ください。

    中村 憲一郎

  20. takayuki より:

    お世話になります。

    いつも情報ありがとうございます。

    登録したプラグインをデバッグしたく、試しておりますが以下エラーの原因がわからず困っております。

    現状としましてはPluginRegistrationToolにてデバッグしたいStepをStart Profilingし、

    CRM画面上で実際の処理を実行しビジネスプロセスエラーとなったログファイルをダウンロードして

    PluginRegistrationToolの「Debug an Existing Plug-in」画面のProfileでそのダウンロードしたファイルを指定して

    Assembly Locationにはプラグインを登録したときのDLLファイルを選択しています。

    この状態で「Start Execution」ボタンを押すと下記エラーが発生します。

    「Unhandled Exception: System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: 型 'System.Security.Permissions.FileIOPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' のアクセス許可の要求に失敗しました。」

    サンドボックスモードにしていることと何か関係があるのでしょうか?

    お手数をおかけ致しますが

    解決方法をご教示頂けると幸いです。

    よろしくお願い致します。

    以上

  21. コメントありがとうございます。

    まずプラグインがサンドボックスに登録されている事はエラーと関係なさそうに思えます。プロファイラーで実行されるものはローカルのソリューションレベルですので CRM に登録されているアセンブリには関連が無いためです。

    以下の手順を一度お試しください。

    1. Plugin Registration Tool を管理者として実行し、Start Execution 手前までの手順を実行。

    2. Visual Studio を起動して、プラグインのプロジェクトを開き、プラグインコードの任意の場所にブレークポイントを設定。

    3. Visua Studio のデバッグ | プロセスのアタッチより Plugin Registration Tool にアタッチ。

    4. Start Execution を実行してエラーの詳細が見れるか確認

    ちなみに、プロファイラを利用されている理由は環境が Dynamics CRM Online だからでしょうか。設置型の場合はサーバーが止まりますが直接サーバーにアタッチしていただくことも可能です。

    – 中村 憲一郎

  22. takayuki より:

    ご回答ありがとうございます。

    デバッグできるようになりました。

    「Start Execution」押下時にアクセス許可のエラーが発生していた件につきましては

    何故だか不明ですがC#にてEventLogクラスでイベントログを出力しようとしているところが

    原因なようでした。取り急ぎその部分をコメントすることでエラーを解消できました。

    それ以降は教えて頂きました通り、Visual Studioにてプロセスのアタッチを行うことにより

    デバッグすることができました。

    ちなみにこちらの環境は設置型になります。

    お忙しいところありがとうございました。

    以上

  23. コメントありがとうございます。

    無事デバッグできたようでよかったです。

    プロファイラにおける注意点としては、デバッグ実行したコードは、実際の環境に反映されます。例えばデバッグ実行した際に、プラグイン内でレコード作成している場合、実際にレコードが作成されます。

    – 中村 憲一郎

  24. takayuki より:

    返信ありがとうございます。

    度々、申し訳ありませんが、もう一つ確認させてください。

    現在、デバッグは動作するようになりましたが

    営業案件エンティティの更新処理(IOrganizationServiceのUpdate)を実行する処理を記述すると

    「オブジェクト参照がオブジェクト インスタンスに設定されていません」のエラーが発生してしまいます。

    Updateメソッドには営業案件エンティティの対象レコードをGuidを条件として取得したEntityオブジェクトに

    更新したい項目(新規の通貨型のカラム)にMoney型の値をセットしたものを引数として渡しております。

    Updateメソッドの中身が参照できないため、なぜエラーとなってしまっているのかが不明です。

    そのUpdateメソッドの1行をコメントにするとエラーは発生しません。

    何か原因がわかりました、ご教示頂けると助かります。

    いつも申し訳ありませんが

    よろしくお願い致します。

    以上

  25. コメントありがとうございます。

    エラーの内容からはオブジェクトが作成されていないという状況ですので、どこかの変数が空になっていると考えられます。

    デバッグ時に Update のラインでブレークしていただき、そのコードに関連するオブジェクトがどれか空になっていないかご確認ください。

    また Entity 型はエンティティの論理名を持つ必要がありますので、LogicalName が正しく設定されているかを見ていただくことと、Guid が設定されていることを確認してください。

    ちなみに、もし元々のプラグインの処理が Create メッセージをトリガーとしている場合、実際にレコードは出来ていないため、そこが原因で失敗している可能性もあります。

    中村 憲一郎

  26. takayuki より:

    いつもお世話になっております。

    返信ありがとうございます。

    デバッグにて変数の状況を確認致しました。渡しているEntityオブジェクトを確認しましたが

    Guid、LogicalNameともに設定されておりました。その二つと更新対象項目に値が入っている状況です。

    ちなみに今回のトリガーはUpdateを指定しております。

    また、UpdateメソッドをもっているIOrganizationServiceが空の可能性もあると思い確認しましたが

    階層が深く、不明な部分が多かったですが、nullのものあればちゃんと値が入っているものとまちまちでした。

    検索処理を正常動作しているため、IOrganizationServiceが悪い可能性は低そうですが・・・

    以上

  27. コメントありがとうございます。

    特定の操作だけで失敗している様ですので、プラグイン内から実行している Update の処理自体で問題が発生しているのかもしれません。デバッグした時だけの問題であれば、コンテキストとして含まれている値に問題があるかもしれません。いずれにしてもより詳細な調査が必要となるため、申し訳ありませんが弊社サポートセンターまでご連絡いただけますでしょうか。

    中村 憲一郎

  28. takayuki より:

    いつもお世話になっております。

    先日まで、お忙しい中ご回答頂きありがとうございました。

    関連する内容で再度2点確認させて頂きたいのですが

    1点目ですが金額項目(通貨型)のフィールドを更新する際は何か注意点等ございますでしょうか。

    以前まで営業案件エンティティの通貨型フィールドにMoney型の値をセットし更新しようとして

    エラーになっておりましたが1行テキストの項目の更新に変更しましたら、うまくいっているようです。

    2点目はプラグインの登録でStep作成時のトリガーをUpdateにした際に

    実行されるプラグインで自身のエンティティを更新する処理を行った場合

    その更新でも再度、プラグインが実行されて無限ループに陥ることはありますでしょうか。

    実際に無限ループが含まれてとのエラーメッセージが出てしまっております。

    プラグイン登録時に回避する設定等ございましたらご教示頂きたく。

    いつもいつも質問させて頂き申し訳ありませんが

    よろしくお願い致します。

    以上

  29. コメントありがとうございます。

    通貨型は通常以下の方法で更新します。

    Account account = new Account();

    account.Id = <レコードの ID>

    account["通貨フィールド名"] = new Money(2000);

    service.Update(account);

    営業案件などで利用される自動集計される類のものは、直接更新が行えないかもしれません。まずはカスタムフィールドとしてシンプルに作成した通貨型で試していただくのがよいと思います。

    無現ループについては、IPluginExecutionContext.Depth プロパティにてループされたものかをチェックできます。呼び出された階層によって値(深度)が変わり、深度が想定されたものより深い場合は無限ループしていることになります。

    その他のベストプラクティスについては SDK および少し古いですが以下の記事をご覧ください。

    blogs.msdn.com/…/dynamics-crm-2011-plug-ins-best-practices.aspx

    – 中村 憲一郎

  30. takayuki より:

    返信おそくなってしまい申し訳ありません。

    ご回答ありがとうございます。

    金額の更新につきましては未だに謎は残りますがデバッグモードではなく普通に実行すれば更新されていました。原因ははっきりしませんが・・・

    無限ループにつきましてはご教示頂きました「IPluginExecutionContext.Depth」にて制御を行うことにより解決できました。

    ありがとうございました。

    以上

  31. 結果を教えていただき、ありがとうございます。

    無事意図したとおりの動作になったようで安心いたしました。

    中村 憲一郎

  32. takayuki より:

    いつもご助言頂きありがとうございます。

    金額項目について1点ご確認させていただきたいのですが、金額項目は金額と金額(基本)と二つで1セットとなっており、(基本)には基本通貨に換算された金額が内部的にセットされているかと思います。

    現在、別々の組織で同じ環境を再現しカスタムフィールド(Money型)に対して金額をセットしておりますが

    それぞれの組織にて(基本)に登録されている値に誤差が生じてしまいます。

    ちなみにそれぞれの組織で該当エンティティの該当レコードの通貨と為替レートは同じ値で対象フィールドの金額も同じ値になっており、どこの設定を確認すればよいかがわかりません。

    ちなみに以下のような計算結果となってしまいます。

    正常結果の組織

    1/レート(0.008403)*金額(5250ドル) = 624776.8654 → 実際の結果624777円

    異常結果の組織

    1/レート(0.008403)*金額(5250ドル) = ???? → 実際の結果624750円

    27円の誤差が発生してしまっております。

    このような結果になってしまう原因と設定確認のあたりが

    お心当たりがありましたらご教示頂けると幸いです。

    お手数をお掛けいたしますがよろしくお願い致します。

    以上

  33. コメントありがとうございます。

    通貨の計算が異なる場合は、通貨の有効な桁数が異なっている場合があり、切り捨てられている可能性があると考えられます。

    お手数ですが両環境の通貨、システム設定レベルで有効な桁数に相違がないかご確認ください。

    中村 憲一郎

  34. takayuki より:

    ご回答ありがとうございます。

    早速、通貨まわりの設定を細かく確認してみました。

    為替レートの小数点第7位以降に差異がありました。

    画面上では小数点第6位までしか表示されていなく、同じであると思い込んでおりました。

    お手数をお掛けしすみませんでした。

    ありがとうございました。

    以上

  35. コメントありがとうございます。

    無事解決したようで安心いたしました。

    通貨型は Dynamics CRM 固有のもののため、少し分かりにくい箇所があるかもしれません。また機会があれば固有型についても記事を書きたいと思います。

    中村 憲一郎

  36. koharu より:

    いつも参考になる情報をありがとうございます。

    dynamicsCRMで今、エンティティ間の関連(マッピング)をプラグインで実装するところで悩んでおります。

    処理の例と致しましては、取引先企業を新規作成時、取引先担当者と重複する項目すべてを引き継いで新規作成したい。

    取引先企業を更新時は、取引先企業に関連する取引先担当者へ、重複する全ての内容を反映させたい。

    //////////////////////////////////////////////////////////////////////////////////////////////////

    1、重複項目が多いので、for文等でフィールドの論理名を指定

    2、取引先企業に関連する全ての取引先担当者へ、重複する全ての内容を反映

    /////////////////////////////////////////////////////////////////////////////////////////////////

    を実装しようと考えているのですが、実現可能でしょうか。

    お手数をおかけ致しますが

    解決方法をご教示頂けると幸いです。

    よろしくお願い致します。

  37. コメントありがとうございます。

    プラグインでは Create/Update の InputParameter にて入力した値は取れますので、希望の動作は実装できると考えます。フィールドの論理名と型が同じであれば値をそのまま受け渡しができます。どのフィールドに値が入ってくるか分からない以上、すでにご検討いただいている通り、取得した Entity オブジェクトの Attributes プロパティをループする必要があります。

    更新時の処理については関連する取引先担当者を全て取得して、ループ処理する必要がありますが、パフォーマンスにより同期処理の場合ユーザーが待たされる可能性があるため、要件が許せば非同期処理もご検討ください。

    – 中村 憲一郎

  38. koharu より:

    返信遅くなって申し訳ありません。

    ご回答ありがとうございます。

    現状、フィールドの論理名と型は同じにしています。

    早速、フィールドの値を全て取得することを確認してみました。

    ①AttributeCollectionに取得したい値のエンティティのAttributesを設定

    ②ループで値をトレースログに書き出して確認

    という流れで行ったのですが、ログを確認するとフィールド全ては取得できませんでした。

    この場合の対処法、他の解決方法等ありましたらご教授頂けると幸いです。

    よろしくお願い致します。

  39. コメントありがとうございます。

    まずプラグインに引き渡されるフィールドと値についてですが、値が入っているフィードのみがプラグインのコンテキストとして渡されます。よって値がないフィールドについてはプラグインのコンテキストに自動では引き渡されません。

    コメントからはメタデータを併用して処理をされている様ですが、InputParameter として渡される Entity の Attributes プロパティから渡された値を確認し、そのまま取引先担当者に渡す処理となると思われます。

    上記内容から再度実装をご検討ください。

    尚、要件に一致するようなサンプルは無かったため、より詳細な情報が必要な場合は、別途弊社サポートセンターまでお問い合わせいただくことも併せてご検討ください。

    – 中村 憲一郎

  40. koharu より:

    お忙しい中、ご回答ありがとうございました。

    度々、申し訳ありませんが確認させてください。

    update時は、書き換わった値のみ取得なので問題ないのですが、

    create時は、空白の部分まで取得してしまいます。

    ①create時も、値が入っている項目のみ取得することは可能ですか。

    いつもいつも質問させて頂き申し訳ありませんが

    よろしくお願い致します。

  41. takayuki より:

    いつもお世話になっております。

    こちらのブログの内容とは少し関係ないかもしれませんが

    dynamics CRM 2013にて新規ユーザーを作成する際にユーザ名、氏名、メールアドレス等が

    自動でActive Directoryから情報が取得されているかと思いますが

    たとえば営業エンティティなどのフィールドにActiveDirectoryの情報をもってくるなどの機能はありますでしょうか?

    またはjavascriptや.net等プログラムを組めば可能でしょうか?

    お手数をお掛け致しますが

    ご教示頂ければ幸いです。

    よろしくお願い致します。

    以上

  42. コメントありがとうございます。

    Dynamics CRM の機能として Active Directory と連携する機能は、ユーザー登録時に情報を取得することだけですので、残念ながら他のエンティティなどに情報を持っていく機能はございません。

    実装の方式にもよりますが別途開発することで対応は可能です。

    セキュリティや更新頻度など要件によるとは思いますが、基本的には Active Directory から情報を取得していただき、CRM SDK にて営業案件を更新するのが容易であると思います。

    是非ご検討ください。

    – 中村 憲一郎

  43. takayuki より:

    ご回答ありがとうございます。

    ご質問の直後にAD情報取得の要件はなくなってしまったのですが、標準機能にはないこと、また開発することによって可能であるということは分かりました。

    同様の要件があった際は別途開発する方向で検討させていただきます。

    ありがとうございました。

    以上

Skip to main content