SAP接口编程之 NCo3.0系列(06) : 会话管理

前面我们看到,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_COUNTERGET_COUNTER,在同一个function group中,共享一个变量count(计数器),每次运行INCREMENT_COUNTER, count就会加一,GET_COUNTER可以获得这个count。因为这两个函数不能被远程调用,所以我们将这两个函数拷贝出另外两个函数ZINCREMENT_COUNTERZGET_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。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容