次の方法で共有


C# および X++ ソース コードを使用したビジネス ロジックを記述する

メモ

コミュニティの関心グループが Yammer から Microsoft Viva Engage に移行されました。 Viva Engage コミュニティに参加し、最新のディスカッションに参加するには、「 Finance and Operations Viva Engage Community へのアクセスを要求する 」フォームに入力し、参加するコミュニティを選択します。

このチュートリアルの主な目的は、 C# と X++ 間で相互運用性について説明することです。 このチュートリアルでは、C# ソース コードおよび X++ ソース コードでビジネス ロジックを記述します。

以下の経験が得られます:

  • Visual Studio の新しいツール。
  • C# でのイベント処理です。
  • C# の言語統合クエリ (LINQ) を使用してデータをフェッチする。

前提条件

このチュートリアルでは、リモート デスクトップを使用して環境にアクセスし、インスタンスの管理者としてプロビジョニングされる必要があります。

メモ

ソリューション内の項目に対してのみシンボルを読み込む チェックボックスが選択されている場合、C# プロジェクトのデバッグ サポートは機能しません。 このオプションが選択されている場合、ラボを実行する前に変更する必要があります。 指定されていない場合、デバッガはC# コードをデバッグできません。 Visual Studio で 拡張機能>オプション>Dynamics 365...>オプション > デバッグ をクリックし、ソリューション内の項目に対してのみシンボルを読み込む チェックボックスをクリアします。

シナリオ

フリート管理レンタル会社の経営陣は、危険な運転習慣の経歴を持つドライバーに、多くの車を貸し出していることに気づきました。 そのため、会社はレンタルを完了する前に、外部ソースから運転記録を確認する必要があります。 上層部は、運輸省 (DOT) が運用するサービスに加入することを決定しました。 これは、運転免許証と関連情報を管理する法人です。 このサービスは、指定された一意のライセンス番号の引用数を取得します。 X++ ソース コードから直接外部サービスを呼び出すことは容易ではありません。 Visual Studio にはサービスを呼び出す "コードビハインド" を (C# で) 生成するツールがあり、これらのツールにより開発作業が簡単になります。 このチュートリアルでは、ロジスティクスが単純なラボ環境の範囲を超えているため、コードが実際に外部サービスを呼び出すことはありません。 代わりに、モック実装を提供します。 このチュートリアルの目的は、C# の現在の状態と X++ との相互運用性を理解することであり、実際のソリューションを提供することではありません。

C# クラス ライブラリの作成

プロジェクトから、C# クラス ライブラリ、またはアセンブリを生成する C# プロジェクトの別のタイプへの参照を作成できます。 このような参照は、ビルド順序に影響します。 C# プロジェクトは、それを参照して依存するプロジェクトより前にビルドされます。 インフラストラクチャは参照を理解し、C# アセンブリが実行前にクラウドに正しく配置されるようにします。 フリート管理ソリューションで C# クラス ライブラリを作成するには、これらの手順に従います。

  1. Visual Studio で、ファイル> プロジェクト/ソリューションを開くをクリックします。

  2. プロジェクトを開くダイアログ ボックスのファイル名テキスト ボックスに次のパスを入力してから Enter キーを押します - C:\users\public\desktop\FleetManagement

  3. FleetManagement.sln というファイルを選択し、開く をクリックします。 ソリューション ファイルが自分のコンピューターにない場合、ファイルを作成するには フリート管理のサンプル アプリケーションのためのエンド ツー エンドのシナリオ を参照してください。

    OpenProject_LinqC.

  4. FleetManagement ソリューションを右クリックし、追加>新しいプロジェクト をクリックします。 新しいプロジェクトの追加 ダイアログ ボックスが表示されます。

  5. 左ウィンドウで、Visual C# をクリックしてから、中央ウィンドウでクラス ライブラリをクリックします。

  6. 下部の 名前テキスト ボックスに名前 DriversLicenseEvaluator と入力します。

  7. 場所テキスト ボックスに、C:\users\public\desktop\FleetManagement というディレクトリ パスを入力します。

  8. 上部にあるドロップダウン リストで、プロジェクトが ".NET Framework 4.5" に設定されていることを確認します。

  9. プロジェクトを作成するには、OK をクリックします。

    AddNewProject_LinqC.

  10. ソリューション エクスプローラーの DriversLicenseEvaluator プロジェクトで、ファイル名 Class1.cs を右クリックして DriversLicenseChecker.cs に名前を変更します。

  11. クラスへのすべての参照の名前を変更するか、確認するメッセージが表示されたら、はいをクリックします。

    RenameClass_LinqC.

CheckDriversLicense という名前で C# メソッドを記述

このセクションでは、CheckDriversLicenseという名前のメソッドのC# コードを追加して、運転免許証を検証します。 これを行うには、メソッドは顧客テーブルに格納されている運転免許証番号を取得する必要があります。 このメソッドには、メソッドで必要な情報が含まれている顧客レコードの RecId 値が与えられます。 C# コードは、LINQ プロバイダーを使用して、顧客テーブルから顧客レコードを検索します。

  1. 以下のコードで使用する共通タイプを含むサポート アセンブリも追加する必要があります。 アプリケーション バージョンの PackagesLocalDirectory フォルダーの下の bin フォルダーから、次のアセンブリを追加します:

    • Microsoft.Dynamics.AX.Xpp.Support.dll
    • Microsoft.Dynamics.AX.Data.Core.dll
  2. 追加をクリックし、OK をクリックします。 アセンブリが、プロジェクトの参照ノードの下に表示されます。

  3. 参照の追加 プロセスを繰り返します。ただし、今回は以下の DLL ファイルを指定されたパスから追加します。

    • C:\Packages\FleetManagement\bin 内の Dynamics.Ax.FleetManagement.dll
  4. ソリューション エクスプローラーで、Dynamics.Ax.FleetManagement.dll の参照を選択し、プロパティ Copy Local = False に設定します。

  5. ソリューション エクスプローラーで、DriversLicenseChecker.cs を右クリックしてから、コードの表示をクリックします。

  6. DriversLicenseEvaluator 名前空間に、次の使用する 3 つのステートメントを追加し、外部クラスを参照するコードの冗長性を減らします。

    • Dynamics.AX.Application の使用;
    • Microsoft.Dynamics.AX.Framework.Linq.Data の使用;
    • Microsoft.Dynamics.AX.Xpp の使用;

    これで、C# コードは次のように見える必要があります。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace DriversLicenseEvaluator
    {
        using Dynamics.AX.Application;
        using Microsoft.Dynamics.AX.Framework.Linq.Data;
        using Microsoft.Dynamics.Ax.Xpp;
    
        public class DriversLicenseChecker
        {
        }
    }
    
  7. クラス CheckDriversLicense を次のコードに置き換えます。

    ヒント

    C:\FMLab ディレクトリ内の DriversLicenseChecker.cs ファイルからコードに貼り付けることもできます。

    public class DriversLicenseChecker
    {
        public static bool CheckDriversLicense(long customerId)
        {
            // Use LINQ to get back to the information about the license number
            FMCustomer customer;
            QueryProvider provider = new AXQueryProvider(null);
            var customers = new QueryCollection<FMCustomer>(provider);
    
            // Build the query (but do not execute it)
            var query = from c in customers 
                where c.RecId == customerId 
                select c;
    
            // Execute the query:
            customer = query.FirstOrDefault();
            if (customer == null)
            {
                throw new ArgumentException
                    ("The customerId does not designate a customer");
            }
    
            if (string.IsNullOrEmpty(customer.DriverLicense))
            {
                // No driver's license was recorded. Veto the rental.
                return false;
            }
    
            // Call the DOT web service to validate the license number.
            // This is not practical for this lab, because all the service providers
            // charge for this service. Instead, just assume that any license number
            // that contains the sequence "89" is valid.
            // In the demo data, this is true for Adrian Lannin,
            // but not for Phil Spencer.
            return customer.DriverLicense.Contains("89");
        }
    }
    

LINQ コードを理解する

さらに C# コードに進む前に、追加した LINQ コードを理解していることを確認してください。 LINQ の詳細については、技術概念ガイド を参照してください。 基本的なことを以下に示します。

  • 最初に、プロバイダーを作成します。 すべてのテーブルへのアクセスを提供します。
  • 次に、すべての顧客のコレクションが作成されます。 利息のある顧客はこのコレクションから取得されます。
  • 次に、RecId によって要求された顧客を指定する where 句で クエリ が作成されます。
  • FirstOrDefault メソッドを呼び出すと、クエリが強制的に実行されます。
  • このメソッドは、一致する単一の顧客を顧客変数に割り当てます。 (指定された RecId 値を持つレコードが顧客データベースに存在しない場合は、Null が割り当てられます。)
  • 最後に、関連付けられている運転免許証が有効かどうかを確認するため、顧客データをテストします。 (おもちゃの例では、ライセンスに "89" が含まれているかどうかを確認しますが、現実の世界のソリューションでは外部サービスを呼び出します。)

レコードが追加されると、イベントが処理されます。

次のサブセクションでは、次の項目について説明します。

  • 次のコード品目および総合関係について説明します。
  • イベント ハンドラーのコードを表示します。
  • ハンドラーをイベントの発生に関連付けます。

準備の概要

テーブルにレコードを追加しようとすると、そのレコードがデータベースに保存される前に、OnValidateWrite イベントが発生します。 顧客のライセンス番号の判断を渡すことができるように、FMRental テーブルに対して OnValidateWrite イベントが発生するたびに、CheckDriversLicense メソッドを呼び出す必要があります。 これを行うには、イベントによって呼び出され、checkDriversLicense メソッドを呼び出す C# メソッドを記述する必要があります。 つまり、CheckDriversLicense メソッドを呼び出すイベント ハンドラーを記述する必要があります。 イベント ハンドラー メソッドは、型 DataEventArgs のパラメーターを受け取ります。 イベント ハンドラーは、レコードを承認または拒否するかを DataEventArgs 構造の値に設定できます。 イベント ハンドラー メソッドを書き込んだ後は、イベントに割り当てて接続するか、または FMRental テーブルのメンバーである OnValidatedWrite をデリゲートして追加します。 FMRental フォームのデータ ソースの init メソッドにこの割り当てを記述します。

デリゲートへのこの割り当ては奇妙に思える場合があります。 結局のところ、既存のコード (FMRental) を変更して、ハンドラーを追加します。これはイベントが提供する予定の疎結合の主な価値提案と矛盾しています。 これを X++ で行う場合、次の例に示すように、SubscribesTo 属性を使用してイベント ハンドラーをイベントに接続します。

    [SubscribesTo(tablestr(CompanyInfo), delegatestr(Customer, validateWriteDelegate))]
    public static void onvalidateWrite(Customer customerInfo, EventHandlerResult eventHandlerResult)
    {
        boolean ok = true; // check for the validity

        eventHandlerResult.result(ok);
    }

ただし、X++ コンパイラによって提供される機能が必要であり、この機能はC# では使用できません。 したがって、C# で使用できるイベントメカニズムを使用する必要があります。

メモ

データ ソース init メソッドは、フォームを開いたときに呼び出されます。 技術的には、init メソッドは FormDataSource クラスから継承されます。

イベント ハンドラー メソッドの記述

C# では、次のイベント ハンドラー メソッドを記述して DriversLicenseChecker クラスに追加します。

public static void OnValidatedWriteHandler(Common table, DataEventArgs args)
{
    var validateEventArgs = args as ValidateEventArgs;

    // Do not check if already rejected.
    if (validateEventArgs.parmValidateResult())
    {
        var rentalTable = table as FMRental;
        if (rentalTable == null)
        {
            throw new ArgumentNullException("table");
        }

        var result = CheckDriversLicense(rentalTable.Customer);
        validateEventArgs.parmValidateResult(result);
    }
}

プロジェクト ノードを右クリックしてからビルドをクリックし、DriversLicenseEvaluator プロジェクトをビルドします。

DriversLIcenseEvaluator プロジェクトを指定する参照の追加

次の手順を実行し、移行された FleetManagement という名前の X++ プロジェクトから DriversLicenseEvaluator という名前の C# プロジェクトへの参照を作成します。

  1. FleetManagement Migrated プロジェクトを右クリックし、追加 をクリックして 参照 をクリックします。 プロジェクト 参照タブで DriversLicenseEvaluator プロジェクトの行を選択し、OK をクリックします。

    AddReference_LinqC.

  2. FleetManagement 移行プロジェクトで 参照 ノードを展開すると、DriversLicenseEvaluator プロジェクトへの新しい参照が表示されます。

    SolutionExplorerReferences_LinqC.

ビルド順序

C# DriversLicenseEvaluator プロジェクトは、 FleetManagement 移行プロジェクトのビルド前にビルドされます。 これは、追加された参照によって、フリート プロジェクトがプロジェクトに依存するためです。 ビルド シーケンスを簡単に確認するには、FleetManagement ソリューションを右クリックし、 プロジェクト ビルド順序 をクリックして、 相互関係 をクリックします。

ProjectDependencies1_LinqC.

ProjectDependencies2_LinqC.

委任へのイベント ハンドラーの追加

  1. ソリューション エクスプローラーで、移行された FleetManagement > ユーザー インターフェイス > フォーム > FMRental に進みます。

  2. FMRental フォームをダブルクリックします。 Visual Studio デザイナーは、このフォームを開きます。

  3. フォームで使われるデータ ソースを表示するには、データ ソースノードを展開します。

  4. FMRental データ ソースおよびメソッドノードを展開し、データ ソースで定義されたメソッドを一覧表示します。

  5. メソッド を右クリックし、オーバーライド > メソッド をクリックします。 リストには、まだ上書きされていないデータ ソース上のすべてのメソッドが表示されます。 init を選択すると、FMRental.xpp ファイルが X++ コード エディタ内に開き、カーソルが init メソッドのテンプレートの近くに表示されます。

  6. 初期化メソッド本体の最後に、+= 演算子を使用してデリゲートに 1 つの割り当てを追加します。

    FMRental.onValidatedWrite += eventhandler
        (DriversLicenseEvaluator.DriversLicenseChecker::OnValidatedWriteHandler);
    
  7. 保存 をクリックして、ソリューション全体をビルドします。

最終テスト

このセクションでは、ブレークポイントを設定し、Visual Studio デバッガーでフリート アプリケーションを実行します。 これにより、次のことを証明できます。

  • LINQ クエリは、OnValidateWrite イベントが発生したときに実行されます。
  • LINQ クエリが、顧客のデータの取得に成功します。

テストの準備

  1. ソリューション エクスプローラーで、移行された FleetManagement > ユーザー インターフェイス > フォームに進みます。

  2. FMRental を右クリックし、スタートアップ オブジェクトとして設定 をクリックします。

  3. DriversLicenseChecker.cs のコード エディターで、OnValidateWriteHandler メソッドを検索します。 次のコード行を検索します。

    var result = CheckDriversLicense(rentalTable.Customer);
    
  4. このコード行にブレークポイントを設定します。 その行の左マージンをクリックします。 ブレークポイントが設定されている場合は、赤いドットが表示されます。

  5. CheckDriversLicense メソッドでは、次の行で別のブレークポイントを設定します。

    if (string.IsNullOrEmpty(customer.DriverLicense))
    

テストの実行

このテストでは、書き込んだ C# コードをデバッグします。 これを行うには、Visual Studio に C# コードを含むアセンブリのシンボルを読み込むように通知する必要があります。 Dynamics 365 > オプション > デバッグ の順に移動し、ソリューション内の項目に対してのみシンボルを読み込む チェックボックスが選択されていないことを確認します。

Options_LinqC.

ヒント

C# コードでブレークポイントに到達できない場合、モジュールウィンドウ (デバッグ>ウィンドウ>モジュール) で開けて、C# モジュールを検索し、明示的に読み込みます。

  1. デバッグ > デバッグを開始とクリックします。 これにより、フリート アプリケーションが開始され、FMRental フォームのブラウザー ウィンドウが表示されます。

  2. 車両レンタル ID をクリックすると詳細が表示されます。

  3. フォームの左上隅にある編集アイコンをクリックします。 アイコンは鉛筆のように見えます。

  4. レンタルセクションの終了フィールドで、1 日ごとに日付を増加させます。

  5. 保存ボタンをクリックします。 これにより、強調表示されたブレークポイントで Visual Studio にフォーカスが移動します。 この行は、OnValidatedWrite イベントが発生し、ハンドラー メソッド が呼び出されたことを示しています。

  6. F5 キーを押して実行を続行します。 すぐに、その他のブレークポイントが強調表示されます。

  7. ブレークポイントの数行上で、変数の顧客を検索します。

  8. 顧客変数を右クリックし、QuickWatch をクリックします。 長整数値は、LINQ クエリが機能していることを証明します。

    QuickWatch_LinqC.

  9. F5 キーを押して保存操作を完了します。