This library provides an alternative SAP .NET Connector based on the SAP NetWeaver RFC Library.
Prepare connection
In order to call remote enabled ABAP function module (ABAP RFM), first a connection must be opened. The connection settings have to be build from a string/string dictionary, for example from a ConfigurationBuilder.
var configurationBuilder =
new ConfigurationBuilder();
configurationBuilder.AddUserSecrets<Program>();
var config = configurationBuilder.Build();
var settings = new Dictionary<string, string>
{
{"ashost", config["saprfc:ashost"]},
{"sysnr", config["saprfc:sysnr"]},
{"client", config["saprfc:client"]},
{"user", config["saprfc:username"]},
{"passwd", config["saprfc:password"]},
{"lang", "EN"}
};
Calling ABAP Function Modules
We provide a extension method on the RFCContext that supports a syntax similar to the ABAP call function command, except that it is using function callbacks to pass or retrieve data:
- IMPORTING parameters are passed in the Input function
- EXPORTING parameters are retured in the Output function
- CHANGING and TABLES parameters can be used in both functions
-
using (var context = new RfcContext(connFunc)) { await context.CallFunction("DDIF_FIELDLABEL_GET", Input: f => f .SetField("TABNAME", "USR01") .SetField("FIELDNAME", "BNAME"), Output: f => f .GetField<string>("LABEL")) // this is from language.ext to extract the value from a either .Match(r => Console.WriteLine($"Result: {r}"), // should return: User Name l => Console.WriteLine($"Error: {l.Message}")); }Structures
- Structures can be set or retrieved the same way. Another example extracting company code details (you may have to change the company code if you try this example):
-
using (var context = new RfcContext(connFunc)) { await context.CallFunction("BAPI_COMPANYCODE_GETDETAIL", Input: f => f .SetField("COMPANYCODEID", "1000"), Output: f => f .MapStructure("COMPANYCODE_DETAIL", s=> s .GetField<string>("COMP_NAME")) ) .Match(r => Console.WriteLine($"Result: {r}"), l => Console.WriteLine($"Error: {l.Message}")); }Alternatively, you can also use a LINQ syntax:
-
using (var context = new RfcContext(connFunc)) { await context.CallFunction("BAPI_COMPANYCODE_GETDETAIL", Input: f => f .SetField("COMPANYCODEID", "1000"), Output: f => f .MapStructure("COMPANYCODE_DETAIL", s => from name in s.GetField<string>("COMP_NAME") select name )) .Match(r => Console.WriteLine($"Result: {r}"), l => Console.WriteLine($"Error: {l.Message}")); } -
Tables
Getting table results is possible by iterating over the table rows to retrieve the table structures. Here an example to extract all company code name and descriptions:
-
using (var context = new RfcContext(connFunc)) { await context.CallFunction("BAPI_COMPANYCODE_GETLIST", Output: f => f .MapTable("COMPANYCODE_LIST", s => from code in s.GetField<string>("COMP_CODE") from name in s.GetField<string>("COMP_NAME") select (code, name))) .Match( r => { foreach (var (code, name) in r) { Console.WriteLine($"{code}\t{name}"); } }, l => Console.WriteLine($"Error: {l.Message}")); } -
Input mapping
For Input (importing / changing ) arguments you can pass the value with the methods SetField, SetStructure and SetTable or a combination of all. For example to set values for a table you pass a IEnumerable to be processed to the SetTable method and provide a mapping function for each record in the IEnumerable:
-
var userNamesSearch = new string[] {"A*", "B*", "C*"}; var userList = await context.CallFunction("BAPI_USER_GETLIST", Input:f => f.SetTable("SELECTION_RANGE", userNamesSearch , (structure,userName) => structure .SetField("PARAMETER", "USERNAME") .SetField("SIGN", "I") .SetField("OPTION", "CP") .SetField("LOW", userName) ), Output: f=> f.MapTable("USERLIST", s=>s.GetField<string>("USERNAME")) ).IfLeftAsync(l=>throw new Exception(l.Message)); foreach (var userName in userList) { Console.WriteLine(userName); }运用案例:
-
1. 出参中既有单个元素,又有结构:
-
using (var context = GetRfcContext()) { await context.CallFunction("ZHR_PLM_GET_MAT_CODE_FERT", Input: f => f .SetField("I_MATTYPE", I_MATTYPE) .SetField("I_STARTWITH", I_STARTWITH), Output: f => { var returnmatnr = f.GetField<string>("EX_MATNR"); matcode_fert_bysap.returnmatnr = ((RightCase<RfcErrorInfo, string>)returnmatnr.Case).Value; return f.MapStructure("EX_RETURN", s => from typ in s.GetField<string>("TYPE") from msg in s.GetField<string>("MESSAGE") select new { typ = typ, msg = msg } ); }) .Match( r => { matcode_fert_bysap.flg = r.typ; matcode_fert_bysap.msg = r.msg; } , l => { matcode_fert_bysap.returnmatnr = ""; } ); }2. 出参中既有结构类型变量,又有表类型变量
-
using (var context = GetRfcContext()) { await context.CallFunction("ZHR_PLM_GET_MAT_CODE_ROH", Input: f => f .SetField("I_BIGTYPECODE", i_bigtypecode) .SetField("I_SMALLTYPECODE", i_smalltypecode) .SetField("I_LIUSHUI_NO", i_liushui_no), Output: f => { var strut = f.MapStructure("EX_RETURN", s => from typ in s.GetField<string>("TYPE") from msg in s.GetField<string>("MESSAGE") select new SAP_OUT_RESULT { type = typ, message = msg } ); var val = ((RightCase<RfcErrorInfo, SAP_OUT_RESULT>)strut.Case).Value; param.flg = ((dynamic)val).type; param.msg = ((dynamic)val).message; return f.MapTable("IT_ZMAKT", s => from matnr in s.GetField<string>("MATNR") select matnr ); }) .Match( r => { foreach (var matnr in r) { sap_matnr_lst.Add(new sap_matnr() { matnr = matnr, from = "TP" }); } } , l => { param.flg = "E"; } ); }
更多推荐

所有评论(0)