SAP接口编程之 NCo3.0系列(06) : 会话管理
2017-01-07 00:43
323 查看
本系列博文由stoneWM原创,在CSDN和简书发布。
前面我们看到,SAP函数调用,Invoke语句的代码是这样的:
我们不用关心与SAP系统的连接,连接都是NCo3.0运行时环境(NCo3.0 runtime)来管理的。NCo3.0 runtime在Invoke执行之后,会重设会话状态(session state),将连接(connetion)归还给连接池(connetion pool)。这样的机制,在对用户会话(user sesseion)有要求的时候,就出问题了。比如说,SAP很多涉及数据操作(creation / modification)的函数都由
举一个具体的例子。
因为nco runtime在
ISessionPovider提供了一个默认实现:
第二种实现方法:程序员自己实现ISessionProvider对象,并且用RfcSessionManger.RegisterSessionProvder()方法进行注册。
注册后,代码中可以设定Session ID,而不是当前的线程ID来作为Session ID,实现会话管理(或者称为有状态的连接管理)。这种实现方法,不同线程中的代码运行可以保持在SAP系统中相同的session中。一个可能的场景,比如nco3.0 runtime运行在web server中,这个时候,客户端请求来自browser,web server对来自客户端不同的请求使用不同的线程来处理。
第二种方法,我没有进行研究。真实接口项目中的处理,一般对涉及SAP数据操作的接口,往往通过在ABAP中自定义函数来接受外部的数据(通过参数获得),然后调用SAP相关的BAPI处理。外部语言处理太复杂的情况,不如在SAP中用ABAP语言来做。
SAP中有两个函数
单元测试:
在控制台中打印的结果是5。
前面我们看到,SAP函数调用,Invoke语句的代码是这样的:
someFunciton.Invoke(sapDestination);
我们不用关心与SAP系统的连接,连接都是NCo3.0运行时环境(NCo3.0 runtime)来管理的。NCo3.0 runtime在Invoke执行之后,会重设会话状态(session state),将连接(connetion)归还给连接池(connetion pool)。这样的机制,在对用户会话(user sesseion)有要求的时候,就出问题了。比如说,SAP很多涉及数据操作(creation / modification)的函数都由
BAPI_TRANSACTION_COMMIT函数来执行提交。SAP要求这两个函数的执行在同一个user session之中,如果第一个函数执行之后,runtime把连接(connection)归还给了连接池(connection pool),后面函数的提交就不会成功。
举一个具体的例子。
BAPI_SALESORDER_CREATEFROMDATA2这个函数的作用是创建销售订单,代码大体是这样的:
IRfcFunction fmSOCreate = sap.Repository.CreateFunction("BAPI_SALESORDER_CREATEFROMDATA2"); IRfFunction fmTxnCommit = sap.Repository.CreateFunction("BAPI_TRANSACTION_COMMIT"); fmSOCreate.Invoke(sap); fmTxnCommit.Invoke(sap);
因为nco runtime在
fmSOCreate.Invoke(sap);之后会重设会话状态,所以第二个函数的执行不会成功。
ISessionProvider
解决办法:ISessionProvider。ISessionProvider是一个接口,实现该接口的对象实例(object instance)需要创建或使用已经存在的Session ID,然后SAP系统根据Session ID,确保不同的函数的执行能够在同一个session之中。ISessionPovider提供了一个默认实现:
RfcSessionManager, 用于处理不复杂的情况。实现的机制是:使用应用程序当前的线程ID(thread ID)作为Session ID, 也就是说如果客户端应用程序在同一个线程下执行,使用RfcSessionManager就能保证在同一个代码在同一个Session ID下运行。典型的代码如下所示:
// 设置目前与SAP系统的连接为独占模式,后续函数调用在同一个Session中 RfcSessionManager.BeginContext(sapDestination); // codes goes here // 重设会话状态,释放连接 RfcSessionManager.EngdContext(sapDestination);
第二种实现方法:程序员自己实现ISessionProvider对象,并且用RfcSessionManger.RegisterSessionProvder()方法进行注册。
注册后,代码中可以设定Session ID,而不是当前的线程ID来作为Session ID,实现会话管理(或者称为有状态的连接管理)。这种实现方法,不同线程中的代码运行可以保持在SAP系统中相同的session中。一个可能的场景,比如nco3.0 runtime运行在web server中,这个时候,客户端请求来自browser,web server对来自客户端不同的请求使用不同的线程来处理。
第二种方法,我没有进行研究。真实接口项目中的处理,一般对涉及SAP数据操作的接口,往往通过在ABAP中自定义函数来接受外部的数据(通过参数获得),然后调用SAP相关的BAPI处理。外部语言处理太复杂的情况,不如在SAP中用ABAP语言来做。
示例
SAP nco3.0提供的实例代码很好地说明了Session management的用法,所以我就没有再费力去考虑用什么函数来演示,仅仅对SAP提供的示例改写。SAP中有两个函数
INCREMENT_COUNTER,
GET_COUNTER,在同一个function group中,共享一个变量count(计数器),每次运行
INCREMENT_COUNTER, count就会加一,
GET_COUNTER可以获得这个count。因为这两个函数不能被远程调用,所以我们将这两个函数拷贝出另外两个函数
ZINCREMENT_COUNTER,
ZGET_COUNTER。
// File name: RfcSessionManagement.cs using SAP.Middleware.Connector; using NCo02; namespace NCo03 { public class RfcSessionManagement { public void SessionManagementDemo() { /* * Shows how to use RfcSessionManager to ensure that multiple functions * can be used in the same user session * RfcSessionManager is a simple implemenation of IRfcSessionProvider * that uses thread-Id as the session-Id * * ZINCREMENT_COUNTER & ZGET_COUNTER were copied * from INCREMENT_COUNTER & GET_COUNER respectively */ RfcDestination dest = DestinationProvider.GetDestination(); IRfcFunction fmIncCounter = dest.Repository.CreateFunction("ZINCREMENT_COUNTER"); IRfcFunction fmGetCounter = dest.Repository.CreateFunction("ZGET_COUNTER"); // keep the current connection to backend SAP system // to be used exclusively for current session RfcSessionManager.BeginContext(dest); int currentCounter = 0; try { // increment counter for 5 times for (int i = 0; i < 5; i++) { fmIncCounter.Invoke(dest); } // then get the counter fmGetCounter.Invoke(dest); currentCounter = fmGetCounter.GetInt("GET_VALUE"); } finally { // release the connection RfcSessionManager.EndContext(dest); } System.Console.WriteLine(currentCounter); } } }
单元测试:
// TestSessionManagement.cs using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using NCo03; namespace UnitTestProject1 { [TestClass] public class TestSessionManagement { [TestMethod] public void Test_SessionManagement() { RfcSessionManagement rfc = new RfcSessionManagement(); rfc.SessionManagementDemo(); } } }
在控制台中打印的结果是5。
相关文章推荐
- SAP接口编程之 NCo3.0系列(04) : Table作为输出参数
- SAP接口编程-RFC系列06 : Table作为输入参数
- SAP接口编程之 NCo3.0系列(05) : Table作为输入参数
- SAP接口编程-Nco3.0系列01 : RfcDestination
- SAP接口编程之 NCo3.0系列(07) : 异常处理
- SAP接口编程 之 JCo3.0系列(04) : 会话管理
- SAP接口编程之 NCo3.0系列(03) : Meta-data和Container
- SAP接口编程之 NCo3.0系列(02) : RFC Client Programs
- SAP接口编程 之 JCo3.0系列(04) : 会话管理
- SAP接口编程-RFC系列12 : Table Parameter作为输出参数
- SAP接口编程-RFC系列15 : 调用自定义FM
- SAP接口编程-RFC系列04 : 动态调用SAP函数
- SAP接口编程 之 JCo3.0系列(03) : Table参数
- SAP接口编程-RFC系列07 : 通用的数据库表读取
- SAP接口编程-RFC系列14 : 获取SAP DDIC的数据字段
- SAP接口编程 之 JCo3.0系列(05) : Exception Handling
- SAP接口编程 之 JCo3.0系列(02) : JCo Client Programming
- SAP接口编程 之 JCo3.0系列(02) : JCo Client Programming
- SAP接口编程-RFC系列09 : 使用BAPI
- SAP接口编程 之 JCo3.0系列(05) : Exception Handling