转博客园一位前辈关于.NET通过NCO3.0连接SAP的系列文章-创新互联

NET连接SAP系统专题:.NET调用RFC几种方式(一)转博客园一位前辈关于.NET通过
NCO3.0连接SAP的系列文章

本来今天是要写一篇关于NCO3.0的东西,就是关乎.NET调用SAP的RFC的,支持VS2010和.NET 4.0等。现在网上到处都是充斥着NCO1.X和NCO2.0,需要用VS2003来使用,都是一些没什么大用的东西,连.NET 2.0的不能支持,只能算是废材一个。而且相关的资料非常的少,转来转去全部都是那么一个例子,丝毫没有直观的DEMO,更搞笑的是SAP里面的RFC是怎么建立的都没有说明,只有该死的C#代码。同时还有微软发布的Data Provider for mySAP Business Suite这个,开始用的时候觉得还挺有趣,后来试了一下很失望,抓出来的字段居然是断码,不知道是我不懂还是怎么的。同时更让人无语的是用它的话还必须要导入一个Request NO,加入一个自定义的Function才可以使用Data Provider for mySAP Business Suite,很脑残也很不靠谱。

为容城等地区用户提供了全套网页设计制作服务,及容城网站建设行业解决方案。主营业务为成都网站制作、成都做网站、容城网站设计,以传统方式定制建设网站,并提供域名空间备案等一条龙服务,秉承以专业、用心的态度为用户提供真诚的服务。我们深信只要达到每一位用户的要求,就会得到认可,从而选择与我们长期合作。这样,我们也可以走得更远!

  后来发现NCO3.0也发布了,和以前的版本大不相同。后面试用了一下NCO3.0,效果很好。

  公司有几只程序,是在台湾SAP端运行程序,自动下载品号等信息至厦门的SQL Server数据库供OA使用的,每次要用到的品号都需要去SAP系统运行那个程序。虽然Basis设置了4个小时执行一次,但是还是有些过慢。我就想着如果能在OA这边用NCO3.0,然后调用SAP的RFC,就自动下载所需要的品号那就非常方便了。我在030也试用了一下,很OK!

  既然.NET能够和SAP互相通信,在RFC里就可以任意发挥了,想做什么就做什么。这样可以免去SAP系统的账户成本压力。

  呵呵,下篇博文开始介绍一下NCO3.0这个东西。

.NET连接SAP系统专题:SAP中新建可远程调用的RFC(二)

分类: SAP顾问进行时 2011-08-22 22:34 2001人阅读 评论(0) 收藏 举报

  何谓RFC,就是一个Function,可以被非SAP系统调用,比如VB,C#,Java等。如果我们在RFC中INCLUDE了相关的业务逻辑,那么我们就可以完全操控SAP中的业务数据了。就像在TTE里,有一只程序,前端是在OA开发,设计了相关的客户提领库存,然后还要到SAP系统中去执行程序扣减相应的库存,这样是挺费劲的,如果能够在OA中放一个按钮,点击这个按钮就自动执行了这个程序,方便省事。而这一切,可以利用C#调用RFC来实现。

  要实现整个过程,则必须要现在SAP中建立好相应的RFC函数,然后用VS建立好相应的程序,写代码调用就可以了。两者关联就是使用NCO3.0这个东西了。

  OK,本节主要讲在SAP中建立我们想要的RFC出来。

  那么,我们假定要实现这样的一个功能:运行在SAP系统外的一个程序窗体,上面有一个下拉框和文本框。程序运行之后自动载入SAP中某个Client的品号至该下拉框,用户只要点击了这个下拉框,内容一改变,则旁边的文本框就现实该品号的品名出来。够简单吧!

  首先登陆SAP,比如我们要操作的Client为888(我自己建立的,图个吉利)。运行SE37:

   然后:

   建立函数组,输入相关内容:

   完了点击保存。

   之后回到SE37,输入我们要调用的RFC函数名,比如:ZRFC_MARA_INFO  然后点击新建(右一按钮):

   点击保存之后会弹出如下对话框:

  点击打勾,忽略之。

  主画面如下:

   画面切换至 属性 页,设置该RFC为可远程调用。

   因为我们到时候会传递一个品号进来读取品名,SO,在Import页面设置一个参数用来传递进来品号:

   第一个复选框代表此参数可选可不选传递,第二个代表参考。在RFC里如果不打勾,保存会提示:

   因为我们会要抓取品名,需要有一个栏位抛出品名出来。SO,Export页面如下:

   因为我们程序一开始需要抛出所有的品号表格出来,SO,此时我们需要有一个内表专门用于抛出品号信息。Table属性页如下:

   至此,所有参数设置完毕。接下去就要去代码页编写相应的代码了。

   代码如下:

    SELECT * INTO CORRESPONDING FIELDS OF TABLE IT_MARA FROM MARA.

   SELECT SINGLE MAKTX INTO MAKTX FROM MAKT WHERE MATNR = MATNR AND SPRAS = '1'.

   最后点击激活!这里的激活不是单单激活这个RFC这么简单,还有其他的项目,记得要勾选上:

   至此,RFC建立完毕。

   接下去就是在C#中调用它咯,下篇博文放出!

.NET连接SAP系统专题:C#调用RFC代码(三)

分类: SAP顾问进行时 2011-08-22 22:34 2259人阅读 评论(0) 收藏 举报

本文就说明在C#中如何编写代码来调用SAP中的RFC函数获取数据。(Winform32)

  首先需要引用两个NCO3.0的DLL,下载地址在文后。

  然后在程序代码页面引用:

  using SAP.Middleware.Connector;

  然后所有的代码如下:

namespace SAP_RFC

{

  public partial class Form1 : Form

  {

    string MATNR = string.Empty;

    public Form1()

    {

      InitializeComponent();

    }

    public void nco()

    {

      IDestinationConfiguration ID = new MyBackendConfig();

      RfcDestinationManager.RegisterDestinationConfiguration(ID);

      RfcDestination prd = RfcDestinationManager.GetDestination("PRD_000");

      RfcDestinationManager.UnregisterDestinationConfiguration(ID);

      nco(prd);

    }

    public void nco(RfcDestination prd)

    {

      RfcRepository repo = prd.Repository;

      IRfcFunction companyBapi = repo.CreateFunction("ZRFC_MARA_INFO");  //调用函数名

      companyBapi.SetValue("MATNR", MATNR);  //设置Import的参数

      companyBapi.Invoke(prd);  //执行函数

      IRfcTable table = companyBapi.GetTable("IT_MARA");  //获取相应的品号内表

      string MAKTX = companyBapi.GetValue("MAKTX").ToString();  //获取品名

      DataTable dt = new DataTable();  //新建表格

      dt.Columns.Add("品号");  //表格添加一列

      for (int i = 0; i < table.RowCount; i++)

      {

        table.CurrentIndex = i;  //当前内表的索引行

        DataRow dr = dt.NewRow();

        dr[0] = table.GetString("MATNR");  //获取表格的某行某列的值

        dt.Rows.Add(dr);  //填充该表格的值

      }

      if (MATNR == "")

      {

        for (int i = 0; i < dt.Rows.Count; i++)

        {

          this.comboBox1.Items.Add(dt.Rows[i][0].ToString());  //填充下拉框

        }

      }

      this.label1.Text = MAKTX;  //显示品名

      prd = null;

      repo = null;

    }

    //登陆SAP前的准备工作

    public class MyBackendConfig : IDestinationConfiguration

    {

      public RfcConfigParameters GetParameters(String destinationName)

      {

        if ("PRD_000".Equals(destinationName))

        {

          RfcConfigParameters parms = new RfcConfigParameters();

          parms.Add(RfcConfigParameters.AppServerHost, "192.168.1.3");  //SAP主机IP

          parms.Add(RfcConfigParameters.SystemNumber, "00");  //SAP实例

          parms.Add(RfcConfigParameters.User, "MENGXIN");  //用户名

          parms.Add(RfcConfigParameters.Password, "5239898");  //密码

          parms.Add(RfcConfigParameters.Client, "888");  // Client

          parms.Add(RfcConfigParameters.Language, "ZH");  //登陆语言

          parms.Add(RfcConfigParameters.PoolSize, "5");

          parms.Add(RfcConfigParameters.MaxPoolSize, "10");

          parms.Add(RfcConfigParameters.IdleTimeout, "60");

          return parms;

        }

        else return null;

      }

      public bool ChangeEventsSupported()

      {

        return false;

      }

      public event RfcDestinationManager.ConfigurationChangeHandler ConfigurationChanged;

    }

    private void Form1_Load(object sender, EventArgs e)

    {

      comboBox1.Items.Clear();

      nco();

      comboBox1.SelectedIndex = 1;

    }

    //当下拉框索引变化的时候传递品号进去查询出品名出来

    private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)

    {

      MATNR = comboBox1.Text.ToString();

      nco();

    }

  }

}

我想这个C#代码很简单,我就不多做详细说明了。结果如下:

SAP中品号信息如下:

由此可见数据完全OK,调用成功。

程序在第一次载入的时候有点慢,在链接SAP和登陆。后续在下拉框变化的时候就立马显示出品名出来了,丝毫没有任何停顿。第二次链接SAP的时候大概是不必在登陆了,SAP系统中已有登陆信息,运行T-CODE:SM04

红色框中这两个即是我们的RFC调用所留下的登录会话。一旦我们的C#程序退出之后,这两个RFC也就退出了。

如果我们的C#程序是ASP.NET的话,页面关闭之后这个RFC登录信息都还在的。除非IIS关闭,否则只有等到SAP系统超时退出这两个登陆会话了。

DLL下载地址:

https://files.cnblogs.com/mengxin523/SAP_DotNetConnector3.zip

.NET连接SAP系统专题:获取RFC中自定义的异常(四)

分类: SAP顾问进行时 2011-08-22 22:35 1850人阅读 评论(0) 收藏 举报

  有的时候我们需要在RFC中抛出一些自定义的异常,比如输入一个不存在的品号,我们需要抛出一个异常,告知用户品号不存在。有一个笨笨的做法就是通过返回值来判断,但是这样不灵活,同时也会因为品号不存在而继续之行RFC。如果我们能自己抛出异常,程序自动停止执行RFC,那将是两全其美!

  现在设定一个功能:输入两个数,第一个数除以第二个数。2个异常:被除数不能为0和除数不能为100。

  首先,在SE37中建立一个RFC,就用上篇博文的RFC吧。

  在IMPORT页设置如下:

  Export页面设置如下:

  Changing和Table页面放空

  Exceptions页面设置如下:

  然后就是源码咯:

   代码中,RAISE专门用于抛出异常,程序自动停止执行,所有的返回值将被清空!RAISE 后面的内容就是在Exceptions中定义的内容了。

   然后程序记得激活!!如此SAP端设置就结束了。

   回到VS2010中,新建一个程序,界面如下:

  于是,开始写程序:

  首先是引用两个dll(参考上篇),并在程序开头输入:

   using SAP.Middleware.Connector;

   public void nco()

    {

      IDestinationConfiguration ID = new MyBackendConfig();

      RfcDestinationManager.RegisterDestinationConfiguration(ID);

      RfcDestination prd = RfcDestinationManager.GetDestination("PRD_000");

      RfcDestinationManager.UnregisterDestinationConfiguration(ID);  //反注册

      nco(prd);

    }

    public void nco(RfcDestination prd)

    {

      string type = string.Empty;

      RfcRepository repo = prd.Repository;

      IRfcFunction companyBapi = repo.CreateFunction("ZRFC_MARA_INFO");  //指定RFC名称

      try

      {

        companyBapi.SetValue("NUM1", textBox1.Text.Trim());  //输入参数复制

        companyBapi.SetValue("NUM2", textBox2.Text.Trim());  //输入参数复制

        companyBapi.Invoke(prd);  //开始调用执行

        textBox3.Text = companyBapi.GetValue("NUM3").ToString();  //获取返回结果

      }

      catch (RfcAbapException ex)  //此Exception专门用于获取用户自定义的异常信息!!!!

      {

        // companyBapi.Metadata.GetAbapException(ex.Key).Documentation  获取对应的异常的说明文字

        MessageBox.Show(companyBapi.Metadata.GetAbapException(ex.Key).Documentation, "SAP RFC返回信息", MessageBoxButtons.OK, MessageBoxIcon.Error);

      }

      catch (RfcTypeConversionException ex)  //此Exception专门用于获取变量类型转换的异常!!!!

      {

        MessageBox.Show("您输入的不是数值", "SAP RFC返回信息", MessageBoxButtons.OK, MessageBoxIcon.Warning);

      }

      catch (RfcAbapRuntimeException ex)   //此Exception专门用于获取RFC执行过程中的运行时异常!!!!

      {

        MessageBox.Show(companyBapi.Metadata.GetAbapException(ex.Key).Documentation, "SAP RFC返回信息", MessageBoxButtons.OK, MessageBoxIcon.Warning);

      }

      catch (RfcBaseException ex)  //此Exception是总Exception类,可以获取所有的异常,如果有多个Catch,则不可以放第一位!!!!

      {

        MessageBox.Show("其他所有错误", "SAP RFC返回信息", MessageBoxButtons.OK, MessageBoxIcon.Warning);

      }

      prd = null;

      repo = null;

    }

    public class MyBackendConfig : IDestinationConfiguration

    {

      public RfcConfigParameters GetParameters(String destinationName)

      {

        if ("PRD_000".Equals(destinationName))

        {

          RfcConfigParameters parms = new RfcConfigParameters();

          parms.Add(RfcConfigParameters.AppServerHost, "192.168.1.3");

          parms.Add(RfcConfigParameters.SystemNumber, "00");

          parms.Add(RfcConfigParameters.User, "MENGXIN");

          parms.Add(RfcConfigParameters.Password, "5239898");

          parms.Add(RfcConfigParameters.Client, "888");

          parms.Add(RfcConfigParameters.Language, "ZH");

          parms.Add(RfcConfigParameters.PoolSize, "5");

          parms.Add(RfcConfigParameters.MaxPoolSize, "10");

          parms.Add(RfcConfigParameters.IdleTimeout, "60");

          return parms;

        }

        else return null;

      }

      public bool ChangeEventsSupported()

      {

        return false;

      }

      public event RfcDestinationManager.ConfigurationChangeHandler ConfigurationChanged;

       }

    private void button1_Click(object sender, EventArgs e)

    {

      nco();

    }

如此,C#运行结果如下:

以上可以正确得出我们自己抛出的异常的信息出来。程序测试OK!!!

.NET连接SAP系统专题:C#(NCO3)调用BAPI(五)

分类: SAP顾问进行时 2011-08-22 22:35 1636人阅读 评论(0) 收藏 举报

  周六加班,翻看以前写OA程序的时候无意中发现了当初的一个案子,就是让用户现在OA上申请一个SAP用户,然后提交给相关人员审核,通过之后直接在SAP中生成这个用户,不必在登陆到SAP中请系统管理员来做了。至于这一步,当然是使用BAPI来实现了,不可能对用户表进行新增数据,这样少了很多的关联表和一些逻辑判断,会是一场灾难。

  前几篇讲的都是C#去调用RFC的东西,既然BAPI也是属于RFC,如果标准的勾选了那个remote的话,那按道理来说是应该可以实现调用的了。但难点是BAPI里面很多的参数都是引用结构的,而不是单纯的string和int的类型,这点有点困难。在C#中翻看了NCO3是否有相关的结构类,可惜,都没有!

  查看了一下相关内容,发现几乎没有任何调用BAPI的例子,看来使用NCO3的人极少。

  只能自力更生了,还好,经过很严密的思考和尝试,终于实现了在C#中调用BAPI去实现录入业务数据了。我尝试的就是用BAPI_USER_CREATE这个BAPI,通过它可以新增一个用户。

  那么,相关内容和代码说明,就在下篇博文放出吧!

.NET连接SAP系统专题:NCO3调用BAPI的一些说明(六)

分类: SAP顾问进行时 2011-08-24 22:46 1647人阅读 评论(0) 收藏 举报

既然BAPI是一些特殊的RFC,封装了业务逻辑,使得将业务都变成一个一个对象,使用者只需要传入传出参数就可以了。

  NCO3连接BAPI之前先来看看BAPI的一些参数规则。我们以 BAPI_USER_CREATE 为例子。此BAPI调用了可以生成一个用户,它当然不是仅仅对USR02进行写入那么简单。生成之后该账户什么权限也没有。

  输入T-CODE:BAPI,然后在第二个页签下找到该BAPI:

  上图中的红色框框里就是我们要调用的BAPI的名称。双击它,进入到该BAPI的一些说明里:

   看到了,在属性页里它勾选了Remote... 说明它是可以远程操控的!

   上图里,注意到红色框框都是不可选的,也就是后面的复选框没有选中,它告诉我们,在调用BAPI的时候这些参数是必须要有值传进来的!

   这个就是返回的参数。当然,这个Return也是必须要传出来的值。

   细心的人从上面几个图片可以看出,“参考打印”栏位里都是BAPI开头的结构,或者是结构里面的一个字段。双击这些结构进去就可以看到相关的栏位组成。

   现在回到Import页签里,双击USERNAME的“参考打印”——BAPIBNAME-BAPIBNAME。“-”前部分是结构,后面是这个结构里的一个栏位。进入到里面:

   这个BAPINAME结构只有一个栏位,而且是CHAR型,12码,SO,在传 用户名 进来的时候就是写入字符串即可。

   我们看看PASSWORD,对应的结构是:BAPIPWD 双击之,如下图:

   发现这里面只有一个栏位,CHAR型,40码,传密码之用。

   再看看ADDRESS栏位对应的结构BAPIADDR3,双击之:

   这个结构栏位就比较多了。虽然这里没有规定那些是必须要有值的,但确实有些是需要赋值,有些则可以放空。

   我们在SU01里面新建用户的时候系统会提示要求输入姓和名,那么这里的FIRSTNAME和LASTNAME是必须的了。

   BAPI里传入的参数LOGONDATA是放登陆数据的,具体的结构不再赘述。而返回的信息RETURN里有一个MESSAGE是放调用结果的信息,我们在NCO3里调用要用到它来返回结果信息。

   知道了这些原理之后就很清楚知道在C#中要怎么写了,那些参数是必须的就一目了然了。SO,下篇博文放出NCO3调用BAPI的代码!

NET连接SAP系统专题:NCO3调用BAPI的代码(七)

分类: SAP顾问进行时 2011-08-25 22:43 1598人阅读 评论(0) 收藏 举报

   上面博文可知BAPI_USER_CREATE的一些结构和参数。所以在C#中要调用它就很清楚了要输入哪些参数了。

   1、首先引用dll,然后在程序开头:using SAP.Middleware.Connector;

   2、接下去就是设置登陆参数了,以前相关博文都有说明:

    public class MyBackendConfig : IDestinationConfiguration

    {

      public RfcConfigParameters GetParameters(String destinationName)

      {

        if ("PRD_000".Equals(destinationName))

        {

          RfcConfigParameters parms = new RfcConfigParameters();

          parms.Add(RfcConfigParameters.AppServerHost, "192.168.1.3");

          parms.Add(RfcConfigParameters.SystemNumber, "00");

          parms.Add(RfcConfigParameters.User, "MENGXIN");

          parms.Add(RfcConfigParameters.Password, "5239898");

          parms.Add(RfcConfigParameters.Client, "888");

          parms.Add(RfcConfigParameters.Language, "ZH");

          parms.Add(RfcConfigParameters.PoolSize, "5");

          parms.Add(RfcConfigParameters.MaxPoolSize, "10");

          parms.Add(RfcConfigParameters.IdleTimeout, "60");

          return parms;

        }

        else return null;

      }

      public bool ChangeEventsSupported()

      {

        return false;

      }

      public event RfcDestinationManager.ConfigurationChangeHandler ConfigurationChanged;

    }

    3、设置一个方法,引用这个登陆参数的类:

     public void nco()

    {

      IDestinationConfiguration ID = new MyBackendConfig();

      RfcDestinationManager.RegisterDestinationConfiguration(ID);

      RfcDestination prd = RfcDestinationManager.GetDestination("PRD_000");

      RfcDestinationManager.UnregisterDestinationConfiguration(ID);

      nco(prd);

    }

    4、然后就是开始了调用代码,以下代码全部放出,然后一行一行说明:

     public void nco(RfcDestination prd)

    {

      //选择要调用的BAPI的名称

      RfcFunctionMetadata BAPI_COMPANYCODE_GETDETAIL_MD = prd.Repository.GetFunctionMetadata("BAPI_USER_CREATE");

      //新建调用该BAPI的一个“实例”

      IRfcFunction function = null;

      function = BAPI_COMPANYCODE_GETDETAIL_MD.CreateFunction();

      //因为用户名称是一个字段,所以直接赋予字符串即可

      function.SetValue("USERNAME", USERID.Text.Trim());

      //接下去是密码。因为密码是一个结构,该结构只有一个栏位,所以这里先获取这个密码结构

      IRfcStructure PWD = function.GetStructure("PASSWORD");

      //设置这个结构中的这个栏位的内容

      PWD.SetValue("BAPIPWD", password.Text.Trim());

      //再把这个结构传进去给作为密码参数

      function.SetValue("PASSWORD", PWD);

      //这个是登陆信息,类型也是一个结构,所以这里获取出这个登录信息的结构出来

      IRfcStructure logo = function.GetStructure("LOGONDATA");

      //以下两个是设置这个登陆结构的一些栏位的值

      logo.SetValue("GLTGV", "20110821");

      logo.SetValue("GLTGB", "99991231");

      //将登陆信息的结构传进去给LOGONDATA

      function.SetValue("LOGONDATA", logo);  //设置参数

      //这个是地址信息,取结构,然后赋值,再将它传进去

      IRfcStructure address = function.GetStructure("ADDRESS");

      address.SetValue("FIRSTNAME", firstname.Text.Trim());

      address.SetValue("LASTNAME", lastname.Text.Trim());

      address.SetValue("DEPARTMENT", "资讯室");

      function.SetValue("ADDRESS", address);  //设置参数

      //以下这个DEFAULTS是账户的默认信息,不是必须要的。我们这里利用它设置登入账户的语言为ZH

      IRfcStructure DEFAULTS = function.GetStructure("DEFAULTS");

      DEFAULTS.SetValue("LANGU", "1"); //语言代码,对应简体中文!

      function.SetValue("DEFAULTS", DEFAULTS);

      //以下这个是RETURN,是回传结果的结构。记住,这里跟上面不一样,上面是Structure,这里则是Table!!

      IRfcTable returnStructure = function.GetTable("RETURN");

      function.Invoke(prd);//提交调用BAPI

      //弹出对话框显示调用结果

      MessageBox.Show(returnStructure.GetString("MESSAGE").ToString());

      prd = null;

    }

    5、程序运行结果如下:

      6、登陆到SAP,运行SU01,输入IT_XM01,看看结果:

      当然,如果该用户已经存在了你还去调用这个BAPI生成用户,系统会很知趣的提示:

      使用IT_XM01登陆系统,一切OK,系统状态如下:

      新建的账户一点权限也没有的,此时可以调用其他BAPI对其新增权限!!方法大同小异,这里不再详述。

.NET连接SAP系统专题:C#调用BAPI给账户赋予权限(八)

分类: SAP顾问进行时 2011-08-28 11:23 1678人阅读 评论(0) 收藏 举报

接上篇博文。

  上篇博文讲到C#调用BAPI BAPI_USER_CREATE 来生成SAP账户,但是新建的账户一点权限也没有,现在我们就再次利用BAPI给账户授予权限。

  首先,我们在BAPI画面里查找出相关的BAPI出来,利用角色去给用户添加权限:

   双击此BAPI,进入到BAPI预览画面:

   Table属性页:

   第一个ACTIVITYGROUPS是指我们要传进去的表格内容,不再是一个栏位和结构内容了。第二个的RETURN则是返回调用结果。

   双击BAPIAGR的结构,进入结构详情画面:

   以上AGR_NAME是角色名,应该是必须要的。

   那么,接下去就是在C#中编写相应的代码来调用它了。

    1、首先引用dll,然后在程序开头:using SAP.Middleware.Connector;

   2、接下去就是设置登陆参数了,以前相关博文都有说明:

    public class MyBackendConfig : IDestinationConfiguration

    {

      public RfcConfigParameters GetParameters(String destinationName)

      {

        if ("PRD_000".Equals(destinationName))

        {

          RfcConfigParameters parms = new RfcConfigParameters();

          parms.Add(RfcConfigParameters.AppServerHost, "192.168.1.3");

          parms.Add(RfcConfigParameters.SystemNumber, "00");

          parms.Add(RfcConfigParameters.User, "MENGXIN");

          parms.Add(RfcConfigParameters.Password, "5239898");

          parms.Add(RfcConfigParameters.Client, "888");

          parms.Add(RfcConfigParameters.Language, "ZH");

          parms.Add(RfcConfigParameters.PoolSize, "5");

          parms.Add(RfcConfigParameters.MaxPoolSize, "10");

          parms.Add(RfcConfigParameters.IdleTimeout, "60");

          return parms;

        }

        else return null;

      }

      public bool ChangeEventsSupported()

      {

        return false;

      }

      public event RfcDestinationManager.ConfigurationChangeHandler ConfigurationChanged;

    }

    3、设置一个方法,引用这个登陆参数的类:

     public void nco()

    {

      IDestinationConfiguration ID = new MyBackendConfig();

      RfcDestinationManager.RegisterDestinationConfiguration(ID);

      RfcDestination prd = RfcDestinationManager.GetDestination("PRD_000");

      RfcDestinationManager.UnregisterDestinationConfiguration(ID);

      nco(prd);

    }

    4、然后就是开始了调用代码,以下代码全部放出,然后一行一行说明:

     public void nco(RfcDestination prd)

    {

      //调用BAPI

      RfcFunctionMetadata BAPI_COMPANYCODE_GETDETAIL_MD = prd.Repository.GetFunctionMetadata("BAPI_USER_ACTGROUPS_ASSIGN");

      IRfcFunction function = null;

      function = BAPI_COMPANYCODE_GETDETAIL_MD.CreateFunction();

      //传入我们要赋予权限的用户名

      function.SetValue("USERNAME", USERID.Text.Trim());

      //接下去就是传入角色名。由于ACTIVITYGROUPS 是在Table属性页,所以我们是用Table 而不是Import和Export属性页里面用的Structure

      IRfcTable ROFTable = function.GetTable("ACTIVITYGROUPS");

      //上面语句产生的ROFTable 其实是一张空表,里面除了有那几个栏位之外是没有任何记录的,所以在对表格赋值之前需要先进性新增一行

       ROFTable .Insert();

      //接下去就是对表格当前行的相关栏位赋值。如下的角色名“MIS”是预选在SAP中建立好的

       ROFTable .CurrentRow.SetValue("AGR_NAME", "MIS");

       ROFTable .CurrentRow.SetValue("FROM_DAT", "20110825");

       ROFTable .CurrentRow.SetValue("TO_DAT", "99991231");

      //传入该赋值后的表格

      function.SetValue("ACTIVITYGROUPS", ROFTable);

      //引用回传结果

      IRfcTable RETURNStructure = function.GetTable("RETURN");

       //提交调用

      function.Invoke(prd);

      //显示调用结果

      MessageBox.Show(RETURNStructure.GetString("MESSAGE").ToString());

      prd = null;

    }

    5、调用结果如下:

     如此则此用户已经赋予相应的权限了,运行所有T-CODE,没问题!

     对了,如果要赋予多个角色的话,那么就是多做ROFTable.Insert();然后再做相应赋值即可。

     PS:C#调用RFC系列专题就到此告一段落了,如果读者有建议或者疑问欢迎交流指正~!

.NET连接SAP系统专题:sapnco.dll在ASP.NET中载入失败的解决方法(九)

分类: SAP顾问进行时 2011-11-21 16:51 1646人阅读 评论(0) 收藏 举报

当所有一切代码准备就绪之后,如果是ASP.NET那就是要发布网站到服务器了。如果服务器上的系统是WIN2003,那很不幸,系统会提示这样的“红脸”过来:

意思是说sapnco_utils.dll和sapnco.dll这两个文件不能载入。

Could not load file or assembly "sapnco_utils,Version=3.0.0.42,...

网上查找了方法也不尽然,各说纷纭。但是在WIN2008下的IIS7跟WinXP下的IIS5.1都可以完全正常,但是这个WIN2003就不行。

后来在对这两个DLL进行分析的时候发现它们是用VC++2005开发的,想到WIN2003系统可能没有必要的运行库。于是在工作站测试的时候安装了VC++2005 32bit版,然后刷新一切就正常了!

解决方法:安装相应vc++2005运行库即可!(实践证明:VC++2008不行!)

附VC++2005 32位运行库下载地址:

https://files.cnblogs.com/mengxin523/vcredist2005sp1_x86_XiaZaiBa.zip

.NET连接SAP系统专题:BAPI_TRANSACTION_COMMIT的使用方法(十)

分类: SAP顾问进行时 2011-11-21 16:52 1518人阅读 评论(1) 收藏 举报

为什么.net调用SAP的BAPI接口需要调用BAPI_TRANSACTION_COMMIT呢?首先得明白BAPI_TRANSACTION_COMMIT这个BAPI的作用。它功劳很大,在SAP里面很多的BAPI直接调用是不会有结果的,因为需要COMMIT一下才能生效,比如生成资产编号的BAPI:BAPI_FIXEDASSET_CREATE1,如果对他直接在SE37中调用运行或者使用SE38调用它,虽然可以得到一个资产编号,但是在AS03里面查询,系统会很白痴得提示你:该资产编号不存在于XX公司。更搞的是当你在AS01中新建资产编号时,新建的资产编号会跳过之前用BAPI生成“失败”的号码。

  那么,这就需要COMMIT一下,在调用这个BAPI之后再紧接调用BAPI_TRANSACTION_COMMIT这个。但是,在SE38中是可以这样做,而在.net中就没那么简单了,直接在调用完BAPI_FIXEDASSET_CREATE1之后再紧接调用BAPI_TRANSACTION_COMMIT是不可以的,虽然还是生成了资产编号,但仍旧是个废号。跟在SE37中调用无异。

  怎么在.net中解决这个问题呢,这就需要用到RfcSessionManager.BeginContext和RfcSessionManager.EndContext这两个方法了。只有在这两个方法之间调用BAPI才能方保万无一失!

  代码如下:

  1、首先引用:using SAP.Middleware.Connector;

  2、调用代码:

public void nco(DataSet ds)
{
IDestinationConfiguration ID = new RfcConfig();
RfcDestinationManager.RegisterDestinationConfiguration(ID);
RfcDestination prd = RfcDestinationManager.GetDestination("PRD_000");
RfcDestinationManager.UnregisterDestinationConfiguration(ID);
nco(prd, ds);
}
public void nco(RfcDestination prd, DataSet ds)
{
bool asset = false;
//选择要调用的BAPI的名称
RfcFunctionMetadata BAPI_COMPANYCODE_GETDETAIL_MD = prd.Repository.GetFunctionMetadata("BAPI_REQUISITION_CREATE");
//新建调用该BAPI的一个“实例”
IRfcFunction function = null;
function = BAPI_COMPANYCODE_GETDETAIL_MD.CreateFunction();
IRfcTable ITEMS = function.GetTable("REQUISITION_ITEMS");
IRfcTable ACCOUNT = function.GetTable("REQUISITION_ACCOUNT_ASSIGNMENT");
IRfcTable RETURN = function.GetTable("RETURN");
int j = 0;
RfcSessionManager.BeginContext(prd);  //因期间需要同一个时间调用BAPI,而且各个BAPI之间有顺序关联,所以最好用这个包围起来
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
ITEMS.Insert();
j = j + 1;
j = j * 10;
ITEMS.CurrentRow.SetValue("PREQ_ITEM", j.ToString());
ITEMS.CurrentRow.SetValue("PREQ_NAME", ds.Tables[0].Rows[i]["QGA27"].ToString());
ITEMS.CurrentRow.SetValue("CREATED_BY", ds.Tables[0].Rows[i]["QGA27"].ToString());
ITEMS.CurrentRow.SetValue("PREQ_DATE", Convert.ToDateTime(ds.Tables[0].Rows[i]["QGA15"].ToString()).Date);
ITEMS.CurrentRow.SetValue("MATERIAL", ds.Tables[0].Rows[i]["QGA04"].ToString());
ITEMS.CurrentRow.SetValue("SHORT_TEXT", ds.Tables[0].Rows[i]["QGA05"].ToString());
ITEMS.CurrentRow.SetValue("PLANT", "1201");
ITEMS.CurrentRow.SetValue("QUANTITY", Convert.ToDecimal(ds.Tables[0].Rows[i]["QGA07"].ToString()));
ITEMS.CurrentRow.SetValue("DELIV_DATE", Convert.ToDateTime(ds.Tables[0].Rows[i]["QGA09"].ToString()).Date);
ITEMS.CurrentRow.SetValue("C_AMT_BAPI", Convert.ToDecimal(ds.Tables[0].Rows[i]["QGA14"].ToString()));
ITEMS.CurrentRow.SetValue("ACCTASSCAT", ds.Tables[0].Rows[i]["QGA12"].ToString());
ITEMS.CurrentRow.SetValue("DOC_TYPE", ds.Tables[0].Rows[i]["QGA28"].ToString());
ITEMS.CurrentRow.SetValue("UNIT", ds.Tables[0].Rows[i]["QGA06"].ToString());

ACCOUNT.Insert();
ACCOUNT.CurrentRow.SetValue("PREQ_ITEM", j.ToString());
ACCOUNT.CurrentRow.SetValue("COST_CTR", ds.Tables[0].Rows[i]["QGA31"].ToString());
ACCOUNT.CurrentRow.SetValue("ORDER_NO", ds.Tables[0].Rows[i]["QGA10"].ToString());

if (ds.Tables[0].Rows[i]["QGA12"].ToString().Trim() == "A")  //如果类别是A,即资产,则需要资产编号
{
ACCOUNT.CurrentRow.SetValue("ASSET_NO", GetASSET(prd, i, ds));  //设置新建的资产编号
ACCOUNT.CurrentRow.SetValue("CO_AREA", "1000");
ACCOUNT.CurrentRow.SetValue("SUB_NUMBER", "0000");
}
}
function.SetValue("REQUISITION_ITEMS", ITEMS);
function.SetValue("REQUISITION_ACCOUNT_ASSIGNMENT", ACCOUNT);
function.Invoke(prd);//提交调用BAPI
RfcSessionManager.EndContext(prd);
if (RETURN.GetString("TYPE").ToString().Trim() == "I")
{
Suess.Text = RETURN.GetString("MESSAGE").ToString();
BANFN.Text = "返回的请购单号:" + function.GetString("NUMBER").Trim();
}
else if (RETURN.GetString("TYPE").ToString().Trim() == "E")
{
Error.Text = RETURN.GetString("MESSAGE").ToString();
}
prd = null;
}
///


/// 取得资产编号
///

///
///
public string GetASSET(RfcDestination prd, int i, DataSet ds)
{
RfcFunctionMetadata BAPI_COMPANYCODE_GETDETAIL_MD = prd.Repository.GetFunctionMetadata("BAPI_FIXEDASSET_CREATE1");
IRfcFunction function = null;
function = BAPI_COMPANYCODE_GETDETAIL_MD.CreateFunction();
IRfcStructure KEY = function.GetStructure("KEY");
KEY.SetValue("COMPANYCODE", "2012");
IRfcStructure GENERALDATA = function.GetStructure("GENERALDATA");
GENERALDATA.SetValue("ASSETCLASS", "00005990");
GENERALDATA.SetValue("DESCRIPT", ds.Tables[0].Rows[i]["QGA05"].ToString());
IRfcStructure GENERALDATAX = function.GetStructure("GENERALDATAX");
GENERALDATAX.SetValue("ASSETCLASS", "X");
GENERALDATAX.SetValue("DESCRIPT", "X");
function.SetValue("KEY", KEY);
function.SetValue("GENERALDATA", GENERALDATA);
function.SetValue("GENERALDATAX", GENERALDATAX);

prd.Repository.ClearFunctionMetadata();  //貌似这句可以省略...
RfcFunctionMetadata BAPI_COMPANYCODE_GETDETAIL_MD1 = prd.Repository.GetFunctionMetadata("BAPI_TRANSACTION_COMMIT");
IRfcFunction function1 = null;
function1 = BAPI_COMPANYCODE_GETDETAIL_MD1.CreateFunction();
function1.SetValue("WAIT", "X");
RfcSessionManager.BeginContext(prd);
function.Invoke(prd);   //提交调用BAPI_FIXEDASSET_CREATE1  生成资产编号
function1.Invoke(prd);  //提交调用BAPI_TRANSACTION_COMMIT 进行COMMIT一下
RfcSessionManager.EndContext(prd);
twMsgbox.AjaxAlert(function.GetValue("ASSET").ToString().Trim());
return function.GetValue("ASSET").ToString().Trim();
}

新建立之后的请购单一切OK,同时,建立的资产编号在AS03已经可以认出来了!!


新闻名称:转博客园一位前辈关于.NET通过NCO3.0连接SAP的系列文章-创新互联
当前地址:http://pwwzsj.com/article/cojhps.html