SapNwRfc .NET Library

repository·develop·Indexed 41 days ago

https://github.com/huysentruitw/sapnwrfc

A cross-platform .NET library supporting .NET 5+, .NET Core, and .NET Framework for calling SAP NetWeaver RFC functions on Windows, Linux, and macOS. It provides a wrapper for the SAP NetWeaver RFC Library 7.50 SDK C++ binaries, featuring support for complex data models, connection pooling for ASP.NET Core, and the ability to implement an RFC server to receive calls from SAP.

Tokens
3.5K
Snippets
5
Records
11
Agent score
2%

What's inside SapNwRfc

  1. Use connection pooling for concurrent applications

    develop

    For complex or concurrent applications, use SapPooledConnection and SapConnectionPool from the Pooling namespace instead of single connections. This provides connection pooling and automatic retry on disconnect.

    Configuration options are available in the SapConnectionPool class.

  2. Define complex data models (Nested and Tables)

    develop

    When mapping SAP structures, you can use standard C# types to represent nested structures and tables.

    Nested Structures

    Use a property of a specific class type to represent a nested SAP structure.

    class SomeFunctionResult
    {
        [SapName("RES_ABC")]
        public string Abc { get; set; }
    
        [SapName("RES_ADDR")]
        public SomeFunctionResultAddress Address { get; set; }
    }
    
    class SomeFunctionResultAddress
    {
        [SapName("STREET")]
        public string Street { get; set; }
    }

    Tables and Collections

    Use arrays (T[]) or IEnumerable<T> to represent SAP tables.

    class SomeFunctionResult
    {
        [SapName("RES_ITEMS")]
        public IEnumerable<SomeFunctionResultItem> Items { get; set; }
    }
    
    class SomeFunctionResultItem
    {
        [SapName("ITM_NAME")]
        public string Name { get; set; }
    }

    Excluding properties

    Use the [SapIgnore] attribute to prevent a property from being mapped to SAP.

    class SomeFunctionParameters
    {
        [SapIgnore]
        public string IgnoredProperty { get; set; }
    
        [SapName("SOME_FIELD")]
        public string SomeField { get; set; }
    }
  3. Prerequisites for SapNwRfc

    develop

    This library is a wrapper and requires the SAP NetWeaver RFC Library 7.50 SDK C++ binaries to be installed on your system. Refer to SAP Note 2573790 for download instructions.

    Binary Location

    You must ensure the binaries are discoverable by the application:

    • Windows: Add the folder to the system PATH or place DLLs in the project output folder. Note: Windows users also need the 64-bit Visual C++ 2013 Redistributable.
    • Linux: Add the folder to the LD_LIBRARY_PATH environment variable.
    • macOS: Add the folder to the DYLD_LIBRARY_PATH environment variable.

    macOS Workaround for DYLD_LIBRARY_PATH

    If running via Visual Studio for Mac, DYLD_LIBRARY_PATH might not be forwarded. You can solve this by:

    1. Placing SAP binaries in the application's working directory.
    2. Using NativeLibrary.SetDllImportResolver to manually resolve the sapnwrfc library.
    NativeLibrary.SetDllImportResolver(
        assembly: typeof(SapLibrary).Assembly,
        resolver: (string libraryName, Assembly assembly, DllImportSearchPath? searchPath) =>
        {
            if (libraryName == "sapnwrfc")
            {
                NativeLibrary.TryLoad(
                    libraryPath: Path.Combine("<your_sap_rfc_binaries_path>", libraryName),
                    handle: out IntPtr handle);
    
                return handle;
            }
    
            return IntPtr.Zero;
        });
  4. Implement an RFC Server

    develop

    The library allows you to host an RFC server to receive calls from SAP. You can use a generic handler or a full SapServer instance.

    Using SapServer

    Create a server by providing a connection string (containing GatewayHost, GatewayService, and ProgramId) and a callback function to handle incoming requests.

    string connectionString = "GatewayHost=MY_GW_HOST; GatewayService=MY_GW_SERV; ProgramId=MY_PROGRAM_ID; RegistrationCount=1";
    
    using var server = SapServer.Create(connectionString, (ISapServerConnection connection, ISapServerFunction function) =>
    {
        var attributes = connection.GetAttributes();
    
        switch (function.GetName())
        {
            case "BAPI_SOME_FUNCTION_NAME":
                var parameters = function.GetParameters<SomeFunctionParameters>();
                function.SetResult(new SomeFunctionResult { Abc = "Some Value" });
            break;
        }
    });
    
    server.Error += (object sender, SapServerErrorEventArgs args) => Console.WriteLine(args.Error.Message);
    server.StateChange += (object sender, SapServerStateChangeEventArgs args) => Console.WriteLine(args.OldState + " -> " + args.NewState);
    server.Launch();
  5. Configure connection pooling in ASP.NET Core

    develop

    To integrate connection pooling into an ASP.NET Core application, register the pool as a singleton and the pooled connection as a scoped service in your Startup.cs (or Program.cs) ConfigureServices method.

    Registering services

    services.AddSingleton<ISapConnectionPool>(_ => new SapConnectionPool(connectionString));
    services.AddScoped<ISapPooledConnection, SapPooledConnection>();

    Resolving a connection in a Controller or Service

    Inject ISapPooledConnection into your constructor to invoke SAP functions.

    [ApiController]
    public class UserController : ControllerBase
    {
        private readonly ISapPooledConnection _connection;
    
        public UserController(ISapPooledConnection connection)
        {
            _connection = connection;
        }
    
        [HttpPost]
        public IActionResult DoSomething(string action)
        {
            _connection.InvokeFunction("BAPI_SOME_FUNCTION_NAME");
            return Ok();
        }
    }
    // Registration
    services.AddSingleton<ISapConnectionPool>(_ => new SapConnectionPool(connectionString));
    services.AddScoped<ISapPooledConnection, SapPooledConnection>();
    
    // Usage
    [ApiController]
    public class UserController : ControllerBase
    {
        private readonly ISapPooledConnection _connection;
    
        public UserController(ISapPooledConnection connection)
        {
            _connection = connection;
        }
    
        [HttpPost]
        public IActionResult DoSomething(string action)
        {
            _connection.InvokeFunction("BAPI_SOME_FUNCTION_NAME");
            return Ok();
        }
    }
  6. Connect to SAP NetWeaver

    develop

    Use SapConnection with a connection string to establish a connection to an SAP system. The connection string uses a semicolon-separated format of key-value pairs.

    string connectionString = "AppServerHost=MY_SERVER_HOST; SystemNumber=00; User=MY_SAP_USER; Password=SECRET; Client=100; Language=EN; PoolSize=5; Trace=8";
    
    using var connection = new SapConnection(connectionString);
    connection.Connect();
  7. Inspect Type and Function Metadata

    develop

    You can programmatically inspect the structure of SAP types and functions using the connection object.

    Type Metadata

    Retrieve details about a specific SAP structure.

    var typeMetadata = connection.GetTypeMetadata("MY_STRUCTURE");
    var fieldCount = typeMetadata.Fields.Count;
    foreach (var fieldMetadata in typeMetadata.Fields)
    {
        var fieldName = fieldMetadata.Name;
        var fieldType = fieldMetadata.Type;
    }

    Function Metadata

    Retrieve details about an RFC function's parameters.

    var functionMetadata = connection.GetFunctionMetadata("BAPI_SOME_FUNCTION_NAME");
    var parameterCount = functionMetadata.Parameters.Count;
    foreach (var parameterMetadata in functionMetadata.Parameters)
    {
        var parameterName = parameterMetadata.Name;
        var parameterType = parameterMetadata.Type;
    }
  8. Call SAP RFC functions

    develop

    You can call RFC functions using several patterns depending on the function's signature:

    1. No parameters

    using var someFunction = connection.CreateFunction("BAPI_SOME_FUNCTION_NAME");
    someFunction.Invoke();

    2. Input parameters only

    Use a class decorated with [SapName] to map C# properties to SAP field names.

    class SomeFunctionParameters
    {
        [SapName("SOME_FIELD")]
        public string SomeField { get; set; }
    }
    
    using var someFunction = connection.CreateFunction("BAPI_SOME_FUNCTION_NAME");
    someFunction.Invoke(new SomeFunctionParameters
    {
        SomeField = "Some value",
    });

    3. Input and Output parameters

    Pass a generic type to Invoke<T> to capture the output parameters into a result object.

    class SomeFunctionResult
    {
        [SapName("RES_ABC")]
        public string Abc { get; set; }
    }
    
    using var someFunction = connection.CreateFunction("BAPI_SOME_FUNCTION_NAME");
    var result = someFunction.Invoke<SomeFunctionResult>(new SomeFunctionParameters
    {
        SomeField = "Some value",
    });

    4. Dynamic parameters

    For quick prototyping or when the schema is unknown, use dynamic.

    using var someFunction = connection.CreateFunction("BAPI_SOME_FUNCTION_NAME");
    var result = someFunction.Invoke<dynamic>(new
    {
        SOME_FIELD = "Some value",
    });
    
    string abc = result.RES_ABC;
  9. Map C# types to SAP RFC parameter types

    develop

    The library maps C# model properties to SAP RFC parameter types by convention. If a property name in your C# model does not match the SAP RFC parameter name, use the [SapName] attribute to specify the correct SAP name.

    Supported Type Mappings

    C# typeSAP RFC typeRemarks
    intRFCTYPE_INT4-byte integer
    longRFCTYPE_INT88-byte integer
    doubleRFCTYPE_FLOATFloating point, double precision
    decimalRFCTYPE_BCD
    stringRFCTYPE_STRING / RFCTYPE_CHAR / ...Gets a data field as string
    byte[]RFCTYPE_BYTERaw binary data, fixed length. Requires [SapBufferLength] attribute
    char[]RFCTYPE_CHARChar data, fixed length. Requires [SapBufferLength] attribute
    DateTime?RFCTYPE_DATEUses only day, month, and year
    TimeSpan?RFCTYPE_TIMEUses only hour, minute, and second
    TRFCTYPE_STRUCTUREConstructed from nested objects in the model
    Array<T>RFCTYPE_TABLEConstructed from arrays of nested objects
    IEnumerable<T>RFCTYPE_TABLETables returned as IEnumerable<T> for memory-efficient processing of large datasets
  10. Reference: Connection String Parameters

    develop

    The following parameters are supported in the connection string for SapConnection and SapConnectionPool.

    | Field | SAP Field |
    |:---|:---|
    | AppServerHost | ASHOST |
    | SncLibraryPath | SNC_LIB |
    | SncQop | SNC_QOP |
    | Trace | TRACE |
    | SapRouter | SAPROUTER |
    | NoCompression | NO_COMPRESSION |
    | OnCharacterConversionError | ON_CCE |
    | CharacterFaultIndicatorToken | CFIT |
    | MaxPoolSize | MAX_POOL_SIZE |
    | PoolSize | POOL_SIZE |
    | SncPartnerNames | SNC_PARTNER_NAMES |
    | IdleTimeout | IDLE_TIMEOUT |
    | MaxPoolWaitTime | MAX_POOL_WAIT_TIME |
    | RegistrationCount | REG_COUNT |
    | PasswordChangeEnforced | PASSWORD_CHANGE_ENFORCED |
    | Name | NAME |
    | RepositoryDestination | REPOSITORY_DESTINATION |
    | RepositoryUser | REPOSITORY_USER |
    | RepositoryPassword | REPOSITORY_PASSWD |
    | RepositorySncMyName | REPOSITORY_SNC_MYNAME |
    | RepositoryX509Certificate | REPOSITORY_X509CERT |
    | IdleCheckTime | IDLE_CHECK_TIME |
    | SncMyName | SNC_MYNAME |
    | SncPartnerName | SNC_PARTNERNAME |
    | ProgramId | PROGRAM_ID |
    | AppServerService | ASSERV |
    | MessageServerHost | MSHOST |
    | MessageServerService | MSSERV |
    | R3Name | R3NAME |
    | LogonGroup | GROUP |
    | GatewayHost | GWHOST |
    | GatewayService | GWSERV |
    | SystemNumber | SYSNR |
    | User | USER |
    | AliasUser | ALIAS_USER |
    | SncMode | SNC_MODE |
    | Client | CLIENT |
    | Password | PASSWD |
    | Codepage | CODEPAGE |
    | PartnerCharSize | PCS |
    | SystemId | SYSID |
    | SystemIds | SYS_IDS |
    | X509Certificate | X509CERT |
    | SapSso2Ticket | MYSAPSSO2 |
    | UseSapGui | USE_SAPGUI |
    | AbapDebug | ABAB_DEBUG |
    | LogonCheck | LCHECK |
    | Language | LANG |