### Install SapNwRfc Package Source: https://github.com/huysentruitw/sapnwrfc/blob/develop/README.md Commands to add the library dependency to a .NET project. ```bash dotnet add package SapNwRfc ``` ```powershell PM> Install-Package SapNwRfc ``` -------------------------------- ### Example Connection String Source: https://github.com/huysentruitw/sapnwrfc/blob/develop/README.md A typical connection string format for establishing a connection to an SAP system. Ensure all required parameters like host, system number, user, and client are provided. ```csharp string connectionString = "AppServerHost=MY_SERVER_HOST; SystemNumber=00; User=MY_SAP_USER; Password=SECRET; Client=100; Language=EN; PoolSize=5; Trace=3"; ``` -------------------------------- ### Verify SAP SDK Installation Source: https://context7.com/huysentruitw/sapnwrfc/llms.txt Use SapLibrary.EnsureLibraryPresent to validate the presence of the SAP NetWeaver RFC SDK binaries before initiating connections. ```csharp using SapNwRfc; using SapNwRfc.Exceptions; try { // Throws SapLibraryNotFoundException if SDK not found SapLibrary.EnsureLibraryPresent(); // Get SDK version information SapLibraryVersion version = SapLibrary.GetVersion(); Console.WriteLine($"SAP RFC SDK Version: {version.Major}.{version.Minor}.{version.Patch}"); } catch (SapLibraryNotFoundException ex) { Console.WriteLine("SAP NetWeaver RFC SDK not found!"); Console.WriteLine("Please install the SAP NetWeaver RFC Library 7.50 SDK."); Console.WriteLine($"Details: {ex.Message}"); } ``` -------------------------------- ### RFC Server Generic Handler Source: https://github.com/huysentruitw/sapnwrfc/blob/develop/README.md Install a generic handler to dynamically retrieve function metadata for incoming requests. ```csharp string connectionString = "AppServerHost=MY_SERVER_HOST; SystemNumber=00; User=MY_SAP_USER; Password=SECRET; Client=100; Language=EN; PoolSize=5; Trace=8"; SapServer.InstallGenericServerFunctionHandler((string functionName, SapAttributes attributes) => { using var connection = new SapConnection(connectionString); connection.Connect(); return connection.GetFunctionMetadata(functionName); }); ``` -------------------------------- ### Create and Use SapConnectionPool Source: https://context7.com/huysentruitw/sapnwrfc/llms.txt Demonstrates creating a connection pool with specified parameters and using a pooled connection to invoke SAP RFC functions. The pool manages connection lifecycle and retries, while the pooled connection handles acquisition and release. ```csharp using SapNwRfc; using SapNwRfc.Pooling; // Create a connection pool (typically as singleton) var pool = new SapConnectionPool( connectionString: "AppServerHost=sap.example.com; SystemNumber=00; User=RFC_USER; Password=secret; Client=100; Language=EN", poolSize: 10, // Maximum concurrent connections connectionIdleTimeout: TimeSpan.FromSeconds(60), // Close idle connections after 60s idleDetectionInterval: TimeSpan.FromSeconds(5) // Check for idle connections every 5s ); // Use pooled connection (request-scoped) using (var connection = new SapPooledConnection(pool)) { // Call functions - connection automatically acquired from pool connection.InvokeFunction("BAPI_TRANSACTION_COMMIT"); // With input parameters connection.InvokeFunction("BAPI_USER_LOCK", new { USERNAME = "TESTUSER" }); // With output var result = connection.InvokeFunction( "BAPI_USER_GET_DETAIL", new { USERNAME = "TESTUSER" } ); Console.WriteLine($"User: {result.Address.FirstName}"); } // Connection automatically returned to pool on dispose // Dispose pool when application shuts down pool.Dispose(); ``` -------------------------------- ### RFC Server Source: https://github.com/huysentruitw/sapnwrfc/blob/develop/README.md Create and launch an RFC server to handle specific function calls, with event listeners for errors and state changes. ```csharp 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(); 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(); ``` -------------------------------- ### Ensure the SAP RFC SDK binaries are present Source: https://github.com/huysentruitw/sapnwrfc/blob/develop/README.md Verify the presence of SAP RFC SDK binaries, throwing an exception if they are missing. ```csharp SapLibrary.EnsureLibraryPresent(); ``` -------------------------------- ### Create and Configure an RFC Server Source: https://context7.com/huysentruitw/sapnwrfc/llms.txt Registers an RFC destination and handles incoming function calls using a generic handler and specific function logic. ```csharp using SapNwRfc; // Connection string for RFC server registration string serverConnectionString = "GatewayHost=sapgw.example.com; GatewayService=sapgw00; ProgramId=MY_DOTNET_SERVER; RegistrationCount=5"; // Client connection string (for metadata retrieval) string clientConnectionString = "AppServerHost=sap.example.com; SystemNumber=00; User=RFC_USER; Password=secret; Client=100; Language=EN"; // Install generic function handler for metadata SapServer.InstallGenericServerFunctionHandler((functionName, attributes) => { using var connection = new SapConnection(clientConnectionString); connection.Connect(); return connection.GetFunctionMetadata(functionName); }); // Create and start server using var server = SapServer.Create(serverConnectionString, (connection, function) => { var clientAttributes = connection.GetAttributes(); Console.WriteLine($"Call from: {clientAttributes.User}@{clientAttributes.Host}"); switch (function.GetName()) { case "Z_GET_CUSTOMER_DATA": var input = function.GetParameters(); // Process request and set result var customerData = GetCustomerFromDatabase(input.CustomerId); function.SetResult(new CustomerOutput { Name = customerData.Name, Address = customerData.Address, Status = "S", Message = "Success" }); break; case "Z_CREATE_ORDER": var orderInput = function.GetParameters(); var orderId = CreateOrderInDatabase(orderInput); function.SetResult(new OrderOutput { OrderId = orderId }); break; default: throw new NotSupportedException($"Function {function.GetName()} not supported"); } }); // Subscribe to server events server.Error += (sender, args) => { Console.WriteLine($"Server error: {args.Error.Message}"); if (args.ClientInfo != null) { Console.WriteLine($"Client: {args.ClientInfo.User}@{args.ClientInfo.Host}"); } }; server.StateChange += (sender, args) => { Console.WriteLine($"State changed: {args.OldState} -> {args.NewState}"); }; // Start listening for RFC calls server.Launch(); Console.WriteLine("RFC Server started. Press Enter to stop..."); Console.ReadLine(); // Graceful shutdown server.Shutdown(timeout: 30); ``` -------------------------------- ### Connect to SAP NetWeaver Source: https://github.com/huysentruitw/sapnwrfc/blob/develop/README.md Establishes a connection to an SAP server using a connection string. ```csharp 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(); ``` -------------------------------- ### Establish SAP Connection with SapConnection Source: https://context7.com/huysentruitw/sapnwrfc/llms.txt Connect to an SAP application server using a connection string and retrieve system attributes. ```csharp using SapNwRfc; // Using connection string string connectionString = "AppServerHost=sap.example.com; SystemNumber=00; User=RFC_USER; Password=secret123; Client=100; Language=EN"; using var connection = new SapConnection(connectionString); connection.Connect(); // Check connection validity bool isValid = connection.IsValid; // Returns true if handle is valid bool isAlive = connection.Ping(); // Actually pings the SAP server // Get connection attributes SapAttributes attributes = connection.GetAttributes(); Console.WriteLine($"Connected to: {attributes.Host}"); Console.WriteLine($"System ID: {attributes.SystemId}"); Console.WriteLine($"Client: {attributes.Client}"); Console.WriteLine($"User: {attributes.User}"); Console.WriteLine($"Language: {attributes.Language}"); // Disconnect explicitly (also happens on Dispose) connection.Disconnect(); ``` -------------------------------- ### Define Nested SAP Models Source: https://github.com/huysentruitw/sapnwrfc/blob/develop/README.md Demonstrates how to structure classes for nested SAP data structures. ```csharp class SomeFunctionResult { [SapName("RES_ABC")] public string Abc { get; set; } [SapName("RES_ADDR")] public SomeFunctionResultItem Address { get; set; } } class SomeFunctionResultAddress { [SapName("STREET")] public string Street { get; set; } [SapName("NR")] public string Number { get; set; } } ``` -------------------------------- ### Controller Usage of ISapPooledConnection Source: https://context7.com/huysentruitw/sapnwrfc/llms.txt Illustrates how to inject and use ISapPooledConnection within an ASP.NET Core controller to interact with SAP RFCs. Demonstrates fetching user details and locking a user. ```csharp // Controller usage [ApiController] [Route("api/[controller]")] public class UsersController : ControllerBase { private readonly ISapPooledConnection _sapConnection; public UsersController(ISapPooledConnection sapConnection) { _sapConnection = sapConnection; } [HttpGet("{username}")] public IActionResult GetUser(string username, CancellationToken cancellationToken) { var result = _sapConnection.InvokeFunction( "BAPI_USER_GET_DETAIL", new { USERNAME = username }, cancellationToken ); return Ok(new { FirstName = result.Address.FirstName, LastName = result.Address.LastName, Email = result.Address.Email }); } [HttpPost("{username}/lock")] public IActionResult LockUser(string username) { _sapConnection.InvokeFunction("BAPI_USER_LOCK", new { USERNAME = username }); _sapConnection.InvokeFunction("BAPI_TRANSACTION_COMMIT"); return NoContent(); } } ``` -------------------------------- ### Configure DllImportResolver for SAP Binaries Source: https://github.com/huysentruitw/sapnwrfc/blob/develop/README.md Use this to manually resolve the SAP RFC library path if environment variables are not propagated to child processes. ```csharp NativeLibrary.SetDllImportResolver( assembly: typeof(SapLibrary).Assembly, resolver: (string libraryName, Assembly assembly, DllImportSearchPath? searchPath) => { if (libraryName == "sapnwrfc") { NativeLibrary.TryLoad( libraryPath: Path.Combine("", libraryName), handle: out IntPtr handle); return handle; } return IntPtr.Zero; }); ``` -------------------------------- ### Invoke RFC with Dynamic Parameters Source: https://context7.com/huysentruitw/sapnwrfc/llms.txt Use anonymous types for input and 'dynamic' for output when strong typing is not required, suitable for quick prototyping. ```csharp using SapNwRfc; using var connection = new SapConnection(connectionString); connection.Connect(); // Using anonymous type for input, dynamic for output using var function = connection.CreateFunction("BAPI_COMPANY_GETLIST"); dynamic result = function.Invoke(new { MAXROWS = 100 }); // Access result properties dynamically foreach (var company in result.COMPANYLIST) { Console.WriteLine($"Company: {company.COMPANY} - {company.NAME1}"); } ``` -------------------------------- ### ASP.NET Core DI Registration for SapNwrfc Source: https://context7.com/huysentruitw/sapnwrfc/llms.txt Shows how to register SapConnectionPool as a singleton and SapPooledConnection as scoped in ASP.NET Core's dependency injection container. This enables automatic injection into controllers and services. ```csharp // Startup.cs or Program.cs using SapNwRfc; using SapNwRfc.Pooling; public class Startup { public void ConfigureServices(IServiceCollection services) { // Register pool as singleton services.AddSingleton(_ => new SapConnectionPool( Configuration.GetConnectionString("SAP"), poolSize: 10, connectionIdleTimeout: TimeSpan.FromMinutes(2) )); // Register pooled connection as scoped (per-request) services.AddScoped(); services.AddControllers(); } } ``` -------------------------------- ### Invoke SAP Function with Input and Output Parameters Source: https://github.com/huysentruitw/sapnwrfc/blob/develop/README.md Executes an SAP function and maps the result to a typed class. ```csharp class SomeFunctionParameters { [SapName("SOME_FIELD")] public string SomeField { get; set; } } class SomeFunctionResult { [SapName("RES_ABC")] public string Abc { get; set; } } using var someFunction = connection.CreateFunction("BAPI_SOME_FUNCTION_NAME"); var result = someFunction.Invoke(new SomeFunctionParameters { SomeField = "Some value", }); // Do something with result.Abc ``` -------------------------------- ### Work with SAP Tables and Arrays Source: https://context7.com/huysentruitw/sapnwrfc/llms.txt Map SAP tables to C# arrays or IEnumerable. Use IEnumerable for large datasets to improve memory management by yielding elements one-by-one. ```csharp using SapNwRfc; // Model with table (array) public class MaterialListInput { [SapName("MATNRSELECTION")] public MaterialSelection[] MaterialSelections { get; set; } } public class MaterialSelection { [SapName("SIGN")] public string Sign { get; set; } [SapName("OPTION")] public string Option { get; set; } [SapName("MATNR_LOW")] public string MaterialNumberLow { get; set; } [SapName("MATNR_HIGH")] public string MaterialNumberHigh { get; set; } } // Output with IEnumerable for memory-efficient large datasets public class MaterialListOutput { [SapName("MATNRLIST")] public IEnumerable Materials { get; set; } [SapName("RETURN")] public BapiReturn[] Returns { get; set; } } public class MaterialItem { [SapName("MATERIAL")] public string MaterialNumber { get; set; } [SapName("MATL_DESC")] public string Description { get; set; } } // Usage using var connection = new SapConnection(connectionString); connection.Connect(); using var function = connection.CreateFunction("BAPI_MATERIAL_GETLIST"); var result = function.Invoke(new MaterialListInput { MaterialSelections = new[] { new MaterialSelection { Sign = "I", Option = "CP", MaterialNumberLow = "MAT*" } } }); // Iterate through materials (memory-efficient with IEnumerable) foreach (var material in result.Materials) { Console.WriteLine($"{material.MaterialNumber}: {material.Description}"); } ``` -------------------------------- ### Invoke SAP Function with Input Parameters Source: https://github.com/huysentruitw/sapnwrfc/blob/develop/README.md Executes an SAP function using a typed class for input parameters. ```csharp 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", }); ``` -------------------------------- ### Custom SapConnectionParameters Class Source: https://github.com/huysentruitw/sapnwrfc/blob/develop/README.md Extend SapConnectionParameters to include custom connection parameters. Use the SapName attribute to map your custom property to the corresponding SAP parameter name. ```csharp public class MySapConnectionParameters : SapConnectionParameters { [SapName("CST_PARAM")] public string CustomParameter { get; set; } } ``` -------------------------------- ### Invoke Parameterless SAP Functions Source: https://context7.com/huysentruitw/sapnwrfc/llms.txt Execute remote functions that do not require input or output parameters using ISapFunction. ```csharp using SapNwRfc; using var connection = new SapConnection(connectionString); connection.Connect(); // Call a function with no input or output using var function = connection.CreateFunction("BAPI_TRANSACTION_COMMIT"); function.Invoke(); // Check if a parameter exists before using it bool hasWait = function.HasParameter("WAIT"); ``` -------------------------------- ### Resolve and Use Pooled Connection in Controller Source: https://github.com/huysentruitw/sapnwrfc/blob/develop/README.md Inject ISapPooledConnection into a controller to invoke RFC functions using the pooled connection. ```csharp [ApiController] public class UserController : ControllerBase { public UserController(ISapPooledConnection connection) { _connection = connection; } [HttpPost] public IActionResult DoSomething(string action) { _connection.InvokeFunction("BAPI_SOME_FUNCTION_NAME"); return Ok(); } } ``` -------------------------------- ### Comprehensive C# Type Mappings for SAP RFC Source: https://context7.com/huysentruitw/sapnwrfc/llms.txt Demonstrates mapping of various C# data types to SAP RFC types, including integers, floats, decimals, strings, byte arrays, character arrays, dates, times, nested structures, and tables. Attributes like [SapName] and [SapBufferLength] are used to configure the mapping. ```csharp using SapNwRfc; public class ComprehensiveTypeExample { // 4-byte integer -> RFCTYPE_INT [SapName("INT_FIELD")] public int IntegerValue { get; set; } // 8-byte integer -> RFCTYPE_INT8 [SapName("INT8_FIELD")] public long LongValue { get; set; } // Double precision float -> RFCTYPE_FLOAT [SapName("FLOAT_FIELD")] public double DoubleValue { get; set; } // Decimal/BCD -> RFCTYPE_BCD [SapName("BCD_FIELD")] public decimal DecimalValue { get; set; } // String -> RFCTYPE_STRING / RFCTYPE_CHAR [SapName("STRING_FIELD")] public string StringValue { get; set; } // Raw binary data -> RFCTYPE_BYTE (requires SapBufferLength) [SapName("BYTE_FIELD")] [SapBufferLength(1024)] public byte[] ByteArray { get; set; } // Char array -> RFCTYPE_CHAR (requires SapBufferLength) [SapName("CHAR_FIELD")] [SapBufferLength(50)] public char[] CharArray { get; set; } // Date (day/month/year only) -> RFCTYPE_DATE [SapName("DATE_FIELD")] public DateTime? DateValue { get; set; } // Time (hour/minute/second only) -> RFCTYPE_TIME [SapName("TIME_FIELD")] public TimeSpan? TimeValue { get; set; } // Nested structure -> RFCTYPE_STRUCTURE [SapName("STRUCTURE_FIELD")] public NestedStructure Structure { get; set; } // Table as array -> RFCTYPE_TABLE [SapName("TABLE_FIELD")] public TableItem[] TableArray { get; set; } // Table as IEnumerable (memory-efficient) -> RFCTYPE_TABLE [SapName("LARGE_TABLE")] public IEnumerable TableEnumerable { get; set; } } public class NestedStructure { [SapName("NESTED_VALUE")] public string Value { get; set; } } public class TableItem { [SapName("ITEM_ID")] public string ItemId { get; set; } [SapName("QUANTITY")] public int Quantity { get; set; } } ``` -------------------------------- ### Register SAP Connection Pool in ASP.NET Core Source: https://github.com/huysentruitw/sapnwrfc/blob/develop/README.md Register the connection pool and pooled connection services within the ConfigureServices method of Startup.cs. ```csharp services.AddSingleton(_ => new SapConnectionPool(connectionString)); services.AddScoped(); ``` -------------------------------- ### Invoke SAP Function with Dynamic Parameters Source: https://github.com/huysentruitw/sapnwrfc/blob/develop/README.md Executes an SAP function using dynamic objects for flexible input and output mapping. ```csharp using var someFunction = connection.CreateFunction("BAPI_SOME_FUNCTION_NAME"); var result = someFunction.Invoke(new { SOME_FIELD = "Some value", }); string abc = result.RES_ABC; ``` -------------------------------- ### Function Metadata Source: https://github.com/huysentruitw/sapnwrfc/blob/develop/README.md Retrieve and iterate over parameter metadata for a specific SAP function. ```csharp var functionMetadata = connection.GetFunctionMetadata("BAPI_SOME_FUNCTION_NAME"); var functionName = functionMetadata.GetName(); var parameterCount = functionMetadata.Parameters.Count; foreach (var parameterMetadata in functionMetadata.Parameters) { var parameterName = parameterMetadata.Name; var parameterType = parameterMetadata.Type; } functionMetadata.Parameters.TryGetValue("PARAMETER_NAME", out var parameterNameMetadata); ``` -------------------------------- ### Type Metadata Source: https://github.com/huysentruitw/sapnwrfc/blob/develop/README.md Retrieve and iterate over metadata fields for a specific SAP structure type. ```csharp var typeMetadata = connection.GetTypeMetadata("MY_STRUCTURE"); var typeName = typeMetadata.GetTypeName(); var fieldCount = typeMetadata.Fields.Count; foreach (var fieldMetadata in typeMetadata.Fields) { var fieldName = fieldMetadata.Name; var fieldType = fieldMetadata.Type; } typeMetadata.Fields.TryGetValue("FIELD_NAME", out var fieldNameMetadata); ``` -------------------------------- ### Specify Buffer Length with SapBufferLengthAttribute Source: https://context7.com/huysentruitw/sapnwrfc/llms.txt Use the [SapBufferLength] attribute for byte[] and char[] properties to define the fixed buffer size required by SAP RFC. This is crucial for handling raw binary data like document content or headers. ```csharp using SapNwRfc; public class DocumentInput { [SapName("DOC_ID")] public string DocumentId { get; set; } [SapName("DOC_CONTENT")] [SapBufferLength(65536)] // 64KB buffer public byte[] Content { get; set; } [SapName("DOC_HEADER")] [SapBufferLength(256)] public char[] Header { get; set; } } // Usage using var connection = new SapConnection(connectionString); connection.Connect(); byte[] fileContent = File.ReadAllBytes("document.pdf"); using var function = connection.CreateFunction("BAPI_DOCUMENT_UPLOAD"); function.Invoke(new DocumentInput { DocumentId = "DOC001", Content = fileContent, Header = "PDF Document".ToCharArray() }); ``` -------------------------------- ### Define models with an IEnumerable Source: https://github.com/huysentruitw/sapnwrfc/blob/develop/README.md Use IEnumerable for collection properties to map nested SAP table structures. ```csharp class SomeFunctionResult { [SapName("RES_ITEMS")] public IEnumerable Items { get; set; } } class SomeFunctionResultItem { [SapName("ITM_NAME")] public string Name { get; set; } } ``` -------------------------------- ### Invoke SAP Function without Parameters Source: https://github.com/huysentruitw/sapnwrfc/blob/develop/README.md Executes an SAP function that requires no input or output data. ```csharp using var someFunction = connection.CreateFunction("BAPI_SOME_FUNCTION_NAME"); someFunction.Invoke(); ``` -------------------------------- ### Retrieve SAP Function Metadata Source: https://context7.com/huysentruitw/sapnwrfc/llms.txt Fetches parameter, type, and exception details for a specific SAP function without executing it. ```csharp using SapNwRfc; using var connection = new SapConnection(connectionString); connection.Connect(); // Get function metadata ISapFunctionMetadata metadata = connection.GetFunctionMetadata("BAPI_USER_GET_DETAIL"); Console.WriteLine($"Function: {metadata.GetName()}"); Console.WriteLine($"Parameters ({metadata.Parameters.Count}):"); foreach (var param in metadata.Parameters) { Console.WriteLine($" - {param.Name}"); Console.WriteLine($" Type: {param.Type}"); Console.WriteLine($" Direction: {param.Direction}"); Console.WriteLine($" Description: {param.Description}"); } // Try to get a specific parameter if (metadata.Parameters.TryGetValue("USERNAME", out var usernameParam)) { Console.WriteLine($"USERNAME parameter found: {usernameParam.Type}"); } // Get exception metadata Console.WriteLine($"Exceptions ({metadata.Exceptions.Count}):"); foreach (var exception in metadata.Exceptions) { Console.WriteLine($" - {exception.Key}: {exception.Message}"); } ``` -------------------------------- ### Invoke Typed SAP Functions Source: https://context7.com/huysentruitw/sapnwrfc/llms.txt Map SAP RFC parameters to strongly-typed C# classes using the [SapName] attribute for automatic type conversion. ```csharp using SapNwRfc; // Define input model public class GetUserDetailsInput { [SapName("USERNAME")] public string UserName { get; set; } } // Define output model with nested structure public class GetUserDetailsOutput { [SapName("ADDRESS")] public UserAddress Address { get; set; } [SapName("LOGONDATA")] public LogonData LogonData { get; set; } [SapName("RETURN")] public BapiReturn Return { get; set; } } public class UserAddress { [SapName("FIRSTNAME")] public string FirstName { get; set; } [SapName("LASTNAME")] public string LastName { get; set; } [SapName("E_MAIL")] public string Email { get; set; } } public class LogonData { [SapName("GLTGV")] public DateTime? ValidFrom { get; set; } [SapName("GLTGB")] public DateTime? ValidTo { get; set; } } public class BapiReturn { [SapName("TYPE")] public string Type { get; set; } [SapName("MESSAGE")] public string Message { get; set; } } // Usage using var connection = new SapConnection(connectionString); connection.Connect(); using var function = connection.CreateFunction("BAPI_USER_GET_DETAIL"); var result = function.Invoke(new GetUserDetailsInput { UserName = "TESTUSER" }); Console.WriteLine($"Name: {result.Address.FirstName} {result.Address.LastName}"); Console.WriteLine($"Email: {result.Address.Email}"); Console.WriteLine($"Return: {result.Return.Type} - {result.Return.Message}"); ``` -------------------------------- ### Define models with a nested table Source: https://github.com/huysentruitw/sapnwrfc/blob/develop/README.md Use an array property decorated with SapName to map nested SAP table structures. ```csharp class SomeFunctionResult { [SapName("RES_ABC")] public string Abc { get; set; } [SapName("RES_ITEMS")] public SomeFunctionResultItem[] Items { get; set; } } class SomeFunctionResultItem { [SapName("ITM_NAME")] public string Name { get; set; } } ``` -------------------------------- ### Retrieve SAP Type Metadata Source: https://context7.com/huysentruitw/sapnwrfc/llms.txt Inspects field definitions and structure metadata for SAP data types. ```csharp using SapNwRfc; using var connection = new SapConnection(connectionString); connection.Connect(); // Get type metadata for a structure ISapTypeMetadata typeMetadata = connection.GetTypeMetadata("BAPIADDR3"); Console.WriteLine($"Type: {typeMetadata.GetName()}"); Console.WriteLine($"Fields ({typeMetadata.Fields.Count}):"); foreach (var field in typeMetadata.Fields) { Console.WriteLine($" - {field.Name}"); Console.WriteLine($" Type: {field.Type}"); Console.WriteLine($" Length: {field.NucLength}"); Console.WriteLine($" Decimals: {field.Decimals}"); } // Check for specific field if (typeMetadata.Fields.TryGetValue("FIRSTNAME", out var firstNameField)) { Console.WriteLine($"FIRSTNAME: Type={firstNameField.Type}, Length={firstNameField.NucLength}"); } ``` -------------------------------- ### Handle SAP RFC Exceptions Source: https://context7.com/huysentruitw/sapnwrfc/llms.txt Catch specific SAP exceptions to access detailed error information, including ABAP message classes and types. ```csharp using SapNwRfc; using SapNwRfc.Exceptions; try { using var connection = new SapConnection(connectionString); connection.Connect(); using var function = connection.CreateFunction("BAPI_USER_GET_DETAIL"); var result = function.Invoke(new { USERNAME = "INVALID_USER" }); } catch (SapCommunicationFailedException ex) { // Network/communication error Console.WriteLine($"Communication failed: {ex.Message}"); Console.WriteLine($"Result Code: {ex.ResultCode}"); } catch (SapException ex) { // General SAP RFC error Console.WriteLine($"SAP Error: {ex.Message}"); Console.WriteLine($"Result Code: {ex.ResultCode}"); Console.WriteLine($"Error Group: {ex.ErrorInfo.ErrorGroup}"); Console.WriteLine($"Error Key: {ex.ErrorInfo.Key}"); // ABAP message details if (!string.IsNullOrEmpty(ex.ErrorInfo.AbapMessageClass)) { Console.WriteLine($"ABAP Message Class: {ex.ErrorInfo.AbapMessageClass}"); Console.WriteLine($"ABAP Message Type: {ex.ErrorInfo.AbapMessageType}"); Console.WriteLine($"ABAP Message Number: {ex.ErrorInfo.AbapMessageNumber}"); Console.WriteLine($"ABAP Message V1: {ex.ErrorInfo.AbapMessageV1}"); Console.WriteLine($"ABAP Message V2: {ex.ErrorInfo.AbapMessageV2}"); } } catch (SapLibraryNotFoundException ex) { Console.WriteLine($"SAP SDK not installed: {ex.Message}"); } ``` -------------------------------- ### Exclude properties from mapping Source: https://github.com/huysentruitw/sapnwrfc/blob/develop/README.md Apply the SapIgnore attribute to prevent specific properties from being included in SAP mapping. ```csharp class SomeFunctionParameters { [SapIgnore] public string IgnoredProperty { get; set; } [SapName("SOME_FIELD")] public string SomeField { get; set; } } class SomeFunctionResult { [SapIgnore] public string IgnoredProperty { get; set; } [SapName("SOME_FIELD")] public string SomeField { get; set; } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.