為替レート プロバイダーの作成

Note

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

この記事では、為替レート プロバイダーを設定する手順について説明します。 この記事では、OANDA 為替レート サービスを使用しています。 この記事の手順に従って、機能する為替レート プロバイダーを作成します。 このコードは生産コードです。 ソースは ExchangeRateProviderOanda クラスで見つけることができます。 必要に応じて、この記事からこのクラスを参照することができます。 OANDA テスト アカウントを要求し、OANDA 為替レート サービスに関する情報を受け取るには、OANDA 為替レート API を参照してください。

用語

  • 現在の通貨為替レートをインポート – 為替レート プロバイダーから為替レートを取得してインポートするプロセス。 このプロセスは、バッチ処理をサポートするシステム操作です。
  • 為替レート プロバイダー – 外部ソースからの為替レートの取得を担当する X++ クラス。
  • 為替レート プロバイダーの登録 – 使用できるように為替レート プロバイダーを有効にするプロセス。 既定では、システムは為替レート プロバイダーをデプロイするときに登録しません。
  • 為替レート プロバイダーの構成 – 使用方法を決定する為替レート プロバイダーの構成設定。
  • 為替レート サービス – 公開する為替レートの一覧を提供する無料または有料のサブスクリプション サービス。 OANDA による外貨為替レートは、為替レートを提供するサービスの例です。
  • フレームワーク – プロバイダーからの為替レートの取得および、その為替レートの適切なストレージを調整するインポート通貨の為替レートのフレームワーク。
  • SysPlugin フレームワーク - この拡張フレームワークは、Managed Extension Framework に基づいています。 マネージ拡張フレームワークは、SysPlugin 拡張フレームワークを非 X++ コードで使用できるようにします。 詳細については、[工場メソッドに対する登録] (../機能性/レジスター - 工場 - メソッド) を参照してください。

概念/クラス モデル

次の図は、為替レート プロバイダーのフレームワークを構成する主なインターフェイスとクラス、およびそれらの関係を示しています。 新しい為替レート プロバイダーは 、IExchangeRateProvider インターフェイスを 実装する必要があります。 X++ で為替レート プロバイダーを記述します。 X++ は .NET 言語であるため、プロバイダーで Microsoft .NET Framework を簡単に使用できます。

為替レート プロバイダー フレームワークの概念/クラス モデルのスクリーンショット。

この図は、次のインターフェイスとクラスを示しています。

  • IExchangeRateProvider – このインタフェースを実装すると、為替レート プロバイダー フレームワークがクラスを為替レート プロバイダーとして認識できるようになります。
  • IExchangeRateProviderFrameworkFactory – このインターフェイスにより、為替レート プロバイダーは、図の中のいくつかのインターフェイスを表す様々なタイプのプロバイダー フレームワーク クラスを作成することができます。
  • IExchangeRateProviderSupportedOptions – 為替レート プロバイダーは、レートをインポートするときにいくつかのオプションをサポートします。 為替レート プロバイダーは、このインターフェイスを使用して、サポートするオプションについてフレームワークに通知します。
  • IExchangeRateProviderConfig – 各為替レート プロバイダーは、固有のコンフィギュレーションを持つことができます。 このインターフェイスにより、プロバイダーはこの構成を取得できます。
  • IExchangeRateProviderConfigDefaults – 為替レート プロバイダーは、構成のデフォルト値を作成して提供できます。 ユーザーは、[ 為替レート プロバイダーの構成 ] ページ ([General ledger>Currencies ]\(通貨\) **>**[為替レート プロバイダーの構成]) でこれらの値を変更できます。
  • IExchangeRateRequest – このインターフェイスは、為替レートのインポートを要求する固有のデータを表します。 このデータには、日付範囲、オプション、レートを取得するための通貨ペアが含まれます。
  • IExchangeRateCalendar – このインターフェイスは、次の作業日 (月曜日から金曜日まで) を取得する場合に使用される為替レート カレンダーを表します。
  • IExchangeRateResponse – 為替レート プロバイダーでは、このインターフェイスを使用して、通貨のペアや、サービスから返される為替レートを格納します。
  • IExchangeRateResponseCurrencyPair – 為替レート プロバイダーでは、このインターフェイスを使用して、サービスから返される特定の通貨ペアの詳細を格納します。
  • IExchangeRateResponseExchangeRate – 為替レート プロバイダーでは、このインターフェイスを使用して、特定の通貨ペアに対して特定の為替レートを格納します。
  • ExchangeRateProviderOanda – Microsoft が実装した為替レート プロバイダーのこの例は、OANDA サービスに接続して為替レートを返します。

為替レート プロバイダーを記述

コード例は 、ExchangeRateProviderOanda クラスに由来します。 為替レート プロバイダーを作成するには、これらの手順に従います。

  1. 自身の開発モデルで、IExchangeRateProvider インターフェイスを実装するクラスを作成します。

    using Microsoft.Dynamics.ApplicationSuite.FinancialManagement.Currency.Framework;
    using Microsoft.Dynamics.Currency.Instrumentation;
    using System.Collections;
    
    using System.ComponentModel.Composition;
    
    /// <summary>
    /// The <c>ExchangeRateProviderOanda</c> class is an exchange rate provider for OANDA.
    /// </summary>
    [ExportMetadataAttribute(enumStr(ExchangeRateProvider), ExchangeRateProvider::OANDA), ExportAttribute('Microsoft.Dynamics.ApplicationSuite.FinancialManagement.Currency.Framework.IExchangeRateProvider')]
    class ExchangeRateProviderOanda implements IExchangeRateProvider
    {
    }
    
  2. クラスに、次の定数と変数宣言を追加します。

    private const URL ServiceURL = 'https://www.oanda.com/rates/api/v1/rates/%1.xml?quote=%2&start=%3&end=%4&fields=%5&decimal_places=%6';
    private const ExchangeRateProviderId ProviderId = '795500B1-4258-4343-868C-433CE390848C';
    private const str OANDADateFormat = 'yyyy-MM-dd';
    private const str HttpWebRequestMethod = 'GET';
    private const str HttpWebRequestContentType = 'application/xml';
    private const str HttpHeaderAuthorization = 'Authorization';
    private const str KeyTokenPrefix = 'Bearer ';
    private const str XPathQuote = '//response/quotes/quote';
    private const str XPathAverageBid = '//bid';
    private const str XPathAverageAsk = '//ask';
    private const str XPathLowBid = '//low_bid';
    private const str XPathLowAsk = '//low_ask';
    private const str XPathMidpoint = '//midpoint';
    private const str XPathDate = '//quote/date';
    private const str XPathHighBid = '//high_bid';
    private const str XPathHighAsk = '//high_ask';
    private const str QuoteParameterAverages = 'averages';
    private const str QuoteParameterLows = 'lows';
    private const str QuoteParameterMidPoint = 'midpoint';
    private const str QuoteParameterHighs = 'highs';
    IExchangeRateProviderFrameworkFactory factory;
    
  3. get_Name メソッドを実装します。 ラベルを使用して適切な翻訳を有効にします。 ユーザーは、プロバイダーの構成情報を設定するときに指定する名前を変更できます。

    public ExchangeRateProviderName get_Name()
    {
        return "@CurrencyExchange:Currency_ConfigField_OandaName";
    }
    
  4. get_Id メソッドを実装します。 このメソッドは、このプロバイダーを一意に識別するグローバル一意識別子 (GUID) を返します。

    public ExchangeRateProviderId get_Id()
    {
        return ProviderId;
    }
    
  5. set_Factory メソッドを実装します。 為替レート プロバイダー フレームワークは、このメソッドを呼び出して、プロバイダーに IExchangeRateProviderFrameworkFactory インターフェイスを実装するオブジェクトを設定します。 このファクトリを使用して、前の図のインターフェイスの一部を表す新しいオブジェクトをインスタンス化します。

    public void set_Factory(IExchangeRateProviderFrameworkFactory _factory)
    {
        factory = _factory;
    }
    
  6. GetSupportedOptions メソッドを実装します。 このメソッドは、為替レート プロバイダーは、一部のフレームワーク機能をサポートするかどうかを示します。

    • 為替レートを取得するために渡すソースおよびターゲットの通貨を渡すことが為替レート サービスに必要な場合にのみ、doesSupportSpecificCurrencyPairs プロパティを true に設定します。 多くの為替レート サービスが、固定通貨または通貨ペアの指定されたセットを返します。 これらのサービスでは、このオプションを false に設定 します。 サービス料金がレート数のクォータに基づく場合、値が true の場合、IExchangeRateRequest インターフェイスには、為替レート ページ (General ledger>>) で為替レートの種類に対して構成されている通貨ペアのみが含まれます。 プロバイダーはその後、これらの料金をサービスから具体的に要求できるため、コストを削減できます。
    • fixedBaseIsoCurrency プロパティを、為替レート サービスが返す為替レートの固定ベース通貨を表す 3 文字の国際標準化機構 (ISO) 通貨コードに設定します。 為替レート サービスが固定基本通貨をサポートしていない場合は、空の文字列を返します。 たとえば、ユーロは固定基本通貨としてよく使用されます。 新しいプロバイダーを作成するときは、正しい値を選択できるように、為替レート サービスをかならず調査してください。
    • サービスが日付範囲全体を表す単一のレートを返すことができる場合、singleRateForDateRange プロパティを true に設定します。 たとえば、1 か月の平均為替レートを表す単一の為替レートを返すには、この設定を使用できます。 サービスがこの機能をサポートしていない場合は、このプロパティを false に設定します。
    public IExchangeRateProviderSupportedOptions GetSupportedOptions()
    {
        IExchangeRateProviderSupportedOptions options = factory.CreateExchangeRateProviderSupportedOptions();
    
        options.set_doesSupportSpecificCurrencyPairs(true);
        options.set_doesSupportSpecificDates(false);
        options.set_fixedBaseIsoCurrency('');
        options.set_singleRateForDateRange(true);                        
        options.set_doesSupportPreventImportOnNationalHoliday(false);
        options.set_DoesSupportExchangeRateFromPreviousDay(false);
    
        return options;
    
  7. GetConfigurationDefaults メソッドを実装します。 既定のコンフィギュレーションは、為替レート プロバイダの既定コンフィギュレーションの設定を表す名前と値の組です。 プロバイダーが登録されると、フレームワークによってこれらの設定が自動的に読み込まれますが、ユーザーは設定を変更できます。 これらの文字列を使用可能な値に変換する場合は、必要な対策を講じてください。 値フィールドは、SQL で暗号化フィールドとして格納されます。 そのため、アプリケーション プログラミング インターフェイス (API) キーなどの機密データの安全性が高くなります。

    public IExchangeRateProviderConfigDefaults GetConfigurationDefaults()
    {
        IExchangeRateProviderConfigDefaults configurationDefaults = factory.CreateExchangeRateProviderConfigDefaults();
        configurationDefaults.addNameValueConfigurationPair("@CurrencyExchange:Currency_ConfigField_ServiceTimeout", '5000');
        configurationDefaults.addNameValueConfigurationPair("@CurrencyExchange:Currency_ConfigField_OandaAPIKey", '');
        configurationDefaults.addNameValueConfigurationPair("@CurrencyExchange:Currency_ConfigField_DecimalPlaces", '5');
        configurationDefaults.addNameValueConfigurationPair("@CurrencyExchange:Currency_ConfigField_QuoteType", '1');
        configurationDefaults.addNameValueConfigurationPair("@CurrencyExchange:Currency_ConfigField_QuoteTypeLocked", '1');
        return configurationDefaults;
    }
    
  8. ValidateConfigurationDetail メソッドを実装します。 このメソッドにより、為替レート プロバイダーは、為替レート プロバイダーの構成ページでユーザーが変更した構成情報を検証できます。

    public boolean ValidateConfigurationDetail(ExchangeRateProviderPropertyKey _key, ExchangeRateProviderPropertyValue _value)
    {
        boolean result = true;
        switch (_key)
        {
            case "@CurrencyExchange:Currency_ConfigField_DecimalPlaces":
                int decimals = str2Int(_value);
                if ((decimals > 12) || (decimals < 1))
                {
                    CurrencyEventSource eventSource = CurrencyEventSource::Log;
                    eventSource.ImportExchangeRateMark("@CurrencyExchange:Currency_ConfigMessage_DecimalPlacesInvalid");
                    error("@CurrencyExchange:Currency_ConfigMessage_DecimalPlacesInvalid");
                    result = false;
                }
                break;
            case "@CurrencyExchange:Currency_ConfigField_OandaAPIKey":
                if (_value == '')
                {
                    CurrencyEventSource eventSource = CurrencyEventSource::Log;
                    eventSource.ImportExchangeRateMark("@CurrencyExchange:Currency_ConfigMessage_OANDAKeyRequired");
                    warning("@CurrencyExchange:Currency_ConfigMessage_OANDAKeyRequired");
                }
                break;
        }
        return result;
    }
    
  9. EnumNameForLookup メソッドを実装します。 このメソッドは、為替レート プロバイダーが特定の ExchangeRateProviderPropertyKey キーを参照できるようにします。 適切なキーに対して列挙された既存の型の名前を返します。 この機能が必要でない場合は、空の文字列を返します。

    public str EnumNameForLookup(ExchangeRateProviderPropertyKey _key)
    {
        if (_key == "@CurrencyExchange:Currency_ConfigField_QuoteType")
        {
            return enumStr(ExchangeRateProviderOANDAQuoteType);
        }
        return '';
    }
    
  10. GetExchangeRates メソッドを実装します。 このメソッドは、構成情報と、IExchangeRateRequest インターフェイスを使用して、交換レート サービスを呼び出すとともに、IExchangeRateResponse クラスの適切なインスタンスを返します。 このメソッドを記述するときは、以下の重要な点を考慮します。

    • IExchangeRateProviderConfig インターフェイスから必要な構成情報を取得します。 そのインターフェイスで GetPropertyValue メソッドを呼び出すと、指定されたプロパティ キーのプロパティ値の文字列表現が提供されます。 この文字列値を別の型に変換する場合は、必要な対策を講じてください。

    • 事前に必要な検証を行います。 たとえば、OANDA は、すべてのサービス コールで API キーを指定するよう要求します。 この API キーが設定されていない場合、サービスは失敗します。 API キーが設定されていることを確認し、早期に終了して適切なエラー メッセージを受け取ります。

    • 一部のプロバイダーには、為替レートが要求される場合に明示的な通貨の組み合わせが必要です。 これらのプロバイダーは、IExchangeRateProviderSupportedOptions.doesSupportSpecificCurrencyPairs プロパティを true に設定したプロバイダーと同じです。 この場合は、 IExchangeRateRequest インターフェイスが提供する通貨ペアを使用して、取得プロセスを実行します。 後に続く OANDA プロバイダーの実装には、このタイプのプロバイダーの適正例が示されます。 通常、特定の通貨の組み合わせをサポートしていないプロバイダーは、固定された通貨の組み合わせのデータを返します。 この場合、IExchangeRateRequest インターフェイスが提示する通貨ペアは無視できます。 プロバイダーは利用可能なすべてのレートを返す必要があります。フレームワークは、必要な通貨ペアを自動的に作成するかどうかに関するユーザーの決定に基づいて、正しいレートをインポートします。 CentralBankOfEuropeProvider プロバイダーは、このタイプのプロバイダーの適切な例です。

    • IExchangeRateRequest インターフェイスには、ImportDateType という名前のプロパティがあります。 このプロパティは、サービスから為替レートを取得するために使用する日付を示します。 利用可能な 2 つの値は、CurrentDateDateRange です。

      • CurrentDate は、為替レート サービスから最新の為替レートを取得します。 また、プロバイダーにこの値が渡されると、フレームワークは、IExchangeRateRequest.FromDate および IExchangeRateRequest.ToDate を、要求している Application Object Server (AOS) コンピュータのシステム日付に設定します。 為替レート サービスが特定の日付の為替レートの取得をサポートしている場合は、フレームワークが提供する日付を渡します。 ただし、(日付に関係なく) 最新の為替レートを取得するための呼び出しを為替レート サービスが提供する場合は、日付を検証して、要求された日付以下であることを確認します。
      • DateRange は、特定の日付範囲の為替レートを取得します。 指定された日付範囲内の為替レートのみ許可される必要があります。 為替レート サービスで、特定の日付が要求に含まれることが必要とされる場合は、このプロセスは簡単です。 ただし、代わりに為替レート サービスが有効日の範囲外の可能性がある履歴日付のグループを返す場合、プロバイダーはフレームワークに日付を戻す前に該当しない日付を除外する必要があります。
    • 為替レートを返す場合は、 IExchangeRateRequest クラスのインスタンスが提供する日付ではなく、為替レート サービスが提供する日付を常に使用します。 この方法では、為替レート サービスが予期されていない日付のレートを返す場合があるため、返される為替レートが正しい日付に関連付けられていることを保証できます。 たとえば、将来の日付に対して為替レートが要求されると、一部のプロバイダーは、エラーをスローしたり何も返さない代わりに、最新の為替レートを返します。

    • 為替レート サービスからの為替レートを取得するときにエラーが発生する場合は、カスタム エラー メッセージをスローしないようにします。 フレームワークは、予想される通貨ペアをプロバイダーから取得できなかったことを示す一般的なエラー メッセージをスローすることで、問題があることをユーザーに警告します。 その他のエラーのログを記録する必要がある場合、CurrencyEventSource を使用します。 例については、次のコードで catch ステートメントおよび oandaKey 変数に対する IF 条件を参照してください。。

      public IExchangeRateResponse GetExchangeRates(IExchangeRateRequest _request, IExchangeRateProviderConfig _config)
      {
          System.Exception exception;
      
          // cache configuration and request properties locally for performance
          ExchangeRateProviderPropertyValue oandaKey = _config.GetPropertyValue(this.get_Id(), "@CurrencyExchange:Currency_ConfigField_OandaAPIKey");
          if (oandaKey == '')
          {
              CurrencyEventSource eventSource = CurrencyEventSource::Log;
              eventSource.ImportRatesException("@CurrencyExchange:Currency_ConfigMessage_OANDAKeyRequired", "");
              throw error("@CurrencyExchange:Currency_ConfigMessage_OANDAKeyRequired");
          }
      
          int decimalPlaces = str2Int(_config.GetPropertyValue(this.get_Id(), "@CurrencyExchange:Currency_ConfigField_DecimalPlaces"));
      
          int serviceTimeout = str2int(_config.getPropertyValue(this.get_Id(), "@CurrencyExchange:Currency_ConfigField_ServiceTimeout"));
      
          boolean singleRateForDateRange = _request.get_SingleRateForDateRange();
      
          ExchangeRateProviderOANDAQuoteType quoteType = str2Int(_config.getPropertyValue(this.get_Id(), "@CurrencyExchange:Currency_ConfigField_QuoteTypeLocked"));
      
          str quoteTypeParameterForOANDA = this.getQuoteTypeParameterForURL(quoteType);
      
          List rates = new List(Types::Real);
          List dates = new List(Types::Date);
      
          System.TimeZone localTimeZone = System.TimeZone::get_CurrentTimeZone();
      
          System.DateTime toUTCDate = localTimeZone.ToUniversalTime(_request.get_ToDate());
          str toDateForRequest = toUTCDate.ToString(OANDADateFormat);
      
          IExchangeRateResponse response = factory.CreateExchangeRateResponse();
      
          // Iterate over the requested currency pairs. This is only required for providers
          // that support specific currency pairs.
          IEnumerator currencyPairsEnumerator = _request.GetEnumerator();
          while(currencyPairsEnumerator.MoveNext())
          {
              URL OandaUrl = ServiceURL;
      
              // This loop will either execute once if singleRateForDateRange is true; otherwise, it will
              // execute once for each day.  If we make a single request for multiple dates
              // then OANDA will return an average rate for the date range.
              System.DateTime fromDate = _request.get_FromDate();
              int compareResult = fromDate.CompareTo(_request.get_ToDate());
              while (compareResult <= 0)
              {
                  IExchangeRateRequestCurrencyPair currencyPairRequest = currencyPairsEnumerator.Current;
      
                  IExchangeRateResponseCurrencyPair currencyPairResponse = factory.CreateExchangeRateResponseCurrencyPair();
                  currencyPairResponse.set_FromCurrency(currencyPairRequest.get_FromCurrency());
                  currencyPairResponse.set_ToCurrency(currencyPairRequest.get_ToCurrency());
      
                  // All rates are requested with a display factor of 1 for this provider. If the rates
                  // internally are represented using a different exchange rate display factor, the
                  // framework will make the necessary adjustments when saving the exchange rates.
                  currencyPairResponse.set_ExchangeRateDisplayFactor(ExchangeRateDisplayFactor::One);
      
                  // convert to UTC which is required by OANDA
                  System.DateTime fromUTCDate = localTimeZone.ToUniversalTime(fromDate);
                  str fromDateForRequest = fromUTCDate.ToString(OANDADateFormat);
      
                  // Build the request URL.
                  str oandaRequestString;
                  if (singleRateForDateRange)
                  {
                      // getting an average rate for the date range so we invoke the service
                      // only once per currency pair using the from and to date
                      oandaRequestString = strFmt(OandaUrl,
                                      currencyPairRequest.get_FromCurrency(),
                                      currencyPairRequest.get_ToCurrency(),
                                      fromDateForRequest,
                                      toDateForRequest,
                                      quoteTypeParameterForOANDA,
                                      decimalPlaces);
                  }
                  else
                  {
                      // invoke the service once for each day. 
                      oandaRequestString = strFmt(OandaUrl,
                                      currencyPairRequest.get_FromCurrency(),
                                      currencyPairRequest.get_ToCurrency(),
                                      fromDateForRequest,
                                      fromDateForRequest,
                                      quoteTypeParameterForOANDA,
                                      decimalPlaces);
                  }
      
                  // Configure the request for OANDA.
                  System.Net.HttpWebRequest httpWebRequest = System.Net.WebRequest::CreateHttp(oandaRequestString);
                  httpWebRequest.set_Method(HttpWebRequestMethod);
                  httpWebRequest.set_ContentType(HttpWebRequestContentType);
                  httpWebRequest.set_Timeout(serviceTimeout);
      
                  // Authentication
                  System.Net.WebHeaderCollection webCollection = httpWebRequest.get_Headers();
                  webCollection.Add(HttpHeaderAuthorization, KeyTokenPrefix + oandaKey);
      
                  try
                  {
                      // Invoke the service
                      System.Net.WebResponse webResponse;
                      webResponse = httpWebRequest.GetResponse();
      
                      // Retrieve the XML response.
                      System.IO.Stream stream = webResponse.GetResponseStream();
                      System.IO.StreamReader streamReader = new System.IO.StreamReader(stream);
                      str XMLOut = streamReader.ReadToEnd();
      
                      // Parse the XML to retrieve the rate and date.
                      this.processResult(quoteType, singleRateForDateRange, _request.get_FromDate(), XMLOut, rates, dates);
      
                      ListEnumerator rateEnumerator = rates.getEnumerator();
                      ListEnumerator dateEnumerator = dates.getEnumerator();
      
                      // Create the Exchange Rate Provider Response.
                      rateEnumerator.moveNext();
                      dateEnumerator.moveNext();
                      CurrencyExchangeRate exchangeRate = rateEnumerator.current();
                      date currentDate = dateEnumerator.current();
      
                      if (currentDate != dateNull() && exchangeRate)
                      {
                          IExchangeRateResponseExchangeRate exchangeRateResponse = factory.CreateExchangeRateResponseExchangeRate();
                          exchangeRateResponse.set_ValidFrom(currentDate);
                          exchangeRateResponse.set_ExchangeRate(exchangeRate);
                          currencyPairResponse.addExchangeRate(exchangeRateResponse);
                      }
                  }
                  catch(exception)
                  {
                      CurrencyEventSource eventSource = CurrencyEventSource::Log;
                      eventSource.ImportRatesException(exception.Message, Exception.StackTrace);
                  }
      
                  response.addOrUpdateCurrencyPair(currencyPairResponse);
      
                  rates = new List(Types::Real);
                  dates = new List(Types::Date);
      
                  fromDate = fromDate.AddDays(1);
      
                  if (singleRateForDateRange)
                  {
                      // getting an average rate across the date range so we invoke the service  
                      // only once per currency pair
                      compareResult = 1;
                  }
                  else
                  {
                      compareResult = fromDate.CompareTo(_request.get_ToDate());
                  }
              }
          }
          return response;
      }
      
  11. 次のヘルパー メソッドを実装します。 これらのメソッドはこの例に固有のものであり、すべてのプロバイダーに必須ではありません。

    private str getQuoteTypeParameterForURL(IExchangeRateProviderConfig _config)
    {
        ExchangeRateProviderOANDAQuoteType quoteType = 
            str2Int(_config.getPropertyValue(this.get_Id(), "@CurrencyExchange:Currency_ConfigField_QuoteType"));
        str quoteTypeParameter;
        switch (quoteType)
        {
            case ExchangeRateProviderOANDAQuoteType::AverageAsk:
            case ExchangeRateProviderOANDAQuoteType::AverageBid:
                quoteTypeParameter = QuoteParameterAverages;
                break;
            case ExchangeRateProviderOANDAQuoteType::LowAsk:
            case ExchangeRateProviderOANDAQuoteType::LowBid:
                quoteTypeParameter = QuoteParameterLows;
                break;
            case ExchangeRateProviderOANDAQuoteType::MidPoint:
                quoteTypeParameter = QuoteParameterMidPoint;
                break;
            case ExchangeRateProviderOANDAQuoteType::HighAsk:
            case ExchangeRateProviderOANDAQuoteType::HighBid:
                quoteTypeParameter = QuoteParameterHighs;
                break;
        }
        return quoteTypeParameter;
    }
    private void readRate(IExchangeRateProviderConfig _config, System.Xml.XmlNode _xmlQuoteNode, List _rates)
    {
        System.Xml.XmlNode xmlRateNode;
        CurrencyExchangeRate exchangeRate;
        str value;
        ExchangeRateProviderOANDAQuoteType quoteType = str2Int(_config.getPropertyValue(this.get_Id(), "@CurrencyExchange:Currency_ConfigField_QuoteType"));
        // Find the exchange rate
        switch (quoteType)
        {
            case ExchangeRateProviderOANDAQuoteType::AverageBid:
                xmlRateNode = _xmlQuoteNode.SelectSingleNode(XPathAverageBid);
                break;
            case ExchangeRateProviderOANDAQuoteType::AverageAsk:
                xmlRateNode = _xmlQuoteNode.SelectSingleNode(XPathAverageAsk);
                break;
            case ExchangeRateProviderOANDAQuoteType::LowBid:
                xmlRateNode = _xmlQuoteNode.SelectSingleNode(XPathLowBid);
                break;
            case ExchangeRateProviderOANDAQuoteType::LowAsk:
                xmlRateNode = _xmlQuoteNode.SelectSingleNode(XPathLowAsk);
                break;
            case ExchangeRateProviderOANDAQuoteType::MidPoint:
                xmlRateNode = _xmlQuoteNode.SelectSingleNode(XPathMidpoint);
                break;
            case ExchangeRateProviderOANDAQuoteType::HighBid:
                xmlRateNode = _xmlQuoteNode.SelectSingleNode(XPathHighBid);
                break;
            case ExchangeRateProviderOANDAQuoteType::HighAsk:
                xmlRateNode = _xmlQuoteNode.SelectSingleNode(XPathHighAsk);
                break;
        }
        if (xmlRateNode)
        {
            value = xmlRateNode.get_InnerText();
            exchangeRate = str2num(value);
            if (exchangeRate)
            {
                _rates.addEnd(exchangeRate);
            }
        }
    }
    private void processResult(IExchangeRateProviderConfig _config, boolean _singleRateForDateRange, System.DateTime _defaultDate, 
        str _xmlString, List _rates, List _dates)
    {
        System.Xml.XmlDocument xmlDom = new System.Xml.XmlDocument();
        System.Xml.XmlNode xmlQuoteNode, xmlDateNode;
        ValidFromDate exchangeDate;
        str value;
        xmlDom.LoadXml(_xmlString);
        // Find the Quote
        xmlQuoteNode = xmlDom.SelectSingleNode(XPathQuote);
        if (xmlQuoteNode)
        {
            this.readRate(_config, xmlQuoteNode, _rates);
            // Find the date of the exchange rate.
            xmlDateNode = xmlQuoteNode.SelectSingleNode(XPathDate);
            if (xmlDateNode || _singleRateForDateRange)
            {
                if (xmlDateNode)
                {
                    value = xmlDateNode.get_InnerText();
                }    
                if (value)
                {
                    // convert the date from UTC to local timezone.
                    exchangeDate = System.DateTime::Parse(value, System.Globalization.CultureInfo::get_CurrentUICulture(),
                        System.Globalization.DateTimeStyles::AssumeUniversal);
                    if (exchangeDate)
                    {
                        _dates.addEnd(exchangeDate);
                    }
                }
                else if (!value && _singleRateForDateRange)
                {
                    exchangeDate = _defaultDate;
                    _dates.addEnd(exchangeDate);
                }
            }
        }
    }
    
  12. ExchangeRateProviderOanda クラスをコンパイルします。 プロバイダーは SysOperation の一部として実行されます。 問題をデバッグするときに、次のフレームワーク クラスおよびメソッドを理解しておくと便利です。

    • ExchangeRateProviderFactory.initialize() - このメソッドは、為替レート プロバイダーのインスタンスを作成し、為替レートの登録またはインポート時に呼び出されます。 プロバイダーにインスタンスが作成されていない場合、ここでデバッグを開始します。
    • ExchangeRateProviderRegistration.initialize() - このメソッドはプロバイダーを検索し、プロバイダーを登録できるようにします。 登録ページでプロバイダーがわからない場合は、ここでデバッグを開始します。
    • ExchangeRateImportOperation.import() - このメソッドでは、必要なプロバイダーを呼び出して為替レートを保存することによって、インポート プロセスを駆動します。
    • ExchangeRateProviderConfig - このクラスはプロバイダーのコンフィギュレーション情報へのアクセスを提供します。

考慮すべき事項

為替レート プロバイダーが為替レートを取得するために使用する方法に制限がないため、フレームワークではいくつかの興味深いシナリオが可能になります。 参照するアイデアを次に示します。

  • 他の種類の為替レートから為替レートを取得するプロバイダー – このシナリオでは、さまざまな為替レートの種類間で為替レートを同期できます。 この機能は、さまざまな台帳間の分離を維持するために、多くの為替レートの種類が存在する状況で役立ちます。
  • 使用するすべてのレートに対して一部の為替レート プロバイダー サービスの料金 が発生します。サービスから消費するレートごとに課金されるシナリオでは、この一覧の最初のアイデアと、サービスから取得するレートの数の制限を組み合わせることを検討してください。