mySAP Business Suite 的 Microsoft BizTalk 适配器可以充当 RFC 服务器来接收 SAP 系统调用的 RFC。
若要在 WCF 服务模型中接收入站 RFC,必须:
确保 SAP 系统上存在 RFC 目标。
确保 RFC 在 SAP 系统上定义。
从适配器公开的元数据中生成 RFC 操作的 WCF 服务协定(接口)。 为此,请使用“添加适配器服务引用 Visual Studio 插件”或“ServiceModel 元数据实用工具”(svcutil.exe)。
从此接口实现 WCF 服务。 WCF 服务的方法包含处理 RFC 并返回对适配器(因此 SAP 系统)的响应所需的逻辑。
使用服务主机(System.ServiceModel.ServiceHost)托管此 WCF 服务。
以下部分介绍如何使用 SAP 适配器从 SAP 系统接收 RFC。
如何设置 SAP 系统以将 RFC 发送到 SAP 适配器
在将 RFC 从 SAP 系统发送到 SAP 适配器之前,必须确保 SAP 系统上满足以下条件:
SAP 适配器的 RFC 目标必须存在。 SAP 适配器会将自身注册到 RFC 目标位置,以从 SAP 系统接收 RFC。 在 SAP 连接 URI 中提供参数,例如 SAP 网关主机、SAP 网关服务和适配器用于注册自身的 SAP 程序 ID。 有关如何在 SAP 上设置 RFC 目标的信息,请参阅 创建 RFC、RFC 目标以及从 SAP 系统发送 RFC。
必须在 SAP 系统上定义 RFC。 必须创建定义 SAP 系统上 RFC 的函数模块。 SAP 适配器使用 SAP 系统上的 RFC 定义来检索有关 RFC 的元数据(在设计时和运行时)。 有关详细信息,请参阅 在 SAP 系统中创建 RFC。
注释
必须在 SAP 系统上定义 RFC;但是,在适配器客户端代码中实现 RFC。 必须在 SAP 系统上定义 RFC,以便适配器可以检索 RFC 的元数据。
下面是一个在 SAP 系统上用于将两个整数相加并返回其结果的 RFC 源代码示例。 代码仅通过指定目标调用 RFC。 函数的实现由 SAP 适配器客户端代码完成。
FUNCTION Z_RFC_SAMPLE_ADD.
*"---------------------------------------------------------------------*"*"Local interface:
*" IMPORTING
*" VALUE(X) TYPE INT4
*" VALUE(Y) TYPE INT4
*" VALUE(DEST) TYPE CHAR20 DEFAULT 'SAPADAPTER'
*" EXPORTING
*" VALUE(RESULT) TYPE INT4
*"---------------------------------------------------------------------CALL FUNCTION 'Z_RFC_MKD_ADD' DESTINATION DEST
EXPORTING X = X
Y = Y
IMPORTING RESULT = RESULT.
ENDFUNCTION.
RFC 的 WCF 服务协定
可以使用“添加适配器服务引用 Visual Studio 插件”或 ServiceModel 元数据实用工具(svcutil.exe)为想从 SAP 系统接收的 RFC 生成 WCF 服务合同。 以下部分展示了为Z_RFC_MKD_ADD操作生成的托管代码类和接口。
Rfc 接口 (WCF 服务协定)
SAP 适配器通过单个服务契约“Rfc”展示所有 RFC 操作。 这意味着将为您想接收的所有RFC操作创建一个单一接口Rfc。 每个目标 RFC 操作都表示为此接口的方法。 每个方法接受一个参数,该参数表示用于操作请求消息的消息合同,并返回一个对象,该对象表示用于操作响应消息的消息合同。
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="http://Microsoft.LobServices.Sap/2007/03/", ConfigurationName="Rfc")]
public interface Rfc {
// CODEGEN: Generating message contract since the wrapper namespace (http://Microsoft.LobServices.Sap/2007/03/Rfc/) of message Z_RFC_MKD_ADDRequest does not match the default value (http://Microsoft.LobServices.Sap/2007/03/)
[System.ServiceModel.OperationContractAttribute(Action="http://Microsoft.LobServices.Sap/2007/03/Rfc/Z_RFC_MKD_ADD", ReplyAction="http://Microsoft.LobServices.Sap/2007/03/Rfc/Z_RFC_MKD_ADD/response")]
Z_RFC_MKD_ADDResponse Z_RFC_MKD_ADD(Z_RFC_MKD_ADDRequest request);
}
请求和响应消息
每个 RFC作采用一个参数,该参数表示请求消息,并返回一个表示响应消息的对象。 请求消息的属性包含 RFC 的 IMPORT 和 (input)CHANGING 参数。 响应消息的属性包含此操作的 EXPORT 和输出 CHANGING 参数。
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="Z_RFC_MKD_ADD", WrapperNamespace="http://Microsoft.LobServices.Sap/2007/03/Rfc/", IsWrapped=true)]
public partial class Z_RFC_MKD_ADDRequest {
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://Microsoft.LobServices.Sap/2007/03/Rfc/", Order=0)]
public string DEST;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://Microsoft.LobServices.Sap/2007/03/Rfc/", Order=1)]
public System.Nullable<int> X;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://Microsoft.LobServices.Sap/2007/03/Rfc/", Order=2)]
public System.Nullable<int> Y;
public Z_RFC_MKD_ADDRequest() {
}
public Z_RFC_MKD_ADDRequest(string DEST, System.Nullable<int> X, System.Nullable<int> Y) {
this.DEST = DEST;
this.X = X;
this.Y = Y;
}
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="Z_RFC_MKD_ADDResponse", WrapperNamespace="http://Microsoft.LobServices.Sap/2007/03/Rfc/", IsWrapped=true)]
public partial class Z_RFC_MKD_ADDResponse {
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://Microsoft.LobServices.Sap/2007/03/Rfc/", Order=0)]
public int RESULT;
public Z_RFC_MKD_ADDResponse() {
}
public Z_RFC_MKD_ADDResponse(int RESULT) {
this.RESULT = RESULT;
}
}
生成的 WCF 服务
添加适配器服务引用插件还会生成实现 WCF 服务协定(Rfc)的 WCF 服务。 此类的方法已经设置为存根。 此类在一个单独的文件中生成。 您可以直接在此类的方法中实现代码。
namespace SAPBindingNamespace {
public class SAPBindingService : Rfc {
// CODEGEN: Generating message contract since the wrapper namespace (http://Microsoft.LobServices.Sap/2007/03/Rfc/) of message Z_RFC_MKD_ADDRequest does not match the default value (http://Microsoft.LobServices.Sap/2007/03/)
public virtual Z_RFC_MKD_ADDResponse Z_RFC_MKD_ADD(Z_RFC_MKD_ADDRequest request) {
throw new System.NotImplementedException("The method or operation is not implemented.");
}
}
}
如何创建 RFC 服务器应用程序
若要使用 WCF 服务模型从 SAP 系统接收 RFC,可以使用 SAP 适配器遵循 WCF 服务模型概述中的步骤。 添加服务终结点时,请务必为服务协定指定“Rfc”(创建和实现 WCF 服务的过程的步骤 6)。
以下代码演示了如何使用 SAP 适配器从 SAP 系统接收Z_RFC_MKD_RFC的完整示例。 此 RFC 采用两个整数参数,并将结果返回到 SAP 系统。
using System;
using System.Collections.Generic;
using System.Text;
// Add WCF, WCF LOB Adapter SDK, and SAP adapter namepaces
using System.ServiceModel;
using Microsoft.Adapters.SAP;
using Microsoft.ServiceModel.Channels;
// Include this namespace for the WCF LOB Adapter SDK and SAP adapter exceptions
using Microsoft.ServiceModel.Channels.Common;
namespace SapRfcServerSM
{
// Implement a WCF service callback class by sub-classing the generated service callback class (SAPBindingService).
// You must annotate this class with the InstanceContextMode.Single ServiceBehavior
// If you implement your code in SAPBindingService.cs be sure to annotate the SAPBindingService class
// The callback method should return a Z_RFC_MKD_ADDResponse to indicate successful processing
// or throw an exception to indicate an error.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,UseSynchronizationContext = false)]
class RfcServerClass : SAPBindingNamespace.SAPBindingService
{
public override Z_RFC_MKD_ADDResponse Z_RFC_MKD_ADD(Z_RFC_MKD_ADDRequest request)
{
// If either parameter is null, throw an exception
if (request.X == null || request.Y == null)
throw new System.ArgumentNullException();
int result = (int) (request.X + request.Y);
Console.WriteLine("\nRfc Received");
Console.WriteLine("X =\t\t" + request.X.ToString());
Console.WriteLine("Y =\t\t" + request.Y.ToString());
Console.WriteLine("Result =\t" + result);
Console.WriteLine("\nHit <RETURN> to end");
return new Z_RFC_MKD_ADDResponse(result);
}
}
class Program
{
static void Main(string[] args)
{
// Listener connection for the service URI -- the connection URI must contain credentials
Uri serviceUri = new Uri("sap://User=YourUserName;Passwd=YourPassword;Client=800;Lang=EN;@a/ADAPSAP47/00?ListenerGwServ=SAPGW00&ListenerGwHost=ADAPSAP47&ListenerProgramId=ADDER");
// The baseUri cannot contain userinfoparams or query_string parameters
Uri[] baseUri = new Uri[] { new Uri("sap://a/ADAPSAP47/00") };
Console.WriteLine("RFC server sample started");
// create service instance
RfcServerClass rfcServerInstance = new RfcServerClass();
try
{
Console.WriteLine("Initializing service host -- please wait");
// Create and initialize a service host
using (ServiceHost srvHost = new ServiceHost(rfcServerInstance, baseUri))
{
// Add service endpoint
// Specify AcceptCredentalsInUri=true for the binding
// NOTE: The contract for the service endpoint is "Rfc".
// This is the generated WCF service callback interface (see SAPBindingInterface.cs).
SAPBinding binding = new SAPBinding();
binding.AcceptCredentialsInUri = true;
srvHost.AddServiceEndpoint("Rfc", binding, serviceUri);
srvHost.Open();
Console.WriteLine("\nReady to receive Z_RFC_MKD_ADD RFC");
Console.WriteLine("Hit <RETURN> to end");
// Wait to receive request
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);
}
}
}
}
}