本篇文章中我主要講的是.NET如何通過RFC從SAP中讀取數據。為了功能的可復用性,我將調用RFC的代碼從業務層中分離出來單獨建立在一個namespace中。
當然除了需要我們自己編寫代碼以外,還需要引用SAP提供的程序集文件(sapnco.dll、sapnco_utils.dll),在代碼文件需要引用相應的命名空間(using SAP.Middleware.Connector;)。
我在這個namespace中建立了三個類來實現這個功能,一個配置類(RfcDestinationConfig)、一個參數類(RfcParam)、一個主體功能類(RfcManager)。
- RfcDestinationConfig
我們需要一個類來實現SAP的連接配置工作,就如同為數據連接層建立一個數據庫配置類一樣重要。
1 public class RfcDestinationConfig : IDestinationConfiguration 2 { 3 #region 事件 4 /// <summary> 5 /// 配置變更事件 6 /// </summary> 7 public event RfcDestinationManager.ConfigurationChangeHandler ConfigurationChanged; 8 /// <summary> 9 /// 默認接收器名稱 10 /// </summary> 11 public static readonly string DefaultDesName = "destination"; 12 #endregion 13 14 #region 方法 15 /// <summary> 16 /// 配置變更事件觸發時,暫時無用 17 /// </summary> 18 /// <param name="destinationName"></param> 19 /// <param name="args"></param> 20 public void OnConfigurationChanged(string destinationName, RfcConfigurationEventArgs args) 21 { 22 if (ConfigurationChanged != null) 23 { 24 ConfigurationChanged(destinationName, args); 25 } 26 } 27 28 /// <summary> 29 /// 獲取SAP配置參數 30 /// </summary> 31 /// <param name="destinationName"></param> 32 /// <returns></returns> 33 public RfcConfigParameters GetParameters(string destinationName) 34 { 35 if (destinationName == DefaultDesName) 36 { 37 RfcConfigParameters parms = new RfcConfigParameters(); 38 parms.Add(RfcConfigParameters.AppServerHost,ConfigManager.GetAppSettings("SAPApplicationServer").Trim()); //SAP主機IP 39 parms.Add(RfcConfigParameters.SystemNumber, ConfigManager.GetAppSettings("SAPSystemNumber").Trim()); //SAP實例 40 parms.Add(RfcConfigParameters.User, ConfigManager.GetAppSettings("SAPUser").Trim()); //用戶名 41 parms.Add(RfcConfigParameters.Password,ConfigManager.GetAppSettings("SAPPwd").Trim()); //密碼 42 parms.Add(RfcConfigParameters.Client, ConfigManager.GetAppSettings("SAPClient").Trim()); // Client 43 parms.Add(RfcConfigParameters.Language,ConfigManager.GetAppSettings("SAPLanguage").Trim()); //登陸語言 44 return parms; 45 } 46 else 47 { 48 return null; 49 } 50 } 51 52 /// <summary> 53 /// 變更事件方法,暫時無用 54 /// </summary> 55 /// <returns>true</returns> 56 public bool ChangeEventsSupported() 57 { 58 return true; 59 } 60 #endregion 61 }
- RfcParam
想要從SAP中讀取數據,就必須將查詢條件作為參數傳遞給RFC。另外為了返回的結果具有通用性,我使用DataTable作為返回結果的類型,然后考慮到不同條件下列是不同的,我又將列也參數化,最終我將輸入參數和輸出參數都封裝在一個參數類之中。
1 public class RfcParam 2 { 3 /// <summary> 4 /// 初始化 5 /// </summary> 6 public RfcParam() 7 { 8 CoulmnNames = new List<string>(); 9 Param = new Dictionary<string, object>(); 10 } 11 /// <summary> 12 /// RFC方法名稱 13 /// </summary> 14 public string RfcName { get; set; } 15 /// <summary> 16 /// RFC表名 17 /// </summary> 18 public string TableName { get; set; } 19 /// <summary> 20 /// 數據表各列的列名 21 /// </summary> 22 public List<string> CoulmnNames { get; set; } 23 /// <summary> 24 /// RFC執行參數 25 /// </summary> 26 public Dictionary<string, object> Param { get; set; } 27 }
- RfcManager
該主角登場了,讀取數據的功能正是業務層真正想要的東西。
方法ExecRfc首先將輸出參數轉換成一個真正可用的新的DataTable,然后將輸入參數傳遞給SAP執行相關的RFC功能並返回IRfcTable(SAP定義的一種接口),最后再將IRfcTable轉換成我們自定義的DataTable。
1 public class RfcManager 2 { 3 #region 屬性字段 4 /// <summary> 5 /// 接收器 6 /// </summary> 7 public RfcDestination Prd { get; set; } 8 /// <summary> 9 /// 數據倉庫 10 /// </summary> 11 public RfcRepository Repo { get; set; } 12 #endregion 13 14 #region 構造函數 15 /// <summary> 16 /// 初始化 17 /// </summary> 18 public RfcManager() 19 { 20 //初始化RFC接收器 21 //配置接收器 22 IDestinationConfiguration IDC = new RfcDestinationConfig(); 23 //注冊 24 RfcDestinationManager.RegisterDestinationConfiguration(IDC); 25 //獲取RFC接收器 26 this.Prd = RfcDestinationManager.GetDestination(RfcDestinationConfig.DefaultDesName); 27 this.Repo = this.Prd.Repository; 28 //注銷 29 RfcDestinationManager.UnregisterDestinationConfiguration(IDC); 30 } 31 #endregion 32 33 #region 方法 34 /// <summary> 35 /// 執行RFC獲取數據表 36 /// </summary> 37 /// <param name="rfcname">rfc方法名稱</param> 38 /// <param name="tablename">rfc表名</param> 39 /// <param name="columnnames">數據表列名列表</param> 40 /// <param name="param">rfc執行參數</param> 41 /// <returns>數據表</returns> 42 public DataTable ExecRfc(string rfcname, string tablename, List<string> columnnames, Dictionary<string, object> param) 43 { 44 DataTable dt = new DataTable(); 45 46 if (columnnames != null && columnnames.Count > 0) 47 { 48 //配置datatable 49 dt.Columns.Clear(); 50 foreach (string cname in columnnames) 51 { 52 dt.Columns.Add(cname, typeof(string)); 53 } 54 dt.AcceptChanges(); 55 56 //從SAP那獲取數據表 57 if (!string.IsNullOrEmpty(rfcname) && param != null && param.Count > 0) 58 { 59 IRfcFunction rfc = this.Repo.CreateFunction(rfcname); 60 foreach (KeyValuePair<string, object> kv in param) 61 { 62 rfc.SetValue(kv.Key, kv.Value); 63 } 64 rfc.Invoke(this.Prd); 65 IRfcTable iTable = rfc.GetTable(tablename); 66 if (iTable.Count > 0) 67 { 68 for (int i = 0; i < iTable.RowCount; i++) 69 { 70 iTable.CurrentIndex = i; 71 DataRow oNewRow = dt.NewRow(); 72 foreach (string cname in columnnames) 73 { 74 oNewRow[cname] = iTable.GetString(cname).ToString(); 75 } 76 dt.Rows.Add(oNewRow); 77 } 78 } 79 } 80 } 81 82 return dt; 83 } 84 #endregion 85 }