Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Why Your D365 F&O Automation Breaks: The Hidden Logic Behind TargetId and RootId

2026年09月15日に「Dev.to」が公開したITニュース「Why Your D365 F&O Automation Breaks: The Hidden Logic Behind TargetId and RootId」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

D365 F&Oの自動化でリクエストが失敗する原因は、UIコントロールの識別子`TargetId`と`RootId`がセッションごとに変化するためだ。これらを固定値として使わず、ウェブページの要素からリクエスト時に毎回リアルタイムで取得し直すことで、特にデータ更新を伴うアクションの自動化を安定させられる。

ITニュース解説

Webアプリケーションの操作を自動化しようとするとき、多くのシステムエンジニアが直面する共通の課題がある。特に、Dynamics 365 Finance & Operations(D365 F&O)のような複雑なエンタープライズアプリケーションで、ユーザーの操作をPostman、JMeter、RPAツール、あるいは自作のスクリプトなどを使って記録・再生・テストする際、以前はうまくいっていたリクエストが、何も変更していないのに突然失敗するという現象に遭遇することがある。これは特定のツールに起因する問題ではなく、D365 F&Oがユーザーインターフェース(UI)上の各コントロールを内部的にどのように識別しているかに深く関係している。

この自動化の障害を引き起こす主な原因は、アプリケーションがサーバーとやり取りするデータの中に含まれる「TargetId」と「RootId」という二つの値にある。これらの値は、まるで静的で常に変わらない識別子のように見える「数字_数字」といった形式をしている。しかし実際には、これらのIDはセッションごとに、またはフォームが再読み込みされるたびにサーバーによって新しく割り当てられる動的な値なのである。以前のセッションで取得したTargetIdやRootIdを次のセッションで再利用しようとすると、一部のアクションが警告もなく失敗したり、リクエスト自体が拒否されたりしてしまう。

なぜこのようなことが起こるのか。TargetIdとRootIdは、Webページを構成するHTML要素、特にUIコントロール(ボタンや入力欄など)に設定された特別な属性に由来する。具体的には、各コントロールのHTML要素には「data-dyn-serverid」という属性にTargetIdが、「data-dyn-rootserverid」という属性にRootIdがそれぞれ格納されている。これらの属性値は、フォームがブラウザに表示されるたび、つまりページがレンダリングされるたびにサーバー側で計算され、そのセッションのためだけに有効な新しい値が発行される。そのため、今日取得した値は明日には無効になっている可能性があり、ページの再読み込みを行っただけで値が変わってしまうことさえあるのだ。

この問題に対処する最も確実な方法は、TargetIdとRootIdの値をハードコーディング(固定値としてプログラムに書き込むこと)するのではなく、常に実行時(ランタイム)に、つまりリクエストを送信する直前に取得することだ。具体的な手順としては、まずブラウザの開発者ツールを使って、自動化したいUIコントロール(例えば「投稿」ボタンなど)を右クリックし、「検証」を選択する。これにより、そのコントロールに対応するHTML要素が開発者ツールに表示される。そのHTML要素の「id」属性(例: LedgerJournalTransDaily_4_PostJournal)を確認する。このid属性もセッションごとに変わる部分があるが、重要なのはその中の「data-dyn-serverid」と「data-dyn-rootserverid」という二つのカスタム属性の値だ。

これらの属性値は、JavaScriptのコードを使って取得できる。例えば、そのコントロールのid属性が「LedgerJournalTransDaily_4_PostJournal」だった場合、ブラウザのコンソールで以下のようなコードを実行することで、TargetIdとRootIdを動的に取得できる。

1document.querySelector('#LedgerJournalTransDaily_4_PostJournal').getAttribute('data-dyn-serverid') // TargetId
2document.querySelector('#LedgerJournalTransDaily_4_PostJournal').getAttribute('data-dyn-rootserverid') // RootId

ここで注意すべき点がある。コントロールの「id」属性全体はセッションごとに変わる部分を含むため、コントロール名(例えば上記の例では「PostJournal」の部分)のような安定した部分だけで要素を特定しようと考えるかもしれない。コントロール名自体はセッション間で安定していることが多いが、同じコントロール名を持つ要素がページ内に複数存在する場合があり、意図しない別の要素のIDを取得してしまうリスクがある。例えば、非表示になっている要素やオーバーフローメニュー内に複製された要素などだ。そのため、より確実に意図するコントロールのIDを取得するためには、ブラウザのデベロッパーツールで直接要素を検証し、その正確なセレクタ(id属性全体など)を用いて、特定のコンテナ要素内で検索範囲を絞り込むなど、慎重な対応が求められる。リクエストを送信する直前、同じセッションのブラウザコンテキスト内でこれらの値を解決し、すぐに使用することが重要となる。この値の取得は、Postman、JMeter、RPA、カスタムスクリプトなど、どのようなツールを使う場合でも、自動化プロセスの最初のステップとして組み込むべきだ。

さらに重要なのは、すべてのアクションがTargetIdの厳密な検証を同じレベルで行うわけではないという点だ。例えば、D365 F&Oのジャーナルフォームにある「保存(Save)」ボタンと「投稿(Post)」ボタンを考えてみよう。これら二つのボタンはUI上の同じ場所にあり、クライアント側では同じメカニズム(CommandName、TargetId、RootIdの構造)で処理される。しかし、「保存」アクションは古いTargetIdであっても成功することがある一方、「投稿」アクションでは古いTargetIdが使用されるとリクエストがすぐに拒否されてしまうのだ。

この違いはクライアント側ではなく、サーバー側での検証の厳しさによるものである。データを直接変更・確定させるような操作、例えば「投稿」のように永続的な影響を伴うビジネスロジックを実行するアクションは、サーバーがTargetIdを現在有効なコントロールに正確に解決できることを要求する。もし解決できない場合、サーバーは推測して実行するのではなく、安全のためにリクエストを拒否する。一方で、「保存」のような汎用的な操作は、フォームの現在の状態を永続化するだけであり、どの特定のコントロールインスタンスがトリガーしたかについてそこまで厳密な解決を必要としないため、古いIDでも許容される場合があるのだ。

D365 F&Oの自動化や負荷テストを行うシステムエンジニアにとって、ここから得られる教訓は明確だ。TargetIdやRootIdは、どんなツールを使ってリクエストを送信するとしても、決してハードコードしてはいけない。常に実行時に、セッションごとに最新の値を解決して使用するべきである。また、UIコントロールを特定する際には、DOMのid属性全体ではなく、「data-dyn-controlname」のようなセッション間で安定した属性を「アンカー」として利用し、それからTargetIdやRootIdを取得する方法が推奨される。特に「投稿」「確定」「請求」といった、データベースのデータを直接変更するようなアクションの前には、これらの値を最新の状態に更新することに細心の注意を払う必要がある。なぜなら、これらのアクションこそ、古いIDが原因で自動化が完全に破綻する可能性が高いからだ。このような動的なIDの解決を実行プロセスに組み込むことで、「なぜか突然動かなくなった」といった将来的なデバッグ作業を大幅に減らすことができるだろう。

関連コンテンツ

関連IT用語

関連ITニュース