前言
最近工作上需要串接 SAP,但是因為現在專案都改用 .NET Core 了,官方的 SAP Connector for Microsoft .NET 主要是支援 .NET Framework,因此就在 NuGet 上面找了幾個套件,經過測試之後,huysentruitw/SapNwRfc
這一個套件,它的使用方式我比較喜歡,而且可以支援強型別的 Model ,使用上會比較順手,另外也需要將程式部署到 App Service 執行,因此也把可能會遇到的問題記錄一下。
實做
環境設定
套件是建立在官方 SAP NetWeaver RFC Library 7.50 SDK C++ 之上,所以需要先到 SAP 官方下載相關檔案,這邊就不方便直接提供檔案了。
下載之後解壓縮之後到 nwrfcsdk\lib
路徑底下會有一些 DLL 檔案,需要將 sapnwrfc.dll
、icudt50.dll
、icuin50.dll
、icuuc50.dll
這四個檔案複製到系統 PATH 目錄內,或是之後複製到程式輸出目錄底下。
實做說明
範例程式是 .NET 6 主控台應用程式專案,首先透過 NuGet 新增 SAPNwRfc
套件。
再來就來實做呼叫 SAP 內建的 Echo 的函數 STFC_STRUCTURE
。再來先新增三個 Model 來作為輸入和輸出使用,可以看到我們自定義的類別加上 SapName
這一個 Attrubute,這樣就可以再送出和接收時候對應的到了,或是直接把名稱定義成和 SAP 的一樣,但是這樣可能會不符合自己專案命名規則,所以我會習慣用 Attrubute 來定義,也可以加上其它非 SAP 結構的欄位,這時候只需要加上 SapIgnore
這一個 Attrubute 就可以了。
/// <summary>
/// Echo Demo Input
/// </summary>
internal class EchoDemoInput
{
/// <summary>
/// RFC Table
/// </summary>
[SapName("RFCTABLE")]
public EchoDemoItem[] RFCTable { get; set; }
}
/// <summary>
/// Echo Demo Item
/// </summary>
internal class EchoDemoItem
{
/// <summary>
/// RfcFloat
/// </summary>
[SapName("RFCFLOAT")]
public double RfcFloat { get; set; }
/// <summary>
/// RfcChar1
/// </summary>
[SapName("RFCCHAR1")]
public string RfcChar1 { get; set; }
/// <summary>
/// RfcChar2
/// </summary>
[SapName("RFCCHAR2")]
public string RfcChar2 { get; set; }
/// <summary>
/// RfcChar4
/// </summary>
[SapName("RFCCHAR4")]
public string RfcChar4 { get; set; }
/// <summary>
/// RfcHEX3
/// </summary>
[SapName("RFCHEX3")]
public byte[] RfcHEX3 { get; set; }
/// <summary>
/// RfcDate
/// </summary>
[SapName("RFCDATE")]
public DateTime? RfcDate { get; set; }
/// <summary>
/// RfcData1
/// </summary>
[SapName("RFCDATA1")]
public string RfcData1 { get; set; }
}
/// <summary>
/// Echo Demo Output
/// </summary>
internal class EchoDemoOutput
{
/// <summary>
/// Response Text
/// </summary>
[SapName("RESPTEXT")]
public string ResponseText { get; set; }
/// <summary>
/// RFCTable
/// </summary>
[SapName("RFCTABLE")]
public EchoDemoItem[] RFCTable { get; set; }
}
再來新增呼叫 Echo Demo 的程式,透過 CreateFunction 來建立呼叫的程式,然後傳入資料,因範例也會回傳資料,因此將回傳的類別也加上,到時候執行完成之後就會 Mapping 資料到類別上了。
internal class SAPService
{
private SapConnection sapConnection;
public SAPService(string connectionString)
{
sapConnection = new SapConnection(connectionString);
sapConnection.Connect();
}
/// <summary>
/// 呼叫 Echo Demo
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="sapFunction">SAP Function</param>
/// <returns></returns>
public EchoDemoOutput EchoDemo(EchoDemoInput input)
{
using var sapFunctionClient = sapConnection.CreateFunction("STFC_STRUCTURE");
return sapFunctionClient.Invoke<EchoDemoOutput>(input);
}
}
再來就可以在主程式裡面呼叫來測試了,不過先來新增一個產生假資料的程式。
/// <summary>
/// 產生假資料
/// </summary>
/// <returns></returns>
EchoDemoInput GenEchoDemoItems()
{
var demoInput = new EchoDemoInput();
var items = new List<EchoDemoItem>();
for (int i = 0; i < 10; i++)
{
var item = new EchoDemoItem()
{
RfcFloat = 12345.6789,
RfcChar1 = "AnYun",
RfcChar2 = "AB",
RfcChar4 = "NCO3",
RfcHEX3 = new byte[] { 0x41, 0x42, 0x43 },
RfcDate = DateTime.Today,
RfcData1 = "Hello World"
};
items.Add(item);
}
demoInput.RFCTable = items.ToArray();
return demoInput;
}
最後呼叫上就很簡單了,連線字串的格式可以參考底下的範例,自行調整輸入相關參數。
// AppServerHost=MY_SERVER_HOST; SystemNumber=00; User=MY_SAP_USER; Password=SECRET; Client=100; Language=EN; PoolSize=5; Trace=8
var connectionString = "";
var sapService = new SAPService(connectionString);
var input = GenEchoDemoItems();
var result = sapService.EchoDemo(input);
如果有正常回應的話,可以看到底下的結果,在我們輸入的資料後面會被加上一筆記錄並且回傳,這樣就完成的程式串接了。
App Service 執行注意事項
因為是命令列程式,所以是上傳到 App Service 作為 WebJob 來執行,在部署的時候有一些點需要注意的,分別說明如下:
1.需手動上傳 SAP 相關 DLL,因為不是直接給 .NET 使用的函示庫,所以沒辦法加入到專案,所以部署時候需要手動上傳檔案,可以透過 Kudu 來拖曳檔案來上傳檔案到執行目錄底下。
2. 需將檔案編譯成 win-x64
格式,不然執行上會失敗,
透過 Virtual Studio 部署時候將目標執行階段設定成 win-x64。
結論
簡單的介紹如何在 .NET Core 串接並呼叫 SAP 的 Function,在實做過程遇到的一些雷,以及實做過程做個記錄,以防未來的自己遇到的時候又忘記要怎麼處理了,希望對有需要的朋友也有一點幫助。
附上完成程式碼 GitHub。