QiitaでSAPをやっている人なんているの?という突込みもあるがそれは気にしないことにして、.NETを利用しSAPへ接続する方法を紹介する。
SAPとはSAP社が提供する業務パッケージで、この中には受注/請求、在庫といった業務に欠かせないデータが蓄積されている。これを外に出して活用したり、あるいは外部システムからSAPにデータを入れたい、という状況でこうした技術の出番となるわけです。
.NET Connectorのインストール
まずはSAPから.NET用のConnectorをダウンロードする。32bit/64bitがあるので注意が必要。
SAP CONNECTOR FOR MICROSOFT .NET
なお、上記のサイトにアクセスするにはSAP Service Marketplaceのアカウントが必要(ただ、パッと見アカウントは普通に作れるようなかんじもする)。
それで、動作には「Microsoft Visual C++ 2010 再頒布可能パッケージ」が必要なのでこちらもダウンロード。これも32bit/64bitがあるので環境に合わせてインストール。
これで準備は完了だ。
web.config/app.configの設定
こちらは、コネクタと共に提供されているサンプルの中にsample_configuration_destinations.config
という設定ファイルがあるので、此方を参考に設定する。
修正が必要なのはSAP.Middleware.Connector
セクションのClientSettings
の箇所。これを自分の環境に応じて変更する。設定はsaplogon.ini
の設定と同義なので、それに合わせて編集する。
SAPへのアクセス
いよいよ本題、SAPへの接続を行う。
接続には、大きく分けて2つの方法がある。
- サイレントログオン
通常のDBアクセスと同じように、ユーザーID/パスワードを設定ファイルに記載しておきユーザー入力無しにログインする。
この場合、RfcDestinationManager.GetDestination(ログイン先)
のみでログイン可能。 - ダイアログログオン
ユーザーにID、パスワードを入力してもらってログインする。
この場合は、RfcCustomDestination
を利用して、そこにユーザーIDとパスワードをセットしログインする。
イメージとしては下記のような感じになる。
Public Function Login() As RfcDestination
Dim connection As RfcDestination = Nothing
Dim destConnection As RfcDestination = RfcDestinationManager.GetDestination(Destination)
If IsSilent Then
connection = destConnection
Else
Dim userLogin As RfcCustomDestination = destConnection.CreateCustomDestination
userLogin.User = User
userLogin.Password = Password
connection = userLogin
End If
If connection IsNot Nothing Then
connection.Ping() 'confirm connection
End If
Return connection
End Function
これでSAPへの接続は完了。
リモートファンクション(RFC)を実行する
SAPには外部コール可能なFunction(RFC)があり、これらをこのコネクタで呼び出すことができる。
具体的には、テーブルTFDIRで更新モードが「R」であるものがこれに該当する(BAPIもこれに含まれる)ので、ほしい情報を提供してくれるファンクションがあるかどうかはこれで検索をかけて調べることができる。
さて、サンプルの中にもあるがまさにこの「RFCを検索するファンクション」があるためこれの呼び出しを見てみる。
'SAPへの接続を読込
Dim destination As RfcDestination = RfcDestinationManager.GetDestination(ABAP_APP_SERVER)
'RFCを検索するRFC_FUNCTION_SEARCHの実行パラメーターを設定する
Dim rfcFunction As IRfcFunction = destination.Repository.CreateFunction("RFC_FUNCTION_SEARCH")
rfcFunction.SetValue("FUNCNAME", "RFC_*")
rfcFunction.SetValue("LANGUAGE", "JA")
'RFCを実行
rfcFunction.Invoke(destination)
'返り値のテーブルを取得
Dim table As IRfcTable = rfcFunction.GetTable("FUNCTIONS")
'テーブル内の内容を取得
For i As Integer = 0 To rfcTable.Count - 1
table.CurrentIndex = i '読込対象行を設定
Console.WriteLine("{0} FUNCNAME={1} GROUPNAME={2} APPL={3} HOST={4} STEXT={5}", _
i.ToString(), _
table.GetString("funcname"), _
table.GetString("groupname"), _
table.GetString("appl"), _
table.GetString("host"), _
table.GetString("stext"))
Next
全体としては以下のような流れになる。
-
destination.Repository.CreateFunction
で、呼び出し対象のRFCのIRfcFunction
を作成する -
IRfcFunction
に対し、SetValue
でパラメーターをセットする。 - Invokeで呼出
-
GetValue
,GetTable
等で実行結果を取得
なお、単純にSetValue
では値がセットができない構造を持つパラメーターもある。
この場合は、以下のようにGetStructure
を使用する
Dim impStruct As IRfcStructure = func.GetStructure("IMPORTSTRUCT")
'取得した構造に値をセット
impStruct.SetValue("RFCFLOAT", 12345.678900000001)
impStruct.SetValue("RFCINT4", 12345)
...
RFCであるSTFC_STRUCTURE
のパラメータIMPORTSTRUCT
は、下記のように構造RFCTEST
で定義されるパラメータとなっている。
当然、構造RFCTEST
は、複数の項目で構成される。
こうしたパラメータに値をセットする際は、まずGetStructure
で構造体を取得し、その後SetValue
で取得した構造にパラメータをセットするという流れになる。
なお、これは返り値の場合も同様で、返り値の値が構造で定義される場合はGetStructure
で構造を取得し、GetString
等のメソッドで値を取得、という流れになる。
後はトランザクション処理などもあるが、普通呼出元クライアントでそんな制御はしないので、上記を覚えておけばほぼ対応できると思う。
おすすめRFC
呼出方法はわかったが、そもそもどれを呼び出せばほしい情報が取れるのかわからん、ということはよくある。
そのため、ここでは業務シーンで利用価値がありそうなRFCを紹介して行こうと思う。
...加筆中