OK,经过前面 10 篇介绍,SAP RFC 接口技术的要领基本上就齐了。之前说过,VBA 并不是一门优雅的语言,专业程序员都看不上。因为 SAP RFC 接口并不限制编程语言,所以接下来用 C# 来演示如何实现与 SAP 的通信。
编程环境:Visual Studio 2012 英文版
ActiveX 控件引用
在 Visual Studio 2012 中添加引用比 VBE 方便,选中 Project 的 Solution Explorer,选中 Reference,右键,Add Reference。因为 ActiveX 是COM 组件,所以类别选择 COM,找到相应控件,打钩即可。
SAPLogonCtrl.Connection 对象
调用 RFC 时候,我们需要一个 Connection
对象,并且 Connection
对象的 IsConnected
属性为 tloRfcConnected
。C# 是 OOP 的,所以我们可以利用 OOP 的特性,将 Connection
封装在一个类 SAPConnection
中,该类提供如下方法:
Connection
属性用于外部获取连接的实例。Logon()
,SilentLogon()
和 Logoff()
三个方法用于登陆 SAP,改变 Connection 的 IsConnected
的状态。
在 Visual Studio 中,如果想了解对象的属性/方法等,通过菜单 [View] - [Object Browser] 查看。我们注意到,Connection
是一个接口,ConnectionClass
实现了 Connection
接口。但代码中并不能直接使用ConnectionClass
。
C# 连接 SAP 代码示例
using System;
using SAPLogonCtrl;
namespace ConnectionProvider
{
public static class SAPConnection
{
// Connection is an interface
private static Connection connection;
private static SAPLogonControl sapLogon;
// Access modifiers are not allowed on static constructors
static SAPConnection()
{
sapLogon = new SAPLogonControl();
}
public static bool Logon()
{
connection = (Connection)sapLogon.NewConnection();
return (connection.Logon(null, false) == true ? true : false);
}
public static bool SilentLogon(String appServer, String system, int systemNo, String client, String user, String pwd, String language)
{
bool result = false;
//In C#, the following properties should be set on SAPLogonControl
//while in VBA, they can be set either on SAPLogonControl or Connection
sapLogon.ApplicationServer = appServer;
sapLogon.System = system;
sapLogon.SystemNumber = systemNo;
sapLogon.Client = client;
sapLogon.User = user;
sapLogon.Password = pwd;
sapLogon.Language = language;
connection = (Connection) sapLogon.NewConnection();
result = connection.Logon(null, true);
return result;
}
public static void Logoff()
{
if (connection.IsConnected == CRfcConnectionStatus.tloRfcConnected) {
connection.Logoff();
}
}
public static Connection Connection
{
get { return connection; }
}
}
}
单元测试
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ConnectionProvider;
namespace UnitTestProject
{
[TestClass]
public class TestConnection
{
[TestMethod]
public void TestLogon()
{
bool result = SAPConnection.Logon();
Console.WriteLine(result);
}
[TestMethod]
public void TestSilentLogon()
{
bool result = SAPConnection.SilentLogon(
"192.168.65.100", "D01", 00, "001", "STONE", "pwdxxx", "ZH");
Console.WriteLine(result); // return true or false
}
}
}
RFC 调用的代码
还记得 VBA RFC 的第一个例子吗,对,BAPI_COMPANYCODE_GETDETAIL
。我的例子都是 FI/CO 模块的,因为本人是FI/CO顾问。C# 仍然使用这个BAPI,方便大家进行语言的对比。
using System;
using System.Collections.Generic;
using SAPLogonCtrl;
using SAPFunctionsOCX;
using ConnectionProvider;
namespace SAPRfcCall
{
public class RFC
{
private Connection connection;
public List GetCocdDetail(String cocd)
{
List info = new List();
bool isSuccessful = SAPConnection.SilentLogon(
"192.168.65.100", "D01", 00, "001", "STONE", "pwdxxx", "ZH");
if (isSuccessful) {
connection = SAPConnection.Connection;
info = DoGetCocdDetail(cocd);
SAPConnection.Logoff();
}
return info;
}
// Get company code detail and returns a List
public List DoGetCocdDetail(String cocd)
{
var cocdData = new List();
if (connection.IsConnected != CRfcConnectionStatus.tloRfcConnected) {
return null;
}
SAPFunctions functions = new SAPFunctions();
functions.Connection = connection;
Function fm = functions.Add("BAPI_COMPANYCODE_GETDETAIL");
fm.Exports["COMPANYCODEID"].Value = cocd;
fm.Call();
// return value is a structure(SAPFunctionsOCX.Structure)
Structure cocdDetail = fm.Imports["COMPANYCODE_DETAIL"];
// index begins from 1 instead of 0
for (int i = 1; i <= cocdDetail.ColumnCount; i++) {
String line = String.Format("{0}\t\t{1}",
cocdDetail.ColumnName[(short)i], cocdDetail.Value[i].ToString());
cocdData.Add(line);
}
return cocdData;
}
}
}
单元测试:
using System;
using SAPRfcCall;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
namespace UnitTestProject
{
[TestClass]
public class TestRFC
{
[TestMethod]
public void TestGetCocdDetail()
{
RFC rfc = new RFC();
List cocdDetail = rfc.GetCocdDetail("Z900");
// print info
foreach (String item in cocdDetail) {
Console.WriteLine(item);
}
}
}
}