RFC servers
The RfcServer
object allows you to add RFC Server functionality to your program. RFC Servers are called from the SAP system and can process and return data.
Introduction to RFC servers
In some situations, the flow of events does not originate from the client application, but from the SAP system itself. For example, the SAP system may send IDOCs to notify another application about data changes, or a SAP transaction may delegate calculations or acquire additional data to/from a third party system. When for these kind of communications RFC is used, the application in question needs to implement a RFC server.
In SAP, possible destinations for remote function calls are called „RFC destinations“. The list of available RFC destinations can be administered with transaction SM59. For each RFC destination in SM59
(for Rfc Connector, only the „TCP/IP connections“ subtree is relevant), a Program ID and an activation type is maintained. For RFC servers created with Rfc Connector, the activation type is always „Registered Server Program“
When the RFC server is started, it registers with the SAP system and the Program ID, which must match the one defined in SM59
. Through this registration, the SAP system knows the address of the listener(s) and is now able to dispatch RFC calls to them. You can check available listeners for a specific RFC destination with the „Connection Test“ button in SM59
, and you can get a list of all listeners currently registered with transaction SMGW
(use „Go To“->“Logged In Clients“)
Implementing an RFC server
To implement an RFC server which can receive function calls from SAP, the following steps are necessary:
- Create a server object and set the necessary parameters:
GatewayHost
,GatewayService
,ProgramID
- Create or import one or more
FunctionCall
prototypes and install them using theInstallFunction
method - Subscribe to the
Logon
event to allow or forbid incoming calls - Subscribe to the
IncomingCall
event - Run the server and wait for incoming calls
1. Create a server and set the necessary parameters
Create an instance of RfcServer and set the necessary parameters: ProgramID
determines the program id under which to register (as configured in SM59
), GatewayHost
is the host name (or IP) of the SAP system to register with, and GatewayService
determines the system number (port) of this SAP system:
Note: The parameter GatewayService
is given in form of a string starting with „sapgw“ followed by the 2-digit system number. For example, SYSNR=00
in a connection string corresponds to sapgw00
, SYSNR=01
corresponds to sapgw01
, and so on.
Dim WithEvents srv As RfcServer 'WithEvents is important here srv = New RfcServer srv.ProgramID = "ZRFCCTEST" srv.GatewayHost = "mysaphost" srv.GatewayService = "sapgw01"
2. Create a function call and install it to the server
To be able to decode the incoming parameters, Rfc Connector needs to know the signature/prototype of the RFC function(s) which are going to be called. In this case, we just import it from the server, but it would also be possible to load it from serialized XML or build it manually:
' import function definitions Dim Session as New RfcSession Dim prototype as FunctionCall, fn2 As FunctionCall Session.RfcSystemData.ConnectString = "SAPLOGON_ID=N4S" Session.LogonData.Client = "001" Session.LogonData.User = "user" Session.LogonData.Password = "password" Session.Connect() If Session.Error Then Console.WriteLine("Error: " + Session.ErrorInfo.Message) End If prototype = Session.ImportCall("BAPI_FLIGHT_GETLIST") Session.Disconnect() ' now register them with server srv.InstallFunction(prototype)
3. Subscribe to the Logon event
Now we add a handler for the Logon
event, which is used to determine whether a request is allowed or not. For this example, we just check the username:
Private Sub srv_Logon(ByVal li As RFCCONNECTORLib.RfcServerLogonInfo) Handles srv.Logon If li.User = "DEVELOPER" Then li.RequestAllowed = True Else li.RequestAllowed = False End If End Sub
4. Subscribe to the IncomingCall event
In the handler for the IncomingCall event, the actual request processing is done. To keep this example simple, we reply with some static data only (real-world examples would be, of course, much more complex):
If parameters are marked „optional“ in the function module definition, they may not be set by the caller. Therefore, for optional parameters use the HasKey
-function to check whether they are set or not before accessing them. Otherwise, you would get an exception.
Private Sub srv_IncomingCall(ByVal fn As RFCCONNECTORLib.FunctionCall) Handles srv.IncomingCall Select Case fn.Function Case "BAPI_FLIGHT_GETLIST" Dim airline As String, dest_from As String, dest_to As String If fn.Importing.HasKey("AIRLINE") Then airline = fn.Importing.HasKey("AIRLINE") Else airline = "LH" End If If fn.Importing.HasKey("DEST_FROM") Then dest_from = fn.Importing.HasKey("DEST_FROM") Else dest_from = "SFO" End If If fn.Importing.HasKey("DEST_TO") Then dest_from = fn.Importing.HasKey("DEST_TO") Else dest_from = "JFK" End If ' add some static rows Dim r As RfcFields, dt As DateTime dt = DateTime.Today For i = 1 To 10 r = fn.Tables("FLIGHT_LIST").Rows.AddRow() r("AIRLINEID").value = airline r("AIRPORTFR").value = dest_from r("AIRPORTTO").value = dest_to r("CONNECTID").value = i r("FLIGHTDATE").value = dt.AddDays(i) Next Case Else ' we don't know about this function, so we raise an exception fn.RaiseException("SYSTEM_ERROR") End Select End Sub
5. Run the server and wait for incoming calls
Now that we have implemented our handlers, it is time to start the server and wait for incoming calls (this is done in the main method). Note that the server always runs in another thread, so Run()
will always return immediately after registering with the SAP system. In this example, we will run the server until the user presses a key:
If srv.Error Then Console.WriteLine("Error: Could not start server.") Console.WriteLine(srv.ErrorInfo.Message) Exit Sub End If Console.WriteLine("Server running. Press key to stop...") Console.ReadLine() srv.Shutdown() Console.WriteLine("Server exited. Press key to leave...") Console.ReadLine()
Handling errors while the server is running
It may happen that the server encounters an error (for example, a temporary network problem, or the SAP host being restarted) while listening for requests.
To handle these cases, applications should subscribe to the ServerError
event, which offers also an option to just restart the server (which is recommended for servers which are designed to run unattended for a longer time):
Private Sub srv_ServerError(ByVal ei As RFCCONNECTORLib.RfcServerErrorInfo) Handles srv.ServerError ' log the error to console Console.WriteLine(ei.Message) ' restart the server ei.Restart = True End Sub