WCF 채널 모델을 사용하여 SAP 시스템에서 작업 호출
IRequestChannel 또는 IOutputChannel 채널 셰이프를 사용하여 SAP 어댑터에서 작업을 호출하여 어댑터에 메시지를 보냅니다. 기본 패턴은 바인딩(SAPBinding) 및 연결 URI에서 만든 엔드포인트를 사용하여 필요한 채널 셰이프에 대한 채널 팩터리를 만드는 것입니다. 그런 다음 대상 작업에 대한 메시지 스키마를 준수하는 SOAP 메시지를 나타내는 메시지 instance 만듭니다. 그런 다음 채널 팩터리에서 만든 채널을 사용하여 이 메시지를 SAP 어댑터로 보낼 수 있습니다. IRequestChannel을 사용하는 경우 응답을 받습니다. SAP 시스템에서 작업을 실행하는 데 문제가 있는 경우 SAP 어댑터는 Microsoft.ServiceModel.Channels.Common.TargetSystemException을 throw합니다.
WCF에서 IRequestChannel 을 사용하여 작업을 보내는 방법에 대한 개요는 클라이언트 Channel-Level 프로그래밍을 참조하세요.
이 항목의 섹션에서는 WCF 채널 모델을 사용하여 SAP 어댑터에서 작업을 호출하는 데 도움이 되는 정보를 제공합니다.
WCF 채널 모델에서 BAPI 트랜잭션 지원
동일한 SAP 연결을 사용하여 호출되는 모든 BAPI는 SAP 시스템에서 동일한 LUW(논리 작업 단위) 또는 트랜잭션의 일부입니다. 각 WCF 채널은 SAP 시스템에 대한 고유한 연결을 나타냅니다. WCF 채널 모델을 사용하여 BAPI 트랜잭션을 지원하려면 다음을 수행합니다.
LUW(트랜잭션)의 모든 BAPI가 동일한 채널을 통해 전송되는지 확인합니다. 여기에는 BAPI_TRANSACTION COMMIT 또는 BAPI_TRANSACTION_ROLLBACK 작업이 포함됩니다.
채널에서 다음 BAPI를 호출하기 전에 BAPI에 대해 받은 응답 메시지를 닫아야 합니다. (모든 작업에 대해 이 작업을 수행해야 하지만 BAPI에 특히 중요합니다.)
BAPI 트랜잭션에 대한 자세한 내용은 SAP의 BAPI에 대한 작업을 참조하세요.
플랫 파일 IPC를 SAP 어댑터로 스트리밍
SendIdoc 작업을 사용하여 플랫 파일(문자열) IDOC를 어댑터로 보냅니다. IDOC 데이터는 이 작업의 단일 노드 아래에 문자열로 표시됩니다. 이러한 이유로 SAP 어댑터는 요청 메시지에서 노드 값 스트리밍을 지원합니다. 노드 값 스트리밍을 수행하려면 IDOC 데이터를 스트리밍할 수 있는 System.ServiceModel.Channels.BodyWriter 를 사용하여 SendIdoc 작업에 대한 요청 메시지를 만들어야 합니다. 이 작업을 수행하는 방법에 대한 자세한 내용은 WCF 채널 모델을 사용하여 SAP의 스트리밍 Flat-File IOC를 참조하세요.
채널을 사용하여 작업을 호출하려면 어떻게 하나요?
IRequestChannel을 사용하여 작업을 호출하려면 다음 단계를 수행합니다.
IRequestChannel의 instance 사용하여 작업을 호출하는 방법
채널 팩터리 빌드(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();
대상 작업에 대한 메시지 instance 만듭니다. 대상 작업에 대한 메시지 동작이 지정되어 있는지 확인합니다. 이 예제에서는 문자열 위에 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을 throw합니다. (SAP가 아닌 예외의 경우 다른 예외가 발생할 수 있습니다.) 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();
}
}
}