次の方法で共有


WCF チャネル モデルを使用して SAP システムから受信操作を受信する

RFC サーバーとして機能し、SAP システムによって呼び出された操作 (IDOC の送信や RFC の呼び出しなど) を受け取るには、 System.ServiceModel.Channels.IReplyChannel チャネル 図形を介して SAP プログラム ID からのメッセージをリッスンできるチャネル リスナーを作成する必要があります。

チャネル リスナー (System.ServiceModel.Channels.IChannelListener) は、特定の WCF エンドポイントからメッセージを受信するために使用できる WCF 通信オブジェクトです。 チャネル リスナーはファクトリとして機能し、クライアント (SAP システム) によって呼び出されたメッセージをサービスで受信できるチャネルを作成できます。 BuildChannelListener メソッドを呼び出して、Microsoft.Adapters.SAP.SAPBinding オブジェクトからチャネル リスナーを作成します。 このメソッドに対する受信操作の受信元となる SAP プログラム ID を指定する SAP 接続 URI を指定します。

SAP アダプターは 、IReplyChannel チャネル図形をサポートしています。 IReplyChannel チャネルは 、受信要求/応答メッセージ交換パターンをサポートします。 つまり、外部プログラムがチャネル経由で要求メッセージを送信し、プログラムが応答を返すパターンです。

WCF で IReplyChannel を使用して操作を受け取る方法の概要については、「 サービス Channel-Level プログラミング」を参照してください。

このセクションでは、SAP システムからの操作の受信に固有の次のトピックについて説明します。

  • チャネル リスナーを使用して特定の操作をフィルター処理する方法。

  • SAP システムで例外を発生させる方法。

  • SAP アダプターからの受信フラット ファイル IDOC のストリーミング。

  • SAP システムから操作を受信する方法。

チャネル リスナーを使用して操作をフィルター処理する方法

InboundActionCollection を使用した操作のフィルター処理

WCF LOB アダプター SDK には 、Microsoft.ServiceModel.Channels.InboundActionCollection クラスが用意されており、チャネル リスナーによって受信され、アプリケーション コードに渡される操作をフィルター処理できます。 特定の操作をフィルター処理するには、リスナー エンドポイント URI を使用してこのクラスのインスタンスを作成します。 次に、各ターゲット操作の (要求) メッセージ アクションをコレクションに追加します。 最後に、受信アクション コレクションを System.ServiceModel.Channels.BindingParameterCollection オブジェクトに追加し、このバインド パラメーター コレクションを呼び出しに渡してチャネル リスナーを作成します。

SAP システムが受信アクション コレクションにない操作を呼び出す場合:

  • SAP アダプターは、SAP システムの呼び出し元に EXCEPTION 例外を返します。次のメッセージが表示されます。"Rfc Server の受信 RFC 呼び出し [RFC_NAME] は処理されません。 このメッセージの [RFC_NAME] は RFC の名前です (たとえば、IDOC_INBOUND_ASYNCHRONOUS)。

  • アダプターは、受信した操作を示すメッセージを含む Microsoft.ServiceModel.Channels.Common.AdapterException をスローします。 この例外の使用方法の例については、このトピックの最後にある例を参照してください。

    次のコード例は、 InboundActionCollection を使用して、単一の RFC Z_RFC_MKD_DIVに対してフィルター処理するチャネル リスナーを作成する方法を示しています。

// The connection Uri must specify listener parameters (or an R-type destination in saprfc.ini)  
// and credentials.  
Uri listeneraddress =  
    new Uri("sap://User=YourUserName;Passwd=YourPassword;Client=800;Lang=EN;@a/YourSAPHost/00?ListenerGwServ=SAPGATEWAY&ListenerGwHost=YourSAPHost&ListenerProgramId=SAPAdapter");  
  
// Create a binding and set AcceptCredentialsInUri to true  
SAPBinding binding = new SAPBinding();  
binding.AcceptCredentialsInUri = true;  
  
// Create an InboundActionCollection and add the message actions to listen for,  
// only the actions added to the InboundActionCollection are received on the channel.  
// In this case a single action is specified: http://Microsoft.LobServices.Sap/2007/03/Rfc/Z_RFC_MKD_DIV  
InboundActionCollection actions = new InboundActionCollection(listeneraddress);  
actions.Add("http://Microsoft.LobServices.Sap/2007/03/Rfc/Z_RFC_MKD_DIV");  
  
// Create a BindingParameterCollection and add the InboundActionCollection  
BindingParameterCollection bpcol = new BindingParameterCollection();  
bpcol.Add(actions);  
  
// Create the channel listener by specifying the binding parameter collection (to filter for the Z_RFC_MKD_DIV action)  
listener = binding.BuildChannelListener<IReplyChannel>(listeneraddress, bpcol);  

手動でフィルター処理する操作

チャネル リスナーに受信アクション コレクションを指定しない場合、SAP システムによって呼び出されたすべての操作がコードに渡されます。 このような操作を手動でフィルター処理するには、受信要求のメッセージ アクションを確認します。

また、コンテンツに基づいて操作をフィルター処理するシナリオもあります。 たとえば、 で IDOC を受信する場合は、次のようになります。

  • 文字列形式 ( ReceiveIDocFormat バインド プロパティは String);すべての IDOC は ReceiveIdoc 操作を使用して受信されます。

  • Rfc 形式 ( ReceiveIDocFormat バインド プロパティは Rfc);すべての IDOC は、IDOC_INBOUND_ASYNCHRONOUS RFC または INBOUND_IDOC_PROCESS RFC を使用して受信されます。

    このシナリオでは、コード内の特定の IDOC パラメーター (IDOC の種類など) に基づいてフィルター処理を実装できます。

    操作を手動でフィルター処理すると、処理しない操作のエラーを SAP アダプターに返すことができます。 これにより、SAP システムの呼び出し元に EXCEPTION 例外が発生します。 SAP で例外を発生させたくない場合は、空の応答を返すこともできます。

    次のコードは、Z_RFC_MKD_DIV操作を手動でフィルター処理する方法を示しています。

// Get the message from the channel  
RequestContext rc = channel.ReceiveRequest();  
Message reqMessage = rc.RequestMessage;  
  
// Filter based on the message action.  
if (reqMessage.Headers.Action == "http://Microsoft.LobServices.Sap/2007/03/Rfc/Z_RFC_MKD_DIV")  
{  
  
    // Process message and return response.  
    ...  
  
}  
else  
{  
    // If this isn't the correct message return an empty response or a fault message.  
    // This example returns an empty response.  
    rc.Reply(Message.CreateMessage(MessageVersion.Default, reqMessage.Headers.Action + "/response"));  
}  

SAP システムで例外を発生させる方法

SAP システム上の呼び出し元にエラーを示すには、SOAP エラーを含む要求メッセージに応答できます。 SAP アダプターに SOAP エラーを返すと、アダプターは SAP システム上の呼び出し元に EXCEPTION 例外を返します。 例外メッセージは、SOAP エラーの要素から作成されます。

SAP アダプターは、次の優先順位に従って SAP EXCEPTION のメッセージを作成します。

  1. SOAP エラーに詳細オブジェクトが含まれている場合、アダプターは詳細を文字列にシリアル化し、例外メッセージはこの文字列に設定されます。

  2. SOAP エラーに理由が含まれている場合、例外メッセージはその値に設定されます。

  3. それ以外の場合、アダプターは MessageFault オブジェクト自体を文字列にシリアル化し、例外メッセージはこの文字列に設定されます。

Note

アダプターは、エラー メッセージのみを使用して、SAP システムで発生した例外で返される例外メッセージを作成します。したがって、これらのエンティティに対して設定する値は完全にユーザーの責任です。

WCF には、SOAP エラーのメモリ内表現をカプセル化するための System.ServiceModel.Channels.MessageFault クラスが用意されています。 静的でオーバーロードされた MessageFault.CreateFault メソッドのいずれかを使用して、新しい SOAP エラーを作成し、適切な Message.CreateMessage オーバーロードを呼び出してエラー メッセージを作成できます。 WCF には、MessageFault オブジェクトを使用せずにエラー メッセージを作成する CreateMessage のオーバーロードも用意されています。

System.ServiceModel.Channels.RequestContext.Reply メソッドを使用して、エラー メッセージをアダプターに返します。 SAP アダプターは、エラー メッセージのメッセージ アクションを無視するため、メッセージ アクションを任意の値に設定できます。

次の例は、SAP アダプターにエラー メッセージを返す方法を示しています。 この例では、チャネル リスナーとチャネルを作成する手順を省略しています。

RequestContext rc = channel.ReceiveRequest();  
…  
// Start processing the inbound message  
…  
// If an error is encountered return a fault to the SAP system  
// This example uses CreateMessage overload to create a fault message.  
// The overload takes a SOAP version, fault code, reason, and message action  
// The SAP adapter ignores the message action for a fault so you can set it to any value you want.   
Message faultMessage = Message.CreateMessage(MessageVersion.Default, new FaultCode("SAP Example Fault"), "Testing SAP Faults", rc.RequestMessage.Headers.Action + "/fault");  
  
rc.Reply(faultMessage);  

SAP アダプターからの受信 Flat-File IDOC のストリーミング

受信 ReceiveIdoc 操作でアダプターからフラット ファイル (文字列) IDOC を受け取ります。 IDOC データは、この操作で 1 つのノードの下の文字列として表されます。 このため、SAP アダプターは要求メッセージでノード値ストリーミングをサポートします。 ノード値ストリーミングを実行するには、System.Xml を使用して Message.WriteBodyContents メソッドを呼び出して、ReceiveIdoc 操作の要求メッセージを使用する必要があります IDOC データをストリーミングできる XmlDictionaryWriter。 これを行う方法については、「 WCF チャネル モデルを使用して SAP で IDOC を Flat-File ストリーミングする」を参照してください。

IReplyChannel を使用して SAP システムから操作を受け取る方法

WCF チャネル モデルを使用して SAP システムから操作を受信するには、次の手順を実行します。

IReplyChannel を使用して SAP システムから操作を受信するには

  1. SAPBinding のインスタンスを作成し、受け取る操作に必要なバインド プロパティを に設定します。 少なくとも AcceptCredentialsInUri バインド プロパティを true に設定する必要があります。 tRFC サーバーとして機能するには、 TidDatabaseConnectionString バインディング プロパティを設定する必要があります。 バインド プロパティの詳細については、「 BizTalk Adapter for mySAP Business Suite のバインド プロパティ」を参照してください。

    SAPBinding binding = new SAPBinding();  
    binding.AcceptCredentialsInUri = true;  
    
  2. BindingParameterCollection を作成し、受信する操作のアクションを含む InboundActionCollection を追加します。 アダプターは、他のすべての操作について SAP システムに例外を返します。 この手順は省略可能です。 詳細については、「 WCF チャネル モデルを使用した SAP システムからの受信操作の受信」を参照してください。

    InboundActionCollection actions = new InboundActionCollection(listeneraddress);  
    actions.Add("http://Microsoft.LobServices.Sap/2007/03/Rfc/Z_RFC_MKD_DIV");  
    BindingParameterCollection bpcol = new BindingParameterCollection();  
    bpcol.Add(actions);  
    
  3. SAPBindingBuildChannelListener<IReplyChannel> メソッドを呼び出してチャネル リスナーを作成し、開きます。 SAP 接続 URI は、このメソッドのパラメーターの 1 つとして指定します。 接続 URI には、SAP システム上の RFC 宛先のパラメーターが含まれている必要があります。 SAP 接続 URI の詳細については、「 SAP システム接続 URI の作成」を参照してください。 手順 3 で BindingParameterCollection を 作成した場合は、チャネル リスナーを作成するときにもこれを指定します。

    Uri listeneraddress =  
        new Uri("sap://User=YourUserName;Passwd=YourPassword;Client=800;Lang=EN;@a/YourSAPHost/00?ListenerGwServ=SAPGATEWAY&ListenerGwHost=YourSAPHost&ListenerProgramId=SAPAdapter");  
    IChannelListener<IReplyChannel> listener = binding.BuildChannelListener<IReplyChannel>(connectionUri, bpcol);  
    listener.Open();  
    
  4. リスナーで AcceptChannel メソッドを呼び出して IReplyChannel チャネルを取得し、開きます。

    IReplyChannel channel = listener.AcceptChannel();  
    channel.Open();  
    
  5. チャネルで ReceiveRequest を呼び出して、アダプターから次の操作の要求メッセージを取得します。

    RequestContext rc = channel.ReceiveRequest();  
    
  6. アダプターによって送信された要求メッセージを使用します。 RequestContextRequestMessage プロパティから要求メッセージを取得します。 メッセージは、 XmlReader または XmlDictionaryWriter を使用して使用できます。

    XmlReader reader = (XmlReader)rc.RequestMessage.GetReaderAtBodyContents();  
    
  7. SAP システムに応答または障害を返して、操作を完了します。

    1. 応答メッセージをアダプターに返すことで、メッセージを処理し、SAP システムに応答を返します。 次の使用例は、空のメッセージを返します。

      respMessage = Message.CreateMessage(MessageVersion.Default, rc.RequestMessage.Headers.Action + "/response");  
      rc.Reply(respMessage);  
      
    2. エラー メッセージをアダプターに返して、SAP システムに例外を返します。 メッセージ アクション、エラー コード、および理由には、任意の値を使用できます。

      MessageFault fault = MessageFault.CreateFault(new FaultCode("ProcFault"), "Processing Error");  
      Message respMessage = Message.CreateMessage(MessageVersion.Default, fault, String.Empty);  
      rc.Reply(respMessage);  
      
  8. メッセージを送信した後、要求コンテキストを閉じます。

    rc.Close();  
    
  9. 要求の処理が完了したら、チャネルを閉じます。

    channel.Close()  
    

    重要

    操作の処理が完了したら、チャネルを閉じる必要があります。 チャネルを閉じ失敗すると、コードの動作に影響する可能性があります。

  10. SAP システムからの操作の受信が完了したら、リスナーを閉じます。

    listener.Close()  
    

    重要

    リスナーの使用が完了したら、明示的にリスナーを閉じる必要があります。そうしないと、プログラムが正しく動作しない可能性があります。 リスナーを閉じても、リスナーを使用して作成されたチャネルは閉じません。 また、リスナーを使用して作成された各チャネルを明示的に閉じる必要もあります。

次の例では、SAP システムから RFC Z_RFC_MKD_DIVを受け取ります。 この RFC では、2 つの数値が除算されます。 この例の実装では 、InboundActionCollection を使用してZ_RFC_MKD_DIV操作をフィルター処理し、メッセージが受信されたときに次の処理を行います。

  • 除数が 0 以外の場合は、除算の結果をコンソールに書き込み、SAP システムに返します。

  • 除数が 0 の場合、結果の例外メッセージをコンソールに書き込み、SAP システムにエラーを返します。

  • SAP システムから他の操作が送信されると、コンソールにメッセージが書き込まれます。 この場合、アダプター自体は SAP システムに障害を返します。

using System;  
using System.Collections.Generic;  
using System.Text;  
  
using System.Runtime.Serialization;  
using System.Xml;  
using System.IO;  
  
// Add WCF, Adapter LOB SDK, and SAP Adapter namepaces  
using System.ServiceModel;  
using Microsoft.Adapters.SAP;  
using Microsoft.ServiceModel.Channels;  
  
// Add this namespace to use Channel Model   
using System.ServiceModel.Channels;  
  
// Include this namespace for Adapter LOB SDK and SAP exceptions  
using Microsoft.ServiceModel.Channels.Common;  
  
// This sample demonstrates using the adapter as an rfc server over a channel.  
// The sample implements an RFC, Z_RFC_MKD_DIV that divides two numbers and returns the result  
// 1)  A SAPBinding instance is created and configured (AcceptCredentialsInUri is set true)  
// 2)  A binding parameter collection is created with an InboundAction collection that specifies  
//     target RFC (Z_RFC_MKD_DIV) so that only messages with this action will be received by the  
//     listener (and channel).  
// 3)  An <IReplyChannel> listener is created from the binding and binding parameter collection  
// 4)  A channel is created and opened to receive a request  
// 6)  When Z_RFC_MKD_DIV is received the two parameters are divided and the parameters and result  
//     are written to the console, then the result is returned to the adapter by using a template  
//     message.  
// 7)  If a divide by 0 occurs the exception message is written to the console and a  
//     fault is returned to the SAP system  
// 8)  If any other operation is received an error message is written to the console and the adapter  
///    returns a fault to the SAP system  
// 9)  IMPORTANT you must close the channel and listener to deregister them from the SAP Program ID.  
namespace SapRfcServerCM  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            // Variables to hold the listener and channel  
            IChannelListener<IReplyChannel> listener = null;  
            IReplyChannel channel = null;  
  
            Console.WriteLine("Sample started");  
            Console.WriteLine("Initializing and creating channel listener -- please wait");  
            try  
            {  
  
                // The connection Uri must specify listener parameters (or an R-type destination in saprfc.ini)  
                // and also credentials.  
                Uri listeneraddress =  
                    new Uri("sap://User=YourUserName;Passwd=YourPassword;Client=800;Lang=EN;@a/YourSAPHost/00?ListenerGwServ=SAPGATEWAY&ListenerGwHost=YourSAPHost&ListenerProgramId=SAPAdapter");  
  
                // Create a binding -- set AcceptCredentialsInUri true  
                SAPBinding binding = new SAPBinding();  
                binding.AcceptCredentialsInUri = true;  
  
                // Create a binding parameter collection with a list of SOAP actions to listen on  
                // in this case: http://Microsoft.LobServices.Sap/2007/03/Rfc/Z_RFC_MKD_DIV  
                // This ensures that only these actions are received on the channel.  
                InboundActionCollection actions = new InboundActionCollection(listeneraddress);  
                actions.Add("http://Microsoft.LobServices.Sap/2007/03/Rfc/Z_RFC_MKD_DIV");  
                BindingParameterCollection bpcol = new BindingParameterCollection();  
                bpcol.Add(actions);  
  
                // Pass the Uri and the binding parameter collection (to specify the Z_RFC_MKD_DIV action)  
                listener = binding.BuildChannelListener<IReplyChannel>(listeneraddress, bpcol);  
  
                Console.WriteLine("Opening listener");  
                // Open the listener  
                listener.Open();  
  
                // Get an IReplyChannel  
                channel = listener.AcceptChannel();  
  
                Console.WriteLine("Opening channel");  
                // Open the channel  
                channel.Open();  
  
                Console.WriteLine("\nReady to receive Z_RFC_MKD_DIV RFC");  
  
                try  
                {  
                    // Get the message from the channel  
                    RequestContext rc = channel.ReceiveRequest();  
  
                    // Get the request message sent by SAP  
                    Message reqMessage = rc.RequestMessage;  
  
                    // get the message body  
                    XmlReader reader = reqMessage.GetReaderAtBodyContents();  
  
                    reader.ReadStartElement("Z_RFC_MKD_DIV");  
                    reader.ReadElementString("DEST");  
                    int x_in = int.Parse(reader.ReadElementString("X"));  
                    int y_in = int.Parse(reader.ReadElementString("Y"));  
                    reader.ReadEndElement();  
  
                    Console.WriteLine("\nRfc Received");  
                    Console.WriteLine("X =\t\t" + x_in);  
                    Console.WriteLine("Y =\t\t" + y_in);  
  
                    Message messageOut = null;  
  
                    try   
                    {  
                        int result_out = x_in/y_in;  
  
                        Console.WriteLine("RESULT =\t" + result_out.ToString());  
  
                        string out_xml = "<Z_RFC_MKD_DIVResponse xmlns=\"http://Microsoft.LobServices.Sap/2007/03/Rfc/\"><RESULT>" + result_out + "</RESULT></Z_RFC_MKD_DIVResponse>";  
                        StringReader sr = new StringReader(out_xml);  
                        reader = XmlReader.Create(sr);  
  
                        // create a response message  
                        // be sure to specify the response action  
                        messageOut = Message.CreateMessage(MessageVersion.Default, reqMessage.Headers.Action + "/response", reader);  
  
                    }  
                    catch (DivideByZeroException ex)  
                    {  
                        Console.WriteLine();  
                        Console.WriteLine(ex.Message + " Returning fault to SAP");  
  
                        // Create a message that contains a fault  
                        // The fault code and message action can be any value  
  
                        messageOut = Message.CreateMessage(MessageVersion.Default, new FaultCode("Fault"), ex.Message, string.Empty);  
                    }  
  
                    // Send the reply  
                    rc.Reply(messageOut);  
  
                    // Close the request context  
                    rc.Close();  
  
                }  
                catch (AdapterException aex)  
                {  
                    // Will get here if the message received was not in the InboundActionCollection  
                    Console.WriteLine();  
                    Console.WriteLine(aex.Message);  
                }  
  
                // Wait for a key to exit  
                Console.WriteLine("\nHit <RETURN> to end");  
                Console.ReadLine();  
            }  
            catch (ConnectionException cex)  
            {  
                Console.WriteLine("Exception occurred connecting to the SAP system");  
                Console.WriteLine(cex.InnerException.Message);  
            }  
            catch (TargetSystemException tex)  
            {  
                Console.WriteLine("Exception occurred on the SAP system");  
                Console.WriteLine(tex.InnerException.Message);  
            }  
            catch (Exception ex)  
            {  
                Console.WriteLine("Exception is: " + ex.Message);  
                if (ex.InnerException != null)  
                {  
                    Console.WriteLine("Inner Exception is: " + ex.InnerException.Message);  
                }  
            }  
            finally  
            {  
                // IMPORTANT: close the channel and listener to stop listening on the Program ID  
                if (channel != null)  
                {  
                    if (channel.State == CommunicationState.Opened)  
                        channel.Close();  
                    else  
                        channel.Abort();  
                }  
  
                if (listener != null)  
                {  
                    if (listener.State == CommunicationState.Opened)  
                        listener.Close();  
                    else  
                        listener.Abort();  
                }  
            }  
        }  
    }  
}  

参照

WCF チャネル モデルを使用してアプリケーションを開発する