次の方法で共有


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 で、[拡張機能>Options>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. 次のコードで使用される Common 型を含むサポート アセンブリを追加します。 アプリケーション バージョンの PackagesLocalDirectory フォルダーの下の bin フォルダーから、次のアセンブリを追加します:

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

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

    • Dynamics.Ax.FleetManagement.dll、in C:\Packages\FleetManagement\bin
  4. ソリューション エクスプローラーで、参照Dynamics.Ax.FleetManagement.dllを選択し、[ローカルコピー] プロパティを [Falseに設定します。

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

  6. 外部クラスを参照するコードの詳細度を減らすために、 DriversLicenseEvaluator 名前空間に次の 3 つの using ステートメントを追加します。

    • using Dynamics.AX.Application;
    • using Microsoft.Dynamics.AX.Framework.Linq.Data;
    • using 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 を次のコードに置き換えます。

    ヒント

    必要に応じて、DriversLicenseChecker.cs ディレクトリのC:\FMLab ファイルからコードを貼り付けることができます。

    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 イベントが発生します。 CheckDriversLicense テーブルに対してOnValidateWrite イベントが発生するたびに、FMRental メソッドを呼び出して、顧客のライセンス番号を確認できるようにします。 これを行うには、イベントが呼び出す C# メソッドを記述し、 CheckDriversLicense メソッドを呼び出します。 つまり、 CheckDriversLicense メソッドを呼び出すイベント ハンドラーを記述します。 イベント ハンドラー メソッドは、 DataEventArgs型のパラメーターを受け取ります。 イベント ハンドラーは、レコードを受け入れるか拒否するために、 DataEventArgs 構造体の値を設定できます。 イベント ハンドラー メソッドを記述した後、OnValidatedWrite テーブルのメンバーであるFMRental デリゲートに割り当てるか追加して、イベントに接続します。 この割り当てを、init フォームのデータ ソースのFMRentalメソッドに記述します。

デリゲートへのこの割り当ては奇妙に思える場合があります。 結局のところ、既存のコード (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 プロジェクトを指す参照を追加する

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

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

    Visual Studio の [参照の追加] ダイアログ ボックスのスクリーンショット。

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

    DriversLicenseEvaluator 参照を含む [参照] ノードを示すソリューション エクスプローラーのスクリーンショット。

ビルド順序

C# DriversLicenseEvaluator プロジェクトは、 FleetManagement 移行プロジェクトのビルド前にビルドされます。 追加された参照によって Fleet プロジェクトがプロジェクトに依存するため、このビルド順序が存在します。 ビルド シーケンスを表示するには、FleetManagement ソリューションを右クリックし、[ プロジェクトのビルド順序] を選択し、[依存関係] を選択 します

Visual Studio のビルド順序を示す [プロジェクトの依存関係] ダイアログ ボックスのスクリーンショット。

Visual Studio のプロジェクトの依存関係を示す [プロジェクトの依存関係] ダイアログ ボックスのスクリーンショット。

デリゲートにイベントハンドラーを追加します

  1. ソリューション エクスプローラーで、FleetManagement Migrated > User Interface > Forms > FMRental に移動します。

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

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

  4. FMRental データ ソースを展開し、[メソッド] ノードを展開して、データ ソースで定義されているメソッドを一覧表示します。

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

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

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

最終テスト

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

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

テストの準備

  1. ソリューション エクスプローラーでFleetManagement Migrated > User Interface > Forms に移動します。

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

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

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

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

    if (string.IsNullOrEmpty(customer.DriverLicense))
    

テストの実行

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

Visual Studio の [デバッグ オプション] ダイアログ ボックスのスクリーンショット。

ヒント

C# コードでブレークポイントに到達できない場合は、[モジュール] ウィンドウを開き (Windows > モジュール>デバッグ)、C# モジュールを見つけて、明示的に読み込むことができます。

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

  2. 詳細を表示するには、 車両レンタル ID を 選択します。

  3. フォームの左上付近にある [編集] アイコンを選択します。 アイコンは鉛筆のように見えます。

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

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

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

  7. ブレークポイントの数行上で、カスタマーという変数を見つけます。

  8. 顧客変数を右クリックし、[ クイック ウォッチ] を選択します。 長整数値は、LINQ クエリが機能していることを証明します。

    顧客変数を示す Visual Studio の [クイック ウォッチ] ウィンドウのスクリーンショット。

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