Aufrufen von Vorgängen im SAP-System mithilfe des WCF-Kanalmodells
Sie rufen Vorgänge auf dem SAP-Adapter auf, indem Sie ein IRequestChannel - oder IOutputChannel-Kanal-Shape verwenden, um Nachrichten an den Adapter zu senden. Das grundlegende Muster besteht darin, eine Kanalfactory für das erforderliche Kanal-Shape mithilfe einer Bindung (SAPBinding) und eines Endpunkts zu erstellen, der aus einem Verbindungs-URI erstellt wird. Anschließend erstellen Sie eine Message instance, die eine SOAP-Nachricht darstellt, die dem Nachrichtenschema für Ihren Zielvorgang entspricht. Anschließend können Sie diese Nachricht mithilfe eines Kanals, der von der Kanalfactory erstellt wurde, an den SAP-Adapter senden. Wenn Sie einen IRequestChannel verwenden, erhalten Sie eine Antwort. Wenn beim Ausführen des Vorgangs auf dem SAP-System ein Problem auftritt, löst der SAP-Adapter eine Microsoft.ServiceModel.Channels.Common.TargetSystemException aus.
Eine Übersicht über das Senden von Vorgängen mit einem IRequestChannel in WCF finden Sie unter Client Channel-Level Programming.
Die Abschnitte in diesem Thema enthalten Informationen zum Aufrufen von Vorgängen auf dem SAP-Adapter mithilfe des WCF-Kanalmodells.
Unterstützung von BAPI-Transaktionen im WCF-Kanalmodell
Alle BAPIs, die mit derselben SAP-Verbindung aufgerufen werden, sind Teil derselben LUW (Logical Unit of Work) (bzw. Transaktion) im SAP-System. Jeder WCF-Kanal stellt eine eindeutige Verbindung mit dem SAP-System dar. So unterstützen Sie BAPI-Transaktionen mithilfe des WCF-Kanalmodells:
Stellen Sie sicher, dass jede BAPI in einer LUW (Transaktion) über denselben Kanal gesendet wird. Dies schließt die BAPI_TRANSACTION COMMIT- oder BAPI_TRANSACTION_ROLLBACK-Vorgänge ein.
Stellen Sie sicher, dass Sie alle für eine BAPI empfangenen Antwortnachrichten schließen, bevor Sie die nächste BAPI im Kanal aufrufen. (Sie sollten dies für jeden Vorgang tun, aber es ist besonders wichtig für BAPIs.)
Weitere Informationen zu BAPI-Transaktionen finden Sie unter Vorgänge für BAPIs in SAP.
Streamen von Flatfile-IDOCs an den SAP-Adapter
Sie verwenden den SendIdoc-Vorgang, um ein Flatfile-IDOC (Zeichenfolge) an den Adapter zu senden. Die IDOC-Daten werden in diesem Vorgang als Zeichenfolge unter einem einzelnen Knoten dargestellt. Aus diesem Grund unterstützt der SAP-Adapter das Knotenwertstreaming für die Anforderungsnachricht. Zum Ausführen des Knoten-Wert-Streamings müssen Sie die Anforderungsnachricht für den SendIdoc-Vorgang erstellen, indem Sie einen System.ServiceModel.Channels.BodyWriter verwenden, der die IDOC-Daten streamen kann. Informationen dazu finden Sie unter Streaming Flat-File IDOCs in SAP mithilfe des WCF-Kanalmodells.
Wie kann ich einen Vorgang mithilfe eines Kanals aufrufen?
Führen Sie die folgenden Schritte aus, um einen Vorgang mit einem IRequestChannel aufzurufen.
Aufrufen eines Vorgangs mithilfe einer instance von IRequestChannel
Erstellen Sie eine Kanalfactory (ChannelFactory<IRequestChannel>). Dazu müssen Sie eine Bindung (SAPBinding) und eine Endpunktadresse angeben. Sie können die Bindungs- und Endpunktadresse entweder zwingend in Ihrem Code oder deklarativ in der Konfiguration angeben. Sie sollten alle Bindungseigenschaften festlegen, die für die Vorgänge erforderlich sind, die Sie senden, bevor Sie die Factory öffnen. Weitere Informationen zum Angeben der Bindungs- und Endpunktadresse in der Konfiguration finden Sie unter Erstellen eines Kanals mit 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);
Legen Sie die Kennwortanmeldeinformationen für den Benutzernamen für die Kanalfactory mithilfe der ClientCredentials-Eigenschaft fest.
factory.Credentials.UserName.UserName = "YourUserName"; factory.Credentials.UserName.Password = "YourPassword";
Öffnen Sie die Kanalfactory.
factory.Open();
Rufen Sie einen Kanal aus der Factory ab, und öffnen Sie ihn.
IRequestChannel channel = factory.CreateChannel(); channel.Open();
Erstellen Sie eine Meldung instance für den Zielvorgang. Stellen Sie sicher, dass die Nachrichtenaktion für den Zielvorgang angegeben ist. In diesem Beispiel wird der Nachrichtentext übergeben, indem ein XmlReader über eine Zeichenfolge erstellt wird. Der Zielvorgang ruft den SD_RFC_CUSTOMER_GET RFC auf einem SAP-System auf.
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);
Rufen Sie die Request-Methode im Kanal auf, um die Nachricht an den SAP-Adapter zu senden und die Antwort zu empfangen. Wenn im SAP-System eine Ausnahme auftritt, löst der Adapter eine TargetSystemException aus. (Andere Ausnahmen sind für Nicht-SAP-Ausnahmen möglich.) Sie können eine Beschreibung des SAP-Fehlers aus der InnerException.Message-Eigenschaft der TargetSystemException abrufen.
try { Message messageOut = channel.Request(messageIn); } catch (Exception ex) { // handle exception }
Verarbeiten Sie die Antwort. In diesem Beispiel wird GetReaderAtBodyContents für die Antwortnachricht aufgerufen, um den Nachrichtentext abzurufen.
XmlReader readerOut = messageOut.GetReaderAtBodyContents();
Wenn Sie die Verarbeitung der Antwortnachricht abgeschlossen haben, schließen Sie den Reader und die Nachricht.
readerOut.Close(); messageOut.Close();
Wenn Sie mit der Verwendung des Kanals und der Kanalfactory fertig sind, schließen Sie sie. Durch das Schließen der Factory werden alle Kanäle geschlossen, die damit erstellt wurden.
channel.Close() factory.Close();
Führen Sie die gleichen Schritte aus, um eine Nachricht mithilfe des IOutputChannel-Shapes zu senden, außer:
Sie erstellen in Schritt 1 eine ChannelFactory<IOutputChannel> .
Sie rufen die Send-Methode für den Kanal in Schritt 6 auf.
channel.Send(messageIn);
.Es wird keine Antwortnachricht für einen IOutputChannel zurückgegeben.
Beispiel
Das folgende Beispiel zeigt, wie ein RFC mithilfe eines IRequestChannel-Kanals aufgerufen wird . In diesem Beispiel wird der SD_RFC_CUSTOMER_GET RFC aufgerufen, um eine Liste von Kunden abzurufen, deren Namen mit "AB" beginnen. Die Antwortnachricht wird mit einem XmlReader verarbeitet, und die Kundennummer und der Name jedes zurückgegebenen Kunden werden in die Konsole geschrieben.
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();
}
}
}