使用 WCF 服务模型在 SAP 中调用 BAPI
SAP 适配器将 BAPI 显示为:
RFC 操作。 与任何其他 RFC 一样,BAPI 显示在“添加适配器服务引用插件”中的 RFC 节点下。
SAP 业务对象的方法。 作为业务对象的方法,BAPI 由业务对象显示在“添加适配器服务引用插件”中的 BAPI 节点下。
无论是将 BAPI 作为 RFC 操作调用还是作为业务对象方法调用,每个 BAPI 始终是 SAP 系统上 LUW 的一部分。
有关 SAP 适配器如何支持 BAPI 的概述,请参阅 SAP 中 BAPI 的操作。
使用 WCF 服务模型将 BAPI 作为业务对象方法调用时,每个 SAP 业务对象由 WCF 客户端类表示,该业务对象的 BAPI 在客户端上表示为方法。 可以使用添加适配器服务引用 Visual Studio 插件为包含要在代码中调用的每个 BAPI 的方法的特定业务对象生成 WCF 客户端类。 添加适配器服务引用插件还会生成 .NET 类型,以封装每个 BAPI 使用的参数和数据类型。 然后,可以创建此 WCF 客户端类的实例,并调用其方法来调用目标 BAPI。
以下部分演示如何调用 BAPI 作为业务对象的方法,并讨论 WCF 服务模型中如何支持 BAPI 事务。
WCF 客户端类
SAP 适配器针对每个业务对象显示不同的服务协定。 这意味着将为每个业务对象创建一个唯一的 WCF 客户端类。 此类的名称基于业务对象类型。 例如,对于 Sales Order 业务对象 (业务对象类型BUS2032) ,WCF 客户端类为 BapiBUS2032Client。 业务对象中的每个目标 BAPI 都表示为生成的 WCF 客户端类中的一个方法。 在每个方法中:
SAP 导出参数显示为 out 参数
SAP 调用参数显示为 ref 参数。
复杂的 SAP 类型(如结构)显示为 .NET 类,其属性对应于 SAP 类型的字段。 这些类在以下命名空间中定义:microsoft.lobservices.sap._2007._03.Types.Rfc。
将为每个业务对象显示BAPI_TRANSACTION_COMMIT和BAPI_TRANSACTION_ROLLBACK,应始终将这些对象包含在 WCF 客户端中。
下面的代码显示了为 Sales Order 业务对象生成的 WCF 客户端类的一部分。 此客户端包含调用 CREATEFROMDAT2、BAPI_TRANSACTION_COMMIT 和 BAPI_TRANSACTION_ROLLBACK 的方法。 为清楚起见,省略了构造函数和其他代码。
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class BapiBUS2032Client : System.ServiceModel.ClientBase<BapiBUS2032>, BapiBUS2032 {
// Code has been removed for clarity
/// <summary>The Metadata for this RFC was generated using the RFC SDK.</summary>
/// <param name="SALESDOCUMENT">Number of Generated Document</param>
/// <param name="BEHAVE_WHEN_ERROR">Error Handling</param>
/// …
/// <param name="ORDER_TEXT">Texts</param>
/// <param name="PARTNERADDRESSES">BAPI Reference Structure for Addresses (Org./Company)</param>
/// <param name="RETURN">Return Messages</param>
/// <returns></returns>
public string CREATEFROMDAT2(
string BEHAVE_WHEN_ERROR,
string BINARY_RELATIONSHIPTYPE,
string CONVERT,
string INT_NUMBER_ASSIGNMENT,
microsoft.lobservices.sap._2007._03.Types.Rfc.BAPISDLS LOGIC_SWITCH,
microsoft.lobservices.sap._2007._03.Types.Rfc.BAPISDHD1 ORDER_HEADER_IN,
microsoft.lobservices.sap._2007._03.Types.Rfc.BAPISDHD1X ORDER_HEADER_INX,
string SALESDOCUMENTIN,
microsoft.lobservices.sap._2007._03.Types.Rfc.BAPI_SENDER SENDER,
string TESTRUN,
ref microsoft.lobservices.sap._2007._03.Types.Rfc.BAPIPAREX[] EXTENSIONIN,
ref microsoft.lobservices.sap._2007._03.Types.Rfc.BAPICCARD[] ORDER_CCARD,
ref microsoft.lobservices.sap._2007._03.Types.Rfc.BAPICUBLB[] ORDER_CFGS_BLOB,
ref microsoft.lobservices.sap._2007._03.Types.Rfc.BAPICUINS[] ORDER_CFGS_INST,
ref microsoft.lobservices.sap._2007._03.Types.Rfc.BAPICUPRT[] ORDER_CFGS_PART_OF,
ref microsoft.lobservices.sap._2007._03.Types.Rfc.BAPICUCFG[] ORDER_CFGS_REF,
ref microsoft.lobservices.sap._2007._03.Types.Rfc.BAPICUREF[] ORDER_CFGS_REFINST,
ref microsoft.lobservices.sap._2007._03.Types.Rfc.BAPICUVAL[] ORDER_CFGS_VALUE,
ref microsoft.lobservices.sap._2007._03.Types.Rfc.BAPICUVK[] ORDER_CFGS_VK,
ref microsoft.lobservices.sap._2007._03.Types.Rfc.BAPICOND[] ORDER_CONDITIONS_IN,
ref microsoft.lobservices.sap._2007._03.Types.Rfc.BAPICONDX[] ORDER_CONDITIONS_INX,
ref microsoft.lobservices.sap._2007._03.Types.Rfc.BAPISDITM[] ORDER_ITEMS_IN,
ref microsoft.lobservices.sap._2007._03.Types.Rfc.BAPISDITMX[] ORDER_ITEMS_INX,
ref microsoft.lobservices.sap._2007._03.Types.Rfc.BAPISDKEY[] ORDER_KEYS,
ref microsoft.lobservices.sap._2007._03.Types.Rfc.BAPIPARNR[] ORDER_PARTNERS,
ref microsoft.lobservices.sap._2007._03.Types.Rfc.BAPISCHDL[] ORDER_SCHEDULES_IN,
ref microsoft.lobservices.sap._2007._03.Types.Rfc.BAPISCHDLX[] ORDER_SCHEDULES_INX,
ref microsoft.lobservices.sap._2007._03.Types.Rfc.BAPISDTEXT[] ORDER_TEXT,
ref microsoft.lobservices.sap._2007._03.Types.Rfc.BAPIADDR1[] PARTNERADDRESSES,
ref microsoft.lobservices.sap._2007._03.Types.Rfc.BAPIRET2[] RETURN) { ...}
/// <summary>The Metadata for this RFC was generated using the RFC SDK.</summary>
/// <param name="RETURN">Confirmations</param>
/// <param name="WAIT">Using the command `COMMIT AND WAIT`</param>
/// <returns></returns>
public microsoft.lobservices.sap._2007._03.Types.Rfc.BAPIRET2 BAPI_TRANSACTION_COMMIT(string WAIT) { ... }
/// <summary>The Metadata for this RFC was generated using the RFC SDK.</summary>
/// <param name="RETURN">Confirmations</param>
/// <returns></returns>
public microsoft.lobservices.sap._2007._03.Types.Rfc.BAPIRET2 BAPI_TRANSACTION_ROLLBACK() { ... }
}
WCF 服务模型中的 BAPI 事务
每个 BAPI(无论是作为 RFC 调用还是作为业务对象方法调用)都是 SAP 系统上 (LUW) 事务的一部分;通过同一 SAP 连接接收的每个 BAPI 都是 SAP 系统上同一 BAPI 事务的一部分。 SAP 在收到连接上的BAPI_TRANSACTION_COMMIT或BAPI_TRANSACTION_ROLLBACK时提交或回滚 BAPI 事务。 执行提交或回滚后,通过连接收到的下一个 BAPI 将开始一个新事务。
对于适配器,每个 WCF 通道都有一个专用的 SAP 连接。 在 WCF 服务模型中,每个 WCF 客户端都有一个内部通道,用于将消息发送到 SAP 系统。 这意味着,使用特定 WCF 客户端调用的 BAPI 是 SAP 系统上唯一 BAPI 事务的一部分。 使用 WCF 服务模型将 BAPI 作为业务对象方法调用时,这会施加重大限制。 由于每个 SAP 业务对象都由专用的 WCF 客户端类表示,因此不能从两个不同的业务对象调用 BAPI 作为同一事务的一部分。 解决方法是调用 BAPI 作为 RFC 操作。 这是因为添加适配器服务引用插件为 RFC 操作生成单个 WCF 客户端,因此,使用该客户端调用的所有操作都通过同一 WCF 通道发送。
重要
如果要在同一 BAPI 事务中包含来自不同 SAP 业务对象的 BAPI,则必须使用相同的 WCF 客户端) (作为 RFC 操作调用它们。 不能将它们作为业务对象方法调用。
调用 BAPI_TRANSACTION_COMMIT 或 BAPI_TRANSACTION_ROLLBACK 以在 SAP 系统上提交或回滚 BAPI 事务。 适配器显示以下两个 BAPI:
在“基”节点下作为 RFC 操作。
在每个业务对象下。
有关适配器如何支持 SAP 上的 BAPI 事务的详细信息,请参阅 SAP 中 BAPI 的操作。
如何创建将 BAPI 作为业务对象方法调用的应用程序
本部分介绍如何将 BAPI 作为业务对象的方法调用。 应遵循相同的基本过程来调用 BAPI 作为 RFC 操作,只不过创建一个以 BAPI 为目标的 WCF 客户端作为 RFC 操作,并使用它来调用每个 BAPI。
若要创建 BAPI 客户端应用程序,请执行以下步骤。
创建 BAPI 客户端应用程序
生成 WCF 客户端类。 使用添加适配器服务引用 Visual Studio 插件或 ServiceModel 元数据实用工具 (svcutil.exe) 生成 WCF 客户端类 (或类) ,该类面向要使用的业务对象和 BAPI。 请确保包括为每个目标业务对象公开的BAPI_TRANSACTION_COMMIT和) BAPI_TRANSACTION_ROLLBACK方法 (BAPI。 有关如何生成 WCF 客户端的详细信息,请参阅 为 SAP 解决方案项目生成 WCF 客户端或 WCF 服务协定。
创建步骤 1 中生成的 WCF 客户端类的实例,并创建和配置 WCF 客户端。 配置 WCF 客户端涉及指定客户端将使用的绑定和终结点地址。 可以在代码中强制执行此操作,也可以在配置中以声明方式执行此操作。 有关如何指定客户端绑定的详细信息,请参阅 为 SAP 系统配置客户端绑定。 以下代码从配置中初始化 Sales Order (BUS2032) SAP 业务对象的 WCF 客户端,并设置 SAP 系统的凭据。
BapiBUS2032Client bapiClient = new BapiBUS2032Client("SAPBinding_BapiBUS2032"); bapiClient.ClientCredentials.UserName.UserName = "YourUserName"; bapiClient.ClientCredentials.UserName.Password = "YourPassword";
打开 WCF 客户端。
bapiClient.Open();
在步骤 2 中创建的 WCF 客户端上调用方法,以调用 SAP 系统上的相应 BAPI。 可以在 SAP 系统上调用多个 BAPI。
通过以下方式结束事务:
调用 BAPI_TRANSACTION_COMMIT 方法来提交事务。
bapiClient.BAPI_TRANSACTION_COMMIT("X");
调用 BAPI_TRANSACTION_ROLLBACK 方法来回滚事务。
bapiClient.BAPI_TRANSACTION_ROLLBACK();
关闭 WCF 客户端。
bapiClient.Close();
示例
以下示例对 Sales Order 业务对象调用 CREATEFROMDAT2 BAPI。 它多次调用 BAPI,然后调用BAPI_TRANSACTION_COMMIT来提交事务。 如果在调用 BAPI 时发生错误,则会在异常处理程序中调用BAPI_TRANSACTION_ROLLBACK以回滚事务。
CREATEFROMDAT2 方法采用许多参数;为简洁起见,示例中省略了这些内容。 可以在 Microsoft BizTalk 适配器包随附的示例中找到演示 BAPI 事务的示例。 有关详细信息,请参阅 SAP 适配器的示例。
using System;
using System.Collections.Generic;
using System.Text;
// Add WCF, Adapter LOB SDK, and SAP Adapter namepaces
using System.ServiceModel;
using Microsoft.Adapters.SAP;
using Microsoft.ServiceModel.Channels;
// Include this namespace for Adapter LOB SDK and SAP exceptions
using Microsoft.ServiceModel.Channels.Common;
using microsoft.lobservices.sap._2007._03.Types.Rfc;
// This Example demonstrates BAPI transactions. Two sales orders are
// created using the CREATEFROMDAT2 method of a SAP Business Object.
// After the orders are created, the BAPI transaction is committed.
// If an exception occurs when sending the BAPIs, the BAPI transaction is
// rolled back.
//
namespace SapBapiTxClientSM
{
class Program
{
static void Main(string[] args)
{
// Create the BAPI client from the generated endpoint configuration.
BapiBUS2032Client bapiClient = null;
Console.WriteLine("BAPI transaction sample started");
Console.WriteLine("\nCreating business object client");
try
{
bapiClient = new BapiBUS2032Client("SAPBinding_BapiBUS2032");
bapiClient.ClientCredentials.UserName.UserName = "YourUserName";
bapiClient.ClientCredentials.UserName.Password = "YourPassword";
// Open the BAPI Client
bapiClient.Open();
...
// send first BAPI
try
{
string salesDocNumber1 = bapiClient.CREATEFROMDAT2(
...
// parameters ommitted
...
);
}
catch (Exception ex)
{
bapiClient.BAPI_TRANSACTION_ROLLBACK();
throw;
}
...
// send second BAPI
try
{
string salesDocNumber1 = bapiClient.CREATEFROMDAT2(
...
// parameters omitted
...
);
}
catch (Exception ex)
{
bapiClient.BAPI_TRANSACTION_ROLLBACK();
throw;
}
...
// Commit BAPI Transaction
try
{
bapiClient.BAPI_TRANSACTION.Commit();
}
catch (Exception ex)
{
bapiClient.BAPI_TRANSACTION_ROLLBACK();
throw;
}
...
}
catch (ConnectionException cex)
{
// Get here if problem connecting to the SAP system
Console.WriteLine("Exception occurred connecting to the SAP system");
Console.WriteLine(cex.InnerException.Message);
}
catch (TargetSystemException tex)
{
// Get here if the SAP system returns an exception
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);
}
}
finally
{
// Close the client when finished
if (bapiClient != null)
{
if (bapiClient.State == CommunicationState.Opened)
bapiClient.Close();
else
bapiClient.Abort();
}
}
}
}
}