Condividi tramite


Richiamare operazioni nel sistema SAP usando il modello di canale WCF

Per inviare messaggi all'adapter, è possibile richiamare operazioni sull'adapter SAP usando una forma di canale IRequestChannel o IOutputChannel . Il modello di base consiste nel creare una channel factory per la forma del canale richiesta usando un'associazione (SAPBinding) e un endpoint creato da un URI di connessione. Si crea quindi un'istanza del messaggio che rappresenta un messaggio SOAP conforme allo schema del messaggio per l'operazione di destinazione. È quindi possibile inviare questo messaggio all'adapter SAP usando un canale creato dalla channel factory. Se si usa un IRequestChannel, si riceve una risposta. Se si verifica un problema durante l'esecuzione dell'operazione nel sistema SAP, l'adapter SAP genera un'eccezione Microsoft.ServiceModel.Channels.Common.TargetSystemException.

Per una panoramica dell'invio di operazioni tramite IRequestChannel in WCF, vedere Programmazione Channel-Level client.

Le sezioni di questo argomento forniscono informazioni utili per richiamare le operazioni sull'adapter SAP usando il modello di canale WCF.

Supporto delle transazioni BAPI nel modello di canale WCF

Tutti i BAPI richiamati usando la stessa connessione SAP fanno parte della stessa unità logica di lavoro (LUW) o della stessa transazione nel sistema SAP. Ogni canale WCF rappresenta una connessione univoca al sistema SAP. Per supportare le transazioni BAPI usando il modello di canale WCF:

  • Assicurarsi che ogni BAPI in una transazione LUW (LUW) venga inviato sullo stesso canale. Sono incluse le operazioni BAPI_TRANSACTION COMMIT o BAPI_TRANSACTION_ROLLBACK.

  • Assicurarsi di chiudere qualsiasi messaggio di risposta ricevuto per un BAPI prima di richiamare il bapi successivo nel canale. È consigliabile eseguire questa operazione per ogni operazione, ma è particolarmente importante per bapi.

    Per altre informazioni sulle transazioni BAPI, vedere Operazioni su BAPIs in SAP.

Streaming di IDOC di file flat nell'adapter SAP

Usare l'operazione SendIdoc per inviare un IDOC (string) file flat all'adapter. I dati IDOC sono rappresentati come stringa in un singolo nodo in questa operazione. Per questo motivo, l'adattatore SAP supporta lo streaming node-value nel messaggio di richiesta. Per eseguire lo streaming node-value, è necessario creare il messaggio di richiesta per l'operazione SendIdoc usando un System.ServiceModel.Channels.BodyWriter in grado di trasmettere i dati IDOC. Per informazioni su come eseguire questa operazione, vedere Streaming Flat-File IDOCs in SAP usando il modello di canale WCF.

Come richiamare un'operazione usando un canale?

Per richiamare un'operazione usando un IRequestChannel, seguire questa procedura.

Come richiamare un'operazione usando un'istanza di IRequestChannel

  1. Creare una channel factory (ChannelFactory<IRequestChannel>). A tale scopo, è necessario specificare un'associazione (SAPBinding) e un indirizzo endpoint. È possibile specificare l'indirizzo dell'associazione e dell'endpoint in modo imperativo nel codice o in modo dichiarativo nella configurazione. È necessario impostare le proprietà di associazione necessarie per le operazioni che verranno inviate prima di aprire la factory. Per altre informazioni su come specificare l'associazione e l'indirizzo dell'endpoint nella configurazione, vedere Creare un canale usando SAP.

    // Create a binding  
    SAPBinding binding = new SAPBinding();  
    // Create an endpoint address by using the connection URI  
    EndpointAddress endpointAddress = new EndpointAddress("sap://Client=800;lang=EN@A/YourSAPHost/00");  
    // Create the channel factory  
    ChannelFactory<IRequestChannel> factory = new ChannelFactory<IRequestChannel>(binding, address);  
    
  2. Impostare le credenziali della password del nome utente per la channel factory usando la proprietà ClientCredentials .

    factory.Credentials.UserName.UserName = "YourUserName";  
    factory.Credentials.UserName.Password = "YourPassword";  
    
  3. Aprire la channel factory.

    factory.Open();  
    
  4. Ottenere un canale dalla factory e aprirlo.

    IRequestChannel channel = factory.CreateChannel();  
    channel.Open();  
    
  5. Creare un'istanza del messaggio per l'operazione di destinazione. Assicurarsi che sia specificata l'azione del messaggio per l'operazione di destinazione. In questo esempio il corpo del messaggio viene passato creando un XmlReader su una stringa. L'operazione di destinazione richiama il SD_RFC_CUSTOMER_GET RFC in un sistema SAP.

    string inputXml = "\<SD_RFC_CUSTOMER_GET xmlns="http://Microsoft.LobServices.Sap/2007/03/Rfc/\"> <KUNNR i:nil=\"true\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"> </KUNNR> <NAME1>AB*</NAME1> <CUSTOMER_T> </CUSTOMER_T> </SD_RFC_CUSTOMER_GET>";  
    
    //create an XML reader from the input XML  
    XmlReader reader = XmlReader.Create(new MemoryStream(Encoding.Default.GetBytes(inputXml)));  
    
    //create a WCF message from our XML reader  
    Message inputMessge = Message.CreateMessage(MessageVersion.Soap11, "http://Microsoft.LobServices.Sap/2007/03/Rfc/SD_RFC_CUSTOMER_GET", reader);  
    
  6. Richiamare il metodo Request sul canale per inviare il messaggio all'adapter SAP e ricevere la risposta. Se il sistema SAP rileva un'eccezione, l'adapter genera un'eccezione TargetSystemException. Altre eccezioni sono possibili per le eccezioni non SAP. È possibile ottenere una descrizione dell'errore SAP dalla proprietà InnerException.Message di TargetSystemException.

    try  
    {  
        Message messageOut = channel.Request(messageIn);  
    }  
    catch (Exception ex)  
    {  
        // handle exception  
    }  
    
  7. Elaborare la risposta. In questo esempio GetReaderAtBodyContents viene chiamato sul messaggio di risposta per ottenere il corpo del messaggio.

    XmlReader readerOut = messageOut.GetReaderAtBodyContents();  
    
  8. Al termine dell'elaborazione del messaggio di risposta, chiudere il lettore e il messaggio.

    readerOut.Close();  
    messageOut.Close();  
    
  9. Al termine dell'uso del canale e della channel factory, chiuderli. La chiusura della factory chiuderà tutti i canali creati con esso.

    channel.Close()  
    factory.Close();  
    
  10. Seguire la stessa procedura per inviare un messaggio usando la forma IOutputChannel , ad eccezione di:

  • Si crea un canale<IOutputChannel> nel passaggio 1.

  • Chiamare il metodo Send sul canale nel passaggio 6. channel.Send(messageIn);.

  • Non viene restituito alcun messaggio di risposta per IOutputChannel.

Esempio

Nell'esempio seguente viene illustrato come richiamare un RFC usando un canale IRequestChannel . In questo esempio viene richiamato il SD_RFC_CUSTOMER_GET RFC per ottenere un elenco di clienti i cui nomi iniziano con "AB". Il messaggio di risposta viene utilizzato utilizzando un XmlReader e il numero e il nome di ogni cliente restituito vengono scritti nella console.

using System;  
using System.Collections.Generic;  
using System.Text;  
  
using System.Xml;  
using System.IO;  
  
using System.ServiceModel;  
using Microsoft.Adapters.SAP;  
using Microsoft.ServiceModel.Channels;  
using System.ServiceModel.Channels;  
  
namespace SapRfcClientCM  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            //create a binding  
            SAPBinding binding = new SAPBinding();  
  
            //set up an endpoint address.  
            EndpointAddress endpointAddress = new EndpointAddress("sap://Client=800;lang=EN@A/YourSAPHost/00");  
  
            //create a channel factory, capable of sending a request to SAP and receiving a reply (IRequestChannel)  
            ChannelFactory<IRequestChannel> factory = new ChannelFactory<IRequestChannel>(binding, endpointAddress);  
  
            // add credentials  
            factory.Credentials.UserName.UserName = "YourUserName";  
            factory.Credentials.UserName.Password = "YourPassword";  
  
            //open the factory  
            factory.Open();  
  
            //obtain a channel from the factory by specifying the address you want to connect to  
            IRequestChannel channel = factory.CreateChannel();  
  
            //open the channel  
            channel.Open();  
  
            //create an XML message to send to the SAP system  
            //We are invoking the SD_RFC_CUSTOMER_GET RFC.  
            //The XML below specifies that we want to search for customers with names starting with "AB"  
            string inputXml = "<SD_RFC_CUSTOMER_GET xmlns=\"http://Microsoft.LobServices.Sap/2007/03/Rfc/\"> <KUNNR i:nil=\"true\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"> </KUNNR> <NAME1>AB*</NAME1> <CUSTOMER_T> </CUSTOMER_T> </SD_RFC_CUSTOMER_GET>";  
  
            //create an XML reader from the input XML  
            XmlReader readerOut = XmlReader.Create(new MemoryStream(Encoding.Default.GetBytes(inputXml)));  
  
            //create a WCF message from the XML reader  
            Message messageOut = Message.CreateMessage(MessageVersion.Default, "http://Microsoft.LobServices.Sap/2007/03/Rfc/SD_RFC_CUSTOMER_GET", readerOut);  
  
            //send the message to SAP and obtain a reply  
            Message messageIn = channel.Request(messageOut);  
  
            // Write the KUNNR and NAME1 fields for each returned record to the Console  
            Console.WriteLine("Results of SD_RFC_CUSTOMER_GET");  
            Console.WriteLine("KUNNR\t\tNAME1");  
  
            XmlReader readerIn = messageIn.GetReaderAtBodyContents();  
  
            while (readerIn.Read())  
            {  
                if (readerIn.IsStartElement())  
                {  
                    switch (readerIn.Name)  
                    {  
                        case "RFCCUST":  
                            Console.Write("\n");  
                            break;  
  
                        case "KUNNR":  
                            readerIn.Read();  
                            Console.Write(readerIn.ReadString() + "\t");  
                            break;  
  
                        case "NAME1":  
                            readerIn.Read();  
                            Console.Write(readerIn.ReadString() + "\t");  
                            break;  
  
                        default:  
                            break;  
                    }  
                }  
            }  
  
            // return the cursor  
            Console.WriteLine();  
  
            // Close the input reader  
            readerIn.Close();  
  
            // Close the input message. You should do this for every message you   
            // send on the channel  
            messageIn.Close();  
  
            // close the channel when you are done using it.  
            channel.Close();  
  
            //close the factory  
            //note: closing the factory will close all of its channels.  
            factory.Close();  
        }  
    }  
}  

Vedere anche

Sviluppare applicazioni tramite il modello di canale WCF