Partager via


Recevoir des opérations de trafic entrant à partir du système SAP à l’aide du modèle de canal WCF

Pour agir en tant que serveur RFC et recevoir des opérations appelées par le système SAP (telles que l’envoi d’un IDOC ou l’appel d’un RFC), vous devez créer un écouteur de canal qui peut écouter les messages d’un ID de programme SAP sur une forme de canal System.ServiceModel.Channels.IReplyChannel .

Un écouteur de canal (System.ServiceModel.Channels.IChannelListener) est un objet de communication WCF qui peut être utilisé pour recevoir des messages à partir de points de terminaison WCF spécifiques. L’écouteur de canal fonctionne comme une fabrique à partir de laquelle vous pouvez créer des canaux sur lesquels les messages appelés par un client (le système SAP) peuvent être reçus par votre service. Vous créez un écouteur de canal à partir d’un objet Microsoft.Adapters.SAP.SAPBinding en appelant la méthode BuildChannelListener . Vous fournissez un URI de connexion SAP qui spécifie l’ID de programme SAP à partir duquel les opérations entrantes seront reçues pour cette méthode.

L’adaptateur SAP prend en charge la forme de canal IReplyChannel . Les canaux IReplyChannel prennent en charge un modèle d’échange de messages demande-réponse entrant. Autrement dit, un modèle dans lequel un programme externe envoie un message de demande sur le canal et votre programme retourne une réponse.

Pour obtenir une vue d’ensemble de la réception d’opérations à l’aide d’un IReplyChannel dans WCF, consultez Programmation de Channel-Level de service.

Cette section couvre les rubriques suivantes qui sont spécifiques à la réception d’opérations à partir d’un système SAP :

  • Comment filtrer des opérations spécifiques à l’aide de l’écouteur de canal.

  • Comment déclencher une exception sur le système SAP.

  • Diffusion en continu d’AIDO de fichiers plats entrants à partir de l’adaptateur SAP.

  • Comment recevoir des opérations du système SAP.

Comment filtrer les opérations à l’aide de l’écouteur de canal ?

Utilisation d’un inboundActionCollection pour filtrer les opérations

Le Kit de développement logiciel (SDK) de l’adaptateur LOB WCF fournit la classe Microsoft.ServiceModel.Channels.InboundActionCollection pour vous permettre de filtrer les opérations reçues par un écouteur de canal et passées au code de votre application. Pour filtrer des opérations spécifiques, vous créez une instance de cette classe à l’aide de l’URI du point de terminaison de l’écouteur. Ensuite, vous ajoutez l’action de message (demande) pour chaque opération cible à la collection. Enfin, vous ajoutez la collection d’actions entrantes à un objet System.ServiceModel.Channels.BindingParameterCollection , puis transmettez cette collection de paramètres de liaison dans l’appel pour créer l’écouteur de canal.

Si le système SAP appelle une opération qui ne se trouve pas dans la collection d’actions entrantes :

  • L’adaptateur SAP retourne une exception EXCEPTION à l’appelant sur le système SAP avec le message suivant : « L’appel RFC entrant [RFC_NAME] sur le serveur Rfc n’est pas géré ». Dans ce message, [RFC_NAME] est le nom de la RFC (par exemple, IDOC_INBOUND_ASYNCHRONOUS).

  • L’adaptateur lève une exception Microsoft.ServiceModel.Channels.Common.AdapterException avec un message qui indique l’opération qui a été reçue. Pour obtenir un exemple d’utilisation de cette exception, consultez l’exemple à la fin de cette rubrique.

    L’exemple de code suivant montre comment utiliser un InboundActionCollection pour créer un écouteur de canal qui filtre une seule 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);  

Opérations de filtrage manuel

Si vous ne spécifiez pas de collection d’actions entrantes pour l’écouteur de canal, toutes les opérations appelées par le système SAP sont passées à votre code. Vous pouvez filtrer manuellement ces opérations en vérifiant l’action de message des demandes entrantes.

Il peut également y avoir des scénarios dans lesquels vous souhaitez filtrer une opération en fonction de son contenu. Par exemple, si vous recevez des IDOCs dans :

  • Format de chaîne (la propriété de liaison ReceiveIDocFormat est String) ; tous les IDOC sont reçus à l’aide de l’opération ReceiveIdoc.

  • Format Rfc (la propriété de liaison ReceiveIDocFormat est Rfc) ; tous les IDOC sont reçus à l’aide de la RFC IDOC_INBOUND_ASYNCHRONOUS ou de la RFC INBOUND_IDOC_PROCESS.

    Dans ce scénario, vous souhaiterez peut-être implémenter le filtrage en fonction de paramètres IDOC spécifiques (tels que le type d’IDOC) dans votre code.

    Lorsque vous filtrez manuellement les opérations, vous pouvez retourner une erreur à l’adaptateur SAP pour les opérations que vous ne gérez pas. L’exception EXCEPTION est alors levée pour l’appelant sur le système SAP. Vous pouvez également retourner une réponse vide si vous ne souhaitez pas déclencher d’exception sur SAP.

    Le code suivant montre comment filtrer manuellement l’opération 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"));  
}  

Comment déclencher une exception sur le système SAP ?

Pour indiquer une erreur à l’appelant sur le système SAP, vous pouvez répondre à un message de demande avec une erreur SOAP. Lorsque vous retournez une erreur SOAP à l’adaptateur SAP, l’adaptateur retourne une exception EXCEPTION à l’appelant sur le système SAP. Le message d’exception est créé à partir des éléments de l’erreur SOAP.

L’adaptateur SAP crée le message pour l’EXCEPTION SAP selon l’ordre de priorité suivant :

  1. Si l’erreur SOAP contient un objet de détail, l’adaptateur sérialise le détail en une chaîne et le message d’exception est défini sur cette chaîne.

  2. Si l’erreur SOAP contient une raison, le message d’exception est défini sur sa valeur.

  3. Sinon, l’adaptateur sérialise l’objet MessageFault lui-même en une chaîne et le message d’exception est défini sur cette chaîne.

Notes

L’adaptateur utilise uniquement le message d’erreur pour créer le message d’exception retourné dans l’exception déclenchée sur le système SAP ; Par conséquent, les valeurs que vous définissez pour ces entités vous incombent entièrement.

WCF fournit la classe System.ServiceModel.Channels.MessageFault pour encapsuler une représentation en mémoire d’une erreur SOAP. Vous pouvez utiliser l’une des méthodes statiques et surchargées MessageFault.CreateFault pour créer une erreur SOAP à partir de laquelle vous pouvez ensuite créer un message d’erreur en appelant la surcharge Message.CreateMessage appropriée. WCF fournit également des surcharges de CreateMessage qui créent un message d’erreur sans utiliser d’objet MessageFault .

Vous utilisez la méthode System.ServiceModel.Channels.RequestContext.Reply pour renvoyer le message d’erreur à l’adaptateur. L’adaptateur SAP ignore l’action de message pour les messages d’erreur. Vous pouvez donc définir l’action de message sur n’importe quelle valeur.

L’exemple suivant montre comment retourner un message d’erreur à l’adaptateur SAP. Cet exemple omet les étapes de création de l’écouteur et du canal de canal.

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);  

Streaming inbound Flat-File IDOCs à partir de l’adaptateur SAP

Vous recevez des IDOC de fichier plat (chaîne) de l’adaptateur dans l’opération ReceiveIdoc entrante. Les données IDOC sont représentées sous la forme d’une chaîne sous un nœud unique dans cette opération. Pour cette raison, l’adaptateur SAP prend en charge la diffusion en continu de valeur de nœud sur le message de demande. Pour effectuer une diffusion en continu de valeur de nœud, vous devez utiliser le message de demande pour l’opération ReceiveIdoc en appelant la méthode Message.WriteBodyContents avec un System.Xml. XmlDictionaryWriter capable de diffuser en continu les données IDOC. Pour plus d’informations sur la procédure à suivre, consultez Streaming Flat-File IDOCs dans SAP à l’aide du modèle de canal WCF.

Comment recevoir des opérations à partir d’un système SAP à l’aide d’un IReplyChannel ?

Pour recevoir des opérations à partir d’un système SAP à l’aide du modèle de canal WCF, procédez comme suit.

Pour recevoir des opérations du système SAP à l’aide d’un IReplyChannel

  1. Créez un instance de SAPBinding et définissez les propriétés de liaison requises sur pour les opérations que vous souhaitez recevoir. Au minimum, vous devez définir la propriété de liaison AcceptCredentialsInUri sur true. Pour agir en tant que serveur tRFC, vous devez définir la propriété de liaison TidDatabaseConnectionString . Pour plus d’informations sur les propriétés de liaison, consultez En savoir plus sur les propriétés de liaison de l’adaptateur BizTalk pour mySAP Business Suite.

    SAPBinding binding = new SAPBinding();  
    binding.AcceptCredentialsInUri = true;  
    
  2. Créez un BindingParameterCollection et ajoutez un InboundActionCollection qui contient les actions des opérations que vous souhaitez recevoir. L’adaptateur retourne une exception au système SAP pour toutes les autres opérations. Cette étape est facultative. Pour plus d’informations, consultez Réception d’opérations entrantes à partir du système SAP à l’aide du modèle de canal WCF.

    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. Créez un écouteur de canal en appelant la méthode BuildChannelListener<IReplyChannel> sur sapBinding et ouvrez-la. Vous spécifiez l’URI de connexion SAP comme l’un des paramètres de cette méthode. L’URI de connexion doit contenir des paramètres pour une destination RFC sur le système SAP. Pour plus d’informations sur l’URI de connexion SAP, consultez Créer l’URI de connexion système SAP. Si vous avez créé un BindingParameterCollection à l’étape 3, vous le spécifiez également lorsque vous créez l’écouteur de canal.

    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. Obtenez un canal IReplyChannel en appelant la méthode AcceptChannel sur l’écouteur et en l’ouvrant.

    IReplyChannel channel = listener.AcceptChannel();  
    channel.Open();  
    
  5. Appelez ReceiveRequest sur le canal pour obtenir le message de demande de l’opération suivante à partir de l’adaptateur.

    RequestContext rc = channel.ReceiveRequest();  
    
  6. Consommez le message de demande envoyé par l’adaptateur. Vous obtenez le message de demande à partir de la propriété RequestMessage du RequestContext. Vous pouvez utiliser le message à l’aide d’un XmlReader ou d’un XmlDictionaryWriter.

    XmlReader reader = (XmlReader)rc.RequestMessage.GetReaderAtBodyContents();  
    
  7. Terminez l’opération en retournant une réponse ou une erreur au système SAP :

    1. Traitez le message et retournez une réponse au système SAP en retournant le message de réponse à l’adaptateur. Cet exemple retourne un message vide.

      respMessage = Message.CreateMessage(MessageVersion.Default, rc.RequestMessage.Headers.Action + "/response");  
      rc.Reply(respMessage);  
      
    2. Retourne une exception au système SAP en retournant un message d’erreur à l’adaptateur. Vous pouvez utiliser n’importe quelle valeur pour l’action de message, le code d’erreur et la raison.

      MessageFault fault = MessageFault.CreateFault(new FaultCode("ProcFault"), "Processing Error");  
      Message respMessage = Message.CreateMessage(MessageVersion.Default, fault, String.Empty);  
      rc.Reply(respMessage);  
      
  8. Fermez le contexte de la demande après avoir envoyé le message.

    rc.Close();  
    
  9. Fermez le canal une fois que vous avez terminé de traiter la demande.

    channel.Close()  
    

    Important

    Vous devez fermer le canal une fois que vous avez terminé le traitement de l’opération. L’échec de la fermeture du canal peut affecter le comportement de votre code.

  10. Fermez l’écouteur lorsque vous avez fini de recevoir les opérations du système SAP.

    listener.Close()  
    

    Important

    Vous devez fermer explicitement l’écouteur lorsque vous avez terminé de l’utiliser ; dans le cas contraire, votre programme risque de ne pas se comporter correctement. La fermeture de l’écouteur ne ferme pas les canaux créés à l’aide de l’écouteur. Vous devez également fermer explicitement chaque canal créé à l’aide de l’écouteur.

Exemple

L’exemple suivant reçoit un RFC, Z_RFC_MKD_DIV du système SAP. Cette RFC divise deux nombres. L’implémentation de cet exemple utilise un inboundActionCollection pour filtrer l’opération Z_RFC_MKD_DIV et effectue les opérations suivantes lorsqu’un message est reçu :

  • Si le diviseur n’est pas égal à zéro, il écrit le résultat de la division dans la console et le retourne au système SAP.

  • Si le diviseur est égal à zéro, il écrit le message d’exception résultant dans la console et retourne une erreur au système SAP.

  • Si une autre opération est envoyée par le système SAP, il écrit un message dans la console. Dans ce cas, l’adaptateur lui-même retourne une erreur au système 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();  
                }  
            }  
        }  
    }  
}  

Voir aussi

Développer des applications en utilisant le modèle de canal WCF