OK,经过前面10篇介绍,SAP RFC接口技术的要领基本上就齐了。之前说过,VBA并不是一门优雅的语言,专业程序员都看不上。因为SAP RFC接口并不限制编程语言,所以接下来用C#来演示如何实现跟SAP的互通。
编程环境:Visual Studio 2012英文版
在Visual Studio 2012中添加引用比VBE方便,Project的Solution Explorer中,选中Reference,右键,Add Reference。因为ActiveX是COM组件,所以类别选择COM,找到相应控件,打钩即可。
调用RFC时候,我们需要一个Connection对象,并且Connection对象的IsConnected属性为tloRfcConnected。C#是OOP的,所以我们要重复发挥OOP的特点,将Connection封装在一个类SAPConnection中,并提供如下方法:
Connection属性用于外部获取到SAPLogonCtrl.Connection
Logon()/SilentLogon()/Logoff()三个方法用于登陆SAP,改变Connection的IsConnected的状态。
在Visual Studio中,如果想了解对象的属性/方法等,通过菜单[View] - [Object Browser]查看。我们注意到,Connection是一个接口,ConnectionClass实现了Connection接口。代码中并不能直接使用ConnectionClass。
以下是SAPConnection类的代码和单元测试。
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
}
}
}
还记得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<String> GetCocdDetail(String cocd)
{
List<String> info = new List<String>();
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<String> DoGetCocdDetail(String cocd)
{
var cocdData = new List<String>();
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<String> cocdDetail = rfc.GetCocdDetail("Z900");
// print info
foreach (String item in cocdDetail) {
Console.WriteLine(item);
}
}
}
}