使用 WCF 通道模型叫用 SAP 系統上的作業
您可以使用 IRequestChannel 或 IOutputChannel 通道圖形,在 SAP 配接器上叫用作業,以將訊息傳送至配接器。 基本模式是使用系結 (SAPBinding) 和從連線 URI 建立的端點,為必要的通道圖形建立通道處理站。 然後,您可以建立 Message 實例,代表符合目標作業之訊息架構的 SOAP 訊息。 然後,您可以使用從通道處理站建立的通道,將此 訊息 傳送至 SAP 配接器。 如果您使用 IRequestChannel,您會收到回應。 如果 SAP 系統上執行作業時發生問題,SAP 配接器會擲回 Microsoft.ServiceModel.Channels.Common.TargetSystemException。
如需如何在 WCF 中使用 IRequestChannel 傳送作業的概觀,請參閱 用戶端 Channel-Level 程式設計。
本主題中的各節提供資訊,協助您使用 WCF 通道模型在 SAP 配接器上叫用作業。
支援 WCF 通道模型中的 BAPI 交易
所有使用相同 SAP 連線叫用的 BAP,都是 SAP 系統上的相同邏輯單位 (LUW) 或交易的一部分。 每個 WCF 通道都代表與 SAP 系統的唯一連線。 若要使用 WCF 通道模型支援 BAPI 交易:
請確定 LUW (交易中的每個 BAPI 都會透過相同的通道傳送) 。 這包括 COMMIT 或BAPI_TRANSACTION_ROLLBACK作業BAPI_TRANSACTION。
在通道上叫用下一個 BAPI 之前,請確定您關閉針對 BAPI 接收的任何回應訊息。 (您應該針對每個作業執行此動作;但對 BAPIs.) 特別重要
如需 BAPI 交易的詳細資訊,請參閱 SAP 中的 BAPIs 作業。
將一般檔案IDOC 串流至 SAP 配接器
您可以使用 SendIdoc 作業,將一般檔案傳送至配接器 (字串) IDOC。 IDOC 資料會以此作業中單一節點底下的字串表示。 基於這個理由,SAP 配接器支援要求訊息上的節點值串流。 若要執行節點值串流,您必須使用能夠串流 IDOC 資料的 System.ServiceModel.Channels.BodyWriter 來建立 SendIdoc 作業的要求訊息。 如需如何執行這項操作的詳細資訊,請參閱 使用 WCF 通道模型在 SAP 中串流 Flat-File IDOC。
如何使用通道叫用作業?
若要使用 IRequestChannel叫用作業,請執行下列步驟。
如何使用 IRequestChannel 實例叫用作業
(ChannelFactory < IRequestChannel >) 建置通道處理站。 若要這樣做,您必須指定 (SAPBinding) 和端點位址的系結。 您可以在程式碼中以命令方式指定系結和端點位址,或以宣告方式在組態中指定。 您應該在開啟處理站之前,設定將傳送之作業所需的任何系結屬性。 如需如何在組態中指定系結和端點位址的詳細資訊,請參閱 使用 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);
使用 ClientCredentials 屬性設定通道處理站的使用者名稱密碼認證。
factory.Credentials.UserName.UserName = "YourUserName"; factory.Credentials.UserName.Password = "YourPassword";
開啟通道處理站。
factory.Open();
從處理站取得通道並加以開啟。
IRequestChannel channel = factory.CreateChannel(); channel.Open();
建立目標作業的 訊息 實例。 請確定已指定目標作業的訊息動作。 在此範例中,訊息本文會透過透過字串建立 XmlReader 來傳遞。 目標作業會在 SAP 系統上叫用SD_RFC_CUSTOMER_GET RFC。
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);
叫用通道上的 Request 方法,將訊息傳送至 SAP 配接器並接收回複。 如果 SAP 系統遇到例外狀況,配接器會擲回 TargetSystemException。 (非 SAP exceptions.) 您可以從TargetSystemException的 InnerException.Message屬性取得 SAP 錯誤的描述。
try { Message messageOut = channel.Request(messageIn); } catch (Exception ex) { // handle exception }
處理回應。 在此範例中,回應訊息上會呼叫 GetReaderAtBodyContents 以取得訊息本文。
XmlReader readerOut = messageOut.GetReaderAtBodyContents();
當您完成處理回應訊息時,請關閉讀取器和訊息。
readerOut.Close(); messageOut.Close();
當您使用通道和通道處理站完成時,請關閉它們。 關閉處理站將會關閉與其建立的所有通道。
channel.Close() factory.Close();
您可以遵循相同的步驟,使用 IOutputChannel 圖形來傳送訊息,但除外:
您在步驟 1 中建立ChannelFactory < IOutputChannel >。
您在步驟 6 的通道上呼叫 Send 方法。
channel.Send(messageIn);
.IOutputChannel沒有傳回的回應訊息。
範例
下列範例示範如何使用 IRequestChannel 通道叫用 RFC。 此範例會叫用 SD_RFC_CUSTOMER_GET RFC,以取得名稱開頭為 「AB」 的客戶清單。 回應訊息是使用 XmlReader 來取用,而傳回之每個客戶的客戶號碼和名稱都會寫入主控台。
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();
}
}
}