Transaktionaler RFC 
From Theobald Software
Im folgenden Beispiel wollen wir einen RFC-Server entwerfen, der transaktionale RFCs unterstützt.
Ein ABAP-Programm soll einfach zwei Strings per Exportparameter übergeben. Diese Strings werden auf .Net-Seite zusammen gefügt und in den SQL Server eingetragen. Bei einem tRFC werden nur Exportparameter und Tabellen übergeben, da der Client (in diesem Fall das aufrufende SAP-System) bei einem transaktionalen RFC keine Ergebnisse empfangen kann.
Der folgende Code basiert auf dem bereits bekannten Beispiel RFC-Server
[C#]
static RFCServer s = new RFCServer(); static SqlConnection SQLConn = null; static void Main(string[] args) { RFCServer s = new RFCServer(); s.GatewayHost = "hamlet"; s.GatewayService = "sapgw11"; s.ProgramID = "ERPTEST"; s.IncomingCall += new ERPConnect.RFCServer.OnIncomingCall(s_IncomingCall); s.TRFCCheckTID += new RFCServer.OnTRFCCheckTID(s_TRFCCheckTID); s.TRFCCommit += new RFCServer.OnTRFCCommit(s_TRFCCommit); s.TRFCConfirm += new RFCServer.OnTRFCConfirm(s_TRFCConfirm); s.TRFCRollback += new RFCServer.OnTRFCRollback(s_TRFCRollback); // Add and register function module RFCServerFunction f = s.RegisteredFunctions.Add("Z_TRFC"); f.Imports.Add("STRING1", RFCTYPE.CHAR,10 ); f.Imports.Add("STRING2", RFCTYPE.CHAR,10 ); // start server s.Start(); Console.Write("Server started. Please press any key to stop"); Console.ReadLine(); s.Stop(); }
Es werden die Ereignise
- TRFCCheckTID
- IncomingCall
- TRFCCommit
- TRFCConfirm
- TRFCRollback
vom Client (SAP) im Server (.NET) ausgelöst.
Im ABAP Programm wird der Funktionsbaustein mit dem ABAP Befehl
CALL FUNCTION 'Z_TRFC' DESTINATION Destination IN BACKGROUND TASK
zur asynchronen Ausführung vorgemerkt.
REPORT ZTESTTRFC .
CALL FUNCTION 'Z_TRFC' in background task DESTINATION 'ERPTEST'
EXPORTING
STRING1 = 'Hello'
STRING2 = 'World'.
Commit Work.
WRITE: / 'strings sent'.
Er wird nicht sofort ausgeführt, sondern die mit EXPORTING bzw. TABLES übergebenen Daten werden in eine Datenbanktabelle gestellt. Ein COMMIT WORK löst dann die Verarbeitung des Funktionsbausteins aus, und auf der .Net Seite wird das Ereignis TRFCCheckTID ausgeführt. Die Transaktions-ID (TID) wird in dem Beispiel überprüft, ob sie schon in unserer Tabelle auf dem SQL-Server vorhanden ist und schon ausgeführt wurde. Wenn die TID nicht vorhanden ist, oder vorhanden aber bisher noch nicht ausgeführt worden ist, wird TRFCCheckTID True zurückmeldet (Check erfolgreich). Dadurch wird das IncomingCall-Ereignis ausgeführt. Bei erfolgreicher Abarbeitung erfolgt der Commit, welcher die Ausführung bestätigt und danach der Confirm, falls die Transaktion auf der Client Seite erfolgreich beendet worden ist. Confirm dient dem 'Aufräumen' der Transaktionsbearbeitung.
Bei Rückgabe des Wertes 'False' beim TRFCCheckTID-Ereignis wird die Funktion nicht ausgeführt; statt dessen findet ein Rollback statt.
Mit dem tRFC wird gewährleistet das remote gerufene Funktionsbausteine auch dann verarbeitet werden, wenn zu dem Zeitpunkt des Aufrufs der Remote Partner nicht aktiv war, oder die Verbindung unterbrochen war.
Im Gegensatz zum synchronen RFC kann man verschiedene Funktionsbausteine für die Remote-Verarbeitung zu einer logischen Einheit (SAP-LUW) zusammenfassen. Dann ist auch ein Rollback auf der kompletten Serie an Bausteinen möglich. tRFC-Aufrufe, die im Client eine SAP-LUW bilden, werden im .Net ebenfalls als LUW abgebildet. Desweiteren stehen mit der SM58 Werkzeuge für Monitoring und Verwaltung zur Verfügung, mit denen Probleme und 'hängende' Aufrufe nachverfolgt werden können.
[C#]
static void s_TRFCCheckTID(RFCServer Sender, string TID, ref bool OK) { DataTable DtTID = GetDataTableBySQL("Select * from TransactionID where TID = '" + TID + "' and XExecuted = 'False'"); if (DtTID.Rows.Count > 0) { Console.WriteLine("TransactionalID " + TID + " is already executed"); OK = false; } else { Console.WriteLine("TRFCCheckTID is OK"); InsertUpdateBySQL("Insert TransactionID (TID) Values ('" + TID + "')"); OK = true; } } static void s_IncomingCall(RFCServer Sender, RFCServerFunction CalledFunction) { if (CalledFunction.FunctionName == "Z_TRFC") { string string1 = CalledFunction.Imports["STRING1"].ToString(); string string2 = CalledFunction.Imports["STRING2"].ToString(); string string3 = string1 + " " + string2 ; InsertUpdateBySQL("Update TransactionID set Result = '" + string3 + "', XExecuted = 'True' where TID = '" + Sender.LastTID.ToString() + "'"); } else throw new ERPConnect.ERPException("Function unknown"); } static void s_TRFCCommit(RFCServer Sender, string TID, ref bool OK) { Console.WriteLine("TransactionalID " + TID + " is committed"); InsertUpdateBySQL("Update TransactionID set XCommit = 'True' where TID = '" + TID + "'"); OK = false; } static void s_TRFCConfirm(RFCServer Sender, string TID, ref bool OK) { Console.WriteLine("TransactionalID " + TID + " was confirmed"); InsertUpdateBySQL("Update TransactionID set XConfirm = 'True' where TID = '" + TID + "'"); OK = true; } static void s_TRFCRollback(RFCServer Sender, string TID) { Console.WriteLine("TransactionalID " + TID + " is rolled back"); InsertUpdateBySQL("Update TransactionID set XRolledBack = 'True' where TID = '" + TID + "'"); }
Wir benötigen für unser Beispiel eine Tabelle auf dem SQL-Server (TransactionID). In dieser befinden sich 4 Flags (XCommit, XConfirm, XRollback und XExecuted), das Feld mit der Transaktions-ID (TID) und ein Feld für das Ergebnis (Result).


