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";
                }
                );
    }

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐