SAP RFC介绍:关于sRFC,aRFC,tRFC,qRFC和bgRFC

【转】权限管法学习 一、ASP.NET
Forms身份认证

大约四月份的时候做过一个有关六个SAP系统间资产平摊传输的项目,使用到了RFC(Remote
Function
Call)技术。因为在此以前所有医疗-CRM相关接口开发的经验,以为自己对RFC很熟识了,做起来会很顺利,不想要么碰着了些问题。打算整治一下关于它们的始末,进一步深造。

表明:本文示例使用的VS2017和MVC5。
系统无论大小、牛逼或屌丝,一般都离不开注册、登录。那么接下去我们就来分析下用户地点认证。

本文内容的第一来源于是SAP的英文文档。会相比较偏重基本概念上的事物,偶尔涉及实际的代码、配置。后续可能会基于本人的莫过于行使情状更新更详细的介绍。

简简单单实现登录、注销

此前在学习.net的时候不通晓如何Forms身份申明,直接用session实现登录,效果也蛮好嘛。而且用户音讯留存服务端,安全。
前者代码:

@if (string.IsNullOrWhiteSpace(ViewBag.UserName))
{
    <form action="/home/login1">
        <input type="text" name="userName" />
        <input type="submit" value="登录" />
    </form>
}
else
{
    <form action="/home/logout1">
        <div>当前用户已登录,登录名:@ViewBag.UserName</div>
        <input type="submit" value="退出" />
    </form>
}

后台代码:

public ActionResult Index()
{
    ViewBag.UserName = Session["userName"]?.ToString();           
    return View();
}       

public void Login1(string userName)
{
    if (!string.IsNullOrWhiteSpace(userName))  //为了方便演示,就不做真的验证了     
        Session["userName"] = userName;
    else
        Session["userName"] = null;
    Response.Redirect(Request.UrlReferrer.LocalPath);//重定向到原来页面
}

public void Logout1()
{
    Session["userName"] = null;
    Response.Redirect(Request.UrlReferrer.LocalPath);//重定向到原来页面
}

是不是,简单明了。想要自己壮大或是定制什么效益都特别好用。但是大家需要维护session。比如系统再一次发布,或者iis被自动重启。就会产出session丢失的气象。也就是用户会莫名其妙提高需要再行登录。体验异常不好。(这里先不钻探session服务和数据库的情况)。既然微软有一套成熟的权杖管理咱们为啥不用吧?

 

Forms认证登录、注销

率先在web.config里打开Forms身份验证:

<system.web>
  <authentication mode="Forms"></authentication>

后台代码:

public void Login2(string userName)
{
    if (!string.IsNullOrWhiteSpace(userName))  //为了方便演示,就不做真的验证了
        FormsAuthentication.SetAuthCookie(userName, true); //登录
    Response.Redirect(Request.UrlReferrer.LocalPath);//重定向到原来页面
}

public void Logout2()
{
    FormsAuthentication.SignOut();//登出
    Response.Redirect(Request.UrlReferrer.LocalPath);//重定向到原来页面
}

前台代码:

@if (!Request.IsAuthenticated)
{
    <form action="/home/login2">
        <input type="text" name="userName" />
        <input type="submit" value="登录" />
    </form>
}
else
{
    <form action="/home/logout2">
        <div>当前用户已登录,登录名:@Context.User.Identity.Name</div>
        <input type="submit" value="退出" />
    </form>
}

如此这般几句代码就实现了我们的记名和收回。和大家团结一心用session管理登录不同。Forms身份声明是直接把音讯存cookie到浏览器的。通过SetAuthCookie这个模式名也足以看出来。不过库克ie音信透过了加密。
这边有必要表达session和cookie的涉及。当我们应用session来维持用户意况的时候,其实也利用了cookie。
管理 1
可是Forms身份认证仅仅只是把信息存了cookie,而从未在服务端维护一个对应的session。
不信你能够测试。可以用三种艺术都登录,然后去掉session就足以测出来了。(怎么清session?重启iis,或者修改下后台代码在再度编译访问)
【表达】用户认证为何要存cookie?因为HTTP是一个无状态的合计。对于服务器来说,每趟请求都是平等的。所以,只可以通过每一趟请求带的cookie来识别用户了。(暂时不考虑任何艺术)

正文链接:http://www.cnblogs.com/hhelibeb/p/8066753.html

自定义的地方验证标识

地点使用的记名很简短,但其实情况屡屡很复杂。显著正常作业需要存的用户消息会要更多。那么大家是否足以扩张身份标识呢?答案是必定的。
后台代码:

public void Login3(string userName)
{
    if (!string.IsNullOrWhiteSpace(userName))  //为了方便演示,就不做真的验证了     
    {
        UserInfo user = new UserInfo()
        {
            Name = userName,
            LoginTime = DateTime.Now
        };
        //1、序列化要保存的用户信息
        var data = JsonConvert.SerializeObject(user);

        //2、创建一个FormsAuthenticationTicket,它包含登录名以及额外的用户数据。
        FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(2, userName, DateTime.Now, DateTime.Now.AddDays(1), true, data);

        //3、加密保存
        string cookieValue = FormsAuthentication.Encrypt(ticket);

        // 4. 根据加密结果创建登录Cookie
        HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, cookieValue);
        cookie.HttpOnly = true;
        cookie.Secure = FormsAuthentication.RequireSSL;
        cookie.Domain = FormsAuthentication.CookieDomain;
        cookie.Path = FormsAuthentication.FormsCookiePath;

        // 5. 写登录Cookie
        Response.Cookies.Remove(cookie.Name);
        Response.Cookies.Add(cookie);
    }
    Response.Redirect(Request.UrlReferrer.LocalPath);//重定向到原来页面
}

然后在Global.asax的Application_AuthenticateRequest方法:

protected void Application_AuthenticateRequest()
{
    GetUserInfo();
}

//通过coolie解密 读取用户信息到 HttpContext.Current.User
public void GetUserInfo()
{
    // 1. 读登录Cookie
    HttpCookie cookie = Request.Cookies[FormsAuthentication.FormsCookieName];

    try
    {
        UserInfo userData = null;
        // 2. 解密Cookie值,获取FormsAuthenticationTicket对象
        FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);

        if (ticket != null && string.IsNullOrEmpty(ticket.UserData) == false)
            // 3. 还原用户数据
            userData = JsonConvert.DeserializeObject<UserInfo>(ticket.UserData);

        if (ticket != null && userData != null)
            // 4. 构造我们的MyFormsPrincipal实例,重新给context.User赋值。
            HttpContext.Current.User = new MyFormsPrincipal<UserInfo>(ticket, userData);
    }
    catch { /* 有异常也不要抛出,防止攻击者试探。 */ }
}

前者代码:

@{
    MyFormsPrincipal<UserInfo> user = Context.User as MyFormsPrincipal<UserInfo>;
    if (user == null)
    {
        <form action="/home/login3">
            <input type="text" name="userName" />
            <input type="submit" value="登录" />
        </form>
    }
    else
    {

        <form action="/home/logout2">
            <div>当前用户已登录,登录名:@Context.User.Identity.Name</div>
            <div>当前用户已登录,登录时间:@user.UserData.LoginTime</div>
            <input type="submit" value="退出" />
        </form>
    }
}

其实所有过程和FormsAuthentication.SetAuthCookie(userName, true); //登录是同一的。只是我们透过扩充,存了大家想要存储的数额。
经过也相比简单:

  • 结构要存储的数据
  • 序列化
  • 把连串化音信放入FormsAuthenticationTicket对象
  • 经过FormsAuthentication.Encrypt加密对象
  • 出殡cookie到浏览器

此处稍微复杂点的地点就是解密然后给User赋值HttpContext.Current.User = new MyFormsPrincipal<UserInfo>(ticket, userData);
MyFormsPrincipal需要实现接口MyFormsPrincipal

public class MyFormsPrincipal<TUserData> : IPrincipal where TUserData : class, new()
{
    private IIdentity _identity;
    private TUserData _userData;

    public MyFormsPrincipal(FormsAuthenticationTicket ticket, TUserData userData)
    {
        if (ticket == null)
            throw new ArgumentNullException("ticket");
        if (userData == null)
            throw new ArgumentNullException("userData");

        _identity = new FormsIdentity(ticket);
        _userData = userData;
    }

    public TUserData UserData
    {
        get { return _userData; }
    }

    public IIdentity Identity
    {
        get { return _identity; }
    }

    public bool IsInRole(string role)//这里暂时不实现
    {
        return false;
    }
}

倒也一向不什么特别,就是实例化的时候传出票据和自定义数据就好了。

总述

对于SAP与SAP系统及SAP与非SAP系统之间的接连而言,远程函数调用(Remote
Function
Call,以下简称RFC)是一种标准的通信模式,它能够兑现对长途系统中函数的调用。

具备RFC类型都通过CPI-C或TCP/IP协议进行传输。
它们构成了一种Gateway通信。

本文是对具有RFC变体的描述,它们有着不同的风味和切合的使用境况。

授权

有了登录一般都离不开授权。微软的东西好就好在,一般都是一体成套的。

[Authorize]
public ActionResult LoginOk()
{
    return View();
}

直白给Action添加一个Authorize特性就好了,这人就会自动检查是不是登录。假若没有登录活动跳转到登录页面。登录页面的设置仍然在web.config里面

<system.web>
  <authentication mode="Forms" >
    <forms loginUrl="/home/index"></forms>

这种概括的授权验声彰着是不够的。很多时候某些页面只有少数人才能访问。比如VIP。那么我们又要推而广之了。

//继承 AuthorizeAttribute
public class MyAuthorizeAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.User.Identity.Name != "农码一生")
        {
            filterContext.HttpContext.Response.Write("您不是vip用户,不能访问机密数据");
            filterContext.HttpContext.Response.End();
            return;
        }
        base.OnAuthorization(filterContext);
    }
}

[MyAuthorize]
public ActionResult LoginVIP()
{
    return View();
}

不错,就是如此简单。说了如此多,来张效果图吧:
管理 2

 

引进阅读:

 

同步RFC:sRFC

同步RFC(Synchronous
RFC,sRFC)是最基本的RFC形式。在sRFC调用中,调用者会等待远程被调用者的处理过程。

它的语法格局是:

CALL FUNCTION func DESTINATION dest. 

压倒元白的运用情况包括:

  • 销售:为不同体系创制采购订单(central sales)。
  • 销售:对于某个查询,在供应商系统里举办一个对于指定物料的可用性检查。
  • 物品管理:在另一个序列里对某个物料订单执行来源判断。
  • CRM/SRM:对SAP后端系统倡导某个物料的可用性检查。
  • CRM/SRM:在SRM组件中成立采购订单时,在先生集中核算中为你的资金中央开展预算检查。
  • 会计:向会计集中核算体系请求一个基金中央清单。
  • BW:调用BW组件(商业信息仓库)来呼吁一个专程的evaluation。

异步RFC:aRFC

异步RFC(Asynchronous
RFC,aRFC)类似与tRFC,用户在连续调用会话此前,不需要拭目以待它们的落成。不过,aRFC和tRFC之间也设有几点不同的地方:

  • 当调用者起首一个aRFC的时候,被调用的服务器必须可以接过请求。aRFC的参数不会记录在数据库中,而是间接发送给对方服务器。
  • aRFC允许用户与长途系统举办交互式对话。
  • 调用程序能够从aRFC接收结果。

你可以在当您需要树立和一个远端系统的总是、可是指望在调用RFC后不指望等待结果而是希望持续处理时行使aRFC。aRFC也得以发送给相同的类别。在这种状态下,系统打开一个新的对话(窗口)。你可以在调用对话和被调用会话间切换。使用下边的语句开启一个aRFC:

CALL FUNCTION Remotefunction STARTING NEW TASK Taskname

DESTINATION ...

EXPORTING...

TABLES ...

EXCEPTIONS...

 RECEIVE RESULTS FROM FUNCTION Remotefunction 用于一个子顺序内经受aRFC的调用结果。可以利用以下收取参数:

  • IMPORTING

  • TABLES

  • EXCEPTIONS

附加项KEEPING
TASK
堵住连接在吸收处理结果后关闭。相关的中远距离上下文(滚动区域)保持可以采取的情状,直至调用者终止连接。

更多关于aRFC的信息可以从以下地方得到:

关于aRFC变体的叙说:

事务RFC:tRFC

在采用事务RFC( transactional
RFC,tRFC)的时候,被调用的函数模块在被调用系统中恰恰运行五回(Exactly Once)。

远端系统不需要在RFC客户端程序运行tRFC的时候可用。tRFC组件将被调用的RFC函数和连锁数据存储在SAP系统的数据库里,包含一个唯一的政工标识符(transaction
identifier,TID)。

假如调用发送了,接收系统却是宕机状态,调用会保留在地面队列中一段时间。调用对话程序可以在不等待远程调用成功/战败的状态下继续运行。倘诺接到系统在一段时间后依然不可用,调用将被计划为后台作业运行。

tRFC使用后缀IN BACKGROUND TASK.

就和一道调用一样,参数
DESTINATION在长距离系统定义了程序上下文。结果是,假诺你对一个destination重复地调用一个函数(或者一回性调用多少个函数),则可以在同一的上下文中访问被调用函数的大局数据。。

系统会在表ARFCSSTATE和表ARFCSDATA中著录远程连接请求和它们的漫天参数值。你能够运用事务SM58来查看。当调用程序到达COMMIT
WORK
话语时,远程调用会被转发到给对方系统。

在两个COMMIT
WORK
里头,所有的所有同一个destination的tRFC属于同一个逻辑单元(LUW)。

tRFC处理流图示:

管理 3

您可以在少数意况下使用使用tRFC,比如,对于急需在作业的例外等级更新相关数据库表的扑朔迷离的处理过程。

tRFC会确保所有的计划更新在先后到达COMMIT WORK语句时被实践。

(注意:tRFC的概念中不可能有任何EXPORT参数,因为调用程序中一经有IMPORT参数,就会造成语法错误。别的,你也不可以对实践回调的程序举办异步调用)

系统可用性:

假若远程系统不可用,SAP系统会将报表RSARFCSE计划为后台作业,并将有关的政工ID作为变式,再拓展拍卖。那一个表格程序会再也地被调用,直到它成功地连续对方系统截至。

当被计划为后台作业时,RSARFCSE自动地以一个时刻距离运行(默认是每15分钟运行三次,最多尝试30次)。你可以通过增强程序SABP0000和SABP0003来自定义该时间间隔。

通过SM59安排destination,采用一个destination并且选用编辑->TRFC选项,在此地定义连接尝试次数上限和另行连接尝试的年华距离。

管理 4

一经在品尝指定的次数后依旧不足抵达相应的系列,系统会停下调用RSARFCSE,并写入状态CPICERR至表ARFCSDATA中。在另一个指定的时日后(默认是8天),在表ARFCSSTATE内的条规也会被剔除。当然也足以定制这个时刻,或者手动在SM59启动相应的事体条目。

tRFC的缺点:

  • tRFC独立地拍卖所有LUW。依据激活的tRFC数量,程序有可能会强烈地回落调用系统和被调用系统的性质。
  • 此外,在使用中定义的LUW的调用顺序是不可以得到保障的。由此不可以保证事务会依据使用期望的相继运行。tRFC唯一能确保的唯有:所有LUW都会或早或晚地被传输。

可以在这边查看tRFC语句的描述:

CALL FUNCTION IN BACKGROUND
TASK

队列RFC:qRFC

队列RFC(queued Remote Function
Call,qRFC)是tRFC的一个恢宏。它同意你将五个tRFC调用连串化为一个队列。

qRFC调用会首先被函数模块TRFC_SET_QUEUE_NAME举行体系化处理,然后那一个调用被一个tRFC举办实际的dispatch。

qRFC可以看成外向队列(由调用系统系列化)处理,或者是内向队列(由被调用系统体系化)。

* *

以下是两种业务数据传输的现象(为何图片中的文字是德文?):

管理 5

场景1:tRFC

这一场所适用于数据互相间独立发送的气象。系统1中设有一个调用应用(client)使用tRFC连接系统2中的被调用应用(r
server)。在该场景中,数据由tRFC传输,意味着发送到目的序列的函数模块调用会被保险只运行两遍。你不得以定义函数模块运行的逐一和时间。倘若传输过程中产生了不当,系统会计划一个后台作业,在15分钟后重新发送函数模块调用。

场景2:带有外向队列的qRFC

在本场景中,发送系统应用一个活泼队列来体系化被发送的多寡。这表示发送系统的外向队列包含着存在依靠关系的函数模块调用。当数码发送时,会维持确定的次第,并且调用会以正好三次且有序的方法(exactly once in order)发送给目的体系。

专注:目的体系处理时不需要转移qRFC的逐条,但是,它必须拉开tRFC效能。

情景3:带有内向队列的qRFC(以及活跃队列)

在这一个场景下,不仅发送系统(client)有外向队列,目的系列也有内向队列。倘使qRFC存在有内向队列,那也象征它在殡葬系统上必将存在外向队列。内向队列在一段时间里只可以处理系统资源允许处理的函数模块调用数量。它可以避免服务器被一个客户端阻塞。唯有在服务系统独立存在一个内向队列的光景是不可以存在的,因为需要在客户端系统存在外向队列,来设置顺序并拦截单独的施用阻塞客户端系统的全部办事进程。

更多相关消息可见:

后台RFC:bgRFC

使用

bgRFC(Background Remote Function
Call)允许被调用程序稍晚一些接收数据,而不是一路接收。接收数据的时候,需要保证数据只出现一次且无序(
transactional) 、或者只现出一遍且有序(queued)。

使用bgRFC举办异步调用,会有如下优势:

  • 在同一个SAP系统内(同一个系列ID,同一个client):解耦,同时提供了并行化能力。负载会分布在该序列的可用的应用服务器上。那么些bgRFC场景被当做一个内向程序。

  • 在三个远程SAP系统间:解耦,并且经过可以实现利用或作业场景的物理细分。异步调用的结果是,调用者和被调用者的应用服务器的重中之重特性差别可以取得平衡。记录工作在调用系统中成功。这一个现象是一个活泼程序。

  • 六个程序结合为外-内程序:该方法得以拿到全套优化增选的优势。可是,要是你挑选了如此做,数据会被记录五遍,两次是调用者(外向处理)、五次是被调用应用(
    内向程序的新鲜系列)。这造成数据库、应用服务器会有相当的负担。

bgRFC使用队列协会不同的调用。当一个调用同时被停放在五个系列的时候,系统会为这多少个队列成立依赖。这带来了一个同步点(synchronization
point),类似于锁。

假若一个调用处于看重队列中,那么当且仅当它置身依赖队列的最上层时,它才会被处理。

对于同一个destination,不可以将bgRFC和tRFC、qRFC结合起来使用。但是,对于不同的destination,你可以定义你想利用的通讯类型。

语法:

 CALL FUNCTION 'function_name'

IN BACKGROUND UNIT unit

          EXPORTING ... 

 

集成

从qRFC转换为bgRFC的应用程序,必须协理创造qRFC中的队列与bgRFC中的队列之间的暂时链接的动迁方案。通过如此的方案,可以保证科学的队列顺序,即使是在从qRFC变为bgRFC的每一天。

小心:从bgRFC改回qRFC是不容许的。

在SAP NetWeaver Release
7.11以及更高的版本上,bgRFC也足以和basXML(二进制ABAP序列化XML)通信协议一起利用。

架构

观念的qRFC模型只有在数码被RFC调度程序处理的时候才探测各样独立单元之间的依赖关系。对于每个destination,外向调度程序都会开启一个调度程序来拍卖这么些destination的数目。

与之相对的是,bgRFC的借助关系在多少存储的时候就决定了。通过如此做,RFC调度程序可以两回性找到所有的需要被拍卖的单元,并且经过最小的拼命(minimum
effort)就可以找到它们中间的倚重关系。在仓储数据的时候需要交给的额外努力,则能够在很大程度上由数据库设计中的高功能算法和优化补偿。

每个客户端定义一定数量的活泼计划,并且并行处理队列负载,即便目的体系的负载会在一个较短的时辰距离后被确定,然而也为此会更为规范。

单元和队列的删除程序

和历史观的主次不同,假诺有其他单元或队列被删除,依赖依旧会维持。因为单元会被先打上标记,并且在这事后只是被调度程序删除。

管理 6

如图,在剔除了Unit4之后,Unit6只好在Unit3之后运行,因为Unit4只有在调度程序处理过Unit3之后才会被删除。假设你剔除掉queue2,那么会发生下边的场地:

管理 7

Unit6会在Unit2然后运行,所有选定的unit都会被调度程序删除。

留神:删除队列或者单元总是有着高风险的。在我们的事例里,它会促成Unit6境遇错误,或者造成目的类此外数据库不相同,因为它的前提Unit4因为被删除而尚未运行。

Gateway:Gateway是另一个机密的属性瓶颈,在bgRFC中,它也获取了优化。bgRFC中的新的概念是会调剂在一台应用服务器上同时运转的活泼调度程序的最大数目,也会调剂全体RFC调度程序可用的最第比利(比尔(Bill)y)斯接数。那些限制会敬服当地的Gateway使之不至于过载。

各种发送系统的相互的外向调度程序数量和它们的最阿比让接数也是可部署的,因此对此destination的Gateway也设有过载敬爱。

特性的熏陶:新bgRFC贯彻的优化在高负荷、多倚重的情况下特别彰着。第一次运行的时候,线性对数可伸缩性(a
linear logarithmical
scalability)的RFC数据处理成为可能(视系统兼容性而定)。

函数队列的业务特性使得,在拍卖单独的单元时,bgRFC不太容易拿到显然的性质提升,可是在利用更多或者更快的硬件的时候,则足以明确提高吞吐量。限制因素会是数据库的属性和这么些单元的处理速度。

此外,新的API也是优化的一局部。一些剩下的函数被移除,某些旧的API也不再行使。这使得相关的劳作更是平缓和有效用,缩小协理团队和付出协会的工作量。

更多音信:

更多关于bgRFC的新闻, 请看:

管理,地点数据队列:LDQ

当地数据队列(Local Data Queue
)是一种特其余RFC通信。在这种利用情状下,系统不会再接再厉发送数据。相反,依据拉取规则,系统会把多少存储在当地,直到被表面系统调用(比如移动设备)。

LDQ可以代替原先由qRFC在不发送场景下提供的效果(qRFC No
Send)。相比较之下它提供了更有效能的数据模型。

更多内容:

Local Data Queue
(LDQ)

名词对照

scheduler:调度程序

outbound  queue:外向队列

inbound queue:内向队列

 

有关著作:ABAP
RFC远程调用

 

 

Post Author: admin

发表评论

电子邮件地址不会被公开。 必填项已用*标注